@optionfactory/ful 0.103.0 → 0.104.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
- var ful=function(t,e,s){"use strict";class r{static encode(t,e){const s=e||r.URL_SAFE,i=t.byteLength,n=new Uint8Array(t);let a="";for(let t=0;t<i;t+=3){a+=s[n[t]>>2]+s[(3&n[t])<<4|n[t+1]>>4]+s[(15&n[t+1])<<2|n[t+2]>>6]+s[63&n[t+2]]}return i%3==2?a=a.substring(0,a.length-1):i%3==1&&(a=a.substring(0,a.length-2)),a}static decode(t,e){const s=e||r.URL_SAFE;let i=Math.floor(.75*t.length);for(let e=0;e!==t.length&&"="===t[t.length-e-1];++e)--i;const n=new Uint8Array(i);let a=0,o=0;for(;a<.75*t.length;){const e=s.indexOf(t.charAt(o++)),r=s.indexOf(t.charAt(o++)),i=s.indexOf(t.charAt(o++)),l=s.indexOf(t.charAt(o++));n[a++]=e<<2|r>>4,n[a++]=(15&r)<<4|i>>2,n[a++]=(3&i)<<6|l}return n.buffer}}r.STANDARD="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",r.URL_SAFE="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";class i extends Error{constructor(t,e,s){super(t,{cause:s}),this.name="Failure",this.problems=e}}class n{#t;#e;constructor(t,e){this.#t=t,this.#e=e}get normalized(){return`${this.#t}/${this.#e}`}get type(){return this.#t}get subtype(){return this.#e}static parse(t){if(!t)return new n("unknown","unknown");const[e,s]=t.split(";"),[r,i]=e.trim().split("/");return new n(r.toLowerCase(),i?.toLowerCase())}}class a extends i{constructor(t,e,s,r){super(t,s,r),this.name="HttpClientError",this.status=e}static of(t,e){return new a(e.message,0,[{type:t,context:null,reason:e.message,details:null}],e)}static async fromResponse(t){switch(n.parse(t.headers.get("Content-Type")).normalized){case"application/failures+json":{const e=await t.json(),s=`${t.status} ${t.statusText}: ${e.length} failures`;return new a(s,t.status,e)}case"application/problem+json":{const e=await t.json(),s=`${t.status} ${t.statusText}: ${e.title} ${e.detail}`;return new a(s,t.status,e.problems||[{type:"GENERIC_PROBLEM",context:null,reason:s,details:null}])}default:{const e=await t.text(),s=`${t.status} ${t.statusText}: ${e}`;return new a(s,t.status,[{type:"GENERIC_PROBLEM",context:null,reason:s,details:null}])}}}}class o{#s;#r;constructor(){this.#s=document.querySelector("meta[name='_csrf_header']")?.getAttribute("content"),this.#r=document.querySelector("meta[name='_csrf']")?.getAttribute("content")}async intercept(t,e){return this.#s&&this.#r&&t.headers.set(this.#s,this.#r),await e.proceed(t)}}class l{#i;constructor(t){this.#i=t}async intercept(t,e){const s=await e.proceed(t);return 401===s.status&&(window.location.href=this.#i),s}}class c{#n;constructor(){this.#n=[]}withCsrfToken(){return this.#n.push(new o),this}withRedirectOnUnauthorized(t){return this.#n.push(new l(t)),this}withInterceptors(...t){return this.#n.push(...t),this}build(){return new d(this.#n)}}class h{async intercept(t,e){return await fetch(t)}}class u{#n;#a;constructor(t,e){this.#n=t,this.#a=e}async proceed(t){const e=this.#n[this.#a];return await e.intercept(t,new u(this.#n,this.#a+1))}}class d{#n;static builder(){return new c}constructor(t){this.#n=t||[]}async exchange(t,e,s){const r=[...this.#n,...s||[],new h],i=new u(r,0);return await i.proceed(new Request(t,e))}request(t,e){return f.create(this,t,e)}get(t){return f.create(this,"GET",t)}head(t){return f.create(this,"HEAD",t)}post(t){return f.create(this,"POST",t)}put(t){return f.create(this,"PUT",t)}patch(t){return f.create(this,"PATCH",t)}delete(t){return f.create(this,"DELETE",t)}}const p=async(t,e)=>{try{return await t[e]()}catch(t){throw a.of("UNMARSHALING_PROBLEM",t)}};class f{#o;#l;#c;#h;#u;#d;#p;#n;static create(t,e,s){return new f(t,e,s,new URLSearchParams,new Headers,void 0,{},[])}constructor(t,e,s,r,i,n,a,o){this.#o=t,this.#l=e,this.#c=s,this.#h=r,this.#d=n,this.#u=i,this.#p=a,this.#n=o}headers(t){for(const[e,s]of new Headers(t).entries())null==s?this.#u.delete(e):this.#u.set(e,s);return this}header(t,e){return null==e?this.#u.delete(t):this.#u.set(t,e),this}params(t){for(const[e,s]of new URLSearchParams(t).entries())null==s?this.#h.delete(e):this.#h.set(e,s);return this}param(t,e){return null==e?this.#h.delete(t):this.#h.set(t,e),this}body(t){return this.#d=t,this}json(t){return this.#u.set("Content-Type","application/json"),this.#d=JSON.stringify(t),this}multipart(t){const e=new FormData;return t(new m(e)),this.#d=e,this}options(t){for(const[e,s]of Object.entries(t))this.#p[e]=s;return this}option(t,e){return this.#p[t]=e,this}interceptors(t){for(const e of t)this.#n.push(e);return this}interceptor(t){return this.#n.push(t),this}async exchange(){const t=this.#h.size?`${this.#c}?${this.#h}`:this.#c,e={...this.#p,headers:this.#u,method:this.#l,body:this.#d};return await this.#o.exchange(t,e,this.#n)}async fetch(){const t=this.#h.size?`${this.#c}?${this.#h}`:this.#c,e={...this.#p,headers:this.#u,method:this.#l,body:this.#d};try{const s=await this.#o.exchange(t,e,this.#n);if(!s.ok)throw await a.fromResponse(s);return s}catch(t){if(t instanceof i)throw t;throw a.of("CONNECTION_PROBLEM",t)}}async fetchText(){const t=await this.fetch();return await p(t,"text")}async fetchJson(){const t=await this.fetch();return await p(t,"json")}async fetchBlob(){const t=await this.fetch();return await p(t,"blob")}async fetchArrayBuffer(){const t=await this.fetch();return await p(t,"arrayBuffer")}}class m{#f;constructor(t){this.#f=t}field(t,e){return this.#f.append(t,e),this}blob(t,e,s){return this.#f.append(t,e,s),this}blobs(t,e){for(let s of e)this.#f.append(t,s);return this}json(t,e,s){const r=new Blob([JSON.stringify(e)],{type:"application/json"});return this.#f.append(t,r,s),this}}class g{constructor(t,e){this.prefix=t,this.storage=e}save(t,e){this.storage.setItem(`${this.prefix}-${t}`,JSON.stringify(e))}load(t){const e=this.storage.getItem(`${this.prefix}-${t}`);return void 0===e?void 0:JSON.parse(e)}remove(t){this.storage.removeItem(`${this.prefix}-${t}`)}pop(t){const e=this.load(t);return this.remove(t),e}}class w extends g{constructor(t){super(t,sessionStorage)}}class b{static forKeycloak(t,e,s){return new b(t,"openid profile",{auth:new URL("protocol/openid-connect/auth",e),token:new URL("protocol/openid-connect/token",e),logout:new URL("protocol/openid-connect/logout",e),registration:new URL("protocol/openid-connect/registrations",e),redirect:s})}constructor(t,e,{auth:s,token:r,registration:i,logout:n,redirect:a}){this.storage=new w(t),this.clientId=t,this.scope=e,this.uri={auth:s,token:r,registration:i,logout:n,redirect:a}}async action(t,e){const s=r.encode(crypto.getRandomValues(new Uint8Array(32)).buffer),i=r.encode(await crypto.subtle.digest("SHA-256",(new TextEncoder).encode(s))),n=this.clientId+r.encode(crypto.getRandomValues(new Uint8Array(16)).buffer);this.storage.save(b.PKCE_AND_STATE_KEY,{state:n,verifier:s});const a=new URL(t);a.searchParams.set("client_id",this.clientId),a.searchParams.set("redirect_uri",this.uri.redirect),a.searchParams.set("response_type","code"),a.searchParams.set("scope",this.scope),a.searchParams.set("state",n),a.searchParams.set("code_challenge",i),a.searchParams.set("code_challenge_method","S256"),Object.entries(e||{}).forEach((t=>{a.searchParams.set(t[0],t[1])})),window.location.href=a.toString()}async registration(t){await this.action(this.uri.registration,t)}async applicationInitiatedAction(t,e){await this.action(this.uri.auth,{...e,kc_action:t})}async#m(t,e){window.history.replaceState("","",this.uri.redirect);const s=this.storage.pop(b.PKCE_AND_STATE_KEY);if(s.state!==e)throw new Error("State mismatch");const r=await fetch(this.uri.token,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams([["client_id",this.clientId],["code",t],["grant_type","authorization_code"],["code_verifier",s.verifier],["state",s.state],["redirect_uri",this.uri.redirect]])});if(!r.ok){const t=await r.text();throw new Error("Error:"+r.status+": "+t)}const i=await r.json();return new y(this.clientId,i,this.uri)}async ensureLoggedIn(){const t=new URL(window.location.href),e=t.searchParams.get("code");if(e&&this.storage.load(b.PKCE_AND_STATE_KEY)){const s=t.searchParams.get("state");return await this.#m(e,s)}return await this.action(this.uri.auth,{}),null}}b.PKCE_AND_STATE_KEY="state-and-verifier";class y{static parseToken(t){const[e,s,i]=t.split("."),n=new TextDecoder("utf-8");return{header:JSON.parse(n.decode(r.decode(e,r.STANDARD))),payload:JSON.parse(n.decode(r.decode(s,r.STANDARD))),signature:i}}constructor(t,e,{token:s,logout:r,redirect:i}){this.clientId=t,this.token=e,this.idToken=y.parseToken(e.id_token),this.accessToken=y.parseToken(e.access_token),this.refreshToken=y.parseToken(e.refresh_token),this.uri={token:s,logout:r,redirect:i},this.refreshCallback=null}onRefresh(t){this.refreshCallback=t}async refresh(){const t=await fetch(this.uri.token,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams([["client_id",this.clientId],["grant_type","refresh_token"],["refresh_token",this.token.refresh_token]])});if(!t.ok){const e=await t.text();throw new Error("Error:"+t.status+": "+e)}const e=await t.json();this.token=e,this.idToken=y.parseToken(e.id_token),this.accessToken=y.parseToken(e.access_token),this.refreshToken=y.parseToken(e.refresh_token),this.refreshCallback&&this.refreshCallback(this.token,this.accessToken,this.refreshToken)}shouldBeRefreshed(t){const e=(new Date).getTime(),s=1e3*this.refreshToken.payload.exp;return!(e>s)&&e-t>s}async refreshIf(t){this.shouldBeRefreshed(t)&&await this.refresh()}logout(){const t=new URL(this.uri.logout);t.searchParams.set("post_logout_redirect_uri",this.uri.redirect),t.searchParams.set("id_token_hint",this.token.id_token),window.location.href=t.toString()}bearerToken(){return`Bearer ${this.token.access_token}`}interceptor(t,e){return new v(this,t,e)}}class v{#g;#w;#b;constructor(t,e,s){this.#g=t,this.#w=e||2e3,this.#b=s||3e4}async intercept(t,e){await this.#g.refreshIf(this.#w),t.headers.set("Authorization",this.#g.bearerToken());const s=await e.proceed(t);return await this.#g.refreshIf(this.#b),s}}const A={sleep:t=>new Promise((e=>setTimeout(e,t))),DEBOUNCE_DEFAULT:0,DEBOUNCE_IMMEDIATE:1,debounce(t,e,s){let r=null,i=[],n=0,a=s||A.DEBOUNCE_DEFAULT;const o=()=>{const s=(new Date).getTime()-n;t>s?r=setTimeout(o,t-s):(r=null,a!==A.DEBOUNCE_IMMEDIATE&&e(...i),null===r&&(i=[]))};return function(){i=[...arguments],n=(new Date).getTime(),null===r&&(r=setTimeout(o,t),a===A.DEBOUNCE_IMMEDIATE&&e(...i))}},THROTTLE_DEFAULT:0,THROTTLE_NO_LEADING:1,THROTTLE_NO_TRAILING:2,throttle(t,e,s){let r=null,i=[],n=0,a=s||A.THROTTLE_DEFAULT;const o=()=>{n=a&A.THROTTLE_NO_LEADING?0:(new Date).getTime(),r=null,e(...i),null===r&&(i=[])};return function(){const s=(new Date).getTime();!n&&a&A.THROTTLE_NO_LEADING&&(n=s);const l=t-(s-n);i=[...arguments],l<=0||l>t?(null!==r&&(clearTimeout(r),r=null),n=s,e(...i),null===r&&(i=[])):null!==r||a&A.THROTTLE_NO_TRAILING||(r=setTimeout(o,l))}}};class E{static flatten(t,e){return Object.keys(t).reduce(((s,r)=>{const i=e.length?e+".":"";return"object"==typeof t[r]&&null!==t[r]?Object.assign(s,E.flatten(t[r],i+r)):s[i+r]=t[r],s}),{})}static providePath(t,e,s){const r=e.split(".").map((t=>/^[0-9]+$/.test(t)?+t:t));let i=t??{},n=null;for(let e=0;;++e){const a=r[e],o=r[e-1];if(Number.isInteger(a)&&!Array.isArray(i)&&(null!==n?n[o]=i=[]:t=i=[]),e===r.length-1)return i[a]=void 0!==s?s:a in i?i[a]:null,t;void 0===i[a]&&(i[a]={}),n=i,i=i[a]}}static extract(t){if("radio"===t.getAttribute("type")){if(!t.checked)return;return"boolean"===t.dataset.fulBindType?"true"===t.value:t.value}return"checkbox"===t.getAttribute("type")?t.checked:"boolean"===t.dataset.fulBindType?t.value?"true"===t.value:null:!("INPUT"!==t.tagName&&"SELECT"!==t.tagName||""!==t.value&&void 0!==t.value)?null:t.value}static extractFrom(t,e){let s={};for(const r of t.querySelectorAll("[name]"))"never"!==r.dataset.fulBindInclude&&(e&&"always"!==r.dataset.fulBindInclude&&null!==r.closest(e)||(s=E.providePath(s,r.getAttribute("name"),E.extract(r))));return s}static mutate(t,e){"radio"!==t.getAttribute("type")?"checkbox"!==t.getAttribute("type")?t.value=e:t.checked=e:t.checked=t.getAttribute("value")===e}static mutateIn(t,e){for(const[s,r]of Object.entries(E.flatten(e,"")))for(const e of t.querySelectorAll(`[name='${CSS.escape(s)}']`))E.mutate(e,r)}static errors(t,e,s){const r=e.filter((t=>"FIELD_ERROR"===t.type||"INVALID_FORMAT"===t.type)),i=e.filter((t=>"FIELD_ERROR"!==t.type&&"INVALID_FORMAT"!==t.type));t.querySelectorAll(`.${CSS.escape(s)}`).forEach((t=>t.classList.remove(s))),t.querySelectorAll("ful-errors").forEach((t=>{t.replaceChildren(),t.setAttribute("hidden","")})),r.forEach((e=>{const r=e.context.replace("[",".").replace("].","."),i=`[name='${CSS.escape(r)}'] [ful-validation-target],[name='${CSS.escape(r)}']:not(:has([ful-validation-target]))`;t.querySelectorAll(i).forEach((t=>t.classList.add(s)));const n=`ful-field-error[field='${CSS.escape(r)}']`;t.querySelectorAll(n).forEach((t=>{t.innerText=e.reason}))})),t.querySelectorAll("ful-errors").forEach((t=>{t.innerText=i.map((t=>t.reason)).join("\n"),0!==i.length&&t.removeAttribute("hidden")}))}}class T extends(e.ParsedElement()){static IGNORED_CHILDREN_SELECTOR=".d-none, [hidden]";static SCROLL_OFFSET=50;static INVALID_CLASS="is-invalid";submitter;render(){const t=document.createElement("form");e.Attributes.forward("form-",this,t),t.replaceChildren(...this.childNodes),t.addEventListener("submit",(async t=>{t.preventDefault(),this.spinning((async()=>{await(this.submitter?.(this.values,this))}))})),this.hasAttribute("clear-invalid-on-change")&&this.addEventListener("change",(t=>{const e=t.target;e?.querySelectorAll(`.${CSS.escape(T.INVALID_CLASS)}`).forEach((t=>{t.classList.remove(T.INVALID_CLASS)}))})),this.replaceChildren(t)}spinner(t){this.querySelectorAll("ful-spinner").forEach((e=>{e.hidden=!t})),this.querySelectorAll("[type=submit],[type=reset]").forEach((e=>{e.disabled=t}))}async remoting(t){try{await t()}catch(t){throw t instanceof i&&(this.errors=t.problems),t}}async spinningUntilError(t){this.spinner(!0);try{await this.remoting(t)}catch(t){throw this.spinner(!1),t}}async spinning(t){this.spinner(!0);try{await this.remoting(t)}finally{this.spinner(!1)}}set values(t){E.mutateIn(this,t)}get values(){return E.extractFrom(this,T.IGNORED_CHILDREN_SELECTOR)}set errors(t){if(E.errors(this,t,T.INVALID_CLASS),0==t.length||!this.hasAttribute("scroll-on-error"))return;const e=Array.from(this.querySelectorAll(`ful-errors:not([hidden]), [ful-validated-field]:has(.${T.INVALID_CLASS}) ful-field-error`)).map((t=>t.parentElement?t.parentElement:t)).map((t=>t.getBoundingClientRect().y+window.scrollY)),s=Math.min(...e);s!==1/0&&window.scroll(window.scrollX,s>T.SCROLL_OFFSET?s-T.SCROLL_OFFSET:0)}}const S='\n<div ful-validated-field>\n <label data-tpl-for="id" class="form-label">{{{{ slots.default }}}}</label>\n <div class="input-group">\n <span data-tpl-if="slots.ibefore" class="input-group-text">{{{{ slots.ibefore }}}}</span>\n <div data-tpl-if="slots.before" data-tpl-remove="tag">{{{{ slots.before }}}}</div>\n {{{{ slots.input }}}} \n <div data-tpl-if="slots.after" data-tpl-remove="tag">{{{{ slots.after }}}}</div>\n <span data-tpl-if="slots.iafter" class="input-group-text">{{{{ slots.iafter }}}}</span>\n </div>\n <ful-field-error data-tpl-if="name" data-tpl-field="name"></ful-field-error>\n</div>\n',_=(t,s,r)=>{const i=t.input=r.input=r.input?.firstElementChild??(()=>{const t=document.createElement("input");return t.classList.add("form-control"),t})();i.setAttribute("ful-validation-target",""),i.addEventListener("change",(e=>{e.stopPropagation(),t.dispatchEvent(new CustomEvent("change",{bubbles:!0,cancelable:!1,detail:{value:t.value}}))}));const n=i.getAttribute("id")??t.getAttribute("input-id")??e.Attributes.uid("ful-input");e.Attributes.forward("input-",t,r.input),e.Attributes.defaultValue(r.input,"id",n),e.Attributes.defaultValue(r.input,"type","text"),e.Attributes.defaultValue(r.input,"placeholder"," ");const a=t.getAttribute("name");return s.withOverlay(t,{id:n,name:a,slots:r}).render()};class L extends(e.ParsedElement({observed:["value"],slots:!0,template:S})){input;render({slots:t}){const e=_(this,this.template(),t);this.replaceChildren(e)}get value(){return this.input.value}set value(t){this.input.value=t}}class k extends(e.ParsedElement({observed:["value"],slots:!0,template:'\n <div ful-validated-field>\n <label data-tpl-for="tsId" class="form-label">{{{{ slots.default }}}}</label>\n {{{{ input }}}}\n <div class="input-group">\n <span data-tpl-if="slots.ibefore" class="input-group-text">{{{{ slots.ibefore }}}}</span>\n <div data-tpl-if="slots.before" data-tpl-remove="tag">{{{{ slots.before }}}}</div>\n {{{{ slots.input }}}} \n <div data-tpl-if="slots.after" data-tpl-remove="tag">{{{{ slots.after }}}}</div>\n <span data-tpl-if="slots.iafter" class="input-group-text">{{{{ slots.iafter }}}}</span>\n </div>\n <ful-field-error data-tpl-if="name" data-tpl-field="name"></ful-field-error>\n </div>\n '})){shouldLoad;_unwrappedRemoteLoad;ts;constructor(t){super(),this.tsConfig=t}render({slots:t}){const r="local"!=(this.getAttribute("type")??"local"),i="always"!=this.getAttribute("load"),n=this.getAttribute("name"),a=t.input=t.input?.firstElementChild??document.createElement("select");a.setAttribute("ful-validation-target","");const o=a.getAttribute("id")??this.getAttribute("input-id")??e.Attributes.uid("ful-select"),l=`${o}-ts-control`;e.Attributes.forward("input-",this,a),e.Attributes.defaultValue(a,"id",o),e.Attributes.defaultValue(a,"placeholder"," "),t.input=e.Fragments.from(a),this.loaded=!r;this._remote=r,this._unwrappedRemoteLoad=async(t,e)=>{if(!r||r&&i&&this.loaded)return void e();const s=t&&t.hasOwnProperty("byId")?"id":"query",n="id"===s?t.byId:t,a=await(this.#y?this.#y(n,s):[]);"id"!==s&&(this.loaded=!0),e(a)},this.ts=new s(a,Object.assign(r?{preload:"focus",load:this._unwrappedRemoteLoad,shouldLoad:t=>!this.shouldLoad||this.shouldLoad(t)}:{},{render:{loading:()=>'<ful-spinner class="centered p-2"></ful-spinner>'}},this.tsConfig)),this.ts.on("change",(t=>{this.dispatchEvent(new CustomEvent("change",{bubbles:!0,cancelable:!1,detail:{value:this.value}}))})),a.addEventListener("change",(t=>{t.stopPropagation()})),a.remove(),this.template().withOverlay({id:o,tsId:l,name:n,input:a,slots:t}).renderTo(this)}#y;set loader(t){this.#y=t,this.hasAttribute("value")&&(this.value=this.getAttribute("value"))}get value(){const t=this.ts.getValue();return""===t?null:t}set value(t){(async()=>{this._remote&&await this._unwrappedRemoteLoad({byId:t},this.ts.loadCallback.bind(this.ts));this.ts.setValue(t,!0)})()}}class I extends(e.ParsedElement({observed:["value","disabled:presence"],slots:!0,template:'\n <fieldset ful-validated-field>\n <legend class="form-label">\n {{{{ slots.default }}}}\n </legend>\n <header data-tpl-if="slots.header">\n {{{{ slots.header }}}}\n </header>\n <section>\n <div class="label-wrapper" data-tpl-each="inputsAndLabels" data-tpl-var="ial">\n <label>\n {{{{ ial[0] }}}}\n {{{{ ial[1] }}}}\n </label>\n </div>\n </section>\n <ful-field-error data-tpl-if="name" data-tpl-field="name"></ful-field-error>\n <footer data-tpl-if="slots.footer">\n {{{{ slots.footer }}}}\n </footer>\n </fieldset>\n '})){render({slots:t}){const s=this.getAttribute("name")??e.Attributes.uid("ful-radiogroup"),r=Array.from(t.default.querySelectorAll("ful-radio")),i=r.map((t=>{const r=document.createElement("input");r.setAttribute("type","radio"),e.Attributes.forward("input-",this,r),e.Attributes.forward("",t,r),r.setAttribute("name",`${s}-ignore`),r.setAttribute("ful-validation-target",""),r.dataset.fulBindInclude="never",r.addEventListener("change",(t=>{t.stopPropagation(),this.dispatchEvent(new CustomEvent("change",{bubbles:!0,cancelable:!1,detail:{value:this.value}}))}));return[r,e.Fragments.fromChildNodes(t)]}));r.forEach((t=>t.remove())),this.template().withOverlay({name:s,slots:t,inputsAndLabels:i}).renderTo(this)}get disabled(){return this.hasAttribute("disabled")}set disabled(t){this.reflect((()=>e.Attributes.toggle(this,"disabled",t)))}get value(){const t=this.querySelector("input[type=radio]:checked");return t?t.value:null}set value(t){if(null===t)return void this.querySelectorAll("input[type=radio]").forEach((t=>{t.checked=!1}));const e=this.querySelector(`input[type=radio][value=${CSS.escape(t)}]`);e&&(e.checked=!0)}}class C extends(e.ParsedElement({slots:!0,template:'\n <div class="ful-spinner-wrapper">\n <div class="ful-spinner-text">{{{{ slots.default }}}}</div>\n <div class="ful-spinner-icon"></div>\n </div>\n '})){render({slots:t}){this.template().withOverlay({slots:t}).renderTo(this)}}return t.AuthorizationCodeFlow=b,t.AuthorizationCodeFlowInterceptor=v,t.AuthorizationCodeFlowSession=y,t.Base64=r,t.Bindings=E,t.Deferred=class{constructor(){this.promise=new Promise(((t,e)=>{this.reject=e,this.resolve=t}))}},t.Failure=i,t.Form=T,t.Hex=class{static decode(t){if(t.length%2!=0)throw new Error("invalid length");const e=t.length/2;return new Uint8Array(e).map(((e,s)=>{const r=2*s,i=t.substring(r,r+2);return parseInt(i,16)}))}static encode(t,e){return Array.from(t).map((t=>t.toString(16))).map((t=>e?t.toUpperCase():t)).map((t=>t.padStart(2,0))).join("")}},t.HttpClient=d,t.HttpClientError=a,t.INPUT_TEMPLATE=S,t.Input=L,t.LocalStorage=class extends g{constructor(t){super(t,localStorage)}},t.MediaType=n,t.RadioGroup=I,t.Select=k,t.SessionStorage=w,t.Spinner=C,t.VersionedStorage=class{constructor(t,e,s){this.storage=t,this.key=e,this.dataSupplier=s,this.cache=null}async load(t){const e=this.storage.load(this.key);if(e&&e.revision===t)return void(this.cache=e.value);const s=await this.dataSupplier(t,this.key);this.storage.save(this.key,{revision:t,value:s}),this.cache=s}data(){return this.cache}},t.makeInputFragment=_,t.timing=A,t}({},ftl,window?.TomSelect||{});
1
+ var ful=function(t,e,s){"use strict";class r{static encode(t,e){const s=e||r.URL_SAFE,i=t.byteLength,n=new Uint8Array(t);let a="";for(let t=0;t<i;t+=3){a+=s[n[t]>>2]+s[(3&n[t])<<4|n[t+1]>>4]+s[(15&n[t+1])<<2|n[t+2]>>6]+s[63&n[t+2]]}return i%3==2?a=a.substring(0,a.length-1):i%3==1&&(a=a.substring(0,a.length-2)),a}static decode(t,e){const s=e||r.URL_SAFE;let i=Math.floor(.75*t.length);for(let e=0;e!==t.length&&"="===t[t.length-e-1];++e)--i;const n=new Uint8Array(i);let a=0,o=0;for(;a<.75*t.length;){const e=s.indexOf(t.charAt(o++)),r=s.indexOf(t.charAt(o++)),i=s.indexOf(t.charAt(o++)),l=s.indexOf(t.charAt(o++));n[a++]=e<<2|r>>4,n[a++]=(15&r)<<4|i>>2,n[a++]=(3&i)<<6|l}return n.buffer}}r.STANDARD="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",r.URL_SAFE="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";class i extends Error{constructor(t,e,s){super(t,{cause:s}),this.name="Failure",this.problems=e}}class n{#t;#e;constructor(t,e){this.#t=t,this.#e=e}get normalized(){return`${this.#t}/${this.#e}`}get type(){return this.#t}get subtype(){return this.#e}static parse(t){if(!t)return new n("unknown","unknown");const[e,s]=t.split(";"),[r,i]=e.trim().split("/");return new n(r.toLowerCase(),i?.toLowerCase())}}class a extends i{constructor(t,e,s,r){super(t,s,r),this.name="HttpClientError",this.status=e}static of(t,e){return new a(e.message,0,[{type:t,context:null,reason:e.message,details:null}],e)}static async fromResponse(t){switch(n.parse(t.headers.get("Content-Type")).normalized){case"application/failures+json":{const e=await t.json(),s=`${t.status} ${t.statusText}: ${e.length} failures`;return new a(s,t.status,e)}case"application/problem+json":{const e=await t.json(),s=`${t.status} ${t.statusText}: ${e.title} ${e.detail}`;return new a(s,t.status,e.problems||[{type:"GENERIC_PROBLEM",context:null,reason:s,details:null}])}default:{const e=await t.text(),s=`${t.status} ${t.statusText}: ${e}`;return new a(s,t.status,[{type:"GENERIC_PROBLEM",context:null,reason:s,details:null}])}}}}class o{#s;#r;constructor(){this.#s=document.querySelector("meta[name='_csrf_header']")?.getAttribute("content"),this.#r=document.querySelector("meta[name='_csrf']")?.getAttribute("content")}async intercept(t,e){return this.#s&&this.#r&&t.headers.set(this.#s,this.#r),await e.proceed(t)}}class l{#i;constructor(t){this.#i=t}async intercept(t,e){const s=await e.proceed(t);return 401===s.status&&(window.location.href=this.#i),s}}class c{#n;constructor(){this.#n=[]}withCsrfToken(){return this.#n.push(new o),this}withRedirectOnUnauthorized(t){return this.#n.push(new l(t)),this}withInterceptors(...t){return this.#n.push(...t),this}build(){return new d(this.#n)}}class u{async intercept(t,e){return await fetch(t)}}class h{#n;#a;constructor(t,e){this.#n=t,this.#a=e}async proceed(t){const e=this.#n[this.#a];return await e.intercept(t,new h(this.#n,this.#a+1))}}class d{#n;static builder(){return new c}constructor(t){this.#n=t||[]}async exchange(t,e,s){const r=[...this.#n,...s||[],new u],i=new h(r,0);return await i.proceed(new Request(t,e))}request(t,e){return f.create(this,t,e)}get(t){return f.create(this,"GET",t)}head(t){return f.create(this,"HEAD",t)}post(t){return f.create(this,"POST",t)}put(t){return f.create(this,"PUT",t)}patch(t){return f.create(this,"PATCH",t)}delete(t){return f.create(this,"DELETE",t)}}const p=async(t,e)=>{try{return await t[e]()}catch(t){throw a.of("UNMARSHALING_PROBLEM",t)}};class f{#o;#l;#c;#u;#h;#d;#p;#n;static create(t,e,s){return new f(t,e,s,new URLSearchParams,new Headers,void 0,{},[])}constructor(t,e,s,r,i,n,a,o){this.#o=t,this.#l=e,this.#c=s,this.#u=r,this.#d=n,this.#h=i,this.#p=a,this.#n=o}headers(t){for(const[e,s]of new Headers(t).entries())null==s?this.#h.delete(e):this.#h.set(e,s);return this}header(t,e){return null==e?this.#h.delete(t):this.#h.set(t,e),this}params(t){for(const[e,s]of new URLSearchParams(t).entries())null==s?this.#u.delete(e):this.#u.set(e,s);return this}param(t,e){return null==e?this.#u.delete(t):this.#u.set(t,e),this}body(t){return this.#d=t,this}json(t){return this.#h.set("Content-Type","application/json"),this.#d=JSON.stringify(t),this}multipart(t){const e=new FormData;return t(new m(e)),this.#d=e,this}options(t){for(const[e,s]of Object.entries(t))this.#p[e]=s;return this}option(t,e){return this.#p[t]=e,this}interceptors(t){for(const e of t)this.#n.push(e);return this}interceptor(t){return this.#n.push(t),this}async exchange(){const t=this.#u.size?`${this.#c}?${this.#u}`:this.#c,e={...this.#p,headers:this.#h,method:this.#l,body:this.#d};return await this.#o.exchange(t,e,this.#n)}async fetch(){const t=this.#u.size?`${this.#c}?${this.#u}`:this.#c,e={...this.#p,headers:this.#h,method:this.#l,body:this.#d};try{const s=await this.#o.exchange(t,e,this.#n);if(!s.ok)throw await a.fromResponse(s);return s}catch(t){if(t instanceof i)throw t;throw a.of("CONNECTION_PROBLEM",t)}}async fetchText(){const t=await this.fetch();return await p(t,"text")}async fetchJson(){const t=await this.fetch();return await p(t,"json")}async fetchBlob(){const t=await this.fetch();return await p(t,"blob")}async fetchArrayBuffer(){const t=await this.fetch();return await p(t,"arrayBuffer")}}class m{#f;constructor(t){this.#f=t}field(t,e){return this.#f.append(t,e),this}blob(t,e,s){return this.#f.append(t,e,s),this}blobs(t,e){for(let s of e)this.#f.append(t,s);return this}json(t,e,s){const r=new Blob([JSON.stringify(e)],{type:"application/json"});return this.#f.append(t,r,s),this}}class g{constructor(t,e){this.prefix=t,this.storage=e}save(t,e){this.storage.setItem(`${this.prefix}-${t}`,JSON.stringify(e))}load(t){const e=this.storage.getItem(`${this.prefix}-${t}`);return void 0===e?void 0:JSON.parse(e)}remove(t){this.storage.removeItem(`${this.prefix}-${t}`)}pop(t){const e=this.load(t);return this.remove(t),e}}class w extends g{constructor(t){super(t,sessionStorage)}}class b{static forKeycloak(t,e,s){return new b(t,"openid profile",{auth:new URL("protocol/openid-connect/auth",e),token:new URL("protocol/openid-connect/token",e),logout:new URL("protocol/openid-connect/logout",e),registration:new URL("protocol/openid-connect/registrations",e),redirect:s})}constructor(t,e,{auth:s,token:r,registration:i,logout:n,redirect:a}){this.storage=new w(t),this.clientId=t,this.scope=e,this.uri={auth:s,token:r,registration:i,logout:n,redirect:a}}async action(t,e){const s=r.encode(crypto.getRandomValues(new Uint8Array(32)).buffer),i=r.encode(await crypto.subtle.digest("SHA-256",(new TextEncoder).encode(s))),n=this.clientId+r.encode(crypto.getRandomValues(new Uint8Array(16)).buffer);this.storage.save(b.PKCE_AND_STATE_KEY,{state:n,verifier:s});const a=new URL(t);a.searchParams.set("client_id",this.clientId),a.searchParams.set("redirect_uri",this.uri.redirect),a.searchParams.set("response_type","code"),a.searchParams.set("scope",this.scope),a.searchParams.set("state",n),a.searchParams.set("code_challenge",i),a.searchParams.set("code_challenge_method","S256"),Object.entries(e||{}).forEach((t=>{a.searchParams.set(t[0],t[1])})),window.location.href=a.toString()}async registration(t){await this.action(this.uri.registration,t)}async applicationInitiatedAction(t,e){await this.action(this.uri.auth,{...e,kc_action:t})}async#m(t,e){window.history.replaceState("","",this.uri.redirect);const s=this.storage.pop(b.PKCE_AND_STATE_KEY);if(s.state!==e)throw new Error("State mismatch");const r=await fetch(this.uri.token,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams([["client_id",this.clientId],["code",t],["grant_type","authorization_code"],["code_verifier",s.verifier],["state",s.state],["redirect_uri",this.uri.redirect]])});if(!r.ok){const t=await r.text();throw new Error("Error:"+r.status+": "+t)}const i=await r.json();return new y(this.clientId,i,this.uri)}async ensureLoggedIn(){const t=new URL(window.location.href),e=t.searchParams.get("code");if(e&&this.storage.load(b.PKCE_AND_STATE_KEY)){const s=t.searchParams.get("state");return await this.#m(e,s)}return await this.action(this.uri.auth,{}),null}}b.PKCE_AND_STATE_KEY="state-and-verifier";class y{static parseToken(t){const[e,s,i]=t.split("."),n=new TextDecoder("utf-8");return{header:JSON.parse(n.decode(r.decode(e,r.STANDARD))),payload:JSON.parse(n.decode(r.decode(s,r.STANDARD))),signature:i}}constructor(t,e,{token:s,logout:r,redirect:i}){this.clientId=t,this.token=e,this.idToken=y.parseToken(e.id_token),this.accessToken=y.parseToken(e.access_token),this.refreshToken=y.parseToken(e.refresh_token),this.uri={token:s,logout:r,redirect:i},this.refreshCallback=null}onRefresh(t){this.refreshCallback=t}async refresh(){const t=await fetch(this.uri.token,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams([["client_id",this.clientId],["grant_type","refresh_token"],["refresh_token",this.token.refresh_token]])});if(!t.ok){const e=await t.text();throw new Error("Error:"+t.status+": "+e)}const e=await t.json();this.token=e,this.idToken=y.parseToken(e.id_token),this.accessToken=y.parseToken(e.access_token),this.refreshToken=y.parseToken(e.refresh_token),this.refreshCallback&&this.refreshCallback(this.token,this.accessToken,this.refreshToken)}shouldBeRefreshed(t){const e=(new Date).getTime(),s=1e3*this.refreshToken.payload.exp;return!(e>s)&&e-t>s}async refreshIf(t){this.shouldBeRefreshed(t)&&await this.refresh()}logout(){const t=new URL(this.uri.logout);t.searchParams.set("post_logout_redirect_uri",this.uri.redirect),t.searchParams.set("id_token_hint",this.token.id_token),window.location.href=t.toString()}bearerToken(){return`Bearer ${this.token.access_token}`}interceptor(t,e){return new v(this,t,e)}}class v{#g;#w;#b;constructor(t,e,s){this.#g=t,this.#w=e||2e3,this.#b=s||3e4}async intercept(t,e){await this.#g.refreshIf(this.#w),t.headers.set("Authorization",this.#g.bearerToken());const s=await e.proceed(t);return await this.#g.refreshIf(this.#b),s}}const A={sleep:t=>new Promise((e=>setTimeout(e,t))),DEBOUNCE_DEFAULT:0,DEBOUNCE_IMMEDIATE:1,debounce(t,e,s){let r=null,i=[],n=0,a=s||A.DEBOUNCE_DEFAULT;const o=()=>{const s=(new Date).getTime()-n;t>s?r=setTimeout(o,t-s):(r=null,a!==A.DEBOUNCE_IMMEDIATE&&e(...i),null===r&&(i=[]))};return function(){i=[...arguments],n=(new Date).getTime(),null===r&&(r=setTimeout(o,t),a===A.DEBOUNCE_IMMEDIATE&&e(...i))}},THROTTLE_DEFAULT:0,THROTTLE_NO_LEADING:1,THROTTLE_NO_TRAILING:2,throttle(t,e,s){let r=null,i=[],n=0,a=s||A.THROTTLE_DEFAULT;const o=()=>{n=a&A.THROTTLE_NO_LEADING?0:(new Date).getTime(),r=null,e(...i),null===r&&(i=[])};return function(){const s=(new Date).getTime();!n&&a&A.THROTTLE_NO_LEADING&&(n=s);const l=t-(s-n);i=[...arguments],l<=0||l>t?(null!==r&&(clearTimeout(r),r=null),n=s,e(...i),null===r&&(i=[])):null!==r||a&A.THROTTLE_NO_TRAILING||(r=setTimeout(o,l))}}};class E{static flatten(t,e){return Object.keys(t).reduce(((s,r)=>{const i=e.length?e+".":"";return"object"==typeof t[r]&&null!==t[r]?Object.assign(s,E.flatten(t[r],i+r)):s[i+r]=t[r],s}),{})}static providePath(t,e,s){const r=e.split(".").map((t=>/^[0-9]+$/.test(t)?+t:t));let i=t??{},n=null;for(let e=0;;++e){const a=r[e],o=r[e-1];if(Number.isInteger(a)&&!Array.isArray(i)&&(null!==n?n[o]=i=[]:t=i=[]),e===r.length-1)return i[a]=void 0!==s?s:a in i?i[a]:null,t;void 0===i[a]&&(i[a]={}),n=i,i=i[a]}}static extract(t){if("radio"===t.getAttribute("type")){if(!t.checked)return;return"boolean"===t.dataset.fulBindType?"true"===t.value:t.value}return"checkbox"===t.getAttribute("type")?t.checked:"boolean"===t.dataset.fulBindType?t.value?"true"===t.value:null:!("INPUT"!==t.tagName&&"SELECT"!==t.tagName||""!==t.value&&void 0!==t.value)?null:t.value}static extractFrom(t,e){let s={};for(const r of t.querySelectorAll("[name]"))"never"!==r.dataset.fulBindInclude&&(e&&"always"!==r.dataset.fulBindInclude&&null!==r.closest(e)||(s=E.providePath(s,r.getAttribute("name"),E.extract(r))));return s}static mutate(t,e){"radio"!==t.getAttribute("type")?"checkbox"!==t.getAttribute("type")?t.value=e:t.checked=e:t.checked=t.getAttribute("value")===e}static mutateIn(t,e){for(const[s,r]of Object.entries(E.flatten(e,"")))for(const e of t.querySelectorAll(`[name='${CSS.escape(s)}']`))E.mutate(e,r)}static errors(t,e,s){const r=e.filter((t=>"FIELD_ERROR"===t.type||"INVALID_FORMAT"===t.type)),i=e.filter((t=>"FIELD_ERROR"!==t.type&&"INVALID_FORMAT"!==t.type));t.querySelectorAll(`.${CSS.escape(s)}`).forEach((t=>t.classList.remove(s))),t.querySelectorAll("ful-errors").forEach((t=>{t.replaceChildren(),t.setAttribute("hidden","")})),r.forEach((e=>{const r=e.context.replace("[",".").replace("].","."),i=`[name='${CSS.escape(r)}'] [ful-validation-target],[name='${CSS.escape(r)}']:not(:has([ful-validation-target]))`;t.querySelectorAll(i).forEach((t=>t.classList.add(s)));const n=`ful-field-error[field='${CSS.escape(r)}']`;t.querySelectorAll(n).forEach((t=>{t.innerText=e.reason}))})),t.querySelectorAll("ful-errors").forEach((t=>{t.innerText=i.map((t=>t.reason)).join("\n"),0!==i.length&&t.removeAttribute("hidden")}))}}class T extends(e.ParsedElement()){static IGNORED_CHILDREN_SELECTOR=".d-none, [hidden]";static SCROLL_OFFSET=50;static INVALID_CLASS="is-invalid";submitter;render(){const t=document.createElement("form");e.Attributes.forward("form-",this,t),t.replaceChildren(...this.childNodes),t.addEventListener("submit",(async t=>{t.preventDefault(),this.spinning((async()=>{await(this.submitter?.(this.values,this))}))})),this.hasAttribute("clear-invalid-on-change")&&this.addEventListener("change",(t=>{const e=t.target;e?.querySelectorAll(`.${CSS.escape(T.INVALID_CLASS)}`).forEach((t=>{t.classList.remove(T.INVALID_CLASS)}))})),this.replaceChildren(t)}spinner(t){this.querySelectorAll("ful-spinner").forEach((e=>{e.hidden=!t})),this.querySelectorAll("[type=submit],[type=reset]").forEach((e=>{e.disabled=t}))}async remoting(t){try{await t()}catch(t){throw t instanceof i&&(this.errors=t.problems),t}}async spinningUntilError(t){this.spinner(!0);try{await this.remoting(t)}catch(t){throw this.spinner(!1),t}}async spinning(t){this.spinner(!0);try{await this.remoting(t)}finally{this.spinner(!1)}}set values(t){E.mutateIn(this,t)}get values(){return E.extractFrom(this,T.IGNORED_CHILDREN_SELECTOR)}set errors(t){if(E.errors(this,t,T.INVALID_CLASS),0==t.length||!this.hasAttribute("scroll-on-error"))return;const e=Array.from(this.querySelectorAll(`ful-errors:not([hidden]), [ful-validated-field]:has(.${T.INVALID_CLASS}) ful-field-error`)).map((t=>t.parentElement?t.parentElement:t)).map((t=>t.getBoundingClientRect().y+window.scrollY)),s=Math.min(...e);s!==1/0&&window.scroll(window.scrollX,s>T.SCROLL_OFFSET?s-T.SCROLL_OFFSET:0)}}const S='\n<div ful-validated-field>\n <label data-tpl-for="id" class="form-label">{{{{ slots.default }}}}</label>\n <div class="input-group">\n <span data-tpl-if="slots.ibefore" class="input-group-text">{{{{ slots.ibefore }}}}</span>\n <div data-tpl-if="slots.before" data-tpl-remove="tag">{{{{ slots.before }}}}</div>\n {{{{ slots.input }}}} \n <div data-tpl-if="slots.after" data-tpl-remove="tag">{{{{ slots.after }}}}</div>\n <span data-tpl-if="slots.iafter" class="input-group-text">{{{{ slots.iafter }}}}</span>\n </div>\n <ful-field-error data-tpl-if="name" data-tpl-field="name"></ful-field-error>\n</div>\n',_=(t,s,r)=>{const i=t.input=r.input=r.input?.firstElementChild??(()=>{const t=document.createElement("input");return t.classList.add("form-control"),t})();i.setAttribute("ful-validation-target",""),i.addEventListener("change",(e=>{e.stopPropagation(),t.dispatchEvent(new CustomEvent("change",{bubbles:!0,cancelable:!1,detail:{value:t.value}}))}));const n=i.getAttribute("id")??t.getAttribute("input-id")??e.Attributes.uid("ful-input");e.Attributes.forward("input-",t,r.input),e.Attributes.defaultValue(r.input,"id",n),e.Attributes.defaultValue(r.input,"type","text"),e.Attributes.defaultValue(r.input,"placeholder"," ");const a=t.getAttribute("name");return s.withOverlay(t,{id:n,name:a,slots:r}).render()};class L extends(e.ParsedElement({observed:["value"],slots:!0,template:S})){input;render({slots:t}){const e=_(this,this.template(),t);this.replaceChildren(e)}get value(){return this.input.value}set value(t){this.input.value=t}}class k extends(e.ParsedElement({observed:["value"],slots:!0,template:'\n <div ful-validated-field>\n <label data-tpl-for="tsId" class="form-label">{{{{ slots.default }}}}</label>\n {{{{ input }}}}\n <div class="input-group">\n <span data-tpl-if="slots.ibefore" class="input-group-text">{{{{ slots.ibefore }}}}</span>\n <div data-tpl-if="slots.before" data-tpl-remove="tag">{{{{ slots.before }}}}</div>\n {{{{ slots.input }}}} \n <div data-tpl-if="slots.after" data-tpl-remove="tag">{{{{ slots.after }}}}</div>\n <span data-tpl-if="slots.iafter" class="input-group-text">{{{{ slots.iafter }}}}</span>\n </div>\n <ful-field-error data-tpl-if="name" data-tpl-field="name"></ful-field-error>\n </div>\n '})){shouldLoad;_unwrappedRemoteLoad;ts;constructor(t){super(),this.tsConfig=t}render({slots:t}){const r="local"!=(this.getAttribute("type")??"local"),i="always"!=this.getAttribute("load"),n=this.getAttribute("name"),a=t.input=t.input?.firstElementChild??document.createElement("select");a.setAttribute("ful-validation-target","");const o=a.getAttribute("id")??this.getAttribute("input-id")??e.Attributes.uid("ful-select"),l=`${o}-ts-control`;e.Attributes.forward("input-",this,a),e.Attributes.defaultValue(a,"id",o),e.Attributes.defaultValue(a,"placeholder"," "),t.input=e.Fragments.from(a),this.loaded=!r;this._remote=r,this._unwrappedRemoteLoad=async(t,e)=>{if(!r||r&&i&&this.loaded)return void e();const s=t&&t.hasOwnProperty("byId")?"id":"query",n="id"===s?t.byId:t,a=await(this.#y?this.#y(n,s):[]);"id"!==s&&(this.loaded=!0),e(a)},this.ts=new s(a,Object.assign(r?{preload:"focus",load:this._unwrappedRemoteLoad,shouldLoad:t=>!this.shouldLoad||this.shouldLoad(t)}:{},{render:{loading:()=>'<ful-spinner class="centered p-2"></ful-spinner>'}},this.tsConfig)),this.ts.on("change",(t=>{this.dispatchEvent(new CustomEvent("change",{bubbles:!0,cancelable:!1,detail:{value:this.value}}))})),a.addEventListener("change",(t=>{t.stopPropagation()})),a.remove(),this.template().withOverlay({id:o,tsId:l,name:n,input:a,slots:t}).renderTo(this)}#y;set loader(t){this.#y=t,this.hasAttribute("value")&&(this.value=this.getAttribute("value"))}get value(){const t=this.ts.getValue();return""===t?null:t}set value(t){(async()=>{this._remote&&await this._unwrappedRemoteLoad({byId:t},this.ts.loadCallback.bind(this.ts));this.ts.setValue(t,!0)})()}}class I extends(e.ParsedElement({observed:["value","disabled:presence"],slots:!0,template:'\n <fieldset ful-validated-field>\n <legend class="form-label">\n {{{{ slots.default }}}}\n </legend>\n <header data-tpl-if="slots.header">\n {{{{ slots.header }}}}\n </header>\n <section>\n <div class="label-wrapper" data-tpl-each="inputsAndLabels" data-tpl-var="ial">\n <label>\n {{{{ ial[0] }}}}\n {{{{ ial[1] }}}}\n </label>\n </div>\n </section>\n <ful-field-error data-tpl-if="name" data-tpl-field="name"></ful-field-error>\n <footer data-tpl-if="slots.footer">\n {{{{ slots.footer }}}}\n </footer>\n </fieldset>\n '})){render({slots:t}){const s=this.getAttribute("name")??e.Attributes.uid("ful-radiogroup"),r=Array.from(t.default.querySelectorAll("ful-radio")),i=r.map((t=>{const r=document.createElement("input");r.setAttribute("type","radio"),e.Attributes.forward("input-",this,r),e.Attributes.forward("",t,r),r.setAttribute("name",`${s}-ignore`),r.setAttribute("ful-validation-target",""),r.dataset.fulBindInclude="never",r.addEventListener("change",(t=>{t.stopPropagation(),this.dispatchEvent(new CustomEvent("change",{bubbles:!0,cancelable:!1,detail:{value:this.value}}))}));return[r,e.Fragments.fromChildNodes(t)]}));r.forEach((t=>t.remove())),this.template().withOverlay({name:s,slots:t,inputsAndLabels:i}).renderTo(this)}get disabled(){return this.hasAttribute("disabled")}set disabled(t){this.reflect((()=>e.Attributes.toggle(this,"disabled",t)))}get value(){const t=this.querySelector("input[type=radio]:checked");return t?t.value:null}set value(t){if(null===t)return void this.querySelectorAll("input[type=radio]").forEach((t=>{t.checked=!1}));const e=this.querySelector(`input[type=radio][value=${CSS.escape(t)}]`);e&&(e.checked=!0)}}class C extends(e.ParsedElement({slots:!0,template:'\n <div class="ful-spinner-wrapper">\n <div class="ful-spinner-text">{{{{ slots.default }}}}</div>\n <div class="ful-spinner-icon"></div>\n </div>\n '})){render({slots:t}){this.template().withOverlay({slots:t}).renderTo(this)}}return t.AuthorizationCodeFlow=b,t.AuthorizationCodeFlowInterceptor=v,t.AuthorizationCodeFlowSession=y,t.Base64=r,t.Bindings=E,t.Failure=i,t.Form=T,t.Hex=class{static decode(t){if(t.length%2!=0)throw new Error("invalid length");const e=t.length/2;return new Uint8Array(e).map(((e,s)=>{const r=2*s,i=t.substring(r,r+2);return parseInt(i,16)}))}static encode(t,e){return Array.from(t).map((t=>t.toString(16))).map((t=>e?t.toUpperCase():t)).map((t=>t.padStart(2,0))).join("")}},t.HttpClient=d,t.HttpClientError=a,t.INPUT_TEMPLATE=S,t.Input=L,t.LocalStorage=class extends g{constructor(t){super(t,localStorage)}},t.MediaType=n,t.RadioGroup=I,t.Select=k,t.SessionStorage=w,t.Spinner=C,t.VersionedStorage=class{constructor(t,e,s){this.storage=t,this.key=e,this.dataSupplier=s,this.cache=null}async load(t){const e=this.storage.load(this.key);if(e&&e.revision===t)return void(this.cache=e.value);const s=await this.dataSupplier(t,this.key);this.storage.save(this.key,{revision:t,value:s}),this.cache=s}data(){return this.cache}},t.makeInputFragment=_,t.timing=A,t}({},ftl,window?.TomSelect||{});
2
2
  //# sourceMappingURL=ful.iife.min.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ful.iife.min.js","sources":["../src/encodings.mjs","../src/failure.mjs","../src/http-client.mjs","../src/storage.mjs","../src/oauth-authorization-code.mjs","../src/timing.mjs","../src/elements/bindings.mjs","../src/elements/form.mjs","../src/elements/input.mjs","../src/elements/select.mjs","../src/elements/radio.mjs","../src/elements/spinner.mjs","../src/deferred.mjs"],"sourcesContent":["\n\nclass Base64 {\n static encode(arrayBuffer, dialect) {\n const d = dialect || Base64.URL_SAFE;\n const len = arrayBuffer.byteLength;\n const view = new Uint8Array(arrayBuffer);\n let res = '';\n for (let i = 0; i < len; i += 3) {\n const v1 = d[view[i] >> 2];\n const v2 = d[((view[i] & 3) << 4) | (view[i + 1] >> 4)];\n const v3 = d[((view[i + 1] & 15) << 2) | (view[i + 2] >> 6)];\n const v4 = d[view[i + 2] & 63];\n res += v1 + v2 + v3 + v4;\n }\n if (len % 3 === 2) {\n res = res.substring(0, res.length - 1);\n } else if (len % 3 === 1) {\n res = res.substring(0, res.length - 2);\n }\n return res;\n }\n static decode(str, dialect) {\n const d = dialect || Base64.URL_SAFE;\n let nbytes = Math.floor(str.length * 0.75);\n for (let i = 0; i !== str.length; ++i) {\n if (str[str.length - i - 1] !== '=') {\n break;\n }\n --nbytes;\n }\n const view = new Uint8Array(nbytes);\n\n let vi = 0;\n let si = 0;\n while (vi < str.length * 0.75) {\n const v1 = d.indexOf(str.charAt(si++));\n const v2 = d.indexOf(str.charAt(si++));\n const v3 = d.indexOf(str.charAt(si++));\n const v4 = d.indexOf(str.charAt(si++));\n view[vi++] = (v1 << 2) | (v2 >> 4);\n view[vi++] = ((v2 & 15) << 4) | (v3 >> 2);\n view[vi++] = ((v3 & 3) << 6) | v4;\n }\n\n return view.buffer;\n }\n}\n\nBase64.STANDARD = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\nBase64.URL_SAFE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';\n\n\nclass Hex {\n static decode(hex) {\n if (hex.length % 2 !== 0) {\n throw new Error(\"invalid length\");\n }\n const lenInBytes = hex.length / 2;\n return new Uint8Array(lenInBytes).map((e, i) => {\n const offset = i * 2;\n const octet = hex.substring(offset, offset + 2);\n return parseInt(octet, 16);\n });\n }\n static encode(bytes, upper) {\n return Array.from(bytes)\n .map(b => b.toString(16))\n .map(b => upper ? b.toUpperCase() : b)\n .map(o => o.padStart(2, 0))\n .join('');\n }\n}\n\nexport { Base64, Hex };","\n\n/**\n * @typedef {{ type: string; context: string?; reason: string; details: any?; }} Problem\n */\nclass Failure extends Error {\n /**\n * \n * @param {string} message \n * @param {Problem[]} problems \n * @param {*} cause\n */\n constructor(message, problems, cause) {\n super(message, { cause });\n this.name = 'Failure';\n this.problems = problems;\n }\n}\n\nexport { Failure };","import { Failure } from \"./failure.mjs\";\n\nclass MediaType {\n #type;\n #subtype;\n constructor(type, subtype) {\n this.#type = type;\n this.#subtype = subtype;\n }\n get normalized() {\n return `${this.#type}/${this.#subtype}`;\n }\n get type() {\n return this.#type;\n }\n get subtype() {\n return this.#subtype;\n }\n /**\n * \n * @param {string|null|undefined} v \n * @returns \n */\n static parse(v) {\n if (!v) {\n return new MediaType(\"unknown\", \"unknown\");\n }\n const [prefix, _] = v.split(\";\");\n const [ptype, psubtype] = prefix.trim().split(\"/\");\n return new MediaType(ptype.toLowerCase(), psubtype?.toLowerCase());\n }\n}\n\n\n/**\n * @typedef {Int8Array| Uint8Array| Uint8ClampedArray| Int16Array| Uint16Array| Int32Array| Uint32Array| Float32Array| Float64Array| BigInt64Array| BigUint64Array} TypedArray\n */\n/**\n * @typedef HttpInterceptor\n * @property {function(Request,HttpInterceptorChain):Promise<Response>} intercept \n */\n\nclass HttpClientError extends Failure {\n /**\n * @param {string} message\n * @param {number} status\n * @param {{ type: string; context: string?; reason: string; details: any?; }[]} problems\n * @param {Error|undefined} [cause]\n */\n constructor(message, status, problems, cause) {\n super(message, problems, cause);\n this.name = 'HttpClientError';\n this.status = status;\n }\n /**\n * \n * @param {string} type \n * @param {any} cause \n * @returns \n */\n static of(type, cause) {\n return new HttpClientError(cause.message, 0, [{\n type,\n context: null,\n reason: cause.message,\n details: null\n }], cause);\n }\n /**\n * Creates an HttpClientError from a Response.\n * @param {Response} response \n * @returns an HttpClientError\n */\n static async fromResponse(response) {\n switch (MediaType.parse(response.headers.get(\"Content-Type\")).normalized) {\n case 'application/failures+json': {\n const data = await response.json();\n const message = `${response.status} ${response.statusText}: ${data.length} failures`;\n return new HttpClientError(message, response.status, data);\n }\n case 'application/problem+json': {\n const data = await response.json();\n const message = `${response.status} ${response.statusText}: ${data.title} ${data.detail}`;\n return new HttpClientError(message, response.status, data.problems || [{\n type: \"GENERIC_PROBLEM\",\n context: null,\n reason: message,\n details: null\n }]);\n }\n default: {\n const text = await response.text();\n const message = `${response.status} ${response.statusText}: ${text}`;\n return new HttpClientError(message, response.status, [{\n type: \"GENERIC_PROBLEM\",\n context: null,\n reason: message,\n details: null\n }]);\n }\n }\n }\n}\n\n/**\n * @implements {HttpInterceptor}\n */\nclass CsrfTokenInterceptor {\n #k; #v;\n constructor() {\n this.#k = document.querySelector(\"meta[name='_csrf_header']\")?.getAttribute(\"content\");\n this.#v = document.querySelector(\"meta[name='_csrf']\")?.getAttribute(\"content\");\n }\n async intercept(request, chain) {\n if (this.#k && this.#v) {\n request.headers.set(this.#k, this.#v);\n }\n return await chain.proceed(request);\n }\n}\n/**\n * @implements {HttpInterceptor}\n */\nclass RedirectOnUnauthorizedInterceptor {\n #redirectUri;\n /**\n * @param {string} redirectUri\n */\n constructor(redirectUri) {\n this.#redirectUri = redirectUri;\n }\n async intercept(request, chain) {\n const response = await chain.proceed(request);\n if (response.status === 401) {\n window.location.href = this.#redirectUri;\n }\n return response;\n }\n}\n\nclass HttpClientBuilder {\n /**\n * @type {HttpInterceptor[]}\n */\n #interceptors;\n constructor() {\n this.#interceptors = [];\n }\n withCsrfToken() {\n this.#interceptors.push(new CsrfTokenInterceptor());\n return this;\n }\n withRedirectOnUnauthorized(redirectUri) {\n this.#interceptors.push(new RedirectOnUnauthorizedInterceptor(redirectUri));\n return this;\n }\n /**\n * @param {...HttpInterceptor} interceptors\n */\n withInterceptors(...interceptors) {\n this.#interceptors.push(...interceptors);\n return this;\n }\n build() {\n return new HttpClient(this.#interceptors);\n }\n}\n\n/**\n * @implements {HttpInterceptor}\n */\nclass HttpCall {\n async intercept(request, chain) {\n return await fetch(request);\n }\n}\n\nclass HttpInterceptorChain {\n #interceptors;\n #current;\n /**\n * \n * @param {HttpInterceptor[]} interceptors \n * @param {number} current \n */\n constructor(interceptors, current) {\n this.#interceptors = interceptors;\n this.#current = current;\n }\n /**\n * \n * @param {Request} request \n * @returns {Promise<Response>} the response\n */\n async proceed(request) {\n const interceptor = this.#interceptors[this.#current];\n return await interceptor.intercept(request, new HttpInterceptorChain(this.#interceptors, this.#current + 1));\n }\n}\n\nclass HttpClient {\n #interceptors;\n /**\n * Creates a builder for an HttpClient.\n * @returns {HttpClientBuilder} the client builder\n */\n static builder() {\n return new HttpClientBuilder();\n }\n /**\n * Creates an HttpClient.\n * @param {HttpInterceptor[]|undefined} interceptors - a list of interceptors to be registered for every request performed by the created client. \n */\n constructor(interceptors) {\n this.#interceptors = interceptors || [];\n }\n /**\n * Performs an HTTP exchange.\n * @async\n * @param {string} uri - the (possibly relative) request url\n * @param {RequestInit|undefined} options - fetch options\n * @param {HttpInterceptor[]|undefined} interceptors - the HttpInterceptors to be registered for this exchange.\n * @returns {Promise<Response>} the response\n */\n async exchange(uri, options, interceptors) {\n const is = [...this.#interceptors, ...interceptors || [], new HttpCall()];\n const chain = new HttpInterceptorChain(is, 0);\n return await chain.proceed(new Request(uri, options));\n }\n /**\n * Creates a request builder.\n * @param {string} method - the HTTP method to be used\n * @param {string} uri - the (possibly relative) request url\n * @returns {HttpRequestBuilder} the request builder\n */\n request(method, uri) {\n return HttpRequestBuilder.create(this, method, uri);\n }\n /**\n * Creates a request builder.\n * @param {string} uri - the (possibly relative) request url \n * @returns {HttpRequestBuilder} the request builder\n */\n get(uri) {\n return HttpRequestBuilder.create(this, 'GET', uri);\n }\n /**\n * Creates a request builder.\n * @param {string} uri - the (possibly relative) request url\n * @returns {HttpRequestBuilder} the request builder\n */\n head(uri) {\n return HttpRequestBuilder.create(this, 'HEAD', uri);\n }\n /**\n * Creates a request builder.\n * @param {string} uri - the (possibly relative) request url\n * @returns {HttpRequestBuilder} the request builder\n */\n post(uri) {\n return HttpRequestBuilder.create(this, 'POST', uri);\n }\n /**\n * Creates a request builder.\n * @param {string} uri - the (possibly relative) request url\n * @returns {HttpRequestBuilder} the request builder\n */\n put(uri) {\n return HttpRequestBuilder.create(this, 'PUT', uri);\n }\n /**\n * Creates a request builder.\n * @param {string} uri - the (possibly relative) request url\n * @returns {HttpRequestBuilder} the request builder\n */\n patch(uri) {\n return HttpRequestBuilder.create(this, 'PATCH', uri);\n }\n /**\n * Creates a request builder.\n * @param {string} uri - the (possibly relative) request url\n * @returns {HttpRequestBuilder} the request builder\n */\n delete(uri) {\n return HttpRequestBuilder.create(this, 'DELETE', uri);\n }\n}\n\n/**\n * \n * @param {Response} response \n * @param {'text'|'json'|'blob'|'arrayBuffer'} type \n * @returns \n */\nconst unmarshal = async (response, type) => {\n try {\n return await response[type]();\n } catch (ex) {\n throw HttpClientError.of(\"UNMARSHALING_PROBLEM\", ex);\n }\n}\n\n\nclass HttpRequestBuilder {\n #client;\n #method;\n #uri;\n #params;\n #headers;\n #body;\n #options;\n #interceptors;\n /**\n * Creates an HttpRequestBuilder.\n * @param {HttpClient} client \n * @param {string} method - the HTTP method to be used\n * @param {string} uri - the (possibly relative) request url\n * @returns {HttpRequestBuilder} the builder\n */\n static create(client, method, uri) {\n return new HttpRequestBuilder(\n client,\n method,\n uri,\n new URLSearchParams(),\n new Headers(),\n undefined,\n {},\n []\n );\n }\n /**\n * Creates an HttpRequestBuilder.\n * @param {HttpClient} client \n * @param {string} method - the HTTP method to be used\n * @param {string} uri - the (possibly relative) request url\n * @param {URLSearchParams} params \n * @param {Headers} headers \n * @param {any} body \n * @param {Omit<RequestInit,\"headers\"|\"method\"|\"body\">} options \n * @param {HttpInterceptor[]} interceptors \n */\n constructor(client, method, uri, params, headers, body, options, interceptors) {\n this.#client = client;\n this.#method = method;\n this.#uri = uri;\n this.#params = params;\n this.#body = body;\n this.#headers = headers;\n this.#options = options;\n this.#interceptors = interceptors;\n }\n /**\n * Add all passed headers to the request, overriding existing ones if that key already exists. Null and undefined values cause the key to be removed.\n * @param {HeadersInit} hs \n * @returns {HttpRequestBuilder} this builder\n */\n headers(hs) {\n for (const [k, v] of new Headers(hs).entries()) {\n if (v === null || v === undefined) {\n this.#headers.delete(k);\n } else {\n this.#headers.set(k, v);\n } \n }\n return this;\n }\n /**\n * Adds an header to the request, overriding it if it already exists. Null and undefined values cause the key to be removed\n * @param {string} k \n * @param {string} v \n * @returns {HttpRequestBuilder} this builder\n */\n header(k, v) {\n if (v === null || v === undefined) {\n this.#headers.delete(k);\n } else {\n this.#headers.set(k, v);\n }\n return this;\n }\n /**\n * Add all query parameters to the request, overriding existing ones if that key already exists. Null and undefined values cause the key to be removed\n * @param {URLSearchParams|Record<string,string>|string[][]|string} ps \n * @returns {HttpRequestBuilder} this builder\n */\n params(ps) {\n for (const [k, v] of new URLSearchParams(ps).entries()) {\n if (v === null || v === undefined) {\n this.#params.delete(k);\n } else {\n this.#params.set(k, v);\n }\n }\n return this;\n }\n /**\n * Adds a query parameter to the request, overriding it if it already exists. Null and undefined values cause the key to be removed.\n * @param {string} k \n * @param {string} v \n * @returns {HttpRequestBuilder} this builder\n */\n param(k, v) {\n if (v === null || v === undefined) {\n this.#params.delete(k);\n } else {\n this.#params.set(k, v);\n }\n return this;\n }\n /**\n * Sets the request body. \n * `Content-Type: multipart/form-data` header is automatically added by fetch when data is a FormData instance if not explicitly set.\n * `Content-Type: application/x-www-form-urlencoded` header is automatically added by fetch when data is an URLSearchParams instance if not explicitly set.\n * `Content-Type: text/plain` header is automatically added by fetch when data is a string instance if not explicitly set.\n * @param {string|ArrayBuffer|Blob|DataView|File|FormData|TypedArray|URLSearchParams|ReadableStream} data \n * @returns {HttpRequestBuilder} this builder\n */\n body(data) {\n this.#body = data;\n return this;\n }\n /**\n * Sets the request body that will be serialized as json. Calling this method adds the `Content-Type application/json` header for the request.\n * @param {any} body - the body to be serialized as json\n * @returns {HttpRequestBuilder} this builder\n */\n json(body) {\n this.#headers.set(\"Content-Type\", \"application/json\");\n this.#body = JSON.stringify(body);\n return this;\n }\n /**\n * Sets the request body as a FormData configured using the callback.\n * `Content-Type: multipart/form-data` header is automatically added by fetch if not explicitly set.\n * @param {function(HttpMultipartRequestCustomizer):void} callback\n */\n multipart(callback) {\n const formData = new FormData();\n const builder = new HttpMultipartRequestCustomizer(formData);\n callback(builder);\n this.#body = formData;\n return this;\n }\n /**\n * Sets a fetch options for the request.\n * @param {Omit<RequestInit,\"headers\"|\"method\"|\"body\">} kvs\n * @returns {HttpRequestBuilder} this builder\n */\n options(kvs) {\n for (const [k, v] of Object.entries(kvs)) {\n // @ts-ignore\n this.#options[k] = v;\n }\n return this;\n }\n /**\n * Sets a fetch option for the request.\n * @param {keyof Omit<RequestInit,\"headers\"|\"method\"|\"body\">} k \n * @param {*} v \n * @returns {HttpRequestBuilder} this builder\n */\n option(k, v) {\n this.#options[k] = v;\n return this;\n }\n /**\n * Adds interceptors to the request.\n * @param {[HttpInterceptor]} is - the interceptor to be regisered\n * @returns {HttpRequestBuilder} this builder\n */\n interceptors(is) {\n for (const i of is) {\n this.#interceptors.push(i);\n }\n return this;\n }\n /**\n * Adds an interceptor to the request.\n * @param {HttpInterceptor} i - the interceptor to be regisered\n * @returns {HttpRequestBuilder} this builder\n */\n interceptor(i) {\n this.#interceptors.push(i);\n return this;\n }\n /**\n * Performs an HTTP exchange using the configured client, request and interceptors.\n * @returns {Promise<Response>} the response\n */\n async exchange() {\n const uri = this.#params.size ? `${this.#uri}?${this.#params}` : this.#uri;\n const opts = {\n ...this.#options,\n headers: this.#headers,\n method: this.#method,\n body: this.#body,\n };\n return await this.#client.exchange(uri, opts, this.#interceptors);\n }\n /**\n * Performs an HTTP exchange using the configured client request, and interceptos throwing a failure when response status is not in the 200-299 range.\n * @returns {Promise<Response>} the response\n */\n async fetch() {\n const uri = this.#params.size ? `${this.#uri}?${this.#params}` : this.#uri;\n const opts = {\n ...this.#options,\n headers: this.#headers,\n method: this.#method,\n body: this.#body,\n };\n try {\n const response = await this.#client.exchange(uri, opts, this.#interceptors);\n if (!response.ok) {\n throw await HttpClientError.fromResponse(response);\n }\n return response;\n } catch (ex) {\n if (ex instanceof Failure) {\n throw ex;\n }\n throw HttpClientError.of(\"CONNECTION_PROBLEM\", ex);\n }\n }\n /**\n * Performs an HTTP exchange using the configured client request, and interceptos throwing a failure when response status is not in the 200-299 range.\n * @returns {Promise<string>} the response body, as text\n */\n async fetchText() {\n const response = await this.fetch();\n return await unmarshal(response, 'text');\n }\n /**\n * Performs an HTTP exchange using the configured client request, and interceptos throwing a failure when response status is not in the 200-299 range.\n * @returns {Promise<any>} the response body, deserialized as JSON\n */\n async fetchJson() {\n const response = await this.fetch();\n return await unmarshal(response, 'json');\n }\n /**\n * Performs an HTTP exchange using the configured client request, and interceptos throwing a failure when response status is not in the 200-299 range.\n * @returns {Promise<Blob>} the response body, as a Blob\n */\n async fetchBlob() {\n const response = await this.fetch();\n return await unmarshal(response, 'blob');\n }\n /**\n * Performs an HTTP exchange using the configured client request, and interceptos throwing a failure when response status is not in the 200-299 range.\n * @returns {Promise<ArrayBuffer>} the response body, as an ArrayBuffer\n */\n async fetchArrayBuffer() {\n const response = await this.fetch();\n return await unmarshal(response, 'arrayBuffer');\n }\n}\n\n\nclass HttpMultipartRequestCustomizer {\n #formData;\n /**\n * \n * @param {FormData} formData \n */\n constructor(formData) {\n this.#formData = formData;\n }\n /**\n * Appends a value to the FormData.\n * @param {string} name \n * @param {*} value \n * @returns this builder\n */\n field(name, value) {\n this.#formData.append(name, value);\n return this;\n }\n /**\n * Appends a Blob to the FormData. \n * If `filename` is omitted, FormData defaults are applied:\n * The default filename for Blob objects is \"blob\"; \n * The default filename for File objects is the file's filename.\n * @param {string} name \n * @param {Blob} value \n * @param {string|undefined} filename \n * @returns this builder\n */\n blob(name, value, filename) {\n this.#formData.append(name, value, filename);\n return this;\n }\n /**\n * Appends multiple Blobs to the FormData with the same name. \n * The default filename for Blob objects is \"blob\"; \n * The default filename for File objects is the file's filename.\n * @param {string} name \n * @param {Blob[]} values\n * @returns this builder\n */\n blobs(name, values) {\n for (let v of values) {\n this.#formData.append(name, v);\n }\n return this;\n }\n /**\n * Appends a JSON serialized blob to the FormData.\n * @param {string} name \n * @param {any} value \n * @param {string|undefined} filename \n * @returns this builder\n */\n json(name, value, filename) {\n const blob = new Blob([JSON.stringify(value)], { type: 'application/json' });\n this.#formData.append(name, blob, filename);\n return this;\n }\n}\n\n\nexport { MediaType, HttpClient, HttpClientError };\n","\nclass Storage {\n constructor(prefix, storage) {\n this.prefix = prefix;\n this.storage = storage;\n }\n save(k, v) {\n this.storage.setItem(`${this.prefix}-${k}`, JSON.stringify(v));\n }\n load(k) {\n const got = this.storage.getItem(`${this.prefix}-${k}`);\n return got === undefined ? undefined : JSON.parse(got);\n }\n remove(k) {\n this.storage.removeItem(`${this.prefix}-${k}`);\n }\n pop(k) {\n const decoded = this.load(k);\n this.remove(k);\n return decoded;\n }\n}\n\nclass LocalStorage extends Storage {\n constructor(prefix) {\n super(prefix, localStorage);\n }\n}\n\nclass SessionStorage extends Storage {\n constructor(prefix) {\n super(prefix, sessionStorage);\n }\n}\n\nclass VersionedStorage {\n constructor(storage, key, dataSupplier){\n this.storage = storage;\n this.key = key;\n this.dataSupplier = dataSupplier;\n this.cache = null;\n \n }\n async load(revision){\n const saved = this.storage.load(this.key);\n if (!!saved && saved.revision === revision) {\n this.cache = saved.value;\n return;\n }\n const freshData = await this.dataSupplier(revision, this.key);\n this.storage.save(this.key, {\n revision: revision,\n value: freshData\n });\n this.cache = freshData;\n }\n data(){\n return this.cache;\n }\n}\n\n\n\nexport {LocalStorage, SessionStorage, VersionedStorage};","import { Base64 } from \"./encodings.mjs\";\nimport { SessionStorage } from \"./storage.mjs\";\n\n\nclass AuthorizationCodeFlow {\n static forKeycloak(clientId, realmBaseUrl, redirectUri){\n const scope = \"openid profile\";\n return new AuthorizationCodeFlow(clientId, scope, {\n auth: new URL(\"protocol/openid-connect/auth\", realmBaseUrl),\n token: new URL(\"protocol/openid-connect/token\", realmBaseUrl),\n logout: new URL(\"protocol/openid-connect/logout\", realmBaseUrl),\n registration: new URL(\"protocol/openid-connect/registrations\", realmBaseUrl),\n redirect: redirectUri\n }); \n }\n constructor(clientId, scope, {auth, token, registration, logout, redirect}) {\n this.storage = new SessionStorage(clientId);\n this.clientId = clientId;\n this.scope = scope;\n this.uri = {auth, token, registration, logout, redirect};\n }\n async action(uri, additionalParams){\n const pkceVerifier = Base64.encode(crypto.getRandomValues(new Uint8Array(32)).buffer);\n const pkceChallenge = Base64.encode(await crypto.subtle.digest(\"SHA-256\", new TextEncoder().encode(pkceVerifier)));\n const state = this.clientId + Base64.encode(crypto.getRandomValues(new Uint8Array(16)).buffer);\n this.storage.save(AuthorizationCodeFlow.PKCE_AND_STATE_KEY, {\n state: state,\n verifier: pkceVerifier\n });\n const url = new URL(uri);\n url.searchParams.set(\"client_id\", this.clientId);\n url.searchParams.set(\"redirect_uri\", this.uri.redirect);\n url.searchParams.set(\"response_type\", 'code');\n url.searchParams.set(\"scope\", this.scope);\n url.searchParams.set(\"state\", state);\n url.searchParams.set(\"code_challenge\", pkceChallenge);\n url.searchParams.set(\"code_challenge_method\", 'S256');\n Object.entries(additionalParams || {}).forEach(kv => {\n url.searchParams.set(kv[0], kv[1]);\n });\n window.location.href = url.toString();\n }\n async registration(additionalParams){\n await this.action(this.uri.registration, additionalParams);\n }\n async applicationInitiatedAction(kcAction, additionalParams){\n await this.action(this.uri.auth, {\n ...additionalParams,\n kc_action: kcAction,\n });\n }\n async #tokenExchange(code, state) {\n window.history.replaceState('', \"\", this.uri.redirect);\n const stateAndVerifier = this.storage.pop(AuthorizationCodeFlow.PKCE_AND_STATE_KEY);\n if (stateAndVerifier.state !== state) {\n throw new Error(\"State mismatch\");\n }\n const response = await fetch(this.uri.token, {\n method: \"POST\",\n headers: {\n \"Content-Type\": 'application/x-www-form-urlencoded'\n },\n body: new URLSearchParams([\n [\"client_id\", this.clientId],\n [\"code\", code],\n [\"grant_type\", \"authorization_code\"],\n [\"code_verifier\", stateAndVerifier.verifier],\n [\"state\", stateAndVerifier.state],\n [\"redirect_uri\", this.uri.redirect]\n ])\n });\n if (!response.ok) {\n const text = await response.text();\n throw new Error(\"Error:\" + response.status + \": \" + text);\n }\n const token = await response.json();\n return new AuthorizationCodeFlowSession(this.clientId, token, this.uri);\n }\n async ensureLoggedIn() {\n const url = new URL(window.location.href);\n const code = url.searchParams.get(\"code\");\n if (code && this.storage.load(AuthorizationCodeFlow.PKCE_AND_STATE_KEY)) {\n //if callback from keycloak and we have our state still stored\n const state = url.searchParams.get(\"state\");\n return await this.#tokenExchange(code, state);\n }\n //if not authorized\n await this.action(this.uri.auth, {});\n return null;\n }\n}\nAuthorizationCodeFlow.PKCE_AND_STATE_KEY = \"state-and-verifier\";\n\nclass AuthorizationCodeFlowSession {\n static parseToken(token) {\n const [rawHeader, rawPayload, signature] = token.split(\".\");\n const utf8decoder = new TextDecoder(\"utf-8\");\n return {\n header: JSON.parse(utf8decoder.decode(Base64.decode(rawHeader, Base64.STANDARD))),\n payload: JSON.parse(utf8decoder.decode(Base64.decode(rawPayload, Base64.STANDARD))),\n signature: signature\n };\n } \n constructor(clientId, t, {token, logout, redirect}) {\n this.clientId = clientId;\n this.token = t;\n this.idToken = AuthorizationCodeFlowSession.parseToken(t.id_token);\n this.accessToken = AuthorizationCodeFlowSession.parseToken(t.access_token);\n this.refreshToken = AuthorizationCodeFlowSession.parseToken(t.refresh_token);\n this.uri = { token, logout, redirect }\n this.refreshCallback = null;\n }\n onRefresh(callback) {\n this.refreshCallback = callback;\n }\n async refresh() {\n const response = await fetch(this.uri.token, {\n method: \"POST\",\n headers: {\n \"Content-Type\": 'application/x-www-form-urlencoded'\n },\n body: new URLSearchParams([\n [\"client_id\", this.clientId],\n [\"grant_type\", \"refresh_token\"],\n [\"refresh_token\", this.token.refresh_token]\n ])\n });\n if (!response.ok) {\n const text = await response.text();\n throw new Error(\"Error:\" + response.status + \": \" + text);\n }\n const token = await response.json();\n this.token = token;\n this.idToken = AuthorizationCodeFlowSession.parseToken(token.id_token);\n this.accessToken = AuthorizationCodeFlowSession.parseToken(token.access_token);\n this.refreshToken = AuthorizationCodeFlowSession.parseToken(token.refresh_token);\n if (this.refreshCallback) {\n this.refreshCallback(this.token, this.accessToken, this.refreshToken);\n }\n }\n shouldBeRefreshed(gracePeriod) {\n const now = new Date().getTime();\n const refreshTokenExpiresAt = this.refreshToken.payload.exp * 1000;\n const expired = now > refreshTokenExpiresAt;\n const shouldRefresh = now - gracePeriod > refreshTokenExpiresAt;\n return !expired && shouldRefresh;\n }\n async refreshIf(gracePeriod) {\n if (!this.shouldBeRefreshed(gracePeriod)) {\n return;\n }\n await this.refresh();\n }\n logout() {\n const url = new URL(this.uri.logout);\n url.searchParams.set(\"post_logout_redirect_uri\", this.uri.redirect);\n url.searchParams.set(\"id_token_hint\", this.token.id_token);\n window.location.href = url.toString();\n }\n\n bearerToken() {\n return `Bearer ${this.token.access_token}`;\n }\n \n interceptor(gracePeriodBefore, gracePeriodAfter){\n return new AuthorizationCodeFlowInterceptor(this, gracePeriodBefore, gracePeriodAfter); \n }\n}\n\nclass AuthorizationCodeFlowInterceptor {\n #session;\n #gracePeriodBefore;\n #gracePeriodAfter;\n constructor(session, gracePeriodBefore, gracePeriodAfter) {\n this.#session = session;\n this.#gracePeriodBefore = gracePeriodBefore || 2000;\n this.#gracePeriodAfter = gracePeriodAfter || 30000;\n }\n async intercept(request, chain) {\n await this.#session.refreshIf(this.#gracePeriodBefore);\n request.headers.set(\"Authorization\", this.#session.bearerToken());\n const response = await chain.proceed(request);\n await this.#session.refreshIf(this.#gracePeriodAfter);\n return response;\n }\n}\n\n\nexport {AuthorizationCodeFlow, AuthorizationCodeFlowSession, AuthorizationCodeFlowInterceptor };","\nconst timing = {\n sleep(ms) {\n return new Promise(resolve => setTimeout(resolve, ms));\n },\n DEBOUNCE_DEFAULT: 0,\n DEBOUNCE_IMMEDIATE: 1,\n debounce(timeoutMs, func, options) {\n let tid = null;\n let args = [];\n let previousTimestamp = 0;\n let opts = options || timing.DEBOUNCE_DEFAULT;\n\n const later = () => {\n const elapsed = new Date().getTime() - previousTimestamp;\n if (timeoutMs > elapsed) {\n tid = setTimeout(later, timeoutMs - elapsed);\n return;\n }\n tid = null;\n if (opts !== timing.DEBOUNCE_IMMEDIATE) {\n func(...args);\n }\n // This check is needed because `func` can recursively invoke `debounced`.\n if (tid === null) {\n args = [];\n }\n };\n\n return function () {\n args = [...arguments];\n previousTimestamp = new Date().getTime();\n if (tid === null) {\n tid = setTimeout(later, timeoutMs);\n if (opts === timing.DEBOUNCE_IMMEDIATE) {\n func(...args);\n }\n }\n };\n },\n THROTTLE_DEFAULT: 0,\n THROTTLE_NO_LEADING: 1,\n THROTTLE_NO_TRAILING: 2,\n throttle(timeoutMs, func, options) {\n let tid = null;\n let args = [];\n let previousTimestamp = 0;\n let opts = options || timing.THROTTLE_DEFAULT;\n\n const later = () => {\n previousTimestamp = (opts & timing.THROTTLE_NO_LEADING) ? 0 : new Date().getTime();\n tid = null;\n func(...args);\n if (tid === null) {\n args = [];\n }\n };\n\n return function () {\n const now = new Date().getTime();\n if (!previousTimestamp && (opts & timing.THROTTLE_NO_LEADING)) {\n previousTimestamp = now;\n }\n const remaining = timeoutMs - (now - previousTimestamp);\n args = [...arguments];\n if (remaining <= 0 || remaining > timeoutMs) {\n if (tid !== null) {\n clearTimeout(tid);\n tid = null;\n }\n previousTimestamp = now;\n func(...args);\n if (tid === null) {\n args = [];\n }\n } else if (tid === null && !(opts & timing.THROTTLE_NO_TRAILING)) {\n tid = setTimeout(later, remaining);\n }\n };\n\n }\n};\n\n\nexport { timing };","\nclass Bindings {\n\n /**\n * @param {{ [x: string]: any; }} obj\n * @param {string} prefix\n * @return {{ [x: string]: any; }}\n */\n static flatten(obj, prefix) {\n return Object.keys(obj).reduce((acc, k) => {\n const pre = prefix.length ? prefix + '.' : '';\n if (typeof obj[k] === 'object' && obj[k] !== null) {\n Object.assign(acc, Bindings.flatten(obj[k], pre + k));\n } else {\n acc[pre + k] = obj[k];\n }\n return acc;\n }, {});\n }\n \n /**\n * @param {any} result\n * @param {string} path\n * @param {any} value\n */\n static providePath(result, path, value) {\n const keys = path.split(\".\").map((k) => /^[0-9]+$/.test(k) ? +k : k);\n let current = result ?? {};\n let previous = null;\n for (let i = 0; ; ++i) {\n const ckey = keys[i];\n const pkey = keys[i - 1];\n if (Number.isInteger(ckey) && !Array.isArray(current)) {\n if (previous !== null) {\n previous[pkey] = current = [];\n } else {\n result = current = [];\n }\n }\n if (i === keys.length - 1) {\n //when value is undefined we only want to define the property if it's not defined \n current[ckey] = value !== undefined ? value : (ckey in current ? current[ckey] : null);\n return result;\n }\n if (current[ckey] === undefined) {\n current[ckey] = {};\n }\n previous = current;\n current = current[ckey];\n }\n }\n /**\n * \n * @param {Element & {dataset?: any} & {checked?: boolean} & {value?: any}} el \n * @returns \n */\n static extract(el) {\n if (el.getAttribute('type') === 'radio') {\n if (!el.checked) {\n return undefined;\n }\n return el.dataset['fulBindType'] === 'boolean' ? el.value === 'true' : el.value;\n }\n if (el.getAttribute('type') === 'checkbox') {\n return el.checked;\n }\n if (el.dataset['fulBindType'] === 'boolean') {\n return !el.value ? null : el.value === 'true';\n }\n if (el.tagName === 'INPUT' || el.tagName === 'SELECT') {\n return el.value === '' || el.value === undefined ? null : el.value;\n }\n return el.value;\n }\n\n static extractFrom(root, ignoredChildrenSelector){\n let result = {};\n for(const el of /** @type {NodeListOf<HTMLElement>} */(root.querySelectorAll('[name]'))){\n if (el.dataset['fulBindInclude'] === 'never') {\n continue;\n }\n if(ignoredChildrenSelector && el.dataset['fulBindInclude'] !== 'always' && el.closest(ignoredChildrenSelector) !== null){\n continue;\n }\n result = Bindings.providePath(result, /** @type {string} */(el.getAttribute('name')), Bindings.extract(el))\n }\n return result;\n }\n \n /**\n * \n * @param {Element & {checked?: boolean} & {value?: any}} el \n * @returns \n */ \n static mutate(el, raw) {\n if (el.getAttribute('type') === 'radio') {\n el.checked = el.getAttribute('value') === raw;\n return;\n }\n if (el.getAttribute('type') === 'checkbox') {\n el.checked = raw;\n return;\n }\n el.value = raw;\n }\n\n static mutateIn(root, values){\n for (const [flattenedKey, value] of Object.entries(Bindings.flatten(values, ''))) {\n for(const el of root.querySelectorAll(`[name='${CSS.escape(flattenedKey)}']`)){\n Bindings.mutate(el, value)\n }\n }\n }\n\n\n static errors(root, es, invalidClass){\n const fieldErrors = es.filter(e => e.type === 'FIELD_ERROR' || e.type === 'INVALID_FORMAT');\n const globalErrors = es.filter(e => e.type !== 'FIELD_ERROR' && e.type !== 'INVALID_FORMAT');\n root.querySelectorAll(`.${CSS.escape(invalidClass)}`).forEach(el => el.classList.remove(invalidClass));\n root.querySelectorAll(\"ful-errors\").forEach(el => {\n el.replaceChildren();\n el.setAttribute('hidden', '');\n });\n fieldErrors.forEach(e => {\n const name = e.context.replace(\"[\", \".\").replace(\"].\", \".\");\n const validationTargetsSelector = `[name='${CSS.escape(name)}'] [ful-validation-target],[name='${CSS.escape(name)}']:not(:has([ful-validation-target]))`;\n root.querySelectorAll(validationTargetsSelector).forEach(input => input.classList.add(invalidClass));\n const fieldErrorsSelector = `ful-field-error[field='${CSS.escape(name)}']`;\n root.querySelectorAll(fieldErrorsSelector).forEach(el => {\n const hel = /** @type HTMLElement} */ (el);\n hel.innerText = e.reason\n });\n });\n root.querySelectorAll(\"ful-errors\").forEach(el => {\n const hel = /** @type HTMLElement} */ (el);\n hel.innerText = globalErrors.map(e => e.reason).join(\"\\n\");\n if (globalErrors.length !== 0) {\n el.removeAttribute('hidden');\n }\n });\n\n\n }\n}\n\n\nexport { Bindings }","import { Attributes, ParsedElement } from \"@optionfactory/ftl\"\nimport { Failure } from \"../failure.mjs\";\nimport { Bindings } from \"./bindings.mjs\"\n\nclass Form extends ParsedElement() {\n static IGNORED_CHILDREN_SELECTOR = '.d-none, [hidden]';\n static SCROLL_OFFSET = 50;\n static INVALID_CLASS = 'is-invalid';\n submitter;\n render() {\n const form = document.createElement('form');\n Attributes.forward('form-', this, form);\n form.replaceChildren(...this.childNodes);\n form.addEventListener('submit', async (e) => {\n e.preventDefault();\n this.spinning(async () => {\n await this.submitter?.(this.values, this);\n });\n })\n if (this.hasAttribute(\"clear-invalid-on-change\")) {\n this.addEventListener('change', evt => {\n const target = /** @type HTMLElement */ (evt.target);\n target?.querySelectorAll(`.${CSS.escape(Form.INVALID_CLASS)}`).forEach(el => {\n el.classList.remove(Form.INVALID_CLASS);\n });\n });\n }\n this.replaceChildren(form);\n }\n spinner(spin) {\n this.querySelectorAll('ful-spinner').forEach(el => {\n const hel = /** @type HTMLElement */ (el);\n hel.hidden = !spin;\n })\n this.querySelectorAll('[type=submit],[type=reset]').forEach(el => {\n const hel = /** @type HTMLButtonElement */ (el);\n hel.disabled = spin\n })\n }\n async remoting(fn) {\n try {\n await fn();\n } catch (e) {\n if (e instanceof Failure) {\n this.errors = e.problems;\n }\n throw e;\n }\n }\n async spinningUntilError(fn) {\n this.spinner(true)\n try {\n await this.remoting(fn);\n } catch (e) {\n this.spinner(false);\n throw e;\n }\n }\n async spinning(fn) {\n this.spinner(true)\n try {\n await this.remoting(fn);\n } finally {\n this.spinner(false);\n }\n }\n set values(vs) {\n Bindings.mutateIn(this, vs);\n }\n get values() {\n return Bindings.extractFrom(this, Form.IGNORED_CHILDREN_SELECTOR);\n }\n set errors(es) {\n Bindings.errors(this, es, Form.INVALID_CLASS);\n if (es.length == 0 || !this.hasAttribute('scroll-on-error')) {\n return;\n }\n const ys = Array.from(this.querySelectorAll(`ful-errors:not([hidden]), [ful-validated-field]:has(.${Form.INVALID_CLASS}) ful-field-error`))\n .map(el => el.parentElement ? el.parentElement : el)\n .map(el => el.getBoundingClientRect().y + window.scrollY);\n const miny = Math.min(...ys);\n if (miny !== Infinity) {\n window.scroll(window.scrollX, miny > Form.SCROLL_OFFSET ? miny - Form.SCROLL_OFFSET : 0);\n }\n }\n}\n\nexport { Form };\n","import { Attributes, ParsedElement } from \"@optionfactory/ftl\"\n\nconst INPUT_TEMPLATE = `\n<div ful-validated-field>\n <label data-tpl-for=\"id\" class=\"form-label\">{{{{ slots.default }}}}</label>\n <div class=\"input-group\">\n <span data-tpl-if=\"slots.ibefore\" class=\"input-group-text\">{{{{ slots.ibefore }}}}</span>\n <div data-tpl-if=\"slots.before\" data-tpl-remove=\"tag\">{{{{ slots.before }}}}</div>\n {{{{ slots.input }}}} \n <div data-tpl-if=\"slots.after\" data-tpl-remove=\"tag\">{{{{ slots.after }}}}</div>\n <span data-tpl-if=\"slots.iafter\" class=\"input-group-text\">{{{{ slots.iafter }}}}</span>\n </div>\n <ful-field-error data-tpl-if=\"name\" data-tpl-field=\"name\"></ful-field-error>\n</div>\n`;\n\nconst makeInputFragment = (el, template, slots) => {\n const input = el.input = slots.input = slots.input?.firstElementChild ?? (() => {\n const el = document.createElement(\"input\")\n el.classList.add(\"form-control\");\n return el;\n })();\n input.setAttribute('ful-validation-target', '');\n input.addEventListener('change', (evt) => {\n evt.stopPropagation();\n el.dispatchEvent(new CustomEvent('change', { \n bubbles: true, \n cancelable: false, \n detail: {\n value: el.value\n }\n }));\n });\n const id = input.getAttribute('id') ?? el.getAttribute('input-id') ?? Attributes.uid('ful-input');\n Attributes.forward('input-', el, slots.input)\n Attributes.defaultValue(slots.input, \"id\", id);\n Attributes.defaultValue(slots.input, \"type\", \"text\");\n Attributes.defaultValue(slots.input, \"placeholder\", \" \");\n const name = el.getAttribute('name');\n return template.withOverlay(el, { id, name, slots }).render();\n}\n\nclass Input extends ParsedElement({\n observed: ['value'],\n slots: true,\n template: INPUT_TEMPLATE\n}){\n input;\n render({slots}) {\n const fragment = makeInputFragment(this, this.template(), slots);\n this.replaceChildren(fragment);\n }\n get value() {\n return this.input.value;\n }\n set value(value) {\n this.input.value = value;\n }\n}\n\nexport { makeInputFragment, INPUT_TEMPLATE, Input };\n","import { Fragments, Attributes, ParsedElement } from \"@optionfactory/ftl\"\nimport TomSelect from \"tom-select\";\n/**\n * <script src=\"tom-select.complete.js\"></script>\n * <link href=\"tom-select.bootstrap5.css\" rel=\"stylesheet\" />\n */\n\nclass Select extends ParsedElement({\n observed: [\"value\"],\n slots: true,\n template: `\n <div ful-validated-field>\n <label data-tpl-for=\"tsId\" class=\"form-label\">{{{{ slots.default }}}}</label>\n {{{{ input }}}}\n <div class=\"input-group\">\n <span data-tpl-if=\"slots.ibefore\" class=\"input-group-text\">{{{{ slots.ibefore }}}}</span>\n <div data-tpl-if=\"slots.before\" data-tpl-remove=\"tag\">{{{{ slots.before }}}}</div>\n {{{{ slots.input }}}} \n <div data-tpl-if=\"slots.after\" data-tpl-remove=\"tag\">{{{{ slots.after }}}}</div>\n <span data-tpl-if=\"slots.iafter\" class=\"input-group-text\">{{{{ slots.iafter }}}}</span>\n </div>\n <ful-field-error data-tpl-if=\"name\" data-tpl-field=\"name\"></ful-field-error>\n </div>\n `\n}) {\n shouldLoad;\n _unwrappedRemoteLoad;\n ts;\n constructor(tsConfig) {\n super();\n this.tsConfig = tsConfig;\n }\n render({slots}) {\n const type = this.getAttribute(\"type\") ?? 'local';\n const remote = type != 'local';\n const loadOnce = this.getAttribute('load') != 'always';\n const name = this.getAttribute('name');\n const input = slots.input = slots.input?.firstElementChild ?? (() => {\n return document.createElement(\"select\");\n })();\n input.setAttribute('ful-validation-target', '');\n\n const id = input.getAttribute('id') ?? this.getAttribute('input-id') ?? Attributes.uid('ful-select');\n const tsId = `${id}-ts-control`;\n Attributes.forward('input-', this, input)\n Attributes.defaultValue(input, \"id\", id);\n Attributes.defaultValue(input, \"placeholder\", \" \");\n\n //tomselect needs the input to have a parent.\n //se we move the input to a fragment\n slots.input = Fragments.from(input);\n\n this.loaded = !remote;\n\n const tsDefaultConfig = {\n render: {\n loading: () => '<ful-spinner class=\"centered p-2\"></ful-spinner>'\n }\n }\n\n this._remote = remote;\n // we need to await this load in setValue when remote is configured and the option\n // is not loaded yet.\n // tomselect settings.load does not retun a promise as it wraps the configured load function\n // with a debouncer\n this._unwrappedRemoteLoad = async (query, callback) => {\n\n if (!remote || remote && loadOnce && this.loaded) {\n callback();\n return;\n }\n const type = query && query.hasOwnProperty('byId') ? 'id' : 'query';\n const qvalue = type === 'id' ? query.byId : query;\n const data = await (this.#loader ? this.#loader(qvalue, type) : []);\n if (type !== 'id') {\n this.loaded = true;\n }\n callback(data);\n };\n this.ts = new TomSelect(input, Object.assign(remote ? {\n preload: 'focus',\n load: this._unwrappedRemoteLoad,\n shouldLoad: (query) => this.shouldLoad ? this.shouldLoad(query) : true\n } : {}, tsDefaultConfig, this.tsConfig));\n this.ts.on('change', value => {\n this.dispatchEvent(new CustomEvent('change', { \n bubbles: true, \n cancelable: false, \n detail: {\n value: this.value\n }\n }));\n });\n //we remove the input to move it\n input.addEventListener('change', (evt) => {\n evt.stopPropagation();\n });\n input.remove();\n this.template().withOverlay({ id, tsId, name, input, slots }).renderTo(this);\n }\n #loader;\n set loader(l) {\n this.#loader = l;\n // loader can be configured later so we load now\n if (this.hasAttribute('value')) {\n this.value = this.getAttribute(\"value\");\n }\n }\n get value() {\n const v = this.ts.getValue();\n return v === '' ? null : v;\n }\n set value(value) {\n (async () => {\n if (this._remote) {\n await this._unwrappedRemoteLoad({ byId: value }, this.ts.loadCallback.bind(this.ts));\n }\n const silent = true;\n this.ts.setValue(value, silent);\n })();\n }\n}\n\nexport { Select };\n","import { Attributes, Fragments, ParsedElement } from \"@optionfactory/ftl\"\n\nclass RadioGroup extends ParsedElement({\n observed: ['value', 'disabled:presence'],\n slots: true,\n template: `\n <fieldset ful-validated-field>\n <legend class=\"form-label\">\n {{{{ slots.default }}}}\n </legend>\n <header data-tpl-if=\"slots.header\">\n {{{{ slots.header }}}}\n </header>\n <section>\n <div class=\"label-wrapper\" data-tpl-each=\"inputsAndLabels\" data-tpl-var=\"ial\">\n <label>\n {{{{ ial[0] }}}}\n {{{{ ial[1] }}}}\n </label>\n </div>\n </section>\n <ful-field-error data-tpl-if=\"name\" data-tpl-field=\"name\"></ful-field-error>\n <footer data-tpl-if=\"slots.footer\">\n {{{{ slots.footer }}}}\n </footer>\n </fieldset>\n `\n}) {\n render({slots}) {\n const name = this.getAttribute('name') ?? Attributes.uid('ful-radiogroup');\n const radioEls = Array.from(slots.default.querySelectorAll('ful-radio'));\n const inputsAndLabels = radioEls.map(el => {\n const input = document.createElement('input');\n input.setAttribute('type', 'radio');\n Attributes.forward('input-', this, input);\n Attributes.forward('', el, input);\n input.setAttribute('name', `${name}-ignore`);\n input.setAttribute('ful-validation-target', '');\n input.dataset['fulBindInclude'] = 'never';\n input.addEventListener('change', evt => {\n evt.stopPropagation();\n //change is not cancelable\n this.dispatchEvent(new CustomEvent('change', {\n bubbles: true,\n cancelable: false,\n detail: {\n value: this.value\n }\n }));\n });\n const label = Fragments.fromChildNodes(el);\n return [input, label];\n });\n\n radioEls.forEach(el => el.remove());\n this.template().withOverlay({ name, slots, inputsAndLabels }).renderTo(this);\n }\n get disabled() {\n return this.hasAttribute('disabled');\n }\n set disabled(value) {\n this.reflect(() => Attributes.toggle(this, 'disabled', value));\n } \n get value() {\n /** @type {HTMLInputElement|null} */\n const checked = this.querySelector('input[type=radio]:checked');\n return checked ? checked.value : null;\n }\n set value(value) {\n if (value === null) {\n this.querySelectorAll(`input[type=radio]`).forEach(el => {\n (/** @type {HTMLInputElement} */(el)).checked = false\n });\n return;\n }\n /** @type {HTMLInputElement|null} */\n const el = this.querySelector(`input[type=radio][value=${CSS.escape(value)}]`);\n if (el) {\n el.checked = true;\n }\n }\n}\n\n\nexport { RadioGroup };","import { ParsedElement } from \"@optionfactory/ftl\"\n\nclass Spinner extends ParsedElement({\n slots: true,\n template: `\n <div class=\"ful-spinner-wrapper\">\n <div class=\"ful-spinner-text\">{{{{ slots.default }}}}</div>\n <div class=\"ful-spinner-icon\"></div>\n </div>\n `\n}) {\n render({slots}) {\n this.template().withOverlay({ slots }).renderTo(this);\n }\n}\n\nexport { Spinner };","class Deferred {\n constructor() {\n this.promise = new Promise((resolve, reject) => {\n this.reject = reject;\n this.resolve = resolve;\n });\n }\n}\n\n\nexport { Deferred }"],"names":["Base64","encode","arrayBuffer","dialect","d","URL_SAFE","len","byteLength","view","Uint8Array","res","i","substring","length","decode","str","nbytes","Math","floor","vi","si","v1","indexOf","charAt","v2","v3","v4","buffer","STANDARD","Failure","Error","constructor","message","problems","cause","super","this","name","MediaType","type","subtype","normalized","parse","v","prefix","_","split","ptype","psubtype","trim","toLowerCase","HttpClientError","status","of","context","reason","details","fromResponse","response","headers","get","data","json","statusText","title","detail","text","CsrfTokenInterceptor","k","document","querySelector","getAttribute","intercept","request","chain","set","proceed","RedirectOnUnauthorizedInterceptor","redirectUri","window","location","href","HttpClientBuilder","interceptors","withCsrfToken","push","withRedirectOnUnauthorized","withInterceptors","build","HttpClient","HttpCall","fetch","HttpInterceptorChain","current","interceptor","builder","exchange","uri","options","is","Request","method","HttpRequestBuilder","create","head","post","put","patch","unmarshal","async","ex","client","params","body","URLSearchParams","Headers","undefined","hs","entries","delete","header","ps","param","JSON","stringify","multipart","callback","formData","FormData","HttpMultipartRequestCustomizer","kvs","Object","option","size","opts","ok","fetchText","fetchJson","fetchBlob","fetchArrayBuffer","field","value","append","blob","filename","blobs","values","Blob","Storage","storage","save","setItem","load","got","getItem","remove","removeItem","pop","decoded","SessionStorage","sessionStorage","AuthorizationCodeFlow","forKeycloak","clientId","realmBaseUrl","auth","URL","token","logout","registration","redirect","scope","action","additionalParams","pkceVerifier","crypto","getRandomValues","pkceChallenge","subtle","digest","TextEncoder","state","PKCE_AND_STATE_KEY","verifier","url","searchParams","forEach","kv","toString","applicationInitiatedAction","kcAction","kc_action","tokenExchange","code","history","replaceState","stateAndVerifier","AuthorizationCodeFlowSession","ensureLoggedIn","parseToken","rawHeader","rawPayload","signature","utf8decoder","TextDecoder","payload","t","idToken","id_token","accessToken","access_token","refreshToken","refresh_token","refreshCallback","onRefresh","refresh","shouldBeRefreshed","gracePeriod","now","Date","getTime","refreshTokenExpiresAt","exp","refreshIf","bearerToken","gracePeriodBefore","gracePeriodAfter","AuthorizationCodeFlowInterceptor","session","timing","sleep","ms","Promise","resolve","setTimeout","DEBOUNCE_DEFAULT","DEBOUNCE_IMMEDIATE","debounce","timeoutMs","func","tid","args","previousTimestamp","later","elapsed","arguments","THROTTLE_DEFAULT","THROTTLE_NO_LEADING","THROTTLE_NO_TRAILING","throttle","remaining","clearTimeout","Bindings","flatten","obj","keys","reduce","acc","pre","assign","providePath","result","path","map","test","previous","ckey","pkey","Number","isInteger","Array","isArray","extract","el","checked","dataset","tagName","extractFrom","root","ignoredChildrenSelector","querySelectorAll","closest","mutate","raw","mutateIn","flattenedKey","CSS","escape","errors","es","invalidClass","fieldErrors","filter","e","globalErrors","classList","replaceChildren","setAttribute","replace","validationTargetsSelector","input","add","fieldErrorsSelector","innerText","join","removeAttribute","Form","ParsedElement","static","submitter","render","form","createElement","Attributes","forward","childNodes","addEventListener","preventDefault","spinning","hasAttribute","evt","target","INVALID_CLASS","spinner","spin","hidden","disabled","remoting","fn","spinningUntilError","vs","IGNORED_CHILDREN_SELECTOR","ys","from","parentElement","getBoundingClientRect","y","scrollY","miny","min","Infinity","scroll","scrollX","SCROLL_OFFSET","INPUT_TEMPLATE","makeInputFragment","template","slots","firstElementChild","stopPropagation","dispatchEvent","CustomEvent","bubbles","cancelable","id","uid","defaultValue","withOverlay","Input","observed","fragment","Select","shouldLoad","_unwrappedRemoteLoad","ts","tsConfig","remote","loadOnce","tsId","Fragments","loaded","_remote","query","hasOwnProperty","qvalue","byId","loader","TomSelect","preload","loading","on","renderTo","l","getValue","loadCallback","bind","setValue","RadioGroup","radioEls","default","inputsAndLabels","fromChildNodes","reflect","toggle","Spinner","promise","reject","hex","lenInBytes","offset","octet","parseInt","bytes","upper","b","toUpperCase","o","padStart","localStorage","key","dataSupplier","cache","revision","saved","freshData"],"mappings":"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"}
1
+ {"version":3,"file":"ful.iife.min.js","sources":["../src/encodings.mjs","../src/failure.mjs","../src/http-client.mjs","../src/storage.mjs","../src/oauth-authorization-code.mjs","../src/timing.mjs","../src/elements/bindings.mjs","../src/elements/form.mjs","../src/elements/input.mjs","../src/elements/select.mjs","../src/elements/radio.mjs","../src/elements/spinner.mjs"],"sourcesContent":["\n\nclass Base64 {\n static encode(arrayBuffer, dialect) {\n const d = dialect || Base64.URL_SAFE;\n const len = arrayBuffer.byteLength;\n const view = new Uint8Array(arrayBuffer);\n let res = '';\n for (let i = 0; i < len; i += 3) {\n const v1 = d[view[i] >> 2];\n const v2 = d[((view[i] & 3) << 4) | (view[i + 1] >> 4)];\n const v3 = d[((view[i + 1] & 15) << 2) | (view[i + 2] >> 6)];\n const v4 = d[view[i + 2] & 63];\n res += v1 + v2 + v3 + v4;\n }\n if (len % 3 === 2) {\n res = res.substring(0, res.length - 1);\n } else if (len % 3 === 1) {\n res = res.substring(0, res.length - 2);\n }\n return res;\n }\n static decode(str, dialect) {\n const d = dialect || Base64.URL_SAFE;\n let nbytes = Math.floor(str.length * 0.75);\n for (let i = 0; i !== str.length; ++i) {\n if (str[str.length - i - 1] !== '=') {\n break;\n }\n --nbytes;\n }\n const view = new Uint8Array(nbytes);\n\n let vi = 0;\n let si = 0;\n while (vi < str.length * 0.75) {\n const v1 = d.indexOf(str.charAt(si++));\n const v2 = d.indexOf(str.charAt(si++));\n const v3 = d.indexOf(str.charAt(si++));\n const v4 = d.indexOf(str.charAt(si++));\n view[vi++] = (v1 << 2) | (v2 >> 4);\n view[vi++] = ((v2 & 15) << 4) | (v3 >> 2);\n view[vi++] = ((v3 & 3) << 6) | v4;\n }\n\n return view.buffer;\n }\n}\n\nBase64.STANDARD = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\nBase64.URL_SAFE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';\n\n\nclass Hex {\n static decode(hex) {\n if (hex.length % 2 !== 0) {\n throw new Error(\"invalid length\");\n }\n const lenInBytes = hex.length / 2;\n return new Uint8Array(lenInBytes).map((e, i) => {\n const offset = i * 2;\n const octet = hex.substring(offset, offset + 2);\n return parseInt(octet, 16);\n });\n }\n static encode(bytes, upper) {\n return Array.from(bytes)\n .map(b => b.toString(16))\n .map(b => upper ? b.toUpperCase() : b)\n .map(o => o.padStart(2, 0))\n .join('');\n }\n}\n\nexport { Base64, Hex };","\n\n/**\n * @typedef {{ type: string; context: string?; reason: string; details: any?; }} Problem\n */\nclass Failure extends Error {\n /**\n * \n * @param {string} message \n * @param {Problem[]} problems \n * @param {*} cause\n */\n constructor(message, problems, cause) {\n super(message, { cause });\n this.name = 'Failure';\n this.problems = problems;\n }\n}\n\nexport { Failure };","import { Failure } from \"./failure.mjs\";\n\nclass MediaType {\n #type;\n #subtype;\n constructor(type, subtype) {\n this.#type = type;\n this.#subtype = subtype;\n }\n get normalized() {\n return `${this.#type}/${this.#subtype}`;\n }\n get type() {\n return this.#type;\n }\n get subtype() {\n return this.#subtype;\n }\n /**\n * \n * @param {string|null|undefined} v \n * @returns \n */\n static parse(v) {\n if (!v) {\n return new MediaType(\"unknown\", \"unknown\");\n }\n const [prefix, _] = v.split(\";\");\n const [ptype, psubtype] = prefix.trim().split(\"/\");\n return new MediaType(ptype.toLowerCase(), psubtype?.toLowerCase());\n }\n}\n\n\n/**\n * @typedef {Int8Array| Uint8Array| Uint8ClampedArray| Int16Array| Uint16Array| Int32Array| Uint32Array| Float32Array| Float64Array| BigInt64Array| BigUint64Array} TypedArray\n */\n/**\n * @typedef HttpInterceptor\n * @property {function(Request,HttpInterceptorChain):Promise<Response>} intercept \n */\n\nclass HttpClientError extends Failure {\n /**\n * @param {string} message\n * @param {number} status\n * @param {{ type: string; context: string?; reason: string; details: any?; }[]} problems\n * @param {Error|undefined} [cause]\n */\n constructor(message, status, problems, cause) {\n super(message, problems, cause);\n this.name = 'HttpClientError';\n this.status = status;\n }\n /**\n * \n * @param {string} type \n * @param {any} cause \n * @returns \n */\n static of(type, cause) {\n return new HttpClientError(cause.message, 0, [{\n type,\n context: null,\n reason: cause.message,\n details: null\n }], cause);\n }\n /**\n * Creates an HttpClientError from a Response.\n * @param {Response} response \n * @returns an HttpClientError\n */\n static async fromResponse(response) {\n switch (MediaType.parse(response.headers.get(\"Content-Type\")).normalized) {\n case 'application/failures+json': {\n const data = await response.json();\n const message = `${response.status} ${response.statusText}: ${data.length} failures`;\n return new HttpClientError(message, response.status, data);\n }\n case 'application/problem+json': {\n const data = await response.json();\n const message = `${response.status} ${response.statusText}: ${data.title} ${data.detail}`;\n return new HttpClientError(message, response.status, data.problems || [{\n type: \"GENERIC_PROBLEM\",\n context: null,\n reason: message,\n details: null\n }]);\n }\n default: {\n const text = await response.text();\n const message = `${response.status} ${response.statusText}: ${text}`;\n return new HttpClientError(message, response.status, [{\n type: \"GENERIC_PROBLEM\",\n context: null,\n reason: message,\n details: null\n }]);\n }\n }\n }\n}\n\n/**\n * @implements {HttpInterceptor}\n */\nclass CsrfTokenInterceptor {\n #k; #v;\n constructor() {\n this.#k = document.querySelector(\"meta[name='_csrf_header']\")?.getAttribute(\"content\");\n this.#v = document.querySelector(\"meta[name='_csrf']\")?.getAttribute(\"content\");\n }\n async intercept(request, chain) {\n if (this.#k && this.#v) {\n request.headers.set(this.#k, this.#v);\n }\n return await chain.proceed(request);\n }\n}\n/**\n * @implements {HttpInterceptor}\n */\nclass RedirectOnUnauthorizedInterceptor {\n #redirectUri;\n /**\n * @param {string} redirectUri\n */\n constructor(redirectUri) {\n this.#redirectUri = redirectUri;\n }\n async intercept(request, chain) {\n const response = await chain.proceed(request);\n if (response.status === 401) {\n window.location.href = this.#redirectUri;\n }\n return response;\n }\n}\n\nclass HttpClientBuilder {\n /**\n * @type {HttpInterceptor[]}\n */\n #interceptors;\n constructor() {\n this.#interceptors = [];\n }\n withCsrfToken() {\n this.#interceptors.push(new CsrfTokenInterceptor());\n return this;\n }\n withRedirectOnUnauthorized(redirectUri) {\n this.#interceptors.push(new RedirectOnUnauthorizedInterceptor(redirectUri));\n return this;\n }\n /**\n * @param {...HttpInterceptor} interceptors\n */\n withInterceptors(...interceptors) {\n this.#interceptors.push(...interceptors);\n return this;\n }\n build() {\n return new HttpClient(this.#interceptors);\n }\n}\n\n/**\n * @implements {HttpInterceptor}\n */\nclass HttpCall {\n async intercept(request, chain) {\n return await fetch(request);\n }\n}\n\nclass HttpInterceptorChain {\n #interceptors;\n #current;\n /**\n * \n * @param {HttpInterceptor[]} interceptors \n * @param {number} current \n */\n constructor(interceptors, current) {\n this.#interceptors = interceptors;\n this.#current = current;\n }\n /**\n * \n * @param {Request} request \n * @returns {Promise<Response>} the response\n */\n async proceed(request) {\n const interceptor = this.#interceptors[this.#current];\n return await interceptor.intercept(request, new HttpInterceptorChain(this.#interceptors, this.#current + 1));\n }\n}\n\nclass HttpClient {\n #interceptors;\n /**\n * Creates a builder for an HttpClient.\n * @returns {HttpClientBuilder} the client builder\n */\n static builder() {\n return new HttpClientBuilder();\n }\n /**\n * Creates an HttpClient.\n * @param {HttpInterceptor[]|undefined} interceptors - a list of interceptors to be registered for every request performed by the created client. \n */\n constructor(interceptors) {\n this.#interceptors = interceptors || [];\n }\n /**\n * Performs an HTTP exchange.\n * @async\n * @param {string} uri - the (possibly relative) request url\n * @param {RequestInit|undefined} options - fetch options\n * @param {HttpInterceptor[]|undefined} interceptors - the HttpInterceptors to be registered for this exchange.\n * @returns {Promise<Response>} the response\n */\n async exchange(uri, options, interceptors) {\n const is = [...this.#interceptors, ...interceptors || [], new HttpCall()];\n const chain = new HttpInterceptorChain(is, 0);\n return await chain.proceed(new Request(uri, options));\n }\n /**\n * Creates a request builder.\n * @param {string} method - the HTTP method to be used\n * @param {string} uri - the (possibly relative) request url\n * @returns {HttpRequestBuilder} the request builder\n */\n request(method, uri) {\n return HttpRequestBuilder.create(this, method, uri);\n }\n /**\n * Creates a request builder.\n * @param {string} uri - the (possibly relative) request url \n * @returns {HttpRequestBuilder} the request builder\n */\n get(uri) {\n return HttpRequestBuilder.create(this, 'GET', uri);\n }\n /**\n * Creates a request builder.\n * @param {string} uri - the (possibly relative) request url\n * @returns {HttpRequestBuilder} the request builder\n */\n head(uri) {\n return HttpRequestBuilder.create(this, 'HEAD', uri);\n }\n /**\n * Creates a request builder.\n * @param {string} uri - the (possibly relative) request url\n * @returns {HttpRequestBuilder} the request builder\n */\n post(uri) {\n return HttpRequestBuilder.create(this, 'POST', uri);\n }\n /**\n * Creates a request builder.\n * @param {string} uri - the (possibly relative) request url\n * @returns {HttpRequestBuilder} the request builder\n */\n put(uri) {\n return HttpRequestBuilder.create(this, 'PUT', uri);\n }\n /**\n * Creates a request builder.\n * @param {string} uri - the (possibly relative) request url\n * @returns {HttpRequestBuilder} the request builder\n */\n patch(uri) {\n return HttpRequestBuilder.create(this, 'PATCH', uri);\n }\n /**\n * Creates a request builder.\n * @param {string} uri - the (possibly relative) request url\n * @returns {HttpRequestBuilder} the request builder\n */\n delete(uri) {\n return HttpRequestBuilder.create(this, 'DELETE', uri);\n }\n}\n\n/**\n * \n * @param {Response} response \n * @param {'text'|'json'|'blob'|'arrayBuffer'} type \n * @returns \n */\nconst unmarshal = async (response, type) => {\n try {\n return await response[type]();\n } catch (ex) {\n throw HttpClientError.of(\"UNMARSHALING_PROBLEM\", ex);\n }\n}\n\n\nclass HttpRequestBuilder {\n #client;\n #method;\n #uri;\n #params;\n #headers;\n #body;\n #options;\n #interceptors;\n /**\n * Creates an HttpRequestBuilder.\n * @param {HttpClient} client \n * @param {string} method - the HTTP method to be used\n * @param {string} uri - the (possibly relative) request url\n * @returns {HttpRequestBuilder} the builder\n */\n static create(client, method, uri) {\n return new HttpRequestBuilder(\n client,\n method,\n uri,\n new URLSearchParams(),\n new Headers(),\n undefined,\n {},\n []\n );\n }\n /**\n * Creates an HttpRequestBuilder.\n * @param {HttpClient} client \n * @param {string} method - the HTTP method to be used\n * @param {string} uri - the (possibly relative) request url\n * @param {URLSearchParams} params \n * @param {Headers} headers \n * @param {any} body \n * @param {Omit<RequestInit,\"headers\"|\"method\"|\"body\">} options \n * @param {HttpInterceptor[]} interceptors \n */\n constructor(client, method, uri, params, headers, body, options, interceptors) {\n this.#client = client;\n this.#method = method;\n this.#uri = uri;\n this.#params = params;\n this.#body = body;\n this.#headers = headers;\n this.#options = options;\n this.#interceptors = interceptors;\n }\n /**\n * Add all passed headers to the request, overriding existing ones if that key already exists. Null and undefined values cause the key to be removed.\n * @param {HeadersInit} hs \n * @returns {HttpRequestBuilder} this builder\n */\n headers(hs) {\n for (const [k, v] of new Headers(hs).entries()) {\n if (v === null || v === undefined) {\n this.#headers.delete(k);\n } else {\n this.#headers.set(k, v);\n } \n }\n return this;\n }\n /**\n * Adds an header to the request, overriding it if it already exists. Null and undefined values cause the key to be removed\n * @param {string} k \n * @param {string} v \n * @returns {HttpRequestBuilder} this builder\n */\n header(k, v) {\n if (v === null || v === undefined) {\n this.#headers.delete(k);\n } else {\n this.#headers.set(k, v);\n }\n return this;\n }\n /**\n * Add all query parameters to the request, overriding existing ones if that key already exists. Null and undefined values cause the key to be removed\n * @param {URLSearchParams|Record<string,string>|string[][]|string} ps \n * @returns {HttpRequestBuilder} this builder\n */\n params(ps) {\n for (const [k, v] of new URLSearchParams(ps).entries()) {\n if (v === null || v === undefined) {\n this.#params.delete(k);\n } else {\n this.#params.set(k, v);\n }\n }\n return this;\n }\n /**\n * Adds a query parameter to the request, overriding it if it already exists. Null and undefined values cause the key to be removed.\n * @param {string} k \n * @param {string} v \n * @returns {HttpRequestBuilder} this builder\n */\n param(k, v) {\n if (v === null || v === undefined) {\n this.#params.delete(k);\n } else {\n this.#params.set(k, v);\n }\n return this;\n }\n /**\n * Sets the request body. \n * `Content-Type: multipart/form-data` header is automatically added by fetch when data is a FormData instance if not explicitly set.\n * `Content-Type: application/x-www-form-urlencoded` header is automatically added by fetch when data is an URLSearchParams instance if not explicitly set.\n * `Content-Type: text/plain` header is automatically added by fetch when data is a string instance if not explicitly set.\n * @param {string|ArrayBuffer|Blob|DataView|File|FormData|TypedArray|URLSearchParams|ReadableStream} data \n * @returns {HttpRequestBuilder} this builder\n */\n body(data) {\n this.#body = data;\n return this;\n }\n /**\n * Sets the request body that will be serialized as json. Calling this method adds the `Content-Type application/json` header for the request.\n * @param {any} body - the body to be serialized as json\n * @returns {HttpRequestBuilder} this builder\n */\n json(body) {\n this.#headers.set(\"Content-Type\", \"application/json\");\n this.#body = JSON.stringify(body);\n return this;\n }\n /**\n * Sets the request body as a FormData configured using the callback.\n * `Content-Type: multipart/form-data` header is automatically added by fetch if not explicitly set.\n * @param {function(HttpMultipartRequestCustomizer):void} callback\n */\n multipart(callback) {\n const formData = new FormData();\n const builder = new HttpMultipartRequestCustomizer(formData);\n callback(builder);\n this.#body = formData;\n return this;\n }\n /**\n * Sets a fetch options for the request.\n * @param {Omit<RequestInit,\"headers\"|\"method\"|\"body\">} kvs\n * @returns {HttpRequestBuilder} this builder\n */\n options(kvs) {\n for (const [k, v] of Object.entries(kvs)) {\n // @ts-ignore\n this.#options[k] = v;\n }\n return this;\n }\n /**\n * Sets a fetch option for the request.\n * @param {keyof Omit<RequestInit,\"headers\"|\"method\"|\"body\">} k \n * @param {*} v \n * @returns {HttpRequestBuilder} this builder\n */\n option(k, v) {\n this.#options[k] = v;\n return this;\n }\n /**\n * Adds interceptors to the request.\n * @param {[HttpInterceptor]} is - the interceptor to be regisered\n * @returns {HttpRequestBuilder} this builder\n */\n interceptors(is) {\n for (const i of is) {\n this.#interceptors.push(i);\n }\n return this;\n }\n /**\n * Adds an interceptor to the request.\n * @param {HttpInterceptor} i - the interceptor to be regisered\n * @returns {HttpRequestBuilder} this builder\n */\n interceptor(i) {\n this.#interceptors.push(i);\n return this;\n }\n /**\n * Performs an HTTP exchange using the configured client, request and interceptors.\n * @returns {Promise<Response>} the response\n */\n async exchange() {\n const uri = this.#params.size ? `${this.#uri}?${this.#params}` : this.#uri;\n const opts = {\n ...this.#options,\n headers: this.#headers,\n method: this.#method,\n body: this.#body,\n };\n return await this.#client.exchange(uri, opts, this.#interceptors);\n }\n /**\n * Performs an HTTP exchange using the configured client request, and interceptos throwing a failure when response status is not in the 200-299 range.\n * @returns {Promise<Response>} the response\n */\n async fetch() {\n const uri = this.#params.size ? `${this.#uri}?${this.#params}` : this.#uri;\n const opts = {\n ...this.#options,\n headers: this.#headers,\n method: this.#method,\n body: this.#body,\n };\n try {\n const response = await this.#client.exchange(uri, opts, this.#interceptors);\n if (!response.ok) {\n throw await HttpClientError.fromResponse(response);\n }\n return response;\n } catch (ex) {\n if (ex instanceof Failure) {\n throw ex;\n }\n throw HttpClientError.of(\"CONNECTION_PROBLEM\", ex);\n }\n }\n /**\n * Performs an HTTP exchange using the configured client request, and interceptos throwing a failure when response status is not in the 200-299 range.\n * @returns {Promise<string>} the response body, as text\n */\n async fetchText() {\n const response = await this.fetch();\n return await unmarshal(response, 'text');\n }\n /**\n * Performs an HTTP exchange using the configured client request, and interceptos throwing a failure when response status is not in the 200-299 range.\n * @returns {Promise<any>} the response body, deserialized as JSON\n */\n async fetchJson() {\n const response = await this.fetch();\n return await unmarshal(response, 'json');\n }\n /**\n * Performs an HTTP exchange using the configured client request, and interceptos throwing a failure when response status is not in the 200-299 range.\n * @returns {Promise<Blob>} the response body, as a Blob\n */\n async fetchBlob() {\n const response = await this.fetch();\n return await unmarshal(response, 'blob');\n }\n /**\n * Performs an HTTP exchange using the configured client request, and interceptos throwing a failure when response status is not in the 200-299 range.\n * @returns {Promise<ArrayBuffer>} the response body, as an ArrayBuffer\n */\n async fetchArrayBuffer() {\n const response = await this.fetch();\n return await unmarshal(response, 'arrayBuffer');\n }\n}\n\n\nclass HttpMultipartRequestCustomizer {\n #formData;\n /**\n * \n * @param {FormData} formData \n */\n constructor(formData) {\n this.#formData = formData;\n }\n /**\n * Appends a value to the FormData.\n * @param {string} name \n * @param {*} value \n * @returns this builder\n */\n field(name, value) {\n this.#formData.append(name, value);\n return this;\n }\n /**\n * Appends a Blob to the FormData. \n * If `filename` is omitted, FormData defaults are applied:\n * The default filename for Blob objects is \"blob\"; \n * The default filename for File objects is the file's filename.\n * @param {string} name \n * @param {Blob} value \n * @param {string|undefined} filename \n * @returns this builder\n */\n blob(name, value, filename) {\n this.#formData.append(name, value, filename);\n return this;\n }\n /**\n * Appends multiple Blobs to the FormData with the same name. \n * The default filename for Blob objects is \"blob\"; \n * The default filename for File objects is the file's filename.\n * @param {string} name \n * @param {Blob[]} values\n * @returns this builder\n */\n blobs(name, values) {\n for (let v of values) {\n this.#formData.append(name, v);\n }\n return this;\n }\n /**\n * Appends a JSON serialized blob to the FormData.\n * @param {string} name \n * @param {any} value \n * @param {string|undefined} filename \n * @returns this builder\n */\n json(name, value, filename) {\n const blob = new Blob([JSON.stringify(value)], { type: 'application/json' });\n this.#formData.append(name, blob, filename);\n return this;\n }\n}\n\n\nexport { MediaType, HttpClient, HttpClientError };\n","\nclass Storage {\n constructor(prefix, storage) {\n this.prefix = prefix;\n this.storage = storage;\n }\n save(k, v) {\n this.storage.setItem(`${this.prefix}-${k}`, JSON.stringify(v));\n }\n load(k) {\n const got = this.storage.getItem(`${this.prefix}-${k}`);\n return got === undefined ? undefined : JSON.parse(got);\n }\n remove(k) {\n this.storage.removeItem(`${this.prefix}-${k}`);\n }\n pop(k) {\n const decoded = this.load(k);\n this.remove(k);\n return decoded;\n }\n}\n\nclass LocalStorage extends Storage {\n constructor(prefix) {\n super(prefix, localStorage);\n }\n}\n\nclass SessionStorage extends Storage {\n constructor(prefix) {\n super(prefix, sessionStorage);\n }\n}\n\nclass VersionedStorage {\n constructor(storage, key, dataSupplier){\n this.storage = storage;\n this.key = key;\n this.dataSupplier = dataSupplier;\n this.cache = null;\n \n }\n async load(revision){\n const saved = this.storage.load(this.key);\n if (!!saved && saved.revision === revision) {\n this.cache = saved.value;\n return;\n }\n const freshData = await this.dataSupplier(revision, this.key);\n this.storage.save(this.key, {\n revision: revision,\n value: freshData\n });\n this.cache = freshData;\n }\n data(){\n return this.cache;\n }\n}\n\n\n\nexport {LocalStorage, SessionStorage, VersionedStorage};","import { Base64 } from \"./encodings.mjs\";\nimport { SessionStorage } from \"./storage.mjs\";\n\n\nclass AuthorizationCodeFlow {\n static forKeycloak(clientId, realmBaseUrl, redirectUri){\n const scope = \"openid profile\";\n return new AuthorizationCodeFlow(clientId, scope, {\n auth: new URL(\"protocol/openid-connect/auth\", realmBaseUrl),\n token: new URL(\"protocol/openid-connect/token\", realmBaseUrl),\n logout: new URL(\"protocol/openid-connect/logout\", realmBaseUrl),\n registration: new URL(\"protocol/openid-connect/registrations\", realmBaseUrl),\n redirect: redirectUri\n }); \n }\n constructor(clientId, scope, {auth, token, registration, logout, redirect}) {\n this.storage = new SessionStorage(clientId);\n this.clientId = clientId;\n this.scope = scope;\n this.uri = {auth, token, registration, logout, redirect};\n }\n async action(uri, additionalParams){\n const pkceVerifier = Base64.encode(crypto.getRandomValues(new Uint8Array(32)).buffer);\n const pkceChallenge = Base64.encode(await crypto.subtle.digest(\"SHA-256\", new TextEncoder().encode(pkceVerifier)));\n const state = this.clientId + Base64.encode(crypto.getRandomValues(new Uint8Array(16)).buffer);\n this.storage.save(AuthorizationCodeFlow.PKCE_AND_STATE_KEY, {\n state: state,\n verifier: pkceVerifier\n });\n const url = new URL(uri);\n url.searchParams.set(\"client_id\", this.clientId);\n url.searchParams.set(\"redirect_uri\", this.uri.redirect);\n url.searchParams.set(\"response_type\", 'code');\n url.searchParams.set(\"scope\", this.scope);\n url.searchParams.set(\"state\", state);\n url.searchParams.set(\"code_challenge\", pkceChallenge);\n url.searchParams.set(\"code_challenge_method\", 'S256');\n Object.entries(additionalParams || {}).forEach(kv => {\n url.searchParams.set(kv[0], kv[1]);\n });\n window.location.href = url.toString();\n }\n async registration(additionalParams){\n await this.action(this.uri.registration, additionalParams);\n }\n async applicationInitiatedAction(kcAction, additionalParams){\n await this.action(this.uri.auth, {\n ...additionalParams,\n kc_action: kcAction,\n });\n }\n async #tokenExchange(code, state) {\n window.history.replaceState('', \"\", this.uri.redirect);\n const stateAndVerifier = this.storage.pop(AuthorizationCodeFlow.PKCE_AND_STATE_KEY);\n if (stateAndVerifier.state !== state) {\n throw new Error(\"State mismatch\");\n }\n const response = await fetch(this.uri.token, {\n method: \"POST\",\n headers: {\n \"Content-Type\": 'application/x-www-form-urlencoded'\n },\n body: new URLSearchParams([\n [\"client_id\", this.clientId],\n [\"code\", code],\n [\"grant_type\", \"authorization_code\"],\n [\"code_verifier\", stateAndVerifier.verifier],\n [\"state\", stateAndVerifier.state],\n [\"redirect_uri\", this.uri.redirect]\n ])\n });\n if (!response.ok) {\n const text = await response.text();\n throw new Error(\"Error:\" + response.status + \": \" + text);\n }\n const token = await response.json();\n return new AuthorizationCodeFlowSession(this.clientId, token, this.uri);\n }\n async ensureLoggedIn() {\n const url = new URL(window.location.href);\n const code = url.searchParams.get(\"code\");\n if (code && this.storage.load(AuthorizationCodeFlow.PKCE_AND_STATE_KEY)) {\n //if callback from keycloak and we have our state still stored\n const state = url.searchParams.get(\"state\");\n return await this.#tokenExchange(code, state);\n }\n //if not authorized\n await this.action(this.uri.auth, {});\n return null;\n }\n}\nAuthorizationCodeFlow.PKCE_AND_STATE_KEY = \"state-and-verifier\";\n\nclass AuthorizationCodeFlowSession {\n static parseToken(token) {\n const [rawHeader, rawPayload, signature] = token.split(\".\");\n const utf8decoder = new TextDecoder(\"utf-8\");\n return {\n header: JSON.parse(utf8decoder.decode(Base64.decode(rawHeader, Base64.STANDARD))),\n payload: JSON.parse(utf8decoder.decode(Base64.decode(rawPayload, Base64.STANDARD))),\n signature: signature\n };\n } \n constructor(clientId, t, {token, logout, redirect}) {\n this.clientId = clientId;\n this.token = t;\n this.idToken = AuthorizationCodeFlowSession.parseToken(t.id_token);\n this.accessToken = AuthorizationCodeFlowSession.parseToken(t.access_token);\n this.refreshToken = AuthorizationCodeFlowSession.parseToken(t.refresh_token);\n this.uri = { token, logout, redirect }\n this.refreshCallback = null;\n }\n onRefresh(callback) {\n this.refreshCallback = callback;\n }\n async refresh() {\n const response = await fetch(this.uri.token, {\n method: \"POST\",\n headers: {\n \"Content-Type\": 'application/x-www-form-urlencoded'\n },\n body: new URLSearchParams([\n [\"client_id\", this.clientId],\n [\"grant_type\", \"refresh_token\"],\n [\"refresh_token\", this.token.refresh_token]\n ])\n });\n if (!response.ok) {\n const text = await response.text();\n throw new Error(\"Error:\" + response.status + \": \" + text);\n }\n const token = await response.json();\n this.token = token;\n this.idToken = AuthorizationCodeFlowSession.parseToken(token.id_token);\n this.accessToken = AuthorizationCodeFlowSession.parseToken(token.access_token);\n this.refreshToken = AuthorizationCodeFlowSession.parseToken(token.refresh_token);\n if (this.refreshCallback) {\n this.refreshCallback(this.token, this.accessToken, this.refreshToken);\n }\n }\n shouldBeRefreshed(gracePeriod) {\n const now = new Date().getTime();\n const refreshTokenExpiresAt = this.refreshToken.payload.exp * 1000;\n const expired = now > refreshTokenExpiresAt;\n const shouldRefresh = now - gracePeriod > refreshTokenExpiresAt;\n return !expired && shouldRefresh;\n }\n async refreshIf(gracePeriod) {\n if (!this.shouldBeRefreshed(gracePeriod)) {\n return;\n }\n await this.refresh();\n }\n logout() {\n const url = new URL(this.uri.logout);\n url.searchParams.set(\"post_logout_redirect_uri\", this.uri.redirect);\n url.searchParams.set(\"id_token_hint\", this.token.id_token);\n window.location.href = url.toString();\n }\n\n bearerToken() {\n return `Bearer ${this.token.access_token}`;\n }\n \n interceptor(gracePeriodBefore, gracePeriodAfter){\n return new AuthorizationCodeFlowInterceptor(this, gracePeriodBefore, gracePeriodAfter); \n }\n}\n\nclass AuthorizationCodeFlowInterceptor {\n #session;\n #gracePeriodBefore;\n #gracePeriodAfter;\n constructor(session, gracePeriodBefore, gracePeriodAfter) {\n this.#session = session;\n this.#gracePeriodBefore = gracePeriodBefore || 2000;\n this.#gracePeriodAfter = gracePeriodAfter || 30000;\n }\n async intercept(request, chain) {\n await this.#session.refreshIf(this.#gracePeriodBefore);\n request.headers.set(\"Authorization\", this.#session.bearerToken());\n const response = await chain.proceed(request);\n await this.#session.refreshIf(this.#gracePeriodAfter);\n return response;\n }\n}\n\n\nexport {AuthorizationCodeFlow, AuthorizationCodeFlowSession, AuthorizationCodeFlowInterceptor };","\nconst timing = {\n sleep(ms) {\n return new Promise(resolve => setTimeout(resolve, ms));\n },\n DEBOUNCE_DEFAULT: 0,\n DEBOUNCE_IMMEDIATE: 1,\n debounce(timeoutMs, func, options) {\n let tid = null;\n let args = [];\n let previousTimestamp = 0;\n let opts = options || timing.DEBOUNCE_DEFAULT;\n\n const later = () => {\n const elapsed = new Date().getTime() - previousTimestamp;\n if (timeoutMs > elapsed) {\n tid = setTimeout(later, timeoutMs - elapsed);\n return;\n }\n tid = null;\n if (opts !== timing.DEBOUNCE_IMMEDIATE) {\n func(...args);\n }\n // This check is needed because `func` can recursively invoke `debounced`.\n if (tid === null) {\n args = [];\n }\n };\n\n return function () {\n args = [...arguments];\n previousTimestamp = new Date().getTime();\n if (tid === null) {\n tid = setTimeout(later, timeoutMs);\n if (opts === timing.DEBOUNCE_IMMEDIATE) {\n func(...args);\n }\n }\n };\n },\n THROTTLE_DEFAULT: 0,\n THROTTLE_NO_LEADING: 1,\n THROTTLE_NO_TRAILING: 2,\n throttle(timeoutMs, func, options) {\n let tid = null;\n let args = [];\n let previousTimestamp = 0;\n let opts = options || timing.THROTTLE_DEFAULT;\n\n const later = () => {\n previousTimestamp = (opts & timing.THROTTLE_NO_LEADING) ? 0 : new Date().getTime();\n tid = null;\n func(...args);\n if (tid === null) {\n args = [];\n }\n };\n\n return function () {\n const now = new Date().getTime();\n if (!previousTimestamp && (opts & timing.THROTTLE_NO_LEADING)) {\n previousTimestamp = now;\n }\n const remaining = timeoutMs - (now - previousTimestamp);\n args = [...arguments];\n if (remaining <= 0 || remaining > timeoutMs) {\n if (tid !== null) {\n clearTimeout(tid);\n tid = null;\n }\n previousTimestamp = now;\n func(...args);\n if (tid === null) {\n args = [];\n }\n } else if (tid === null && !(opts & timing.THROTTLE_NO_TRAILING)) {\n tid = setTimeout(later, remaining);\n }\n };\n\n }\n};\n\n\nexport { timing };","\nclass Bindings {\n\n /**\n * @param {{ [x: string]: any; }} obj\n * @param {string} prefix\n * @return {{ [x: string]: any; }}\n */\n static flatten(obj, prefix) {\n return Object.keys(obj).reduce((acc, k) => {\n const pre = prefix.length ? prefix + '.' : '';\n if (typeof obj[k] === 'object' && obj[k] !== null) {\n Object.assign(acc, Bindings.flatten(obj[k], pre + k));\n } else {\n acc[pre + k] = obj[k];\n }\n return acc;\n }, {});\n }\n \n /**\n * @param {any} result\n * @param {string} path\n * @param {any} value\n */\n static providePath(result, path, value) {\n const keys = path.split(\".\").map((k) => /^[0-9]+$/.test(k) ? +k : k);\n let current = result ?? {};\n let previous = null;\n for (let i = 0; ; ++i) {\n const ckey = keys[i];\n const pkey = keys[i - 1];\n if (Number.isInteger(ckey) && !Array.isArray(current)) {\n if (previous !== null) {\n previous[pkey] = current = [];\n } else {\n result = current = [];\n }\n }\n if (i === keys.length - 1) {\n //when value is undefined we only want to define the property if it's not defined \n current[ckey] = value !== undefined ? value : (ckey in current ? current[ckey] : null);\n return result;\n }\n if (current[ckey] === undefined) {\n current[ckey] = {};\n }\n previous = current;\n current = current[ckey];\n }\n }\n /**\n * \n * @param {Element & {dataset?: any} & {checked?: boolean} & {value?: any}} el \n * @returns \n */\n static extract(el) {\n if (el.getAttribute('type') === 'radio') {\n if (!el.checked) {\n return undefined;\n }\n return el.dataset['fulBindType'] === 'boolean' ? el.value === 'true' : el.value;\n }\n if (el.getAttribute('type') === 'checkbox') {\n return el.checked;\n }\n if (el.dataset['fulBindType'] === 'boolean') {\n return !el.value ? null : el.value === 'true';\n }\n if (el.tagName === 'INPUT' || el.tagName === 'SELECT') {\n return el.value === '' || el.value === undefined ? null : el.value;\n }\n return el.value;\n }\n\n static extractFrom(root, ignoredChildrenSelector){\n let result = {};\n for(const el of /** @type {NodeListOf<HTMLElement>} */(root.querySelectorAll('[name]'))){\n if (el.dataset['fulBindInclude'] === 'never') {\n continue;\n }\n if(ignoredChildrenSelector && el.dataset['fulBindInclude'] !== 'always' && el.closest(ignoredChildrenSelector) !== null){\n continue;\n }\n result = Bindings.providePath(result, /** @type {string} */(el.getAttribute('name')), Bindings.extract(el))\n }\n return result;\n }\n \n /**\n * \n * @param {Element & {checked?: boolean} & {value?: any}} el \n * @returns \n */ \n static mutate(el, raw) {\n if (el.getAttribute('type') === 'radio') {\n el.checked = el.getAttribute('value') === raw;\n return;\n }\n if (el.getAttribute('type') === 'checkbox') {\n el.checked = raw;\n return;\n }\n el.value = raw;\n }\n\n static mutateIn(root, values){\n for (const [flattenedKey, value] of Object.entries(Bindings.flatten(values, ''))) {\n for(const el of root.querySelectorAll(`[name='${CSS.escape(flattenedKey)}']`)){\n Bindings.mutate(el, value)\n }\n }\n }\n\n\n static errors(root, es, invalidClass){\n const fieldErrors = es.filter(e => e.type === 'FIELD_ERROR' || e.type === 'INVALID_FORMAT');\n const globalErrors = es.filter(e => e.type !== 'FIELD_ERROR' && e.type !== 'INVALID_FORMAT');\n root.querySelectorAll(`.${CSS.escape(invalidClass)}`).forEach(el => el.classList.remove(invalidClass));\n root.querySelectorAll(\"ful-errors\").forEach(el => {\n el.replaceChildren();\n el.setAttribute('hidden', '');\n });\n fieldErrors.forEach(e => {\n const name = e.context.replace(\"[\", \".\").replace(\"].\", \".\");\n const validationTargetsSelector = `[name='${CSS.escape(name)}'] [ful-validation-target],[name='${CSS.escape(name)}']:not(:has([ful-validation-target]))`;\n root.querySelectorAll(validationTargetsSelector).forEach(input => input.classList.add(invalidClass));\n const fieldErrorsSelector = `ful-field-error[field='${CSS.escape(name)}']`;\n root.querySelectorAll(fieldErrorsSelector).forEach(el => {\n const hel = /** @type HTMLElement} */ (el);\n hel.innerText = e.reason\n });\n });\n root.querySelectorAll(\"ful-errors\").forEach(el => {\n const hel = /** @type HTMLElement} */ (el);\n hel.innerText = globalErrors.map(e => e.reason).join(\"\\n\");\n if (globalErrors.length !== 0) {\n el.removeAttribute('hidden');\n }\n });\n\n\n }\n}\n\n\nexport { Bindings }","import { Attributes, ParsedElement } from \"@optionfactory/ftl\"\nimport { Failure } from \"../failure.mjs\";\nimport { Bindings } from \"./bindings.mjs\"\n\nclass Form extends ParsedElement() {\n static IGNORED_CHILDREN_SELECTOR = '.d-none, [hidden]';\n static SCROLL_OFFSET = 50;\n static INVALID_CLASS = 'is-invalid';\n submitter;\n render() {\n const form = document.createElement('form');\n Attributes.forward('form-', this, form);\n form.replaceChildren(...this.childNodes);\n form.addEventListener('submit', async (e) => {\n e.preventDefault();\n this.spinning(async () => {\n await this.submitter?.(this.values, this);\n });\n })\n if (this.hasAttribute(\"clear-invalid-on-change\")) {\n this.addEventListener('change', evt => {\n const target = /** @type HTMLElement */ (evt.target);\n target?.querySelectorAll(`.${CSS.escape(Form.INVALID_CLASS)}`).forEach(el => {\n el.classList.remove(Form.INVALID_CLASS);\n });\n });\n }\n this.replaceChildren(form);\n }\n spinner(spin) {\n this.querySelectorAll('ful-spinner').forEach(el => {\n const hel = /** @type HTMLElement */ (el);\n hel.hidden = !spin;\n })\n this.querySelectorAll('[type=submit],[type=reset]').forEach(el => {\n const hel = /** @type HTMLButtonElement */ (el);\n hel.disabled = spin\n })\n }\n async remoting(fn) {\n try {\n await fn();\n } catch (e) {\n if (e instanceof Failure) {\n this.errors = e.problems;\n }\n throw e;\n }\n }\n async spinningUntilError(fn) {\n this.spinner(true)\n try {\n await this.remoting(fn);\n } catch (e) {\n this.spinner(false);\n throw e;\n }\n }\n async spinning(fn) {\n this.spinner(true)\n try {\n await this.remoting(fn);\n } finally {\n this.spinner(false);\n }\n }\n set values(vs) {\n Bindings.mutateIn(this, vs);\n }\n get values() {\n return Bindings.extractFrom(this, Form.IGNORED_CHILDREN_SELECTOR);\n }\n set errors(es) {\n Bindings.errors(this, es, Form.INVALID_CLASS);\n if (es.length == 0 || !this.hasAttribute('scroll-on-error')) {\n return;\n }\n const ys = Array.from(this.querySelectorAll(`ful-errors:not([hidden]), [ful-validated-field]:has(.${Form.INVALID_CLASS}) ful-field-error`))\n .map(el => el.parentElement ? el.parentElement : el)\n .map(el => el.getBoundingClientRect().y + window.scrollY);\n const miny = Math.min(...ys);\n if (miny !== Infinity) {\n window.scroll(window.scrollX, miny > Form.SCROLL_OFFSET ? miny - Form.SCROLL_OFFSET : 0);\n }\n }\n}\n\nexport { Form };\n","import { Attributes, ParsedElement } from \"@optionfactory/ftl\"\n\nconst INPUT_TEMPLATE = `\n<div ful-validated-field>\n <label data-tpl-for=\"id\" class=\"form-label\">{{{{ slots.default }}}}</label>\n <div class=\"input-group\">\n <span data-tpl-if=\"slots.ibefore\" class=\"input-group-text\">{{{{ slots.ibefore }}}}</span>\n <div data-tpl-if=\"slots.before\" data-tpl-remove=\"tag\">{{{{ slots.before }}}}</div>\n {{{{ slots.input }}}} \n <div data-tpl-if=\"slots.after\" data-tpl-remove=\"tag\">{{{{ slots.after }}}}</div>\n <span data-tpl-if=\"slots.iafter\" class=\"input-group-text\">{{{{ slots.iafter }}}}</span>\n </div>\n <ful-field-error data-tpl-if=\"name\" data-tpl-field=\"name\"></ful-field-error>\n</div>\n`;\n\nconst makeInputFragment = (el, template, slots) => {\n const input = el.input = slots.input = slots.input?.firstElementChild ?? (() => {\n const el = document.createElement(\"input\")\n el.classList.add(\"form-control\");\n return el;\n })();\n input.setAttribute('ful-validation-target', '');\n input.addEventListener('change', (evt) => {\n evt.stopPropagation();\n el.dispatchEvent(new CustomEvent('change', { \n bubbles: true, \n cancelable: false, \n detail: {\n value: el.value\n }\n }));\n });\n const id = input.getAttribute('id') ?? el.getAttribute('input-id') ?? Attributes.uid('ful-input');\n Attributes.forward('input-', el, slots.input)\n Attributes.defaultValue(slots.input, \"id\", id);\n Attributes.defaultValue(slots.input, \"type\", \"text\");\n Attributes.defaultValue(slots.input, \"placeholder\", \" \");\n const name = el.getAttribute('name');\n return template.withOverlay(el, { id, name, slots }).render();\n}\n\nclass Input extends ParsedElement({\n observed: ['value'],\n slots: true,\n template: INPUT_TEMPLATE\n}){\n input;\n render({slots}) {\n const fragment = makeInputFragment(this, this.template(), slots);\n this.replaceChildren(fragment);\n }\n get value() {\n return this.input.value;\n }\n set value(value) {\n this.input.value = value;\n }\n}\n\nexport { makeInputFragment, INPUT_TEMPLATE, Input };\n","import { Fragments, Attributes, ParsedElement } from \"@optionfactory/ftl\"\nimport TomSelect from \"tom-select\";\n/**\n * <script src=\"tom-select.complete.js\"></script>\n * <link href=\"tom-select.bootstrap5.css\" rel=\"stylesheet\" />\n */\n\nclass Select extends ParsedElement({\n observed: [\"value\"],\n slots: true,\n template: `\n <div ful-validated-field>\n <label data-tpl-for=\"tsId\" class=\"form-label\">{{{{ slots.default }}}}</label>\n {{{{ input }}}}\n <div class=\"input-group\">\n <span data-tpl-if=\"slots.ibefore\" class=\"input-group-text\">{{{{ slots.ibefore }}}}</span>\n <div data-tpl-if=\"slots.before\" data-tpl-remove=\"tag\">{{{{ slots.before }}}}</div>\n {{{{ slots.input }}}} \n <div data-tpl-if=\"slots.after\" data-tpl-remove=\"tag\">{{{{ slots.after }}}}</div>\n <span data-tpl-if=\"slots.iafter\" class=\"input-group-text\">{{{{ slots.iafter }}}}</span>\n </div>\n <ful-field-error data-tpl-if=\"name\" data-tpl-field=\"name\"></ful-field-error>\n </div>\n `\n}) {\n shouldLoad;\n _unwrappedRemoteLoad;\n ts;\n constructor(tsConfig) {\n super();\n this.tsConfig = tsConfig;\n }\n render({slots}) {\n const type = this.getAttribute(\"type\") ?? 'local';\n const remote = type != 'local';\n const loadOnce = this.getAttribute('load') != 'always';\n const name = this.getAttribute('name');\n const input = slots.input = slots.input?.firstElementChild ?? (() => {\n return document.createElement(\"select\");\n })();\n input.setAttribute('ful-validation-target', '');\n\n const id = input.getAttribute('id') ?? this.getAttribute('input-id') ?? Attributes.uid('ful-select');\n const tsId = `${id}-ts-control`;\n Attributes.forward('input-', this, input)\n Attributes.defaultValue(input, \"id\", id);\n Attributes.defaultValue(input, \"placeholder\", \" \");\n\n //tomselect needs the input to have a parent.\n //se we move the input to a fragment\n slots.input = Fragments.from(input);\n\n this.loaded = !remote;\n\n const tsDefaultConfig = {\n render: {\n loading: () => '<ful-spinner class=\"centered p-2\"></ful-spinner>'\n }\n }\n\n this._remote = remote;\n // we need to await this load in setValue when remote is configured and the option\n // is not loaded yet.\n // tomselect settings.load does not retun a promise as it wraps the configured load function\n // with a debouncer\n this._unwrappedRemoteLoad = async (query, callback) => {\n\n if (!remote || remote && loadOnce && this.loaded) {\n callback();\n return;\n }\n const type = query && query.hasOwnProperty('byId') ? 'id' : 'query';\n const qvalue = type === 'id' ? query.byId : query;\n const data = await (this.#loader ? this.#loader(qvalue, type) : []);\n if (type !== 'id') {\n this.loaded = true;\n }\n callback(data);\n };\n this.ts = new TomSelect(input, Object.assign(remote ? {\n preload: 'focus',\n load: this._unwrappedRemoteLoad,\n shouldLoad: (query) => this.shouldLoad ? this.shouldLoad(query) : true\n } : {}, tsDefaultConfig, this.tsConfig));\n this.ts.on('change', value => {\n this.dispatchEvent(new CustomEvent('change', { \n bubbles: true, \n cancelable: false, \n detail: {\n value: this.value\n }\n }));\n });\n //we remove the input to move it\n input.addEventListener('change', (evt) => {\n evt.stopPropagation();\n });\n input.remove();\n this.template().withOverlay({ id, tsId, name, input, slots }).renderTo(this);\n }\n #loader;\n set loader(l) {\n this.#loader = l;\n // loader can be configured later so we load now\n if (this.hasAttribute('value')) {\n this.value = this.getAttribute(\"value\");\n }\n }\n get value() {\n const v = this.ts.getValue();\n return v === '' ? null : v;\n }\n set value(value) {\n (async () => {\n if (this._remote) {\n await this._unwrappedRemoteLoad({ byId: value }, this.ts.loadCallback.bind(this.ts));\n }\n const silent = true;\n this.ts.setValue(value, silent);\n })();\n }\n}\n\nexport { Select };\n","import { Attributes, Fragments, ParsedElement } from \"@optionfactory/ftl\"\n\nclass RadioGroup extends ParsedElement({\n observed: ['value', 'disabled:presence'],\n slots: true,\n template: `\n <fieldset ful-validated-field>\n <legend class=\"form-label\">\n {{{{ slots.default }}}}\n </legend>\n <header data-tpl-if=\"slots.header\">\n {{{{ slots.header }}}}\n </header>\n <section>\n <div class=\"label-wrapper\" data-tpl-each=\"inputsAndLabels\" data-tpl-var=\"ial\">\n <label>\n {{{{ ial[0] }}}}\n {{{{ ial[1] }}}}\n </label>\n </div>\n </section>\n <ful-field-error data-tpl-if=\"name\" data-tpl-field=\"name\"></ful-field-error>\n <footer data-tpl-if=\"slots.footer\">\n {{{{ slots.footer }}}}\n </footer>\n </fieldset>\n `\n}) {\n render({slots}) {\n const name = this.getAttribute('name') ?? Attributes.uid('ful-radiogroup');\n const radioEls = Array.from(slots.default.querySelectorAll('ful-radio'));\n const inputsAndLabels = radioEls.map(el => {\n const input = document.createElement('input');\n input.setAttribute('type', 'radio');\n Attributes.forward('input-', this, input);\n Attributes.forward('', el, input);\n input.setAttribute('name', `${name}-ignore`);\n input.setAttribute('ful-validation-target', '');\n input.dataset['fulBindInclude'] = 'never';\n input.addEventListener('change', evt => {\n evt.stopPropagation();\n //change is not cancelable\n this.dispatchEvent(new CustomEvent('change', {\n bubbles: true,\n cancelable: false,\n detail: {\n value: this.value\n }\n }));\n });\n const label = Fragments.fromChildNodes(el);\n return [input, label];\n });\n\n radioEls.forEach(el => el.remove());\n this.template().withOverlay({ name, slots, inputsAndLabels }).renderTo(this);\n }\n get disabled() {\n return this.hasAttribute('disabled');\n }\n set disabled(value) {\n this.reflect(() => Attributes.toggle(this, 'disabled', value));\n } \n get value() {\n /** @type {HTMLInputElement|null} */\n const checked = this.querySelector('input[type=radio]:checked');\n return checked ? checked.value : null;\n }\n set value(value) {\n if (value === null) {\n this.querySelectorAll(`input[type=radio]`).forEach(el => {\n (/** @type {HTMLInputElement} */(el)).checked = false\n });\n return;\n }\n /** @type {HTMLInputElement|null} */\n const el = this.querySelector(`input[type=radio][value=${CSS.escape(value)}]`);\n if (el) {\n el.checked = true;\n }\n }\n}\n\n\nexport { RadioGroup };","import { ParsedElement } from \"@optionfactory/ftl\"\n\nclass Spinner extends ParsedElement({\n slots: true,\n template: `\n <div class=\"ful-spinner-wrapper\">\n <div class=\"ful-spinner-text\">{{{{ slots.default }}}}</div>\n <div class=\"ful-spinner-icon\"></div>\n </div>\n `\n}) {\n render({slots}) {\n this.template().withOverlay({ slots }).renderTo(this);\n }\n}\n\nexport { Spinner };"],"names":["Base64","encode","arrayBuffer","dialect","d","URL_SAFE","len","byteLength","view","Uint8Array","res","i","substring","length","decode","str","nbytes","Math","floor","vi","si","v1","indexOf","charAt","v2","v3","v4","buffer","STANDARD","Failure","Error","constructor","message","problems","cause","super","this","name","MediaType","type","subtype","normalized","parse","v","prefix","_","split","ptype","psubtype","trim","toLowerCase","HttpClientError","status","of","context","reason","details","fromResponse","response","headers","get","data","json","statusText","title","detail","text","CsrfTokenInterceptor","k","document","querySelector","getAttribute","intercept","request","chain","set","proceed","RedirectOnUnauthorizedInterceptor","redirectUri","window","location","href","HttpClientBuilder","interceptors","withCsrfToken","push","withRedirectOnUnauthorized","withInterceptors","build","HttpClient","HttpCall","fetch","HttpInterceptorChain","current","interceptor","builder","exchange","uri","options","is","Request","method","HttpRequestBuilder","create","head","post","put","patch","unmarshal","async","ex","client","params","body","URLSearchParams","Headers","undefined","hs","entries","delete","header","ps","param","JSON","stringify","multipart","callback","formData","FormData","HttpMultipartRequestCustomizer","kvs","Object","option","size","opts","ok","fetchText","fetchJson","fetchBlob","fetchArrayBuffer","field","value","append","blob","filename","blobs","values","Blob","Storage","storage","save","setItem","load","got","getItem","remove","removeItem","pop","decoded","SessionStorage","sessionStorage","AuthorizationCodeFlow","forKeycloak","clientId","realmBaseUrl","auth","URL","token","logout","registration","redirect","scope","action","additionalParams","pkceVerifier","crypto","getRandomValues","pkceChallenge","subtle","digest","TextEncoder","state","PKCE_AND_STATE_KEY","verifier","url","searchParams","forEach","kv","toString","applicationInitiatedAction","kcAction","kc_action","tokenExchange","code","history","replaceState","stateAndVerifier","AuthorizationCodeFlowSession","ensureLoggedIn","parseToken","rawHeader","rawPayload","signature","utf8decoder","TextDecoder","payload","t","idToken","id_token","accessToken","access_token","refreshToken","refresh_token","refreshCallback","onRefresh","refresh","shouldBeRefreshed","gracePeriod","now","Date","getTime","refreshTokenExpiresAt","exp","refreshIf","bearerToken","gracePeriodBefore","gracePeriodAfter","AuthorizationCodeFlowInterceptor","session","timing","sleep","ms","Promise","resolve","setTimeout","DEBOUNCE_DEFAULT","DEBOUNCE_IMMEDIATE","debounce","timeoutMs","func","tid","args","previousTimestamp","later","elapsed","arguments","THROTTLE_DEFAULT","THROTTLE_NO_LEADING","THROTTLE_NO_TRAILING","throttle","remaining","clearTimeout","Bindings","flatten","obj","keys","reduce","acc","pre","assign","providePath","result","path","map","test","previous","ckey","pkey","Number","isInteger","Array","isArray","extract","el","checked","dataset","tagName","extractFrom","root","ignoredChildrenSelector","querySelectorAll","closest","mutate","raw","mutateIn","flattenedKey","CSS","escape","errors","es","invalidClass","fieldErrors","filter","e","globalErrors","classList","replaceChildren","setAttribute","replace","validationTargetsSelector","input","add","fieldErrorsSelector","innerText","join","removeAttribute","Form","ParsedElement","static","submitter","render","form","createElement","Attributes","forward","childNodes","addEventListener","preventDefault","spinning","hasAttribute","evt","target","INVALID_CLASS","spinner","spin","hidden","disabled","remoting","fn","spinningUntilError","vs","IGNORED_CHILDREN_SELECTOR","ys","from","parentElement","getBoundingClientRect","y","scrollY","miny","min","Infinity","scroll","scrollX","SCROLL_OFFSET","INPUT_TEMPLATE","makeInputFragment","template","slots","firstElementChild","stopPropagation","dispatchEvent","CustomEvent","bubbles","cancelable","id","uid","defaultValue","withOverlay","Input","observed","fragment","Select","shouldLoad","_unwrappedRemoteLoad","ts","tsConfig","remote","loadOnce","tsId","Fragments","loaded","_remote","query","hasOwnProperty","qvalue","byId","loader","TomSelect","preload","loading","on","renderTo","l","getValue","loadCallback","bind","setValue","RadioGroup","radioEls","default","inputsAndLabels","fromChildNodes","reflect","toggle","Spinner","hex","lenInBytes","offset","octet","parseInt","bytes","upper","b","toUpperCase","o","padStart","localStorage","key","dataSupplier","cache","revision","saved","freshData"],"mappings":"qCAEA,MAAMA,EACF,aAAOC,CAAOC,EAAaC,GACvB,MAAMC,EAAID,GAAWH,EAAOK,SACtBC,EAAMJ,EAAYK,WAClBC,EAAO,IAAIC,WAAWP,GAC5B,IAAIQ,EAAM,GACV,IAAK,IAAIC,EAAI,EAAGA,EAAIL,EAAKK,GAAK,EAAG,CAK7BD,GAJWN,EAAEI,EAAKG,IAAM,GACbP,GAAc,EAAVI,EAAKG,KAAW,EAAMH,EAAKG,EAAI,IAAM,GACzCP,GAAkB,GAAdI,EAAKG,EAAI,KAAY,EAAMH,EAAKG,EAAI,IAAM,GAC9CP,EAAgB,GAAdI,EAAKG,EAAI,GAElC,CAMQ,OALIL,EAAM,GAAM,EACZI,EAAMA,EAAIE,UAAU,EAAGF,EAAIG,OAAS,GAC7BP,EAAM,GAAM,IACnBI,EAAMA,EAAIE,UAAU,EAAGF,EAAIG,OAAS,IAEjCH,CACf,CACI,aAAOI,CAAOC,EAAKZ,GACf,MAAMC,EAAID,GAAWH,EAAOK,SAC5B,IAAIW,EAASC,KAAKC,MAAmB,IAAbH,EAAIF,QAC5B,IAAK,IAAIF,EAAI,EAAGA,IAAMI,EAAIF,QACU,MAA5BE,EAAIA,EAAIF,OAASF,EAAI,KADOA,IAI9BK,EAEN,MAAMR,EAAO,IAAIC,WAAWO,GAE5B,IAAIG,EAAK,EACLC,EAAK,EACT,KAAOD,EAAkB,IAAbJ,EAAIF,QAAe,CAC3B,MAAMQ,EAAKjB,EAAEkB,QAAQP,EAAIQ,OAAOH,MAC1BI,EAAKpB,EAAEkB,QAAQP,EAAIQ,OAAOH,MAC1BK,EAAKrB,EAAEkB,QAAQP,EAAIQ,OAAOH,MAC1BM,EAAKtB,EAAEkB,QAAQP,EAAIQ,OAAOH,MAChCZ,EAAKW,KAASE,GAAM,EAAMG,GAAM,EAChChB,EAAKW,MAAe,GAALK,IAAY,EAAMC,GAAM,EACvCjB,EAAKW,MAAe,EAALM,IAAW,EAAKC,CAC3C,CAEQ,OAAOlB,EAAKmB,MACpB,EAGA3B,EAAO4B,SAAW,mEAClB5B,EAAOK,SAAW,mEC7ClB,MAAMwB,UAAgBC,MAOlB,WAAAC,CAAYC,EAASC,EAAUC,GAC3BC,MAAMH,EAAS,CAAEE,UACjBE,KAAKC,KAAO,UACZD,KAAKH,SAAWA,CACxB,ECdA,MAAMK,EACFC,GACAC,GACA,WAAAT,CAAYQ,EAAMC,GACdJ,MAAKG,EAAQA,EACbH,MAAKI,EAAWA,CACxB,CACI,cAAIC,GACA,MAAO,GAAGL,MAAKG,KAASH,MAAKI,GACrC,CACI,QAAID,GACA,OAAOH,MAAKG,CACpB,CACI,WAAIC,GACA,OAAOJ,MAAKI,CACpB,CAMI,YAAOE,CAAMC,GACT,IAAKA,EACD,OAAO,IAAIL,EAAU,UAAW,WAEpC,MAAOM,EAAQC,GAAKF,EAAEG,MAAM,MACrBC,EAAOC,GAAYJ,EAAOK,OAAOH,MAAM,KAC9C,OAAO,IAAIR,EAAUS,EAAMG,cAAeF,GAAUE,cAC5D,EAYA,MAAMC,UAAwBtB,EAO1B,WAAAE,CAAYC,EAASoB,EAAQnB,EAAUC,GACnCC,MAAMH,EAASC,EAAUC,GACzBE,KAAKC,KAAO,kBACZD,KAAKgB,OAASA,CACtB,CAOI,SAAOC,CAAGd,EAAML,GACZ,OAAO,IAAIiB,EAAgBjB,EAAMF,QAAS,EAAG,CAAC,CAC1CO,OACAe,QAAS,KACTC,OAAQrB,EAAMF,QACdwB,QAAS,OACTtB,EACZ,CAMI,yBAAauB,CAAaC,GACtB,OAAQpB,EAAUI,MAAMgB,EAASC,QAAQC,IAAI,iBAAiBnB,YAC1D,IAAK,4BAA6B,CAC9B,MAAMoB,QAAaH,EAASI,OACtB9B,EAAU,GAAG0B,EAASN,UAAUM,EAASK,eAAeF,EAAKhD,kBACnE,OAAO,IAAIsC,EAAgBnB,EAAS0B,EAASN,OAAQS,EACrE,CACY,IAAK,2BAA4B,CAC7B,MAAMA,QAAaH,EAASI,OACtB9B,EAAU,GAAG0B,EAASN,UAAUM,EAASK,eAAeF,EAAKG,SAASH,EAAKI,SACjF,OAAO,IAAId,EAAgBnB,EAAS0B,EAASN,OAAQS,EAAK5B,UAAY,CAAC,CACnEM,KAAM,kBACNe,QAAS,KACTC,OAAQvB,EACRwB,QAAS,OAE7B,CACY,QAAS,CACL,MAAMU,QAAaR,EAASQ,OACtBlC,EAAU,GAAG0B,EAASN,UAAUM,EAASK,eAAeG,IAC9D,OAAO,IAAIf,EAAgBnB,EAAS0B,EAASN,OAAQ,CAAC,CAClDb,KAAM,kBACNe,QAAS,KACTC,OAAQvB,EACRwB,QAAS,OAE7B,EAEA,EAMA,MAAMW,EACFC,GAAIzB,GACJ,WAAAZ,GACIK,MAAKgC,EAAKC,SAASC,cAAc,8BAA8BC,aAAa,WAC5EnC,MAAKO,EAAK0B,SAASC,cAAc,uBAAuBC,aAAa,UAC7E,CACI,eAAMC,CAAUC,EAASC,GAIrB,OAHItC,MAAKgC,GAAMhC,MAAKO,GAChB8B,EAAQd,QAAQgB,IAAIvC,MAAKgC,EAAIhC,MAAKO,SAEzB+B,EAAME,QAAQH,EACnC,EAKA,MAAMI,EACFC,GAIA,WAAA/C,CAAY+C,GACR1C,MAAK0C,EAAeA,CAC5B,CACI,eAAMN,CAAUC,EAASC,GACrB,MAAMhB,QAAiBgB,EAAME,QAAQH,GAIrC,OAHwB,MAApBf,EAASN,SACT2B,OAAOC,SAASC,KAAO7C,MAAK0C,GAEzBpB,CACf,EAGA,MAAMwB,EAIFC,GACA,WAAApD,GACIK,MAAK+C,EAAgB,EAC7B,CACI,aAAAC,GAEI,OADAhD,MAAK+C,EAAcE,KAAK,IAAIlB,GACrB/B,IACf,CACI,0BAAAkD,CAA2BR,GAEvB,OADA1C,MAAK+C,EAAcE,KAAK,IAAIR,EAAkCC,IACvD1C,IACf,CAII,gBAAAmD,IAAoBJ,GAEhB,OADA/C,MAAK+C,EAAcE,QAAQF,GACpB/C,IACf,CACI,KAAAoD,GACI,OAAO,IAAIC,EAAWrD,MAAK+C,EACnC,EAMA,MAAMO,EACF,eAAMlB,CAAUC,EAASC,GACrB,aAAaiB,MAAMlB,EAC3B,EAGA,MAAMmB,EACFT,GACAU,GAMA,WAAA9D,CAAYoD,EAAcU,GACtBzD,MAAK+C,EAAgBA,EACrB/C,MAAKyD,EAAWA,CACxB,CAMI,aAAMjB,CAAQH,GACV,MAAMqB,EAAc1D,MAAK+C,EAAc/C,MAAKyD,GAC5C,aAAaC,EAAYtB,UAAUC,EAAS,IAAImB,EAAqBxD,MAAK+C,EAAe/C,MAAKyD,EAAW,GACjH,EAGA,MAAMJ,EACFN,GAKA,cAAOY,GACH,OAAO,IAAIb,CACnB,CAKI,WAAAnD,CAAYoD,GACR/C,MAAK+C,EAAgBA,GAAgB,EAC7C,CASI,cAAMa,CAASC,EAAKC,EAASf,GACzB,MAAMgB,EAAK,IAAI/D,MAAK+C,KAAkBA,GAAgB,GAAI,IAAIO,GACxDhB,EAAQ,IAAIkB,EAAqBO,EAAI,GAC3C,aAAazB,EAAME,QAAQ,IAAIwB,QAAQH,EAAKC,GACpD,CAOI,OAAAzB,CAAQ4B,EAAQJ,GACZ,OAAOK,EAAmBC,OAAOnE,KAAMiE,EAAQJ,EACvD,CAMI,GAAArC,CAAIqC,GACA,OAAOK,EAAmBC,OAAOnE,KAAM,MAAO6D,EACtD,CAMI,IAAAO,CAAKP,GACD,OAAOK,EAAmBC,OAAOnE,KAAM,OAAQ6D,EACvD,CAMI,IAAAQ,CAAKR,GACD,OAAOK,EAAmBC,OAAOnE,KAAM,OAAQ6D,EACvD,CAMI,GAAAS,CAAIT,GACA,OAAOK,EAAmBC,OAAOnE,KAAM,MAAO6D,EACtD,CAMI,KAAAU,CAAMV,GACF,OAAOK,EAAmBC,OAAOnE,KAAM,QAAS6D,EACxD,CAMI,OAAOA,GACH,OAAOK,EAAmBC,OAAOnE,KAAM,SAAU6D,EACzD,EASA,MAAMW,EAAYC,MAAOnD,EAAUnB,KAC/B,IACI,aAAamB,EAASnB,IACzB,CAAC,MAAOuE,GACL,MAAM3D,EAAgBE,GAAG,uBAAwByD,EACzD,GAIA,MAAMR,EACFS,GACAV,GACAJ,GACAe,GACArD,GACAsD,GACAf,GACAf,GAQA,aAAOoB,CAAOQ,EAAQV,EAAQJ,GAC1B,OAAO,IAAIK,EACPS,EACAV,EACAJ,EACA,IAAIiB,gBACJ,IAAIC,aACJC,EACA,CAAE,EACF,GAEZ,CAYI,WAAArF,CAAYgF,EAAQV,EAAQJ,EAAKe,EAAQrD,EAASsD,EAAMf,EAASf,GAC7D/C,MAAK2E,EAAUA,EACf3E,MAAKiE,EAAUA,EACfjE,MAAK6D,EAAOA,EACZ7D,MAAK4E,EAAUA,EACf5E,MAAK6E,EAAQA,EACb7E,MAAKuB,EAAWA,EAChBvB,MAAK8D,EAAWA,EAChB9D,MAAK+C,EAAgBA,CAC7B,CAMI,OAAAxB,CAAQ0D,GACJ,IAAK,MAAOjD,EAAGzB,KAAM,IAAIwE,QAAQE,GAAIC,UAC7B3E,QACAP,MAAKuB,EAAS4D,OAAOnD,GAErBhC,MAAKuB,EAASgB,IAAIP,EAAGzB,GAG7B,OAAOP,IACf,CAOI,MAAAoF,CAAOpD,EAAGzB,GAMN,OALIA,QACAP,MAAKuB,EAAS4D,OAAOnD,GAErBhC,MAAKuB,EAASgB,IAAIP,EAAGzB,GAElBP,IACf,CAMI,MAAA4E,CAAOS,GACH,IAAK,MAAOrD,EAAGzB,KAAM,IAAIuE,gBAAgBO,GAAIH,UACrC3E,QACAP,MAAK4E,EAAQO,OAAOnD,GAEpBhC,MAAK4E,EAAQrC,IAAIP,EAAGzB,GAG5B,OAAOP,IACf,CAOI,KAAAsF,CAAMtD,EAAGzB,GAML,OALIA,QACAP,MAAK4E,EAAQO,OAAOnD,GAEpBhC,MAAK4E,EAAQrC,IAAIP,EAAGzB,GAEjBP,IACf,CASI,IAAA6E,CAAKpD,GAED,OADAzB,MAAK6E,EAAQpD,EACNzB,IACf,CAMI,IAAA0B,CAAKmD,GAGD,OAFA7E,MAAKuB,EAASgB,IAAI,eAAgB,oBAClCvC,MAAK6E,EAAQU,KAAKC,UAAUX,GACrB7E,IACf,CAMI,SAAAyF,CAAUC,GACN,MAAMC,EAAW,IAAIC,SAIrB,OAFAF,EADgB,IAAIG,EAA+BF,IAEnD3F,MAAK6E,EAAQc,EACN3F,IACf,CAMI,OAAA8D,CAAQgC,GACJ,IAAK,MAAO9D,EAAGzB,KAAMwF,OAAOb,QAAQY,GAEhC9F,MAAK8D,EAAS9B,GAAKzB,EAEvB,OAAOP,IACf,CAOI,MAAAgG,CAAOhE,EAAGzB,GAEN,OADAP,MAAK8D,EAAS9B,GAAKzB,EACZP,IACf,CAMI,YAAA+C,CAAagB,GACT,IAAK,MAAMxF,KAAKwF,EACZ/D,MAAK+C,EAAcE,KAAK1E,GAE5B,OAAOyB,IACf,CAMI,WAAA0D,CAAYnF,GAER,OADAyB,MAAK+C,EAAcE,KAAK1E,GACjByB,IACf,CAKI,cAAM4D,GACF,MAAMC,EAAM7D,MAAK4E,EAAQqB,KAAO,GAAGjG,MAAK6D,KAAQ7D,MAAK4E,IAAY5E,MAAK6D,EAChEqC,EAAO,IACNlG,MAAK8D,EACRvC,QAASvB,MAAKuB,EACd0C,OAAQjE,MAAKiE,EACbY,KAAM7E,MAAK6E,GAEf,aAAa7E,MAAK2E,EAAQf,SAASC,EAAKqC,EAAMlG,MAAK+C,EAC3D,CAKI,WAAMQ,GACF,MAAMM,EAAM7D,MAAK4E,EAAQqB,KAAO,GAAGjG,MAAK6D,KAAQ7D,MAAK4E,IAAY5E,MAAK6D,EAChEqC,EAAO,IACNlG,MAAK8D,EACRvC,QAASvB,MAAKuB,EACd0C,OAAQjE,MAAKiE,EACbY,KAAM7E,MAAK6E,GAEf,IACI,MAAMvD,QAAiBtB,MAAK2E,EAAQf,SAASC,EAAKqC,EAAMlG,MAAK+C,GAC7D,IAAKzB,EAAS6E,GACV,YAAYpF,EAAgBM,aAAaC,GAE7C,OAAOA,CACV,CAAC,MAAOoD,GACL,GAAIA,aAAcjF,EACd,MAAMiF,EAEV,MAAM3D,EAAgBE,GAAG,qBAAsByD,EAC3D,CACA,CAKI,eAAM0B,GACF,MAAM9E,QAAiBtB,KAAKuD,QAC5B,aAAaiB,EAAUlD,EAAU,OACzC,CAKI,eAAM+E,GACF,MAAM/E,QAAiBtB,KAAKuD,QAC5B,aAAaiB,EAAUlD,EAAU,OACzC,CAKI,eAAMgF,GACF,MAAMhF,QAAiBtB,KAAKuD,QAC5B,aAAaiB,EAAUlD,EAAU,OACzC,CAKI,sBAAMiF,GACF,MAAMjF,QAAiBtB,KAAKuD,QAC5B,aAAaiB,EAAUlD,EAAU,cACzC,EAIA,MAAMuE,EACFF,GAKA,WAAAhG,CAAYgG,GACR3F,MAAK2F,EAAYA,CACzB,CAOI,KAAAa,CAAMvG,EAAMwG,GAER,OADAzG,MAAK2F,EAAUe,OAAOzG,EAAMwG,GACrBzG,IACf,CAWI,IAAA2G,CAAK1G,EAAMwG,EAAOG,GAEd,OADA5G,MAAK2F,EAAUe,OAAOzG,EAAMwG,EAAOG,GAC5B5G,IACf,CASI,KAAA6G,CAAM5G,EAAM6G,GACR,IAAK,IAAIvG,KAAKuG,EACV9G,MAAK2F,EAAUe,OAAOzG,EAAMM,GAEhC,OAAOP,IACf,CAQI,IAAA0B,CAAKzB,EAAMwG,EAAOG,GACd,MAAMD,EAAO,IAAII,KAAK,CAACxB,KAAKC,UAAUiB,IAAS,CAAEtG,KAAM,qBAEvD,OADAH,MAAK2F,EAAUe,OAAOzG,EAAM0G,EAAMC,GAC3B5G,IACf,ECzmBA,MAAMgH,EACF,WAAArH,CAAYa,EAAQyG,GAChBjH,KAAKQ,OAASA,EACdR,KAAKiH,QAAUA,CACvB,CACI,IAAAC,CAAKlF,EAAGzB,GACJP,KAAKiH,QAAQE,QAAQ,GAAGnH,KAAKQ,UAAUwB,IAAKuD,KAAKC,UAAUjF,GACnE,CACI,IAAA6G,CAAKpF,GACD,MAAMqF,EAAMrH,KAAKiH,QAAQK,QAAQ,GAAGtH,KAAKQ,UAAUwB,KACnD,YAAegD,IAARqC,OAAoBrC,EAAYO,KAAKjF,MAAM+G,EAC1D,CACI,MAAAE,CAAOvF,GACHhC,KAAKiH,QAAQO,WAAW,GAAGxH,KAAKQ,UAAUwB,IAClD,CACI,GAAAyF,CAAIzF,GACA,MAAM0F,EAAU1H,KAAKoH,KAAKpF,GAE1B,OADAhC,KAAKuH,OAAOvF,GACL0F,CACf,EASA,MAAMC,UAAuBX,EACzB,WAAArH,CAAYa,GACRT,MAAMS,EAAQoH,eACtB,EC5BA,MAAMC,EACF,kBAAOC,CAAYC,EAAUC,EAActF,GAEvC,OAAO,IAAImF,EAAsBE,EADnB,iBACoC,CAC9CE,KAAM,IAAIC,IAAI,+BAAgCF,GAC9CG,MAAO,IAAID,IAAI,gCAAiCF,GAChDI,OAAQ,IAAIF,IAAI,iCAAkCF,GAClDK,aAAc,IAAIH,IAAI,wCAAyCF,GAC/DM,SAAU5F,GAEtB,CACI,WAAA/C,CAAYoI,EAAUQ,GAAON,KAACA,EAAIE,MAAEA,EAAKE,aAAEA,EAAYD,OAAEA,EAAME,SAAEA,IAC7DtI,KAAKiH,QAAU,IAAIU,EAAeI,GAClC/H,KAAK+H,SAAWA,EAChB/H,KAAKuI,MAAQA,EACbvI,KAAK6D,IAAM,CAACoE,OAAME,QAAOE,eAAcD,SAAQE,WACvD,CACI,YAAME,CAAO3E,EAAK4E,GACd,MAAMC,EAAe9K,EAAOC,OAAO8K,OAAOC,gBAAgB,IAAIvK,WAAW,KAAKkB,QACxEsJ,EAAgBjL,EAAOC,aAAa8K,OAAOG,OAAOC,OAAO,WAAW,IAAIC,aAAcnL,OAAO6K,KAC7FO,EAAQjJ,KAAK+H,SAAWnK,EAAOC,OAAO8K,OAAOC,gBAAgB,IAAIvK,WAAW,KAAKkB,QACvFS,KAAKiH,QAAQC,KAAKW,EAAsBqB,mBAAoB,CACxDD,MAAOA,EACPE,SAAUT,IAEd,MAAMU,EAAM,IAAIlB,IAAIrE,GACpBuF,EAAIC,aAAa9G,IAAI,YAAavC,KAAK+H,UACvCqB,EAAIC,aAAa9G,IAAI,eAAgBvC,KAAK6D,IAAIyE,UAC9Cc,EAAIC,aAAa9G,IAAI,gBAAiB,QACtC6G,EAAIC,aAAa9G,IAAI,QAASvC,KAAKuI,OACnCa,EAAIC,aAAa9G,IAAI,QAAS0G,GAC9BG,EAAIC,aAAa9G,IAAI,iBAAkBsG,GACvCO,EAAIC,aAAa9G,IAAI,wBAAyB,QAC9CwD,OAAOb,QAAQuD,GAAoB,CAAE,GAAEa,SAAQC,IAC3CH,EAAIC,aAAa9G,IAAIgH,EAAG,GAAIA,EAAG,GAAG,IAEtC5G,OAAOC,SAASC,KAAOuG,EAAII,UACnC,CACI,kBAAMnB,CAAaI,SACTzI,KAAKwI,OAAOxI,KAAK6D,IAAIwE,aAAcI,EACjD,CACI,gCAAMgB,CAA2BC,EAAUjB,SACjCzI,KAAKwI,OAAOxI,KAAK6D,IAAIoE,KAAM,IAC1BQ,EACHkB,UAAWD,GAEvB,CACI,OAAME,CAAeC,EAAMZ,GACvBtG,OAAOmH,QAAQC,aAAa,GAAI,GAAI/J,KAAK6D,IAAIyE,UAC7C,MAAM0B,EAAmBhK,KAAKiH,QAAQQ,IAAII,EAAsBqB,oBAChE,GAAIc,EAAiBf,QAAUA,EAC3B,MAAM,IAAIvJ,MAAM,kBAEpB,MAAM4B,QAAiBiC,MAAMvD,KAAK6D,IAAIsE,MAAO,CACzClE,OAAQ,OACR1C,QAAS,CACL,eAAgB,qCAEpBsD,KAAM,IAAIC,gBAAgB,CACtB,CAAC,YAAa9E,KAAK+H,UACnB,CAAC,OAAQ8B,GACT,CAAC,aAAc,sBACf,CAAC,gBAAiBG,EAAiBb,UACnC,CAAC,QAASa,EAAiBf,OAC3B,CAAC,eAAgBjJ,KAAK6D,IAAIyE,cAGlC,IAAKhH,EAAS6E,GAAI,CACd,MAAMrE,QAAaR,EAASQ,OAC5B,MAAM,IAAIpC,MAAM,SAAW4B,EAASN,OAAS,KAAOc,EAChE,CACQ,MAAMqG,QAAc7G,EAASI,OAC7B,OAAO,IAAIuI,EAA6BjK,KAAK+H,SAAUI,EAAOnI,KAAK6D,IAC3E,CACI,oBAAMqG,GACF,MAAMd,EAAM,IAAIlB,IAAIvF,OAAOC,SAASC,MAC9BgH,EAAOT,EAAIC,aAAa7H,IAAI,QAClC,GAAIqI,GAAQ7J,KAAKiH,QAAQG,KAAKS,EAAsBqB,oBAAqB,CAErE,MAAMD,EAAQG,EAAIC,aAAa7H,IAAI,SACnC,aAAaxB,MAAK4J,EAAeC,EAAMZ,EACnD,CAGQ,aADMjJ,KAAKwI,OAAOxI,KAAK6D,IAAIoE,KAAM,CAAA,GAC1B,IACf,EAEAJ,EAAsBqB,mBAAqB,qBAE3C,MAAMe,EACF,iBAAOE,CAAWhC,GACd,MAAOiC,EAAWC,EAAYC,GAAanC,EAAMzH,MAAM,KACjD6J,EAAc,IAAIC,YAAY,SACpC,MAAO,CACHpF,OAAQG,KAAKjF,MAAMiK,EAAY7L,OAAOd,EAAOc,OAAO0L,EAAWxM,EAAO4B,YACtEiL,QAASlF,KAAKjF,MAAMiK,EAAY7L,OAAOd,EAAOc,OAAO2L,EAAYzM,EAAO4B,YACxE8K,UAAWA,EAElB,CACD,WAAA3K,CAAYoI,EAAU2C,GAAGvC,MAACA,EAAKC,OAAEA,EAAME,SAAEA,IACrCtI,KAAK+H,SAAWA,EAChB/H,KAAKmI,MAAQuC,EACb1K,KAAK2K,QAAUV,EAA6BE,WAAWO,EAAEE,UACzD5K,KAAK6K,YAAcZ,EAA6BE,WAAWO,EAAEI,cAC7D9K,KAAK+K,aAAed,EAA6BE,WAAWO,EAAEM,eAC9DhL,KAAK6D,IAAM,CAAEsE,QAAOC,SAAQE,YAC5BtI,KAAKiL,gBAAkB,IAC/B,CACI,SAAAC,CAAUxF,GACN1F,KAAKiL,gBAAkBvF,CAC/B,CACI,aAAMyF,GACF,MAAM7J,QAAiBiC,MAAMvD,KAAK6D,IAAIsE,MAAO,CACzClE,OAAQ,OACR1C,QAAS,CACL,eAAgB,qCAEpBsD,KAAM,IAAIC,gBAAgB,CACtB,CAAC,YAAa9E,KAAK+H,UACnB,CAAC,aAAc,iBACf,CAAC,gBAAiB/H,KAAKmI,MAAM6C,mBAGrC,IAAK1J,EAAS6E,GAAI,CACd,MAAMrE,QAAaR,EAASQ,OAC5B,MAAM,IAAIpC,MAAM,SAAW4B,EAASN,OAAS,KAAOc,EAChE,CACQ,MAAMqG,QAAc7G,EAASI,OAC7B1B,KAAKmI,MAAQA,EACbnI,KAAK2K,QAAUV,EAA6BE,WAAWhC,EAAMyC,UAC7D5K,KAAK6K,YAAcZ,EAA6BE,WAAWhC,EAAM2C,cACjE9K,KAAK+K,aAAed,EAA6BE,WAAWhC,EAAM6C,eAC9DhL,KAAKiL,iBACLjL,KAAKiL,gBAAgBjL,KAAKmI,MAAOnI,KAAK6K,YAAa7K,KAAK+K,aAEpE,CACI,iBAAAK,CAAkBC,GACd,MAAMC,GAAM,IAAIC,MAAOC,UACjBC,EAAwD,IAAhCzL,KAAK+K,aAAaN,QAAQiB,IAGxD,QAFgBJ,EAAMG,IACAH,EAAMD,EAAcI,CAElD,CACI,eAAME,CAAUN,GACPrL,KAAKoL,kBAAkBC,UAGtBrL,KAAKmL,SACnB,CACI,MAAA/C,GACI,MAAMgB,EAAM,IAAIlB,IAAIlI,KAAK6D,IAAIuE,QAC7BgB,EAAIC,aAAa9G,IAAI,2BAA4BvC,KAAK6D,IAAIyE,UAC1Dc,EAAIC,aAAa9G,IAAI,gBAAiBvC,KAAKmI,MAAMyC,UACjDjI,OAAOC,SAASC,KAAOuG,EAAII,UACnC,CAEI,WAAAoC,GACI,MAAO,UAAU5L,KAAKmI,MAAM2C,cACpC,CAEI,WAAApH,CAAYmI,EAAmBC,GAC3B,OAAO,IAAIC,EAAiC/L,KAAM6L,EAAmBC,EAC7E,EAGA,MAAMC,EACFC,GACAH,GACAC,GACA,WAAAnM,CAAYqM,EAASH,EAAmBC,GACpC9L,MAAKgM,EAAWA,EAChBhM,MAAK6L,EAAqBA,GAAqB,IAC/C7L,MAAK8L,EAAoBA,GAAoB,GACrD,CACI,eAAM1J,CAAUC,EAASC,SACftC,MAAKgM,EAASL,UAAU3L,MAAK6L,GACnCxJ,EAAQd,QAAQgB,IAAI,gBAAiBvC,MAAKgM,EAASJ,eACnD,MAAMtK,QAAiBgB,EAAME,QAAQH,GAErC,aADMrC,MAAKgM,EAASL,UAAU3L,MAAK8L,GAC5BxK,CACf,ECvLK,MAAC2K,EAAS,CACXC,MAAMC,GACK,IAAIC,SAAQC,GAAWC,WAAWD,EAASF,KAEtDI,iBAAkB,EAClBC,mBAAoB,EACpB,QAAAC,CAASC,EAAWC,EAAM7I,GACtB,IAAI8I,EAAM,KACNC,EAAO,GACPC,EAAoB,EACpB5G,EAAOpC,GAAWmI,EAAOM,iBAE7B,MAAMQ,EAAQ,KACV,MAAMC,GAAU,IAAIzB,MAAOC,UAAYsB,EACnCJ,EAAYM,EACZJ,EAAMN,WAAWS,EAAOL,EAAYM,IAGxCJ,EAAM,KACF1G,IAAS+F,EAAOO,oBAChBG,KAAQE,GAGA,OAARD,IACAC,EAAO,IACvB,EAGQ,OAAO,WACHA,EAAO,IAAII,WACXH,GAAoB,IAAIvB,MAAOC,UACnB,OAARoB,IACAA,EAAMN,WAAWS,EAAOL,GACpBxG,IAAS+F,EAAOO,oBAChBG,KAAQE,GAGnB,CACJ,EACDK,iBAAkB,EAClBC,oBAAqB,EACrBC,qBAAsB,EACtB,QAAAC,CAASX,EAAWC,EAAM7I,GACtB,IAAI8I,EAAM,KACNC,EAAO,GACPC,EAAoB,EACpB5G,EAAOpC,GAAWmI,EAAOiB,iBAE7B,MAAMH,EAAQ,KACVD,EAAqB5G,EAAO+F,EAAOkB,oBAAuB,GAAI,IAAI5B,MAAOC,UACzEoB,EAAM,KACND,KAAQE,GACI,OAARD,IACAC,EAAO,GACvB,EAGQ,OAAO,WACH,MAAMvB,GAAM,IAAIC,MAAOC,WAClBsB,GAAsB5G,EAAO+F,EAAOkB,sBACrCL,EAAoBxB,GAExB,MAAMgC,EAAYZ,GAAapB,EAAMwB,GACrCD,EAAO,IAAII,WACPK,GAAa,GAAKA,EAAYZ,GAClB,OAARE,IACAW,aAAaX,GACbA,EAAM,MAEVE,EAAoBxB,EACpBqB,KAAQE,GACI,OAARD,IACAC,EAAO,KAEI,OAARD,GAAkB1G,EAAO+F,EAAOmB,uBACvCR,EAAMN,WAAWS,EAAOO,GAE/B,CAET,GC/EA,MAAME,EAOF,cAAOC,CAAQC,EAAKlN,GAChB,OAAOuF,OAAO4H,KAAKD,GAAKE,QAAO,CAACC,EAAK7L,KACjC,MAAM8L,EAAMtN,EAAO/B,OAAS+B,EAAS,IAAM,GAM3C,MALsB,iBAAXkN,EAAI1L,IAA8B,OAAX0L,EAAI1L,GAClC+D,OAAOgI,OAAOF,EAAKL,EAASC,QAAQC,EAAI1L,GAAI8L,EAAM9L,IAElD6L,EAAIC,EAAM9L,GAAK0L,EAAI1L,GAEhB6L,CAAG,GACX,GACX,CAOI,kBAAOG,CAAYC,EAAQC,EAAMzH,GAC7B,MAAMkH,EAAOO,EAAKxN,MAAM,KAAKyN,KAAKnM,GAAM,WAAWoM,KAAKpM,IAAMA,EAAIA,IAClE,IAAIyB,EAAUwK,GAAU,CAAE,EACtBI,EAAW,KACf,IAAK,IAAI9P,EAAI,KAAOA,EAAG,CACnB,MAAM+P,EAAOX,EAAKpP,GACZgQ,EAAOZ,EAAKpP,EAAI,GAQtB,GAPIiQ,OAAOC,UAAUH,KAAUI,MAAMC,QAAQlL,KACxB,OAAb4K,EACAA,EAASE,GAAQ9K,EAAU,GAE3BwK,EAASxK,EAAU,IAGvBlF,IAAMoP,EAAKlP,OAAS,EAGpB,OADAgF,EAAQ6K,QAAkBtJ,IAAVyB,EAAsBA,EAAS6H,KAAQ7K,EAAUA,EAAQ6K,GAAQ,KAC1EL,OAEWjJ,IAAlBvB,EAAQ6K,KACR7K,EAAQ6K,GAAQ,CAAE,GAEtBD,EAAW5K,EACXA,EAAUA,EAAQ6K,EAC9B,CACA,CAMI,cAAOM,CAAQC,GACX,GAAgC,UAA5BA,EAAG1M,aAAa,QAAqB,CACrC,IAAK0M,EAAGC,QACJ,OAEJ,MAAqC,YAA9BD,EAAGE,QAAqB,YAA+B,SAAbF,EAAGpI,MAAmBoI,EAAGpI,KACtF,CACQ,MAAgC,aAA5BoI,EAAG1M,aAAa,QACT0M,EAAGC,QAEoB,YAA9BD,EAAGE,QAAqB,YAChBF,EAAGpI,MAA4B,SAAboI,EAAGpI,MAAV,OAEJ,UAAfoI,EAAGG,SAAsC,WAAfH,EAAGG,SACT,KAAbH,EAAGpI,YAA6BzB,IAAb6J,EAAGpI,OAAsB,KAEhDoI,EAAGpI,KAClB,CAEI,kBAAOwI,CAAYC,EAAMC,GACrB,IAAIlB,EAAS,CAAE,EACf,IAAI,MAAMY,KAA6CK,EAAKE,iBAAiB,UACpC,UAAjCP,EAAGE,QAAwB,iBAG5BI,GAA4D,WAAjCN,EAAGE,QAAwB,gBAA0D,OAAxCF,EAAGQ,QAAQF,KAGtFlB,EAAST,EAASQ,YAAYC,EAA8BY,EAAG1M,aAAa,QAAUqL,EAASoB,QAAQC,MAE3G,OAAOZ,CACf,CAOI,aAAOqB,CAAOT,EAAIU,GACkB,UAA5BV,EAAG1M,aAAa,QAIY,aAA5B0M,EAAG1M,aAAa,QAIpB0M,EAAGpI,MAAQ8I,EAHPV,EAAGC,QAAUS,EAJbV,EAAGC,QAAUD,EAAG1M,aAAa,WAAaoN,CAQtD,CAEI,eAAOC,CAASN,EAAMpI,GAClB,IAAK,MAAO2I,EAAchJ,KAAUV,OAAOb,QAAQsI,EAASC,QAAQ3G,EAAQ,KACxE,IAAI,MAAM+H,KAAMK,EAAKE,iBAAiB,UAAUM,IAAIC,OAAOF,QACvDjC,EAAS8B,OAAOT,EAAIpI,EAGpC,CAGI,aAAOmJ,CAAOV,EAAMW,EAAIC,GACpB,MAAMC,EAAcF,EAAGG,QAAOC,GAAgB,gBAAXA,EAAE9P,MAAqC,mBAAX8P,EAAE9P,OAC3D+P,EAAeL,EAAGG,QAAOC,GAAgB,gBAAXA,EAAE9P,MAAqC,mBAAX8P,EAAE9P,OAClE+O,EAAKE,iBAAiB,IAAIM,IAAIC,OAAOG,MAAiBxG,SAAQuF,GAAMA,EAAGsB,UAAU5I,OAAOuI,KACxFZ,EAAKE,iBAAiB,cAAc9F,SAAQuF,IACxCA,EAAGuB,kBACHvB,EAAGwB,aAAa,SAAU,GAAG,IAEjCN,EAAYzG,SAAQ2G,IAChB,MAAMhQ,EAAOgQ,EAAE/O,QAAQoP,QAAQ,IAAK,KAAKA,QAAQ,KAAM,KACjDC,EAA4B,UAAUb,IAAIC,OAAO1P,uCAA0CyP,IAAIC,OAAO1P,0CAC5GiP,EAAKE,iBAAiBmB,GAA2BjH,SAAQkH,GAASA,EAAML,UAAUM,IAAIX,KACtF,MAAMY,EAAsB,0BAA0BhB,IAAIC,OAAO1P,OACjEiP,EAAKE,iBAAiBsB,GAAqBpH,SAAQuF,IACR,EACnC8B,UAAYV,EAAE9O,MAAA,GACpB,IAEN+N,EAAKE,iBAAiB,cAAc9F,SAAQuF,IACD,EACnC8B,UAAYT,EAAa/B,KAAI8B,GAAKA,EAAE9O,SAAQyP,KAAK,MACzB,IAAxBV,EAAazR,QACboQ,EAAGgC,gBAAgB,SACnC,GAIA,EC1IA,MAAMC,UAAaC,EAAaA,iBAC5BC,iCAAmC,oBACnCA,qBAAuB,GACvBA,qBAAuB,aACvBC,UACA,MAAAC,GACI,MAAMC,EAAOlP,SAASmP,cAAc,QACpCC,EAAAA,WAAWC,QAAQ,QAAStR,KAAMmR,GAClCA,EAAKf,mBAAmBpQ,KAAKuR,YAC7BJ,EAAKK,iBAAiB,UAAU/M,MAAOwL,IACnCA,EAAEwB,iBACFzR,KAAK0R,UAASjN,gBACJzE,KAAKiR,YAAYjR,KAAK8G,OAAQ9G,MAAK,GAC3C,IAEFA,KAAK2R,aAAa,4BAClB3R,KAAKwR,iBAAiB,UAAUI,IAC5B,MAAMC,EAAmCD,EAAU,OACnDC,GAAQzC,iBAAiB,IAAIM,IAAIC,OAAOmB,EAAKgB,kBAAkBxI,SAAQuF,IACnEA,EAAGsB,UAAU5I,OAAOuJ,EAAKgB,cAAc,GACzC,IAGV9R,KAAKoQ,gBAAgBe,EAC7B,CACI,OAAAY,CAAQC,GACJhS,KAAKoP,iBAAiB,eAAe9F,SAAQuF,IACH,EAClCoD,QAAUD,CAAI,IAEtBhS,KAAKoP,iBAAiB,8BAA8B9F,SAAQuF,IACZ,EACxCqD,SAAWF,CAAA,GAE3B,CACI,cAAMG,CAASC,GACX,UACUA,GACT,CAAC,MAAOnC,GAIL,MAHIA,aAAaxQ,IACbO,KAAK4P,OAASK,EAAEpQ,UAEdoQ,CAClB,CACA,CACI,wBAAMoC,CAAmBD,GACrBpS,KAAK+R,SAAQ,GACb,UACU/R,KAAKmS,SAASC,EACvB,CAAC,MAAOnC,GAEL,MADAjQ,KAAK+R,SAAQ,GACP9B,CAClB,CACA,CACI,cAAMyB,CAASU,GACXpS,KAAK+R,SAAQ,GACb,UACU/R,KAAKmS,SAASC,EAChC,CAAkB,QACNpS,KAAK+R,SAAQ,EACzB,CACA,CACI,UAAIjL,CAAOwL,GACP9E,EAASgC,SAASxP,KAAMsS,EAChC,CACI,UAAIxL,GACA,OAAO0G,EAASyB,YAAYjP,KAAM8Q,EAAKyB,0BAC/C,CACI,UAAI3C,CAAOC,GAEP,GADArC,EAASoC,OAAO5P,KAAM6P,EAAIiB,EAAKgB,eACd,GAAbjC,EAAGpR,SAAgBuB,KAAK2R,aAAa,mBACrC,OAEJ,MAAMa,EAAK9D,MAAM+D,KAAKzS,KAAKoP,iBAAiB,wDAAwD0B,EAAKgB,mCACpG3D,KAAIU,GAAMA,EAAG6D,cAAgB7D,EAAG6D,cAAgB7D,IAChDV,KAAIU,GAAMA,EAAG8D,wBAAwBC,EAAIjQ,OAAOkQ,UAC/CC,EAAOjU,KAAKkU,OAAOP,GACrBM,IAASE,KACTrQ,OAAOsQ,OAAOtQ,OAAOuQ,QAASJ,EAAOhC,EAAKqC,cAAgBL,EAAOhC,EAAKqC,cAAgB,EAElG,EClFK,MAACC,EAAiB,gpBAcjBC,EAAoB,CAACxE,EAAIyE,EAAUC,KACrC,MAAM/C,EAAQ3B,EAAG2B,MAAQ+C,EAAM/C,MAAQ+C,EAAM/C,OAAOgD,mBAAqB,MACrE,MAAM3E,EAAK5M,SAASmP,cAAc,SAElC,OADAvC,EAAGsB,UAAUM,IAAI,gBACV5B,CACV,EAJwE,GAKzE2B,EAAMH,aAAa,wBAAyB,IAC5CG,EAAMgB,iBAAiB,UAAWI,IAC9BA,EAAI6B,kBACJ5E,EAAG6E,cAAc,IAAIC,YAAY,SAAU,CACvCC,SAAS,EACTC,YAAY,EACZhS,OAAQ,CACJ4E,MAAOoI,EAAGpI,SAEf,IAEP,MAAMqN,EAAKtD,EAAMrO,aAAa,OAAS0M,EAAG1M,aAAa,aAAekP,aAAW0C,IAAI,aACrF1C,EAAAA,WAAWC,QAAQ,SAAUzC,EAAI0E,EAAM/C,OACvCa,EAAAA,WAAW2C,aAAaT,EAAM/C,MAAO,KAAMsD,GAC3CzC,EAAAA,WAAW2C,aAAaT,EAAM/C,MAAO,OAAQ,QAC7Ca,EAAAA,WAAW2C,aAAaT,EAAM/C,MAAO,cAAe,KACpD,MAAMvQ,EAAO4O,EAAG1M,aAAa,QAC7B,OAAOmR,EAASW,YAAYpF,EAAI,CAAEiF,KAAI7T,OAAMsT,UAASrC,QAAQ,EAGjE,MAAMgD,UAAcnD,EAAAA,cAAc,CAC9BoD,SAAU,CAAC,SACXZ,OAAO,EACPD,SAAUF,KAEV5C,MACA,MAAAU,EAAOqC,MAACA,IACJ,MAAMa,EAAWf,EAAkBrT,KAAMA,KAAKsT,WAAYC,GAC1DvT,KAAKoQ,gBAAgBgE,EAC7B,CACI,SAAI3N,GACA,OAAOzG,KAAKwQ,MAAM/J,KAC1B,CACI,SAAIA,CAAMA,GACNzG,KAAKwQ,MAAM/J,MAAQA,CAC3B,EClDA,MAAM4N,UAAetD,EAAAA,cAAc,CAC/BoD,SAAU,CAAC,SACXZ,OAAO,EACPD,SAAU,8wBAeVgB,WACAC,qBACAC,GACA,WAAA7U,CAAY8U,GACR1U,QACAC,KAAKyU,SAAWA,CACxB,CACI,MAAAvD,EAAOqC,MAACA,IACJ,MACMmB,EAAiB,UADV1U,KAAKmC,aAAa,SAAW,SAEpCwS,EAAwC,UAA7B3U,KAAKmC,aAAa,QAC7BlC,EAAOD,KAAKmC,aAAa,QACzBqO,EAAQ+C,EAAM/C,MAAQ+C,EAAM/C,OAAOgD,mBAC9BvR,SAASmP,cAAc,UAElCZ,EAAMH,aAAa,wBAAyB,IAE5C,MAAMyD,EAAKtD,EAAMrO,aAAa,OAASnC,KAAKmC,aAAa,aAAekP,aAAW0C,IAAI,cACjFa,EAAO,GAAGd,eAChBzC,EAAAA,WAAWC,QAAQ,SAAUtR,KAAMwQ,GACnCa,EAAAA,WAAW2C,aAAaxD,EAAO,KAAMsD,GACrCzC,EAAAA,WAAW2C,aAAaxD,EAAO,cAAe,KAI9C+C,EAAM/C,MAAQqE,YAAUpC,KAAKjC,GAE7BxQ,KAAK8U,QAAUJ,EAQf1U,KAAK+U,QAAUL,EAKf1U,KAAKuU,qBAAuB9P,MAAOuQ,EAAOtP,KAEtC,IAAKgP,GAAUA,GAAUC,GAAY3U,KAAK8U,OAEtC,YADApP,IAGJ,MAAMvF,EAAO6U,GAASA,EAAMC,eAAe,QAAU,KAAO,QACtDC,EAAkB,OAAT/U,EAAgB6U,EAAMG,KAAOH,EACtCvT,QAAczB,MAAKoV,EAAUpV,MAAKoV,EAAQF,EAAQ/U,GAAQ,IACnD,OAATA,IACAH,KAAK8U,QAAS,GAElBpP,EAASjE,EAAK,EAElBzB,KAAKwU,GAAK,IAAIa,EAAU7E,EAAOzK,OAAOgI,OAAO2G,EAAS,CAClDY,QAAS,QACTlO,KAAMpH,KAAKuU,qBACXD,WAAaU,IAAUhV,KAAKsU,YAAatU,KAAKsU,WAAWU,IACzD,GA7BoB,CACpB9D,OAAQ,CACJqE,QAAS,IAAM,qDA2BEvV,KAAKyU,WAC9BzU,KAAKwU,GAAGgB,GAAG,UAAU/O,IACjBzG,KAAK0T,cAAc,IAAIC,YAAY,SAAU,CACzCC,SAAS,EACTC,YAAY,EACZhS,OAAQ,CACJ4E,MAAOzG,KAAKyG,SAEjB,IAGP+J,EAAMgB,iBAAiB,UAAWI,IAC9BA,EAAI6B,iBAAiB,IAEzBjD,EAAMjJ,SACNvH,KAAKsT,WAAWW,YAAY,CAAEH,KAAIc,OAAM3U,OAAMuQ,QAAO+C,UAASkC,SAASzV,KAC/E,CACIoV,GACA,UAAIA,CAAOM,GACP1V,MAAKoV,EAAUM,EAEX1V,KAAK2R,aAAa,WAClB3R,KAAKyG,MAAQzG,KAAKmC,aAAa,SAE3C,CACI,SAAIsE,GACA,MAAMlG,EAAIP,KAAKwU,GAAGmB,WAClB,MAAa,KAANpV,EAAW,KAAOA,CACjC,CACI,SAAIkG,CAAMA,GACN,WACQzG,KAAK+U,eACC/U,KAAKuU,qBAAqB,CAAEY,KAAM1O,GAASzG,KAAKwU,GAAGoB,aAAaC,KAAK7V,KAAKwU,KAGpFxU,KAAKwU,GAAGsB,SAASrP,GADF,EAElB,EAND,EAOR,ECtHA,MAAMsP,UAAmBhF,EAAAA,cAAc,CACnCoD,SAAU,CAAC,QAAS,qBACpBZ,OAAO,EACPD,SAAU,kyBAuBV,MAAApC,EAAOqC,MAACA,IACJ,MAAMtT,EAAOD,KAAKmC,aAAa,SAAWkP,EAAUA,WAAC0C,IAAI,kBACnDiC,EAAWtH,MAAM+D,KAAKc,EAAM0C,QAAQ7G,iBAAiB,cACrD8G,EAAkBF,EAAS7H,KAAIU,IACjC,MAAM2B,EAAQvO,SAASmP,cAAc,SACrCZ,EAAMH,aAAa,OAAQ,SAC3BgB,EAAAA,WAAWC,QAAQ,SAAUtR,KAAMwQ,GACnCa,EAAAA,WAAWC,QAAQ,GAAIzC,EAAI2B,GAC3BA,EAAMH,aAAa,OAAQ,GAAGpQ,YAC9BuQ,EAAMH,aAAa,wBAAyB,IAC5CG,EAAMzB,QAAwB,eAAI,QAClCyB,EAAMgB,iBAAiB,UAAUI,IAC7BA,EAAI6B,kBAEJzT,KAAK0T,cAAc,IAAIC,YAAY,SAAU,CACzCC,SAAS,EACTC,YAAY,EACZhS,OAAQ,CACJ4E,MAAOzG,KAAKyG,SAEjB,IAGP,MAAO,CAAC+J,EADMqE,EAAAA,UAAUsB,eAAetH,GAClB,IAGzBmH,EAAS1M,SAAQuF,GAAMA,EAAGtH,WAC1BvH,KAAKsT,WAAWW,YAAY,CAAEhU,OAAMsT,QAAO2C,oBAAmBT,SAASzV,KAC/E,CACI,YAAIkS,GACA,OAAOlS,KAAK2R,aAAa,WACjC,CACI,YAAIO,CAASzL,GACTzG,KAAKoW,SAAQ,IAAM/E,EAAUA,WAACgF,OAAOrW,KAAM,WAAYyG,IAC1D,CACD,SAAIA,GAEA,MAAMqI,EAAU9O,KAAKkC,cAAc,6BACnC,OAAO4M,EAAUA,EAAQrI,MAAQ,IACzC,CACI,SAAIA,CAAMA,GACN,GAAc,OAAVA,EAIA,YAHAzG,KAAKoP,iBAAiB,qBAAqB9F,SAAQuF,IAC/C,EAAsCC,SAAU,CAAA,IAKxD,MAAMD,EAAK7O,KAAKkC,cAAc,2BAA2BwN,IAAIC,OAAOlJ,OAChEoI,IACAA,EAAGC,SAAU,EAEzB,EC9EA,MAAMwH,UAAgBvF,EAAAA,cAAc,CAChCwC,OAAO,EACPD,SAAU,kMAOV,MAAApC,EAAOqC,MAACA,IACJvT,KAAKsT,WAAWW,YAAY,CAAEV,UAASkC,SAASzV,KACxD,4JXwCA,MACI,aAAOtB,CAAO6X,GACV,GAAIA,EAAI9X,OAAS,GAAM,EACnB,MAAM,IAAIiB,MAAM,kBAEpB,MAAM8W,EAAaD,EAAI9X,OAAS,EAChC,OAAO,IAAIJ,WAAWmY,GAAYrI,KAAI,CAAC8B,EAAG1R,KACtC,MAAMkY,EAAa,EAAJlY,EACTmY,EAAQH,EAAI/X,UAAUiY,EAAQA,EAAS,GAC7C,OAAOE,SAASD,EAAO,GAAG,GAEtC,CACI,aAAO7Y,CAAO+Y,EAAOC,GACjB,OAAOnI,MAAM+D,KAAKmE,GACTzI,KAAI2I,GAAKA,EAAEtN,SAAS,MACpB2E,KAAI2I,GAAKD,EAAQC,EAAEC,cAAgBD,IACnC3I,KAAI6I,GAAKA,EAAEC,SAAS,EAAG,KACvBrG,KAAK,GACtB,kFGhDA,cAA2B5J,EACvB,WAAArH,CAAYa,GACRT,MAAMS,EAAQ0W,aACtB,6FASA,MACI,WAAAvX,CAAYsH,EAASkQ,EAAKC,GACtBpX,KAAKiH,QAAUA,EACfjH,KAAKmX,IAAMA,EACXnX,KAAKoX,aAAeA,EACpBpX,KAAKqX,MAAQ,IAErB,CACI,UAAMjQ,CAAKkQ,GACP,MAAMC,EAAQvX,KAAKiH,QAAQG,KAAKpH,KAAKmX,KACrC,GAAMI,GAASA,EAAMD,WAAaA,EAE9B,YADAtX,KAAKqX,MAAQE,EAAM9Q,OAGvB,MAAM+Q,QAAkBxX,KAAKoX,aAAaE,EAAUtX,KAAKmX,KACzDnX,KAAKiH,QAAQC,KAAKlH,KAAKmX,IAAK,CACxBG,SAAUA,EACV7Q,MAAO+Q,IAEXxX,KAAKqX,MAAQG,CACrB,CACI,IAAA/V,GACI,OAAOzB,KAAKqX,KACpB"}