1document.addEventListener("alpine:init",()=>{Alpine.store("productVariant",{selectedVariantId:null,quantity:1,variants:[],selectedOptions:[],init(t,a){this.selectedVariantId=t,this.variants=a||[],this.initFromURL()},setVariants(t){this.variants=t},updateVariant(t){const a=this.variants.find(i=>i.id===t);a&&(this.selectedVariantId=t,this.selectedOptions=[...a.options],this.updateURL(),document.dispatchEvent(new CustomEvent("variantChange",{detail:{variant:a,variantId:t}})))},updateVariantFromOptions(t){this.selectedOptions=[...t];const a=this.variants.find(i=>i.options.every((n,e)=>n===t[e]));a&&(this.selectedVariantId=a.id,this.updateURL(),document.dispatchEvent(new CustomEvent("variantChange",{detail:{variant:a,variantId:a.id}})))},getSelectedVariant(){return this.variants.find(a=>a.id===this.selectedVariantId)},updateQuantity(t){this.quantity=Math.max(1,parseInt(t)||1)},incrementQuantity(){this.quantity++},decrementQuantity(){this.quantity=Math.max(1,this.quantity-1)},updateURL(){if(!this.selectedVariantId)return;const t=new URL(window.location);t.searchParams.set("variant",this.selectedVariantId),window.history.replaceState({variantId:this.selectedVariantId},"",t.toString())},initFromURL(){const a=new URL(window.location).searchParams.get("variant");if(a){const i=parseInt(a),n=this.variants.find(e=>e.id===i);n&&(this.selectedVariantId=i,this.selectedOptions=[...n.options])}},isCurrentVariantAvailable(){const t=this.getSelectedVariant();return t?t.available:!1},getCurrentVariantPrice(){const t=this.getSelectedVariant();return t?t.price:null}}),window.addEventListener("popstate",t=>{t.state&&t.state.variantId?Alpine.store("productVariant").updateVariant(t.state.variantId):Alpine.store("productVariant").initFromURL()})});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.