<!-- 2026-01-25T05:45:47.4087543Z -->
<style>.shoplift-hide { opacity: 0 !important; }</style>
<style id="sl-preview-bar-hide">#preview-bar-iframe, #PBarNextFrameWrapper { display: none !important; }</style>
<script type="text/javascript">(function(rootPath, template, themeRole, themeId, isThemePreview){ /* Generated on 2026-01-29T15:45:02.4955064Z */(function(){"use strict";var $=document.createElement("style");$.textContent=`#shoplift-preview-control{position:fixed;max-width:332px;height:56px;background-color:#141414;z-index:9999;bottom:20px;display:flex;border-radius:8px;box-shadow:13px 22px 7px #0000,9px 14px 7px #00000003,5px 8px 6px #0000000d,2px 4px 4px #00000017,1px 1px 2px #0000001a,0 0 #0000001a;align-items:center;margin:0 auto;left:16px;right:16px;opacity:0;transform:translateY(20px);visibility:hidden;transition:opacity .4s ease-in-out,transform .4s ease-in-out,visibility 0s .4s}#shoplift-preview-control.visible{opacity:1;transform:translateY(0);visibility:visible;transition:opacity .4s ease-in-out,transform .4s ease-in-out,visibility 0s 0s}#shoplift-preview-control *{font-family:Inter,sans-serif;color:#fff;box-sizing:border-box;font-size:16px}#shoplift-preview-variant-title{font-weight:400;line-height:140%;font-size:16px;text-align:start;letter-spacing:-.16px;flex-grow:1;text-wrap:nowrap;overflow:hidden;text-overflow:ellipsis}#shoplift-preview-variant-selector{position:relative;display:block;padding:6px 0;height:100%;min-width:0;flex:1 1 auto}#shoplift-preview-variant-menu-trigger{border:none;cursor:pointer;width:100%;background-color:transparent;padding:0 16px;border-left:1px solid #333;border-right:1px solid #333;height:100%;display:flex;align-items:center;justify-content:start;gap:8px}#shoplift-preview-variant-selector .menu-variant-label{width:24px;height:24px;border-radius:50%;padding:6px;display:flex;justify-content:center;align-items:center;font-size:12px;font-style:normal;font-weight:600;line-height:100%;letter-spacing:-.12px;flex-shrink:0}#shoplift-preview-variant-selector .preview-variant-menu{position:absolute;bottom:110%;transform:translate3d(0,20px,0);visibility:hidden;pointer-events:none;opacity:0;cursor:pointer;background-color:#141414;border:1px solid #141414;border-radius:6px;width:100%;max-height:156px;overflow-y:auto;box-shadow:0 8px 16px #0003;z-index:1;transition:opacity .3s ease-in-out,transform .3s ease-in-out,visibility 0s .3s}#shoplift-preview-variant-selector .preview-variant-menu.preview-variant-menu__visible{visibility:visible;pointer-events:auto;opacity:100;transform:translateZ(0);transition:opacity .3s ease-in-out,transform .3s ease-in-out,visibility 0s 0s}@media screen and (max-width:400px){#shoplift-preview-variant-selector .preview-variant-menu{position:fixed;left:0;right:0;width:auto;bottom:110%}}#shoplift-preview-variant-selector .preview-variant-menu .preview-variant-menu--item{padding:12px 16px;display:flex;overflow:hidden}#shoplift-preview-variant-selector .preview-variant-menu .preview-variant-menu--item .menu-variant-label{margin-right:6px}#shoplift-preview-variant-selector .preview-variant-menu .preview-variant-menu--item span{overflow:hidden;text-overflow:ellipsis;text-wrap:nowrap;white-space:nowrap;color:#f6f6f6;font-size:14px;font-style:normal;font-weight:500}#shoplift-preview-variant-selector .preview-variant-menu .preview-variant-menu--item:hover{background-color:#545454}#shoplift-preview-variant-selector .preview-variant-menu .preview-variant-menu--item:last-of-type{border-bottom-left-radius:6px;border-bottom-right-radius:6px}#shoplift-preview-variant-selector .preview-variant-menu .preview-variant-menu--item:first-of-type{border-top-left-radius:6px;border-top-right-radius:6px}#shoplift-preview-control div:has(#shoplift-exit-preview-button){padding:0 16px}#shoplift-exit-preview-button{padding:6px 8px;font-weight:500;line-height:75%;border-radius:4px;background-color:transparent;border:none;text-decoration:none}#shoplift-exit-preview-button:hover{cursor:pointer;background-color:#333}/*$vite$:1*/`,document.head.appendChild($);var B=" daum[ /]| deusu/| yadirectfetcher|(?:^|[^g])news(?!sapphire)|(?<! (?:channel/|google/))google(?!(app|/google| pixel))|(?<! cu)bots?(?:\\b|_)|(?<!(?: ya| yandex|^job|inapp;) ?)search|(?<!(?:lib))http|(?<![hg]m)score|@[a-z][\\w-]+\\.|\\(\\)|\\.com|\\b\\d{13}\\b|^<|^[\\w \\.\\-\\(?:\\):]+(?:/v?\\d+(?:\\.\\d+)?(?:\\.\\d{1,10})*?)?(?:,|$)|^[^ ]{50,}$|^\\d+\\b|^\\w+/[\\w\\(\\)]*$|^active|^ad muncher|^amaya|^avsdevicesdk/|^biglotron|^bot|^bw/|^clamav[ /]|^client/|^cobweb/|^custom|^ddg[_-]android|^discourse|^dispatch/\\d|^downcast/|^duckduckgo|^facebook|^getright/|^gozilla/|^hobbit|^hotzonu|^hwcdn/|^jeode/|^jetty/|^jigsaw|^microsoft bits|^movabletype|^mozilla/\\d\\.\\d \\(compatible;?\\)$|^mozilla/\\d\\.\\d \\w*$|^navermailapp|^netsurf|^offline|^owler|^postman|^python|^rank|^read|^reed|^rest|^rss|^snapchat|^space bison|^svn|^swcd |^taringa|^thumbor/|^track|^valid|^w3c|^webbandit/|^webcopier|^wget|^whatsapp|^wordpress|^xenu link sleuth|^yahoo|^yandex|^zdm/\\d|^zoom marketplace/|^{{.*}}$|admin|analyzer|archive|ask jeeves/teoma|bit\\.ly/|bluecoat drtr|browsex|burpcollaborator|capture|catch|check|chrome-lighthouse|chromeframe|classifier|clean|cloud|crawl|cypress/|dareboost|datanyze|dejaclick|detect|dmbrowser|download|evc-batch/|feed|firephp|gomezagent|headless|httrack|hubspot marketing grader|hydra|ibisbrowser|images|insight|inspect|iplabel|ips-agent|java(?!;)|library|mail\\.ru/|manager|measure|neustar wpm|node|nutch|offbyone|optimize|pageburst|pagespeed|parser|perl|phantomjs|pingdom|powermarks|preview|proxy|ptst[ /]\\d|reputation|resolver|retriever|rexx;|rigor|rss\\b|scan|scrape|server|sogou|sparkler/|speedcurve|spider|splash|statuscake|synapse|synthetic|tools|torrent|trace|transcoder|url|virtuoso|wappalyzer|watch|webglance|webkit2png|whatcms/|zgrab",G=/bot|spider|crawl|http|lighthouse/i,V;function K(){if(V instanceof RegExp)return V;try{V=new RegExp(B,"i")}catch{V=G}return V}function j(l){return!!l&&K().test(l)}class L{timestamp;constructor(){this.timestamp=new Date}}class W extends L{type;testId;hypothesisId;constructor(t,e,i){super(),this.type=3,this.testId=t,this.hypothesisId=e,this.timestamp=i}}class J extends L{type;path;constructor(t){super(),this.type=4,this.path=t}}class Y extends L{type;cart;constructor(t){super(),this.type=5,this.cart=t}}class D extends Error{isBot;constructor(){super(),this.isBot=!0}}function Z(l,t,e){for(const i of t.selectors){const s=l.querySelectorAll(i.cssSelector);for(let r=0;r<s.length;r++)e(t.testId,t.hypothesisId)}H(l,t,(i,s,r,o,n)=>n(s,r),e)}function x(l,t,e){for(const i of t.selectors)F(l,t.testId,t.hypothesisId,i,e??(()=>{}));H(l,t,F,e??(()=>{}))}function M(l){return l.urlPatterns.reduce((t,e)=>{switch(e.operator){case"contains":return t+`.*${e}.*`;case"endsWith":return t+`.*${e}`;case"startsWith":return t+`${e}.*`}},"")}function H(l,t,e,i){new MutationObserver(()=>{for(const r of t.selectors)e(l,t.testId,t.hypothesisId,r,i)}).observe(l.documentElement,{childList:!0,subtree:!0})}function F(l,t,e,i,s){const r=l.querySelectorAll(i.cssSelector);for(let o=0;o<r.length;o++){let n=r.item(o);if(n instanceof HTMLElement&&n.dataset.shoplift!==""){n.dataset.shoplift="";for(const a of i.actions.sort(ot))n=Q(l,i.cssSelector,n,a)}}return r.length>0&&s?(s(t,e),!0):!1}function Q(l,t,e,i){switch(i.type){case"innerHtml":e.innerHTML=i.value;break;case"attribute":X(e,i.scope,i.value);break;case"css":tt(l,t,i.value);break;case"js":et(l,e,i);break;case"copy":return it(e);case"remove":st(e);break;case"move":rt(e,parseInt(i.value));break}return e}function X(l,t,e){l.setAttribute(t,e)}function tt(l,t,e){const i=l.createElement("style");i.innerHTML=`${t} { ${e} }`,l.getElementsByTagName("head")[0]?.appendChild(i)}function et(l,t,e){Function("document","element",`"use strict"; ${e.value}`)(l,t)}function it(l){const t=l.cloneNode(!0);if(!l.parentNode)throw"Can't copy node outside of DOM";return l.parentNode.insertBefore(t,l.nextSibling),t}function st(l){l.remove()}function rt(l,t){if(t===0)return;const e=Array.prototype.slice.call(l.parentElement.children).indexOf(l),i=Math.min(Math.max(e+t,0),l.parentElement.children.length-1);l.parentElement.children.item(i).insertAdjacentElement(t>0?"afterend":"beforebegin",l)}function ot(l,t){return N(l)-N(t)}function N(l){return l.type==="copy"||l.type==="remove"?0:1}var P=(l=>(l[l.Template=0]="Template",l[l.Theme=1]="Theme",l[l.UrlRedirect=2]="UrlRedirect",l[l.Script=3]="Script",l[l.Dom=4]="Dom",l[l.Price=5]="Price",l))(P||{});const nt="data:image/svg+xml,%3csvg%20width='12'%20height='12'%20viewBox='0%200%2012%2012'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='M9.96001%207.90004C9.86501%207.90004%209.77001%207.86504%209.69501%207.79004L6.43501%204.53004C6.19501%204.29004%205.80501%204.29004%205.56501%204.53004L2.30501%207.79004C2.16001%207.93504%201.92001%207.93504%201.77501%207.79004C1.63001%207.64504%201.63001%207.40504%201.77501%207.26004L5.03501%204.00004C5.56501%203.47004%206.43001%203.47004%206.96501%204.00004L10.225%207.26004C10.37%207.40504%2010.37%207.64504%2010.225%207.79004C10.15%207.86004%2010.055%207.90004%209.96001%207.90004Z'%20fill='white'/%3e%3c/svg%3e",at="data:image/svg+xml,%3csvg%20width='14'%20height='24'%20viewBox='0%200%2014%2024'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='M12.3976%2014.5255C12.2833%2013.8788%2012.0498%2013.3024%2011.6952%2012.7961C11.3416%2012.2898%2010.9209%2011.8353%2010.4353%2011.4317C9.94868%2011.0291%209.43546%2010.6488%208.89565%2010.292C8.48487%2010.049%208.09577%209.78565%207.72637%209.50402C7.35697%209.2224%207.08016%208.89503%206.89694%208.51987C6.71273%208.14471%206.67826%207.69533%206.79055%207.1697C6.86345%206.83216%206.97476%206.54647%207.12351%206.31162C7.27324%206.07778%207.47124%205.89986%207.7175%205.77684C7.96377%205.65483%208.21989%205.59383%208.48389%205.59383C8.88087%205.59383%209.17639%205.7016%209.3734%205.91714C9.56943%206.13268%209.68271%206.42345%209.71424%206.78946C9.74576%207.15547%209.72015%207.55401%209.63839%207.98509C9.55663%208.41617%209.43645%208.84724%209.27687%209.27934L13.5127%208.80149C13.9638%207.52656%2014.1017%206.42447%2013.9264%205.49725C13.751%204.56901%2013.2664%203.85122%2012.4724%203.34491C12.239%203.19648%2011.9779%203.07041%2011.6893%202.96569L12.0026%201.50979L9.86397%200L7.3875%201.50979L7.11169%202.78878C6.65166%202.8874%206.21724%203.01957%205.8114%203.19038C4.85292%203.594%204.06684%204.15115%203.45117%204.86385C2.83452%205.57655%202.42571%206.40108%202.22378%207.33847C2.06616%208.06947%202.04942%208.70796%202.17551%209.25087C2.30061%209.7948%202.52028%2010.2828%202.8355%2010.7139C3.14974%2011.145%203.51816%2011.5344%203.93977%2011.881C4.36039%2012.2288%204.782%2012.5521%205.20164%2012.851C5.68334%2013.1702%206.13844%2013.5169%206.56497%2013.8921C6.99052%2014.2672%207.31954%2014.7125%207.55004%2015.228C7.78055%2015.7445%207.81502%2016.3769%207.65347%2017.1262C7.56482%2017.5389%207.43676%2017.8765%207.27028%2018.1388C7.10381%2018.4011%206.89596%2018.5983%206.64772%2018.7295C6.3985%2018.8606%206.12071%2018.9267%205.8114%2018.9267C5.21641%2018.9267%204.79776%2018.6034%204.62833%2018.1632C4.4589%2017.7229%204.47367%2017.2583%204.60075%2016.5639C4.72782%2015.8705%205.05092%2015.1395%205.37107%2014.3699H1.17665C1.17665%2014.3699%200.207341%2016.1115%200.0310135%2017.6762C-0.0655232%2018.5302%200.0635208%2019.2653%200.41519%2019.8844C0.76686%2020.5036%201.33032%2020.9814%202.10655%2021.319C2.39222%2021.443%202.7104%2021.5447%203.05813%2021.623L2.54589%2024H7.17473L7.7047%2021.5386C8.08493%2021.442%208.43857%2021.3231%208.76562%2021.1787C9.73985%2020.7476%2010.52%2020.1427%2011.1071%2019.3649C11.6932%2018.5871%2012.0873%2017.7291%2012.2892%2016.7917C12.4744%2015.9295%2012.5099%2015.1741%2012.3966%2014.5275L12.3976%2014.5255Z'%20fill='white'/%3e%3c/svg%3e";async function lt(l){let t=l.replace(/-/g,"+").replace(/_/g,"/");for(;t.length%4;)t+="=";const e=atob(t),i=Uint8Array.from(e,o=>o.charCodeAt(0)),s=new Blob([i]).stream().pipeThrough(new DecompressionStream("gzip")),r=await new Response(s).text();return JSON.parse(r)}function _(l,t){return typeof t=="string"&&/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d+(?:Z|[+-]\d+)/.test(t)?new Date(t):t}function O(l,t){return t}function k(l,t=!1,e=!1,i=","){const s=l/100;if(e){const o=Math.round(s).toLocaleString("en-US");return i!==","?o.replace(/,/g,i):o}else{const r=t?",":".",o=s.toFixed(2).split("."),n=parseInt(o[0],10),a=o[1]??"00",c=n.toLocaleString("en-US");return i!==","?`${c.replace(/,/g,i)}${r}${a}`:t?`${c.replace(/,/g,".")}${r}${a}`:`${c}${r}${a}`}}function R(l,t,e,i){const s=t.replace("{{amount}}",k(l,!1,!1)).replace("{{amount_no_decimals}}",k(l,!1,!0)).replace("{{amount_with_comma_separator}}",k(l,!0,!1)).replace("{{amount_no_decimals_with_comma_separator}}",k(l,!0,!0)).replace("{{amount_with_space_separator}}",k(l,!1,!1," ")).replace("{{amount_no_decimals_with_space_separator}}",k(l,!1,!0," ")).replace("{{amount_with_apostrophe_separator}}",k(l,!1,!1,"'")).replace("{{amount_no_decimals_with_apostrophe_separator}}",k(l,!1,!0,"'")).replace("{{amount_with_period_and_space_separator}}",k(l,!1,!1,". ")).replace("{{amount_no_decimals_with_period_and_space_separator}}",k(l,!1,!0,". "));return i?`${s} ${e}`:s}function q(l){return l.replace(/[^\d.,\s-]/g,"").trim()}function ct(l){const t=new Map;for(const[e,i,s]of l.v)t.set(e,{priceInCents:i,compareAtPriceInCents:s});return t}function dt(l,t,e,i){const{priceInCents:s,compareAtPriceInCents:r}=e,{mf:o,c:n,cce:a}=i;if(l.getAttribute("data-sl-attribute-p")===t)l.innerHTML=R(s,o,n,a);else if(l.getAttribute("data-sl-attribute-cap")===t)r<=0||r<=s?l.remove():l.innerHTML=R(r,o,n,a);else if(l.getAttribute("data-sl-attribute-discount")===t&&!(r<=0||r<=s)){const h=Math.round((r-s)/r*100),u=q(R(r-s,o,n,!1)),p=l.getAttribute("data-sl-format")||"percent";p==="percent"?l.textContent=`-${h}%`:p==="amount"?l.textContent=`-${u}`:p==="both"&&(l.textContent=`-${h}% (-${u})`)}}function ht(l){const t=[],e={id:"url-pattern",operator:"contains",value:"/"};for(const[i,s,r]of l.v){t.push({id:`p-${i}`,cssSelector:`[data-sl-attribute-p="${i}"]`,urlPatterns:[e],actions:[{id:`p-action-${i}`,type:"innerHtml",scope:"price",value:R(s,l.mf,l.c,l.cce)}]});const o=r<=0||r<=s;if(t.push({id:`cap-${i}`,cssSelector:`[data-sl-attribute-cap="${i}"]`,urlPatterns:[e],actions:[{id:`cap-action-${i}`,type:o?"remove":"innerHtml",scope:"compare-at-price",value:o?"":R(r,l.mf,l.c,l.cce)}]}),!o&&r>s){const n=Math.round((r-s)/r*100),a=q(R(r-s,l.mf,l.c,!1));t.push({id:`d-${i}`,cssSelector:`[data-sl-attribute-discount="${i}"]`,urlPatterns:[e],actions:[{id:`d-action-${i}`,type:"js",scope:null,value:`(function(doc, el) { var format = el.getAttribute('data-sl-format') || 'percent'; if (format === 'percent') { el.textContent = '-${n}%'; } else if (format === 'amount') { el.textContent = '-${a}'; } else if (format === 'both') { el.textContent = '-${n}% (-${a})'; } })`}]})}}return t}let U=!1;class pt{constructor(t,e,i,s,r,o,n,a,c,h,u){this.shop=t,this.host=e,this.eventHost=i,this.disableReferrerOverride=a,this.logHistory=[],this.legacySessionKey=`SHOPLIFT_SESSION_${this.shop}`,this.cssHideClass=s?"shoplift-hide":"",this.testConfigs=h.map(d=>({...d,startAt:new Date(d.startAt),statusHistory:d.statusHistory.map(v=>({...v,createdAt:new Date(v.createdAt)}))})),this.inactiveTestConfigs=u,this.sendPageView=!!r,this.shopliftDebug=o===!0,this.gaConfig=n!=={"sendEvents":false,"mode":"gtag"}?n:{sendEvents:!1},this.fetch=window.fetch.bind(window),this.localStorageSet=window.localStorage.setItem.bind(window.localStorage),this.localStorageGet=window.localStorage.getItem.bind(window.localStorage);const p=this.getDeviceType();this.device=p!=="tablet"?p:"mobile",this.state=this.loadState(),this.shopifyAnalyticsId=this.getShopifyAnalyticsId(),this.testsFilteredByAudience=h.filter(d=>d.status=="active"),this.getCountryTimeout=c===1000?1e3:c,this.log("State Loaded",JSON.stringify(this.state))}DATA_SL_ATTRIBUTE_P="data-sl-attribute-p";DATA_SL_TEST_ID="data-sl-test-id";VIEWPORT_TRACK_THRESHOLD=.5;temporarySessionKey="Shoplift_Session";essentialSessionKey="Shoplift_Essential";analyticsSessionKey="Shoplift_Analytics";priceSelectorsSessionKey="Shoplift_PriceSelectors";legacySessionKey;cssHideClass;testConfigs;inactiveTestConfigs;testsFilteredByAudience;sendPageView;shopliftDebug;gaConfig;getCountryTimeout;state;shopifyAnalyticsId;cookie=document.cookie;isSyncing=!1;isSyncingGA=!1;fetch;localStorageSet;localStorageGet;sessionStorageSet=window.sessionStorage.setItem.bind(window.sessionStorage);sessionStorageGet=window.sessionStorage.getItem.bind(window.sessionStorage);urlParams=new URLSearchParams(window.location.search);device;logHistory;activeViewportObservers=new Map;deriveCategoryFromExistingTests(){if(!this.state.temporary.testCategory&&this.state.essential.visitorTests.length>0){const t=this.state.essential.visitorTests.some(e=>{if(!e.hypothesisId)return!1;const i=this.getHypothesis(e.hypothesisId);return i&&["theme","basicScript","price"].includes(i.type)});this.state.temporary.testCategory=t?"global":"conditional",this.persistTemporaryState(),this.log("Derived test category from existing visitorTests: %s",this.state.temporary.testCategory)}}async init(){try{if(this.log("Shoplift script initializing"),window.Shopify&&window.Shopify.designMode){this.log("Skipping script for design mode");return}if(window.location.href.includes("slScreenshot=true")){this.log("Skipping script for screenshot");return}if(window.location.hostname.endsWith(".edgemesh.com")){this.log("Skipping script for preview");return}if(window.location.href.includes("isShopliftMerchant")){const e=this.urlParams.get("isShopliftMerchant")==="true";this.log("Setting merchant session to %s",e),this.state.temporary.isMerchant=e,this.persistTemporaryState()}if(this.state.temporary.isMerchant){this.log("Setting up preview for merchant"),typeof window.shoplift!="object"&&this.setShopliftStub(),this.state.temporary.previewConfig||this.hidePage(),await this.initPreview(),document.querySelector("#sl-preview-bar-hide")?.remove();return}if(this.state.temporary.previewConfig=void 0,j(navigator.userAgent))return;if(navigator.userAgent.includes("Chrome/118")){this.log("Random: %o",[Math.random(),Math.random(),Math.random()]);const e=await this.makeRequest({url:`${this.eventHost}/api/v0/events/ip`,method:"get"}).then(i=>i?.json());this.log(`IP: ${e}`),this.makeRequest({url:`${this.eventHost}/api/v0/logs`,method:"post",data:JSON.stringify(this.debugState(),O)}).catch()}if(this.shopifyAnalyticsId=this.getShopifyAnalyticsId(),this.monitorConsentChange(),this.checkForThemePreview())return;if(!this.disableReferrerOverride&&this.state.temporary.originalReferrer!=null){this.log(`Overriding referrer from '${document.referrer}' to '${this.state.temporary.originalReferrer}'`);const e=this.state.temporary.originalReferrer;delete this.state.temporary.originalReferrer,this.persistTemporaryState(),Object.defineProperty(document,"referrer",{get:()=>e,enumerable:!0,configurable:!0})}if(await this.refreshVisitor(this.shopifyAnalyticsId),await this.handleVisitorTest()){this.log("Redirecting for visitor test");return}this.setShoplift(),this.showPage(),this.ensureCartAttributesForExistingPriceTests(!1),await this.finalize(),console.log("SHOPLIFT SCRIPT INITIALIZED!")}catch(t){if(t instanceof D)return;throw t}finally{typeof window.shoplift!="object"&&this.setShopliftStub()}}getVariantColor(t){switch(t){case"a":return{text:"#141414",bg:"#E2E2E2"};case"b":return{text:"rgba(255, 255, 255, 1)",bg:"rgba(37, 99, 235, 1)"}}}getDefaultVariantTitle(t){return t.title?t.title:t.type==="price"?t.isControl?"Original prices":"Variant prices":t.isControl?"Original":"Untitled variant "+t.label.toUpperCase()}async initPreview(){const t=this.urlParams.get("previewConfig");if(t){this.state.temporary.previewConfig=void 0,this.log("Setting up the preview"),this.log("Found preview config, writing to temporary state");const e=await lt(t);if(this.state.temporary.previewConfig=e,this.state.temporary.previewConfig.testTypeCategory===P.Price){this.hidePage(!0);const s=this.state.temporary.previewConfig;let r=`${this.host}/api/dom-selectors/${s.storeId}/${s.testId}/${s.isDraft||!1}`;s.shopifyProductId&&(r+=`?productId=${s.shopifyProductId}`);const o=await this.makeJsonRequest({method:"get",url:r}).catch(n=>(this.log("Error getting domSelectors",n),null));s.variants.forEach(n=>n.domSelectors=o[n.id]?.domSelectors)}this.persistTemporaryState();const i=new URL(window.location.toString());i.searchParams.delete("previewConfig"),this.queueRedirect(i)}else if(this.state.temporary.previewConfig){this.showPage();const e=this.state.temporary.previewConfig;e.testTypeCategory===P.Template&&this.handleTemplatePreview(e)&&this.initPreviewControls(e),e.testTypeCategory===P.UrlRedirect&&this.handleUrlPreview(e)&&this.initPreviewControls(e),e.testTypeCategory===P.Script&&this.handleScriptPreview(e)&&this.initPreviewControls(e),e.testTypeCategory===P.Price&&await this.handlePricePreview(e)&&this.initPreviewControls(e)}}initPreviewControls(t){document.addEventListener("DOMContentLoaded",()=>{const e=t.variants.find(v=>v.id===t.currentVariant),i=e?.label||"a",s=t.variants,r=document.createElement("div");r.id="shoplift-preview-control";const o=document.createElement("div"),n=document.createElement("img");n.src=at,n.height=24,n.width=14,o.style.padding="0 16px",o.style.lineHeight="100%",o.appendChild(n),r.appendChild(o);const a=document.createElement("div");a.id="shoplift-preview-variant-selector";const c=document.createElement("button");c.id="shoplift-preview-variant-menu-trigger";const h=document.createElement("div");h.className="menu-variant-label",h.style.backgroundColor=this.getVariantColor(i).bg,h.style.color=this.getVariantColor(i).text,h.innerText=i.toUpperCase(),c.appendChild(h);const u=document.createElement("span");if(u.id="shoplift-preview-variant-title",u.innerText=e?this.getDefaultVariantTitle(e):"Untitled variant "+i.toUpperCase(),c.appendChild(u),s.length>1){const v=document.createElement("img");v.src=nt,v.width=12,v.height=12,v.style.height="12px",v.style.width="12px",c.appendChild(v);const T=document.createElement("div");T.className="preview-variant-menu";for(const m of t.variants.filter(S=>S.id!==t.currentVariant)){const S=document.createElement("div");S.className="preview-variant-menu--item";const I=document.createElement("div");I.className="menu-variant-label",I.style.backgroundColor=this.getVariantColor(m.label).bg,I.style.color=this.getVariantColor(m.label).text,I.style.flexShrink="0",I.innerText=m.label.toUpperCase(),S.appendChild(I);const y=document.createElement("span");y.innerText=this.getDefaultVariantTitle(m),S.appendChild(y),S.addEventListener("click",()=>{this.pickVariant(m.id)}),T.appendChild(S)}a.appendChild(T),c.addEventListener("click",()=>{T.className!=="preview-variant-menu preview-variant-menu__visible"?T.classList.add("preview-variant-menu__visible"):T.classList.remove("preview-variant-menu__visible")}),document.addEventListener("click",m=>{m.target instanceof Element&&!c.contains(m.target)&&T.className==="preview-variant-menu preview-variant-menu__visible"&&T.classList.remove("preview-variant-menu__visible")})}else c.style.pointerEvents="none",h.style.margin="0";a.appendChild(c),r.appendChild(a);const p=document.createElement("div"),d=document.createElement("button");d.id="shoplift-exit-preview-button",d.innerText="Exit",p.appendChild(d),d.addEventListener("click",()=>{this.exitPreview()}),r.appendChild(p),document.body.appendChild(r),requestAnimationFrame(()=>{r.classList.add("visible")})}),this.ensureCartAttributesForExistingPriceTests(!0)}pickVariant(t){if(this.state.temporary.previewConfig){const e=this.state.temporary.previewConfig,i=new URL(window.location.toString());if(e.testTypeCategory===P.UrlRedirect){const s=e.variants.find(r=>r.id===e.currentVariant)?.redirectUrl;if(i.pathname===s){const r=e.variants.find(o=>o.id===t)?.redirectUrl;r&&(i.pathname=r)}}if(e.testTypeCategory===P.Template){const s=e.variants.find(r=>r.id===e.currentVariant)?.pathName;if(s&&i.pathname===s){const r=e.variants.find(o=>o.id===t)?.pathName;r&&r!==s&&(i.pathname=r)}}e.currentVariant=t,this.persistTemporaryState(),this.queueRedirect(i)}}exitPreview(){const t=new URL(window.location.toString());if(this.state.temporary.previewConfig?.testTypeCategory===P.Template&&t.searchParams.delete("view"),this.state.temporary.previewConfig?.testTypeCategory===P.Script&&t.searchParams.delete("slVariant"),this.state.temporary.previewConfig?.testTypeCategory===P.UrlRedirect){const i=this.state.temporary.previewConfig.variants.filter(r=>!r.isControl&&r.redirectUrl!==null).map(r=>r.redirectUrl),s=this.state.temporary.previewConfig.variants.find(r=>r.label==="a")?.redirectUrl;i.includes(t.pathname)&&s&&(t.pathname=s)}this.state.temporary.isMerchant=!1,t.searchParams.delete("isShopliftMerchant"),this.state.temporary.previewConfig=void 0,this.persistTemporaryState(),this.hidePage(),this.queueRedirect(t)}handleTemplatePreview(t){const e=t.currentVariant,i=t.variants.find(a=>a.id===e);if(!i)return!1;const s=t.variants.find(a=>a.isControl);if(!s)return!1;this.log("Setting up template preview for type",s.type);const r=new URL(window.location.toString()),o=r.searchParams.get("view"),n=i.type===s.type;return!n&&!i.isControl&&template.suffix===s.affix&&this.typeFromTemplate()===s.type&&i.pathName!==null?(this.log("Hit control template type, redirecting to the variant url"),this.hidePage(),r.pathname=i.pathName,this.queueRedirect(r),!0):(!i.isControl&&this.typeFromTemplate()==i.type&&template.suffix===s.affix&&n&&o!==(i.affix||"__DEFAULT__")&&(this.log("Template type and affix match control, updating the view param"),r.searchParams.delete("view"),this.log("Setting the new viewParam to",i.affix||"__DEFAULT__"),this.hidePage(),r.searchParams.set("view",i.affix||"__DEFAULT__"),this.queueRedirect(r)),o!==null&&o!==i.affix&&(r.searchParams.delete("view"),this.hidePage(),this.queueRedirect(r)),!0)}handleUrlPreview(t){const e=t.currentVariant,i=t.variants.find(o=>o.id===e),s=t.variants.find(o=>o.isControl)?.redirectUrl;if(!i)return!1;this.log("Setting up URL redirect preview");const r=new URL(window.location.toString());return r.pathname===s&&!i.isControl&&i.redirectUrl!==null&&(this.log("Url matches control, redirecting"),this.hidePage(),r.pathname=i.redirectUrl,this.queueRedirect(r)),!0}handleScriptPreview(t){const e=t.currentVariant,i=t.variants.find(o=>o.id===e);if(!i)return!1;this.log("Setting up script preview");const s=new URL(window.location.toString());return s.searchParams.get("slVariant")!==i.id&&(this.log("current id doesn't match the variant, redirecting"),s.searchParams.delete("slVariant"),this.log("Setting the new slVariantParam"),this.hidePage(),s.searchParams.set("slVariant",i.id),this.queueRedirect(s)),!0}async handlePricePreview(t){const e=t.currentVariant,i=t.variants.find(s=>s.id===e);return i?(this.log("Setting up price preview"),i.domSelectors&&i.domSelectors.length>0&&(x(document,{testId:t.testId,hypothesisId:i.id,selectors:i.domSelectors}),this.ensureCartAttributesForExistingPriceTests(!0)),!0):!1}async finalize(){const t=await this.getCartState();t!==null&&this.queueCartUpdate(t),this.pruneStateAndSave(),await this.syncAllEvents()}setShoplift(){this.log("Setting up public API");const e=this.urlParams.get("slVariant")==="true",i=e?null:this.urlParams.get("slVariant");window.shoplift={isHypothesisActive:async s=>{if(this.log("Script checking variant for hypothesis '%s'",s),e)return this.log("Forcing variant for hypothesis '%s'",s),!0;if(i!==null)return this.log("Forcing hypothesis '%s'",i),s===i;const r=this.testConfigs.find(n=>n.hypotheses.some(a=>a.id===s));if(!r)return this.log("No test found for hypothesis '%s'",s),!1;const o=this.state.essential.visitorTests.find(n=>n.testId===r.id);return o?(this.log("Active visitor test found",s),o.hypothesisId===s):(await this.manuallySplitVisitor(r),this.testConfigs.some(n=>n.hypotheses.some(a=>a.id===s&&this.state.essential.visitorTests.some(c=>c.hypothesisId===a.id))))},setAnalyticsConsent:async s=>{await this.onConsentChange(s,!0)},getVisitorData:()=>({visitor:this.state.analytics.visitor,visitorTests:this.state.essential.visitorTests.filter(s=>!s.isInvalid).map(s=>{const{shouldSendToGa:r,savedAt:o,...n}=s;return n})})}}setShopliftStub(){this.log("Setting up stubbed public API");const e=this.urlParams.get("slVariant")==="true",i=e?null:this.urlParams.get("slVariant");window.shoplift={isHypothesisActive:s=>Promise.resolve(e||s===i),setAnalyticsConsent:()=>Promise.resolve(),getVisitorData:()=>({visitor:null,visitorTests:[]})}}async manuallySplitVisitor(t){this.log("Starting manual split for test '%s'",t.id),await this.handleVisitorTest([t]);const e=this.getReservationForTest(t.id);e&&!e.isRealized&&e.entryCriteriaKey&&(this.log("Realizing manual API reservation for test '%s'",t.id),this.realizeReservationForCriteria(e.entryCriteriaKey)),this.saveState(),this.syncAllEvents()}async handleVisitorTest(t){await this.filterTestsByAudience(this.testConfigs,this.state.analytics.visitor??this.buildBaseVisitor(),this.state.essential.visitorTests),this.deriveCategoryFromExistingTests(),this.clearStaleReservations();let e=t?t.filter(i=>this.testsFilteredByAudience.some(s=>s.id===i.id)):[...this.testsForUrl(this.testsFilteredByAudience),...this.domTestsForUrl(this.testsFilteredByAudience)];try{if(e.length===0)return this.log("No tests found"),!1;this.log("Checking for existing visitor test on page");const i=this.getCurrentVisitorHypothesis(e);if(i){this.log("Found current visitor test");const a=this.considerRedirect(i);return a&&(this.log("Redirecting for current visitor test"),this.redirect(i)),a}const s=this.getReservationForCurrentPage();if(s){this.log("Found matching reservation for current page: %s",s.testId);const a=this.getHypothesis(s.hypothesisId);if(a){a.type!=="price"&&this.realizeReservationForCriteria(s.entryCriteriaKey);const c=this.considerRedirect(a);return c&&this.redirect(a),c}}this.log("No active test relation for test page");const r=this.testsForUrl(this.inactiveTestConfigs.filter(a=>this.testIsPaused(a)&&a.hypotheses.some(c=>this.state.essential.visitorTests.some(h=>h.hypothesisId===c.id)))).map(a=>a.id);if(r.length>0)return this.log("Visitor has paused tests for test page, skipping test assignment: %o",r),!1;if(!this.state.temporary.testCategory){const a=this.testsFilteredByAudience.filter(h=>this.isGlobalEntryCriteria(this.getEntryCriteriaKey(h))),c=this.testsFilteredByAudience.filter(h=>!this.isGlobalEntryCriteria(this.getEntryCriteriaKey(h)));if(this.log("Category dice roll - global tests: %o, conditional tests: %o",a.map(h=>({id:h.id,title:h.title,criteria:this.getEntryCriteriaKey(h)})),c.map(h=>({id:h.id,title:h.title,criteria:this.getEntryCriteriaKey(h)}))),a.length>0&&c.length>0){const h=a.length,u=c.length,p=h+u,d=Math.random()*p;this.state.temporary.testCategory=d<h?"global":"conditional",this.log("Category dice roll: rolled %.2f of %d (global weight: %d, conditional weight: %d), selected '%s'",d,p,h,u,this.state.temporary.testCategory)}else a.length>0?(this.state.temporary.testCategory="global",this.log("Only global tests available, setting category to global")):(this.state.temporary.testCategory="conditional",this.log("Only conditional tests available, setting category to conditional"));this.persistTemporaryState()}const o=this.state.temporary.testCategory;if(this.log("Visitor test category: %s",o),o==="global"){const a=this.testsFilteredByAudience.filter(c=>!this.isGlobalEntryCriteria(this.getEntryCriteriaKey(c)));for(const c of a)this.markTestAsBlocked(c,"category:global");e=e.filter(c=>this.isGlobalEntryCriteria(this.getEntryCriteriaKey(c)))}else{const a=this.testsFilteredByAudience.filter(c=>this.isGlobalEntryCriteria(this.getEntryCriteriaKey(c)));for(const c of a)this.markTestAsBlocked(c,"category:conditional");e=e.filter(c=>!this.isGlobalEntryCriteria(this.getEntryCriteriaKey(c)))}if(e.length===0)return this.log("No tests remaining after category filter"),!1;this.createReservations(e);const n=this.getReservationForCurrentPage();if(n&&!n.isRealized){const a=this.getHypothesis(n.hypothesisId);if(a){a.type!=="price"&&this.realizeReservationForCriteria(n.entryCriteriaKey);const c=this.considerRedirect(a);return c&&(this.log("Redirecting for new test"),this.redirect(a)),c}}return!1}finally{this.includeInDomTests(),this.saveState()}}includeInDomTests(){this.applyControlForAudienceFilteredPriceTests();const t=this.getDomTestsForCurrentUrl(),e=this.getVisitorDomHypothesis(t);for(const i of t){this.log("Evaluating dom test '%s'",i.id);const s=i.hypotheses.some(d=>d.type==="price");if(this.state.essential.visitorTests.find(d=>d.testId===i.id&&d.isInvalid&&!d.hypothesisId)){if(this.log("Visitor is blocked from test '%s', applying control prices if price test",i.id),s){const d=i.hypotheses.find(v=>v.isControl);d?.priceData&&(this.applyPriceTestWithMapLookup(i.id,d,[d],()=>{this.log("Control prices applied for blocked visitor, no metrics tracked")}),this.updatePriceTestHiddenInputs(i.id,"control",!1))}continue}const o=this.getReservationForTest(i.id);let n=null,a=!1;const c=e.find(d=>i.hypotheses.some(v=>d.id===v.id));if(o)n=this.getHypothesis(o.hypothesisId)??null,this.log("Using reserved hypothesis '%s' for test '%s'",o.hypothesisId,i.id);else if(c)n=c,this.log("Using existing hypothesis assignment for test '%s'",i.id);else if(s){const d=this.visitorActiveTestTypeWithReservations();d?(a=!0,this.log("Visitor already in test type '%s', treating as non-test for price test '%s'",d,i.id)):n=this.pickHypothesis(i)}else n=this.pickHypothesis(i);if(a&&s){const d=i.hypotheses.find(v=>v.isControl);d?.priceData&&(this.log("Applying control prices for non-test visitor on price test '%s' (Map-based)",i.id),this.applyPriceTestWithMapLookup(i.id,d,[d],()=>{this.log("Control prices applied for non-test visitor, no metrics tracked")}),this.updatePriceTestHiddenInputs(i.id,"control",!1));continue}if(!n){this.log("Failed to pick hypothesis for test");continue}const h=i.bayesianRevision??4,u=n.type==="price",p=h>=5;if(u&&p){if(this.log(`Price test with Map-based lookup (v${h}): ${i.id}`),!n.priceData){this.log("No price data for hypothesis '%s', skipping",n.id);continue}const d=n.isControl?"control":"variant";this.log(`Setting up Map-based price test for ${d} (test: ${i.id})`),this.applyPriceTestWithMapLookup(i.id,n,i.hypotheses,v=>{const T=this.getReservationForTest(v);T&&!T.isRealized&&T.entryCriteriaKey?this.realizeReservationForCriteria(T.entryCriteriaKey):this.queueAddVisitorToTest(v,n),this.saveState(),this.queuePageView(window.location.pathname),this.syncAllEvents()});continue}if(u&&!p){this.log(`Price test without viewport tracking (v${h}): ${i.id}`);const d=this.getDomSelectorsForHypothesis(n);if(d.length===0)continue;x(document,{testId:i.id,hypothesisId:n.id,selectors:d},v=>{this.queueAddVisitorToTest(v,n),this.saveState(),this.queuePageView(window.location.pathname),this.syncAllEvents()});continue}if(!n.domSelectors||n.domSelectors.length===0){this.log("No selectors found, skipping hypothesis");continue}x(document,{testId:i.id,hypothesisId:n.id,selectors:n.domSelectors},d=>{this.queueAddVisitorToTest(d,n),this.saveState(),this.queuePageView(window.location.pathname),this.syncAllEvents()})}}considerRedirect(t){if(this.log("Considering redirect for hypothesis '%s'",t.id),t.isControl)return this.log("Skipping redirect for control"),!1;if(t.type==="basicScript"||t.type==="manualScript")return this.log("Skipping redirect for script test"),!1;const e=this.state.essential.visitorTests.find(o=>o.hypothesisId===t.id),i=new URL(window.location.toString()),r=new URLSearchParams(window.location.search).get("view");if(t.type==="theme"){if(!(t.themeId===themeId)){if(this.log("Theme id '%s' is not hypothesis theme ID '%s'",t.themeId,themeId),e&&e.themeId!==t.themeId&&(e.themeId===themeId||!this.isThemePreview()))this.log("On old theme, redirecting and updating local visitor"),e.themeId=t.themeId;else if(this.isThemePreview())return this.log("On non-test theme, skipping redirect"),!1;return this.log("Hiding page to redirect for theme test"),this.hidePage(),!0}return!1}else if(t.type!=="dom"&&t.type!=="price"&&t.affix!==template.suffix&&t.affix!==r||t.redirectPath&&!i.pathname.endsWith(t.redirectPath))return this.log("Hiding page to redirect for template test"),this.hidePage(),!0;return this.log("Not redirecting"),!1}redirect(t){if(this.log("Redirecting to hypothesis '%s'",t.id),t.isControl)return;const e=new URL(window.location.toString());if(e.searchParams.delete("view"),t.redirectPath){const i=RegExp("^(/w{2}-w{2})/").exec(e.pathname);if(i&&i.length>1){const s=i[1];e.pathname=`${s}${t.redirectPath}`}else e.pathname=t.redirectPath}else t.type==="theme"?(e.searchParams.set("_ab","0"),e.searchParams.set("_fd","0"),e.searchParams.set("_sc","1"),e.searchParams.set("preview_theme_id",t.themeId.toString())):t.type!=="urlRedirect"&&e.searchParams.set("view",t.affix);this.queueRedirect(e)}async refreshVisitor(t){if(t===null||!this.state.essential.isFirstLoad||!this.testConfigs.some(i=>i.visitorOption!=="all"))return;this.log("Refreshing visitor"),this.hidePage();const e=await this.getVisitor(t);e&&e.id&&this.updateLocalVisitor(e)}buildBaseVisitor(){return{shopifyAnalyticsId:this.shopifyAnalyticsId,device:this.device,country:null,...this.state.essential.initialState}}getInitialState(){const t=this.getUTMValue("utm_source")??"",e=this.getUTMValue("utm_medium")??"",i=this.getUTMValue("utm_campaign")??"",s=this.getUTMValue("utm_content")??"",r=window.document.referrer,o=this.device;return{createdAt:new Date,utmSource:t,utmMedium:e,utmCampaign:i,utmContent:s,referrer:r,device:o}}checkForThemePreview(){return this.log("Checking for theme preview"),window.location.hostname.endsWith(".shopifypreview.com")?(this.log("on shopify preview domain"),this.clearThemeBar(!0,!1,this.state),document.querySelector("#sl-preview-bar-hide")?.remove(),!1):this.isThemePreview()?this.state.essential.visitorTests.some(t=>t.isThemeTest&&t.hypothesisId!=null&&this.getHypothesis(t.hypothesisId)&&t.themeId===themeId)?(this.log("On active theme test, removing theme bar"),this.clearThemeBar(!1,!0,this.state),!1):this.state.essential.visitorTests.some(t=>t.isThemeTest&&t.hypothesisId!=null&&!this.getHypothesis(t.hypothesisId)&&t.themeId===themeId)?(this.log("Visitor is on an inactive theme test, redirecting to main theme"),this.redirectToMainTheme(),!0):this.state.essential.isFirstLoad?(this.log("No visitor found on theme preview, redirecting to main theme"),this.redirectToMainTheme(),!0):this.inactiveTestConfigs.some(t=>t.hypotheses.some(e=>e.themeId===themeId))?(this.log("Current theme is an inactive theme test, redirecting to main theme"),this.redirectToMainTheme(),!0):this.testConfigs.some(t=>t.hypotheses.some(e=>e.themeId===themeId))?(this.log("Falling back to clearing theme bar"),this.clearThemeBar(!1,!0,this.state),!1):(this.log("No tests on current theme, skipping script"),this.clearThemeBar(!0,!1,this.state),document.querySelector("#sl-preview-bar-hide")?.remove(),!0):(this.log("Not on theme preview"),this.clearThemeBar(!0,!1,this.state),!1)}redirectToMainTheme(){this.hidePage();const t=new URL(window.location.toString());t.searchParams.set("preview_theme_id",""),this.queueRedirect(t)}testsForUrl(t){const e=new URL(window.location.href),i=this.typeFromTemplate();return t.filter(s=>s.hypotheses.some(r=>r.type!=="dom"&&r.type!=="price"&&(r.isControl&&r.type===i&&r.affix===template.suffix||r.type==="theme"||r.isControl&&r.type==="urlRedirect"&&r.redirectPath&&e.pathname.endsWith(r.redirectPath)||r.type==="basicScript"))&&(s.ignoreTestViewParameterEnforcement||!e.searchParams.has("view")||s.hypotheses.map(r=>r.affix).includes(e.searchParams.get("view")??"")))}domTestsForUrl(t){const e=new URL(window.location.href);return t.filter(i=>i.hypotheses.some(s=>s.type!=="dom"&&s.type!=="price"?!1:s.type==="price"&&s.priceData&&s.priceData.v.length>0?!0:s.domSelectors&&s.domSelectors.some(r=>new RegExp(M(r)).test(e.toString()))))}async filterTestsByAudience(t,e,i){const s=[];let r=e.country;!r&&t.some(o=>o.requiresCountry&&!i.some(n=>n.testId===o.id))&&(this.log("Hiding page to check geoip"),this.hidePage(),r=await this.makeJsonRequest({method:"get",url:`${this.eventHost}/api/v0/visitors/get-country`,signal:AbortSignal.timeout(this.getCountryTimeout)}).catch(o=>(this.log("Error getting country",o),null)));for(const o of t){if(this.log("Checking audience for test '%s'",o.id),this.state.essential.visitorTests.some(c=>c.testId===o.id&&c.hypothesisId==null)){console.log(`Skipping blocked test '${o.id}'`);continue}const n=this.visitorCreatedDuringTestActive(o.statusHistory);(i.some(c=>c.testId===o.id&&(o.device==="all"||o.device===e.device&&o.device===this.device))||this.isTargetAudience(o,e,n,r))&&(this.log("Visitor is in audience for test '%s'",o.id),s.push(o))}this.testsFilteredByAudience=s}isTargetAudience(t,e,i,s){const r=this.getChannel(e);return(t.device==="all"||t.device===e.device&&t.device===this.device)&&(t.visitorOption==="all"||t.visitorOption==="new"&&i||t.visitorOption==="returning"&&!i)&&(t.targetAudiences.length===0||t.targetAudiences.reduce((o,n)=>o||n.reduce((a,c)=>a&&c(e,i,r,s),!0),!1))}visitorCreatedDuringTestActive(t){let e="";for(const i of t){if(this.state.analytics.visitor!==null&&this.state.analytics.visitor.createdAt<i.createdAt||this.state.essential.initialState.createdAt<i.createdAt)break;e=i.status}return e==="active"}getDomTestsForCurrentUrl(){return this.domTestsForUrl(this.testsFilteredByAudience)}getCurrentVisitorHypothesis(t){return t.flatMap(e=>e.hypotheses).find(e=>e.type!=="dom"&&e.type!=="price"&&this.state.essential.visitorTests.some(i=>i.hypothesisId===e.id))}getVisitorDomHypothesis(t){return t.flatMap(e=>e.hypotheses).filter(e=>(e.type==="dom"||e.type==="price")&&this.state.essential.visitorTests.some(i=>i.hypothesisId===e.id))}getHypothesis(t){return this.testConfigs.filter(e=>e.hypotheses.some(i=>i.id===t)).map(e=>e.hypotheses.find(i=>i.id===t))[0]}getDomSelectorsForHypothesis(t){if(!t)return[];if(t.domSelectors&&t.domSelectors.length>0)return t.domSelectors;if(t.priceData){const e=`${this.priceSelectorsSessionKey}_${t.id}`;try{const s=sessionStorage.getItem(e);if(s){const r=JSON.parse(s);return t.domSelectors=r,this.log("Loaded %d price selectors from cache for hypothesis '%s'",r.length,t.id),r}}catch{}const i=ht(t.priceData);t.domSelectors=i;try{sessionStorage.setItem(e,JSON.stringify(i)),this.log("Generated and cached %d price selectors for hypothesis '%s'",i.length,t.id)}catch{this.log("Generated %d price selectors for hypothesis '%s' (cache unavailable)",i.length,t.id)}return i}return[]}hasThemeTest(t){return t.some(e=>e.hypotheses.some(i=>i.type==="theme"))}hasTestThatIsNotThemeTest(t){return t.some(e=>e.hypotheses.some(i=>i.type!=="theme"&&i.type!=="dom"&&i.type!=="price"))}hasThemeAndOtherTestTypes(t){return this.hasThemeTest(t)&&this.hasTestThatIsNotThemeTest(t)}testIsPaused(t){return t.status==="paused"||t.status==="incompatible"||t.status==="suspended"}visitorActiveTestType(){const t=this.state.essential.visitorTests.filter(e=>this.testConfigs.some(i=>i.hypotheses.some(s=>s.id==e.hypothesisId)));return t.length===0?null:t.some(e=>e.isThemeTest)?"theme":"templateOrUrlRedirect"}getReservationType(t){return t==="price"||this.isTemplateTestType(t)?"deferred":"immediate"}isTemplateTestType(t){return["product","collection","landing","index","cart","search","blog","article","collectionList"].includes(t)}getEntryCriteriaKey(t){const e=t.hypotheses.find(i=>i.isControl);if(!e)return`unknown:${t.id}`;switch(e.type){case"theme":return"global:theme";case"basicScript":return"global:autoApi";case"price":return"global:price";case"manualScript":return`conditional:manualApi:${t.id}`;case"urlRedirect":return`conditional:url:${e.redirectPath||"unknown"}`;default:return`conditional:template:${e.type}`}}isGlobalEntryCriteria(t){return t.startsWith("global:")}groupTestsByEntryCriteria(t){const e=new Map;for(const i of t){const s=this.getEntryCriteriaKey(i),r=e.get(s)||[];r.push(i),e.set(s,r)}return e}doesCurrentPageMatchEntryCriteria(t){if(this.isGlobalEntryCriteria(t))return!0;if(t==="conditional:manualApi")return!1;if(t.startsWith("conditional:url:")){const e=t.replace("conditional:url:","");return window.location.pathname.endsWith(e)}if(t.startsWith("conditional:template:")){const e=t.replace("conditional:template:","");return this.typeFromTemplate()===e}return!1}hasActiveReservation(){const t=this.getActiveReservations();return Object.values(t).some(e=>!e.isRealized)}getActiveReservation(){const t=this.getActiveReservations();return Object.values(t).find(e=>!e.isRealized)??null}clearStaleReservations(){const t=this.state.temporary.testReservations;if(!t)return;let e=!1;for(const[i,s]of Object.entries(t)){const r=this.testConfigs.find(n=>n.id===s.testId);if(!r){this.log("Test '%s' no longer in config, clearing reservation for criteria '%s'",s.testId,i),delete t[i],e=!0;continue}if(r.status!=="active"){this.log("Test '%s' status is '%s', clearing reservation for criteria '%s'",s.testId,r.status,i),delete t[i],e=!0;continue}this.testsFilteredByAudience.some(n=>n.id===s.testId)||(this.log("Visitor no longer passes audience for test '%s', clearing reservation for criteria '%s'",s.testId,i),delete t[i],e=!0)}e&&this.persistTemporaryState()}createReservations(t){if(this.state.temporary.testReservations||(this.state.temporary.testReservations={}),this.state.temporary.rolledEntryCriteria||(this.state.temporary.rolledEntryCriteria=[]),this.state.temporary.testCategory==="global"){this.createSingleReservation(t,"global");return}const i=t.filter(n=>this.doesCurrentPageMatchEntryCriteria(this.getEntryCriteriaKey(n))),s=t.filter(n=>!this.doesCurrentPageMatchEntryCriteria(this.getEntryCriteriaKey(n)));this.log("Conditional tests split - matching current page: %d, not matching: %d",i.length,s.length),i.length>0&&this.log("Tests matching current page (same pool): %o",i.map(n=>({id:n.id,title:n.title,criteria:this.getEntryCriteriaKey(n)})));const r=`conditional:current-page:${this.typeFromTemplate()}`;if(i.length>0&&!this.state.temporary.rolledEntryCriteria.includes(r)){this.createSingleReservation(i,r);for(const n of i){const a=this.getEntryCriteriaKey(n);this.state.temporary.rolledEntryCriteria.includes(a)||this.state.temporary.rolledEntryCriteria.push(a)}}const o=this.groupTestsByEntryCriteria(s);for(const[n,a]of o){if(this.state.temporary.rolledEntryCriteria.includes(n)){this.log("Already rolled for criteria '%s', skipping",n);continue}if(a.some(m=>this.state.essential.visitorTests.some(S=>S.testId===m.id))){this.log("Visitor already has VT for criteria '%s', skipping",n),this.state.temporary.rolledEntryCriteria.push(n);continue}const h=[...a].sort((m,S)=>m.id.localeCompare(S.id));this.log("Test dice roll for criteria '%s' - available tests: %o",n,h.map(m=>({id:m.id,title:m.title})));const u=Math.floor(Math.random()*h.length),p=h[u];this.log("Test dice roll: picked index %d of %d, selected test '%s' (%s)",u+1,a.length,p.id,p.title);const d=this.pickHypothesis(p);if(!d){this.log("No hypothesis picked for test '%s'",p.id);continue}const v=this.getReservationType(d.type),T={testId:p.id,hypothesisId:d.id,testType:d.type,reservationType:v,isThemeTest:d.type==="theme",themeId:d.themeId,createdAt:new Date,isRealized:!1,entryCriteriaKey:n};this.state.temporary.testReservations[n]=T,this.state.temporary.rolledEntryCriteria.push(n),this.log("Created %s reservation for test '%s' (criteria: %s)",v,p.id,n);for(const m of a)m.id!==p.id&&this.markTestAsBlocked(m,n)}this.persistTemporaryState()}createSingleReservation(t,e){if(this.state.temporary.rolledEntryCriteria.includes(e)){this.log("Already rolled for pool '%s', skipping",e);return}if(t.some(u=>this.state.essential.visitorTests.some(p=>p.testId===u.id&&!p.isInvalid))){this.log("Visitor already has VT for pool '%s', skipping",e),this.state.temporary.rolledEntryCriteria.push(e);return}if(t.length===0){this.log("No tests in pool '%s'",e);return}const s=[...t].sort((u,p)=>u.id.localeCompare(p.id));this.log("Test dice roll for pool '%s' - available tests: %o",e,s.map(u=>({id:u.id,title:u.title,criteria:this.getEntryCriteriaKey(u)})));const r=Math.floor(Math.random()*s.length),o=s[r];this.log("Test dice roll: picked index %d of %d, selected test '%s' (%s)",r,t.length,o.id,o.title);const n=this.pickHypothesis(o);if(!n){this.log("No hypothesis picked for test '%s'",o.id);return}const a=this.getReservationType(n.type),c=this.getEntryCriteriaKey(o),h={testId:o.id,hypothesisId:n.id,testType:n.type,reservationType:a,isThemeTest:n.type==="theme",themeId:n.themeId,createdAt:new Date,isRealized:!1,entryCriteriaKey:c};this.state.temporary.testReservations[c]=h,this.state.temporary.rolledEntryCriteria.push(e),this.log("Created %s reservation for test '%s' from pool '%s' (criteria: %s)",a,o.id,e,c);for(const u of t)u.id!==o.id&&this.markTestAsBlocked(u,`pool:${e}`);this.persistTemporaryState()}markTestAsBlocked(t,e){this.state.essential.visitorTests.some(i=>i.testId===t.id)||(this.log("Blocking visitor from test '%s' (reason: %s)",t.id,e),this.state.essential.visitorTests.push({createdAt:new Date,testId:t.id,hypothesisId:null,isThemeTest:t.hypotheses.some(i=>i.type==="theme"),shouldSendToGa:!1,isSaved:!0,isInvalid:!0,themeId:void 0}))}realizeReservationForCriteria(t){const e=this.state.temporary.testReservations?.[t];if(!e)return this.log("No reservation found for criteria '%s'",t),!1;if(e.isRealized)return this.log("Reservation already realized for criteria '%s'",t),!1;if(this.state.essential.visitorTests.some(s=>s.testId===e.testId&&!s.isInvalid))return this.log("Visitor already assigned to test '%s'",e.testId),!1;const i=this.getHypothesis(e.hypothesisId);return i?(e.isRealized=!0,this.persistTemporaryState(),this.queueAddVisitorToTest(e.testId,i),this.saveState(),this.log("Realized reservation for test '%s' (criteria: %s)",e.testId,t),!0):(this.log("Hypothesis '%s' not found",e.hypothesisId),!1)}getActiveReservations(){return this.state.temporary.testReservations??{}}getReservationForCurrentPage(){const t=this.getActiveReservations();for(const[e,i]of Object.entries(t)){if(i.isRealized)continue;const s=this.testConfigs.find(r=>r.id===i.testId);if(!(!s||s.status!=="active")&&this.doesCurrentPageMatchEntryCriteria(e))return i}return null}getReservationForTest(t){const e=this.getActiveReservations();return Object.values(e).find(i=>i.testId===t)??null}getReservationTestType(){const t=this.getActiveReservations(),e=Object.values(t);if(e.length===0)return null;for(const i of e)if(i.isThemeTest)return"theme";for(const i of e)if(i.testType==="price")return"price";return e.some(i=>!i.isRealized)?"templateOrUrlRedirect":null}hasPriceTests(t){return t.some(e=>e.hypotheses.some(i=>i.type==="price"))}_priceTestProductIds=null;getPriceTestProductIds(){if(this._priceTestProductIds)return this._priceTestProductIds;const t=new Set;for(const e of this.testConfigs)for(const i of e.hypotheses)if(i.type==="price"){for(const s of i.domSelectors||[]){const r=s.cssSelector.match(/data-sl-attribute-(?:p|cap)="(\d+)"/);r?.[1]&&t.add(r[1])}if(i.priceData?.v)for(const[s]of i.priceData.v)t.add(s)}return this._priceTestProductIds=t,this.log("Built price test product ID cache with %d products",t.size),t}isProductInAnyPriceTest(t){return this.getPriceTestProductIds().has(t)}visitorActiveTestTypeWithReservations(){const t=this.getActiveReservations();for(const r of Object.values(t)){if(r.isThemeTest)return"theme";if(r.testType==="price")return"price"}if(Object.values(t).some(r=>!r.isRealized)){if(this.state.temporary.testCategory==="global")for(const o of Object.values(t)){if(o.testType==="theme")return"theme";if(o.testType==="price")return"price";if(o.testType==="basicScript")return"theme"}return"templateOrUrlRedirect"}const i=this.state.essential.visitorTests.filter(r=>!r.isInvalid&&this.testConfigs.some(o=>o.hypotheses.some(n=>n.id===r.hypothesisId)));return i.length===0?null:i.some(r=>this.getHypothesis(r.hypothesisId)?.type==="price")?"price":i.some(r=>r.isThemeTest)?"theme":"templateOrUrlRedirect"}applyControlForAudienceFilteredPriceTests(){const t=this.testConfigs.filter(s=>s.status==="active"&&s.hypotheses.some(r=>r.type==="price"));if(t.length===0)return;const e=this.testsFilteredByAudience.filter(s=>s.hypotheses.some(r=>r.type==="price")),i=t.filter(s=>!e.some(r=>r.id===s.id));if(i.length!==0){this.log("Found %d price tests filtered by audience, applying control selectors",i.length);for(const s of i){const r=s.hypotheses.find(c=>c.isControl),o=this.getDomSelectorsForHypothesis(r);if(o.length===0){this.log("No control selectors for audience-filtered price test '%s'",s.id);continue}const n=new URL(window.location.href);o.some(c=>{try{return new RegExp(M(c)).test(n.toString())}catch{return!1}})&&(this.log("Applying control selectors for audience-filtered price test '%s'",s.id),x(document,{testId:s.id,hypothesisId:r.id,selectors:o},()=>{this.log("Control selectors applied for audience-filtered visitor, no metrics tracked")}),this.updatePriceTestHiddenInputs(s.id,"control",!1))}}}pickHypothesis(t){let e=Math.random();const i=t.hypotheses.reduce((r,o)=>r+o.visitorCount,0);return t.hypotheses.sort((r,o)=>r.isControl?o.isControl?0:-1:o.isControl?1:0).reduce((r,o)=>{if(r!==null)return r;const a=t.hypotheses.reduce((c,h)=>c&&h.visitorCount>20,!0)?o.visitorCount/i-o.trafficPercentage:0;return e<=o.trafficPercentage-a?o:(e-=o.trafficPercentage,null)},null)}typeFromTemplate(){switch(template.type){case"list-collections":return"collectionList";case"page":return"landing";case"article":case"blog":case"cart":case"collection":case"index":case"product":case"search":return template.type;default:return null}}queueRedirect(t){this.saveState(),this.disableReferrerOverride||(this.log(`Saving temporary referrer override '${document.referrer}'`),this.state.temporary.originalReferrer=document.referrer,this.persistTemporaryState()),window.setTimeout(()=>window.location.assign(t),0),window.setTimeout(()=>{this.syncAllEvents()},2e3)}async syncAllEvents(){const t=async()=>{if(this.isSyncing){window.setTimeout(()=>{(async()=>await t())()},500);return}try{this.isSyncing=!0,this.syncGAEvents(),await this.syncEvents()}finally{this.isSyncing=!1}};await t()}async syncEvents(){if(!this.state.essential.consentApproved||!this.shopifyAnalyticsId||this.state.analytics.queue.length===0)return;const t=this.state.analytics.queue.length,e=this.state.analytics.queue.splice(0,t);this.log("Syncing %s events",t);try{const i={shop:this.shop,visitorDetails:{shopifyAnalyticsId:this.shopifyAnalyticsId,device:this.state.analytics.visitor?.device??this.device,country:this.state.analytics.visitor?.country??null,...this.state.essential.initialState},events:this.state.essential.visitorTests.filter(r=>!r.isInvalid&&!r.isSaved&&r.hypothesisId!=null).map(r=>new W(r.testId,r.hypothesisId,r.createdAt)).concat(e)};await this.sendEvents(i);const s=await this.getVisitor(this.shopifyAnalyticsId);s!==null&&this.updateLocalVisitor(s);for(const r of this.state.essential.visitorTests.filter(o=>!o.isInvalid&&!o.isSaved))r.isSaved=!0,r.savedAt=Date.now()}catch{this.state.analytics.queue.splice(0,0,...e)}finally{this.saveState()}}syncGAEvents(){if(!this.gaConfig.sendEvents){if(U)return;U=!0,this.log("UseGtag is false — skipping GA Events");return}if(this.isSyncingGA){this.log("Already syncing GA - skipping GA events");return}const t=this.state.essential.visitorTests.filter(e=>e.shouldSendToGa);t.length!==0&&(this.isSyncingGA=!0,this.log("Syncing %s GA Events",t.length),Promise.allSettled(t.map(e=>this.sendGAEvent(e))).then(()=>this.log("All gtag events sent")).finally(()=>this.isSyncingGA=!1))}sendGAEvent(t){return new Promise(e=>{this.log("Sending GA Event for test %s, hypothesis %s",t.testId,t.hypothesisId);const i=()=>{this.log("GA acknowledged event for hypothesis %s",t.hypothesisId),t.shouldSendToGa=!1,this.persistEssentialState(),e()},s={exp_variant_string:`SL-${t.testId}-${t.hypothesisId}`};this.shopliftDebug&&Object.assign(s,{debug_mode:!0});function r(o,n,a){window.dataLayer=window.dataLayer||[],window.dataLayer.push(arguments)}this.gaConfig.mode==="gtag"?r("event","experience_impression",{...s,event_callback:i}):(window.dataLayer=window.dataLayer||[],window.dataLayer.push({event:"experience_impression",...s,eventCallback:i}))})}updateLocalVisitor(t){let e;({visitorTests:e,...this.state.analytics.visitor}=t),this.log("updateLocalVisitor - server returned %d tests: %o",e.length,e.map(s=>({testId:s.testId,hypothesisId:s.hypothesisId,isInvalid:s.isInvalid}))),this.log("updateLocalVisitor - local has %d tests: %o",this.state.essential.visitorTests.length,this.state.essential.visitorTests.map(s=>({testId:s.testId,hypothesisId:s.hypothesisId,isSaved:s.isSaved,isInvalid:s.isInvalid})));const i=300*1e3;for(const s of this.state.essential.visitorTests.filter(r=>r.isSaved&&(!r.savedAt||Date.now()-r.savedAt>i)&&!e.some(o=>o.testId===r.testId)))this.log("updateLocalVisitor - marking LOCAL test as INVALID (isSaved && not in server): testId=%s, hypothesisId=%s",s.testId,s.hypothesisId),s.isInvalid=!0;for(const s of e){const r=this.state.essential.visitorTests.findIndex(n=>n.testId===s.testId);if(!(r!==-1))this.log("updateLocalVisitor - ADDING server test (not found locally): testId=%s, hypothesisId=%s",s.testId,s.hypothesisId),this.state.essential.visitorTests.push(s);else{const n=this.state.essential.visitorTests.at(r);this.log("updateLocalVisitor - REPLACING local test with server test: testId=%s, local hypothesisId=%s -> server hypothesisId=%s, local isInvalid=%s -> false",s.testId,n?.hypothesisId,s.hypothesisId,n?.isInvalid),s.isInvalid=!1,s.shouldSendToGa=n?.shouldSendToGa??!1,s.testType=n?.testType,s.assignedTo=n?.assignedTo,s.testTitle=n?.testTitle,this.state.essential.visitorTests.splice(r,1,s)}}this.log("updateLocalVisitor - FINAL local tests: %o",this.state.essential.visitorTests.map(s=>({testId:s.testId,hypothesisId:s.hypothesisId,isSaved:s.isSaved,isInvalid:s.isInvalid}))),this.state.analytics.visitor.storedAt=new Date}async getVisitor(t){try{return await this.makeJsonRequest({method:"get",url:`${this.eventHost}/api/v0/visitors/by-key/${this.shop}/${t}`})}catch{return null}}async sendEvents(t){await this.makeRequest({method:"post",url:`${this.eventHost}/api/v0/events`,data:JSON.stringify(t)})}getUTMValue(t){const i=decodeURIComponent(window.location.search.substring(1)).split("&");for(let s=0;s<i.length;s++){const r=i[s].split("=");if(r[0]===t)return r[1]||null}return null}hidePage(t){this.log("Hiding page"),this.cssHideClass&&!window.document.documentElement.classList.contains(this.cssHideClass)&&(window.document.documentElement.classList.add(this.cssHideClass),t||setTimeout(this.removeAsyncHide(this.cssHideClass),2e3))}showPage(){this.cssHideClass&&this.removeAsyncHide(this.cssHideClass)()}getDeviceType(){function t(){let i=!1;return(function(s){(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(s)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(s.substr(0,4)))&&(i=!0)})(navigator.userAgent||navigator.vendor),i}function e(){let i=!1;return(function(s){(/android|ipad|playbook|silk/i.test(s)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(s.substr(0,4)))&&(i=!0)})(navigator.userAgent||navigator.vendor),i}return t()?"mobile":e()?"tablet":"desktop"}removeAsyncHide(t){return()=>{t&&window.document.documentElement.classList.remove(t)}}async getCartState(){try{let t=await this.makeJsonRequest({method:"get",url:`${window.location.origin}/cart.js`});return t===null||(t.note===null&&(t=await this.makeJsonRequest({method:"post",url:`${window.location.origin}/cart/update.js`,data:JSON.stringify({note:""})})),t==null)?null:{token:t.token,total_price:t.total_price,total_discount:t.total_discount,currency:t.currency,items_subtotal_price:t.items_subtotal_price,items:t.items.map(e=>({quantity:e.quantity,variant_id:e.variant_id,key:e.key,price:e.price,final_line_price:e.final_line_price,sku:e.sku,product_id:e.product_id}))}}catch(t){return this.log("Error sending cart info",t),null}}ensureCartAttributesForExistingPriceTests(t){try{if(this.log("Checking visitor assignments for active price tests"),t&&this.state.temporary.previewConfig){const e=this.state.temporary.previewConfig;this.log("Using preview config for merchant:",e.testId);let i="variant";if(e.variants&&e.variants.length>0){const s=e.variants.find(r=>r.id===e.currentVariant);s&&s.isControl&&(i="control")}this.log("Merchant preview - updating hidden inputs:",e.testId,i),this.updatePriceTestHiddenInputs(e.testId,i,!0);return}for(const e of this.state.essential.visitorTests){const i=this.testConfigs.find(o=>o.id===e.testId);if(!i){this.log("Test config not found:",e.testId);continue}const s=i.hypotheses.find(o=>o.id===e.hypothesisId);if(!s||s.type!=="price")continue;const r=s.isControl?"control":"variant";this.log("Updating hidden inputs for price test:",e.testId,r),this.updatePriceTestHiddenInputs(e.testId,r,t)}}catch(e){this.log("Error ensuring cart attributes for existing price tests:",e)}}updatePriceTestHiddenInputs(t,e,i){try{this.cleanupPriceTestObservers();const s=`${t}:${e}:${i?"t":"f"}`,r=y=>{const f=y.getAttribute("data-sl-pid");if(!f)return!0;if(i&&this.state.temporary.previewConfig){const g=this.state.temporary.previewConfig,b=e==="control"?"a":"b",C=g.variants.find(A=>A.label===b);if(!C)return!1;for(const A of C.domSelectors||[]){const E=A.cssSelector.match(/data-sl-attribute-(?:p|cap)="(\d+)"/);if(E){const z=E[1];if(this.log(`Extracted ID from selector: ${z}, comparing to: ${f}`),z===f)return this.log("Product ID match found in preview config:",f,"variant:",C.label),!0}else this.log(`Could not extract ID from selector: ${A.cssSelector}`)}return this.log("No product ID match in preview config for:",f,"variant:",b),!1}const w=this.testConfigs.find(g=>g.id===t);if(!w)return this.log("Test config not found for testId:",t),!1;for(const g of w.hypotheses||[]){for(const b of g.domSelectors||[]){const C=b.cssSelector.match(/data-sl-attribute-(?:p|cap)="(\d+)"/);if(C&&C[1]===f)return this.log("Product ID match found in domSelectors:",f,"for test:",t),!0}if(g.priceData?.v){for(const b of g.priceData.v)if(b[0]===f)return this.log("Product ID match found in priceData:",f,"for test:",t),!0}}return this.log("No product ID match for:",f,"in test:",t),!1},o=new Set;let n=!1,a=null;const c=(y,f)=>{if(document.querySelectorAll("[data-sl-attribute-p]").forEach(g=>{if(g instanceof Element&&g.nodeType===Node.ELEMENT_NODE&&g.isConnected&&document.contains(g))try{y.observe(g,{childList:!0,subtree:!0,characterData:!0,characterDataOldValue:!0,attributes:!1})}catch(b){this.log(`Failed to observe element (${f}):`,b)}}),document.body&&document.body.isConnected)try{y.observe(document.body,{childList:!0,subtree:!0,characterData:!0,characterDataOldValue:!0,attributes:!1})}catch(g){this.log(`Failed to observe document.body (${f}):`,g)}},h=(y,f,w,g)=>{const b=y.filter(C=>{const A=C.cssSelector.match(/data-sl-attribute-(?:p|cap)="(\d+)"/);return A&&A[1]===g});this.log(`Applying ${w} DOM selectors, total: ${y.length}, filtered: ${b.length}`),b.length>0&&x(document,{testId:t,hypothesisId:f,selectors:b})},u=(y,f)=>{this.log(`Applying DOM selector changes for product ID: ${y}`),f.disconnect(),n=!0;try{if(i&&this.state.temporary.previewConfig){const w=e==="control"?"a":"b",g=this.state.temporary.previewConfig.variants.find(b=>b.label===w);if(!g?.domSelectors){this.log(`No DOM selectors found for preview variant: ${w}`);return}h(g.domSelectors,g.id,"preview config",y)}else{const w=this.testConfigs.find(b=>b.id===t);if(!w){this.log(`No test config found for testId: ${t}`);return}const g=w.hypotheses.find(b=>e==="control"?b.isControl:!b.isControl);if(!g?.domSelectors){this.log(`No DOM selectors found for assignment: ${e}`);return}h(g.domSelectors,g.id,"live config",y)}}finally{a!==null&&clearTimeout(a),a=window.setTimeout(()=>{n=!1,a=null,c(f,"reconnection"),this.log("Re-established innerHTML observer after DOM changes")},50)}},p=new MutationObserver(y=>{if(!n)for(const f of y){if(f.type!=="childList"&&f.type!=="characterData")continue;let w=f.target;f.type==="characterData"&&(w=f.target.parentElement||f.target.parentNode);let g=w,b=g.getAttribute("data-sl-attribute-p");for(;!b&&g.parentElement;)g=g.parentElement,b=g.getAttribute("data-sl-attribute-p");if(!b)continue;const C=g.innerHTML||g.textContent||"";let A="";f.type==="characterData"&&f.oldValue!==null&&(A=f.oldValue),this.log(`innerHTML changed on element with data-sl-attribute-p="${b}"`),A&&this.log(`Previous content: "${A}"`),this.log(`Current content: "${C}"`),u(b,p)}});c(p,"initial setup"),o.add(p);const d=new MutationObserver(y=>{y.forEach(f=>{f.addedNodes.forEach(w=>{if(w.nodeType===Node.ELEMENT_NODE){const g=w;T(g);const b=g.matches('input[name="properties[_slpt]"]')?[g]:g.querySelectorAll('input[name="properties[_slpt]"]');b.length>0&&this.log(`MutationObserver found ${b.length} new hidden input(s)`),b.forEach(C=>{const A=C.getAttribute("data-sl-pid");if(this.log(`MutationObserver checking new input with data-sl-pid="${A}"`),r(C))C.value!==s&&(C.value=s,this.log("Updated newly added hidden input:",s)),m(C);else{const E=C.getAttribute("data-sl-pid");E&&this.isProductInAnyPriceTest(E)?this.log("Preserving hidden input for product ID '%s' - belongs to a different price test",E):(C.remove(),this.log("Removed newly added non-matching hidden input for product ID:",E))}})}})})});o.add(d);const v=new MutationObserver(y=>{y.forEach(f=>{if(f.type==="attributes"&&f.attributeName==="data-sl-pid"){const w=f.target;if(this.log("AttributeObserver detected data-sl-pid attribute change on:",w.tagName),w.matches('input[name="properties[_slpt]"]')){const g=w,b=f.oldValue,C=g.getAttribute("data-sl-pid");this.log(`data-sl-pid changed from "${b}" to "${C}" - triggering payment placement updates`),r(g)?(g.value!==s&&(g.value=s,this.log("Updated hidden input after data-sl-pid change:",s)),C&&u(C,p),this.log("Re-running payment placement updates after variant change"),T(document.body)):C&&this.isProductInAnyPriceTest(C)?this.log("Preserving hidden input for product ID '%s' - belongs to a different price test",C):(g.remove(),this.log("Removed non-matching hidden input after data-sl-pid change:",C))}}})});o.add(v);const T=y=>{y.tagName==="SHOPIFY-PAYMENT-TERMS"&&(this.log("MutationObserver found new shopify-payment-terms element"),this.updateShopifyPaymentTerms(t,e));const f=y.querySelectorAll("shopify-payment-terms");f.length>0&&(this.log(`MutationObserver found ${f.length} shopify-payment-terms in added node`),this.updateShopifyPaymentTerms(t,e)),y.tagName==="AFTERPAY-PLACEMENT"&&(this.log("MutationObserver found new afterpay-placement element"),this.updateAfterpayPlacements(t,e,"afterpay"));const w=y.querySelectorAll("afterpay-placement");w.length>0&&(this.log(`MutationObserver found ${w.length} afterpay-placement in added node`),this.updateAfterpayPlacements(t,e,"afterpay")),y.tagName==="SQUARE-PLACEMENT"&&(this.log("MutationObserver found new square-placement element"),this.updateAfterpayPlacements(t,e,"square"));const g=y.querySelectorAll("square-placement");g.length>0&&(this.log(`MutationObserver found ${g.length} square-placement in added node`),this.updateAfterpayPlacements(t,e,"square")),y.tagName==="KLARNA-PLACEMENT"&&(this.log("MutationObserver found new klarna-placement element"),this.updateKlarnaPlacements(t,e));const b=y.querySelectorAll("klarna-placement");b.length>0&&(this.log(`MutationObserver found ${b.length} klarna-placement in added node`),this.updateKlarnaPlacements(t,e))},m=y=>{v.observe(y,{attributes:!0,attributeFilter:["data-sl-pid"],attributeOldValue:!0,subtree:!1});const f=y.getAttribute("data-sl-pid");this.log(`Started AttributeObserver on specific input with data-sl-pid="${f}"`)},S=()=>{const y=document.querySelectorAll('input[name="properties[_slpt]"]');this.log(`Found ${y.length} existing hidden inputs to check`),y.forEach(f=>{const w=f.getAttribute("data-sl-pid");this.log(`Checking existing input with data-sl-pid="${w}"`),r(f)?(f.value=s,this.log("Updated existing hidden input:",s),w&&(this.log("Applying initial DOM selector changes for existing product"),u(w,p)),m(f)):w&&this.isProductInAnyPriceTest(w)?this.log("Preserving hidden input for product ID '%s' - belongs to a different price test",w):(f.remove(),this.log("Removed non-matching hidden input for product ID:",w))})},I=()=>{document.body?(d.observe(document.body,{childList:!0,subtree:!0}),this.log("Started MutationObserver on document.body"),S(),T(document.body)):document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>{document.body&&(d.observe(document.body,{childList:!0,subtree:!0}),this.log("Started MutationObserver after DOMContentLoaded"),S(),T(document.body))}):(this.log("Set timeout on observer"),setTimeout(I,10))};I(),window.__shopliftPriceTestObservers=o,window.__shopliftPriceTestValue=s,this.log("Set up DOM observer for price test hidden inputs")}catch(s){this.log("Error updating price test hidden inputs:",s)}}updateKlarnaPlacements(t,e){this.updatePlacementElements(t,e,"klarna-placement",(i,s)=>{i.setAttribute("data-purchase-amount",s.toString())})}cleanupPriceTestObservers(){const t=window.__shopliftPriceTestObservers;t&&(t.forEach(e=>{e.disconnect()}),t.clear(),this.log("Cleaned up existing price test observers")),delete window.__shopliftPriceTestObservers,delete window.__shopliftPriceTestValue}updateAfterpayPlacements(t,e,i="afterpay"){const s=i==="square"?"square-placement":"afterpay-placement";if(document.querySelectorAll(s).length===0){this.log(`No ${s} elements found on page - early return`);return}this.updatePlacementElements(t,e,s,(o,n)=>{if(i==="afterpay"){const a=(n/100).toFixed(2);o.setAttribute("data-amount",a)}else o.setAttribute("data-amount",n.toString())}),this.log("updateAfterpayPlacements completed")}updatePlacementElements(t,e,i,s){const r=document.querySelectorAll(i);if(r.length===0){this.log(`No ${i} elements found - early return`);return}let o;if(this.state.temporary.isMerchant&&this.state.temporary.previewConfig){const a=e==="control"?"a":"b",c=this.state.temporary.previewConfig.variants.find(h=>h.label===a);if(!c?.domSelectors){this.log(`No variant found for label ${a} in preview config for ${i}`);return}o=c.domSelectors,this.log(`Using preview config for ${i} in merchant mode, variant: ${a}`)}else{const a=this.testConfigs.find(h=>h.id===t);if(!a){this.log(`No testConfig found for id: ${t} - early return`);return}const c=a.hypotheses.find(h=>e==="control"?h.isControl:!h.isControl);if(!c?.domSelectors){this.log(`No hypothesis or domSelectors found for assignment: ${e} - early return`);return}o=c.domSelectors}const n=new RegExp(`${this.DATA_SL_ATTRIBUTE_P}=["'](\\d+)["']`);r.forEach(a=>{let c=null;const h=a.parentElement;if(h&&(c=h.querySelector('input[name="properties[_slpt]"]')),c||(c=a.querySelector('input[name="properties[_slpt]"]')),!c){this.log(`No hidden input found for ${i} element`);return}const u=c.getAttribute("data-sl-pid");if(!u){this.log("Hidden input has no data-sl-pid attribute - skipping");return}const p=o.find(m=>{const S=m.cssSelector.match(n);return S&&S[1]===u});if(!p){this.log(`No matching selector found for productId: ${u} - skipping element`);return}const d=p.actions.find(m=>m.scope==="price");if(!d?.value){this.log("No price action or value found - skipping element");return}const v=parseFloat(d.value.replace(/[^0-9.]/g,""));if(Number.isNaN(v)){this.log(`Invalid price "${d.value}" for product ${u} - skipping`);return}const T=Math.round(v*100);s(a,T)}),this.log(`updatePlacementElements completed for ${i}`)}updateShopifyPaymentTerms(t,e){const i=document.querySelectorAll("shopify-payment-terms");if(i.length===0)return;this.log("Store using shopify payments");let s;if(this.state.temporary.isMerchant&&this.state.temporary.previewConfig){const o=e==="control"?"a":"b",n=this.state.temporary.previewConfig.variants.find(a=>a.label===o);if(!n||!n.domSelectors){this.log(`No variant found for label ${o} in preview config`);return}s=n.domSelectors,this.log(`Using preview config for shopify-payment-terms in merchant mode, variant: ${o}`)}else{const o=this.testConfigs.find(a=>a.id===t);if(!o)return;const n=o.hypotheses.find(a=>e==="control"?a.isControl===!0:a.isControl===!1);if(!n||!n.domSelectors)return;s=n.domSelectors}const r=new RegExp(`${this.DATA_SL_ATTRIBUTE_P}=["'](\\d+)["']`);i.forEach(o=>{const n=o.getAttribute("variant-id");if(!n)return;const a=s.find(c=>{const h=c.cssSelector.match(r);return h&&h[1]===n});if(a){const c=a.actions.find(h=>h.scope==="price");if(c&&c.value){const h=o.getAttribute("shopify-meta");if(h)try{const u=JSON.parse(h);if(u.variants&&Array.isArray(u.variants)){const p=u.variants.find(d=>d.id?.toString()===n);if(p){p.full_price=c.value;const d=parseFloat(c.value.replace(/[^0-9.]/g,""));if(p.number_of_payment_terms&&p.number_of_payment_terms>1){const v=d/p.number_of_payment_terms;p.price_per_term=`$${v.toFixed(2)}`}o.setAttribute("shopify-meta",JSON.stringify(u))}}}catch(u){this.log("Error parsing/updating shoplift-meta:",u)}}}})}async makeJsonRequest(t){const e=await this.makeRequest(t);return e===null?null:JSON.parse(await e.text(),_)}async makeRequest(t){const{url:e,method:i,headers:s,data:r,signal:o}=t,n=new Headers;if(s)for(const c in s)n.append(c,s[c]);(!s||!s.Accept)&&n.append("Accept","application/json"),(!s||!s["Content-Type"])&&n.append("Content-Type","application/json"),(this.eventHost.includes("ngrok.io")||this.eventHost.includes("ngrok-free.app"))&&n.append("ngrok-skip-browser-warning","1234");const a=await this.fetch(e,{method:i,headers:n,body:r,signal:o});if(!a.ok){if(a.status===204)return null;if(a.status===422){const c=await a.json();if(typeof c<"u"&&c.isBot)throw new D}throw new Error(`Error sending shoplift request ${a.status}`)}return a}queueAddVisitorToTest(t,e){if(this.state.essential.visitorTests.some(s=>s.testId===t))return;const i=this.testConfigs.find(s=>s.id===t);if(this.state.essential.visitorTests.push({createdAt:new Date,testId:t,hypothesisId:e.id,isThemeTest:e.type==="theme",themeId:e.themeId,isSaved:!1,isInvalid:!1,shouldSendToGa:!0,testType:e.type,assignedTo:e.isControl?"control":"variant",testTitle:i?.title}),e.type==="price"){const s=e.isControl?"control":"variant";this.log("Price test assignment detected, updating cart attributes:",t,s),this.updatePriceTestHiddenInputs(t,s,!1)}}queueCartUpdate(t){this.queueEvent(new Y(t))}queuePageView(t){this.queueEvent(new J(t))}queueEvent(t){!this.state.essential.consentApproved&&this.state.essential.hasConsentInteraction||this.state.analytics.queue.length>10||this.state.analytics.queue.push(t)}legacyGetLocalStorageVisitor(){const t=this.localStorageGet(this.legacySessionKey);if(t)try{return JSON.parse(t,_)}catch{}return null}pruneStateAndSave(){this.state.essential.visitorTests=this.state.essential.visitorTests.filter(t=>this.testConfigs.some(e=>e.id==t.testId)||this.inactiveTestConfigs.filter(e=>this.testIsPaused(e)).some(e=>e.id===t.testId)),this.saveState()}saveState(){this.persistEssentialState(),this.persistAnalyticsState()}loadState(){const t=this.loadAnalyticsState(),e={analytics:t,essential:this.loadEssentialState(t),temporary:this.loadTemporaryState()},i=this.legacyGetLocalStorageVisitor(),s=this.legacyGetCookieVisitor(),r=[i,s].filter(o=>o!==null).sort((o,n)=>+n.storedAt-+o.storedAt)[0];return e.analytics.visitor===null&&r&&({visitorTests:e.essential.visitorTests,...e.analytics.visitor}=r,e.essential.isFirstLoad=!1,e.essential.initialState={createdAt:r.createdAt,referrer:r.referrer,utmCampaign:r.utmCampaign,utmContent:r.utmContent,utmMedium:r.utmMedium,utmSource:r.utmSource,device:r.device},this.deleteCookie("SHOPLIFT"),this.deleteLocalStorage(this.legacySessionKey)),!e.essential.consentApproved&&e.essential.hasConsentInteraction&&this.deleteLocalStorage(this.analyticsSessionKey),e}loadEssentialState(t){const e=this.loadLocalStorage(this.essentialSessionKey),i=this.loadCookie(this.essentialSessionKey),s=this.getInitialState();t.visitor?.device&&(s.device=t.visitor.device);const r={timestamp:new Date,consentApproved:!1,hasConsentInteraction:!1,debugMode:!1,initialState:s,visitorTests:[],isFirstLoad:!0},o=[e,i].filter(n=>n!==null).sort((n,a)=>+a.timestamp-+n.timestamp)[0]??r;return o.initialState||(t.visitor!==null?o.initialState=t.visitor:(o.initialState=s,o.initialState.createdAt=o.timestamp)),o}loadAnalyticsState(){const t=this.loadLocalStorage(this.analyticsSessionKey),e=this.loadCookie(this.analyticsSessionKey),i={timestamp:new Date,visitor:null,queue:[]},s=[t,e].filter(r=>r!==null).sort((r,o)=>+o.timestamp-+r.timestamp)[0]??i;return s.queue.length===0&&t&&t.queue.length>1&&(s.queue=t.queue),s}loadTemporaryState(){const t=this.sessionStorageGet(this.temporarySessionKey),e=t?JSON.parse(t,_):null,i=this.loadCookie(this.temporarySessionKey);return e??i??{isMerchant:!1,timestamp:new Date}}persistEssentialState(){this.log("Persisting essential state"),this.state.essential.isFirstLoad=!1,this.state.essential.timestamp=new Date,this.persistLocalStorageState(this.essentialSessionKey,this.state.essential),this.persistCookieState(this.essentialSessionKey,this.state.essential)}persistAnalyticsState(){this.log("Persisting analytics state"),this.state.essential.consentApproved&&(this.state.analytics.timestamp=new Date,this.persistLocalStorageState(this.analyticsSessionKey,this.state.analytics),this.persistCookieState(this.analyticsSessionKey,{...this.state.analytics,queue:[]}))}persistTemporaryState(){this.log("Setting temporary session state"),this.state.temporary.timestamp=new Date,this.sessionStorageSet(this.temporarySessionKey,JSON.stringify(this.state.temporary)),this.persistCookieState(this.temporarySessionKey,this.state.temporary,!0)}loadLocalStorage(t){const e=this.localStorageGet(t);if(e===null)return null;try{return JSON.parse(e,_)}catch{return null}}loadCookie(t){const e=this.getCookie(t);if(e===null)return null;try{return JSON.parse(e,_)}catch{return null}}persistLocalStorageState(t,e){this.localStorageSet(t,JSON.stringify(e))}persistCookieState(t,e,i=!1){const s=JSON.stringify(e),r=i?"":`expires=${new Date(new Date().getTime()+864e5*365).toUTCString()};`;document.cookie=`${t}=${s};domain=.${window.location.hostname};path=/;SameSite=Strict;${r}`}deleteCookie(t){const e=new Date(0).toUTCString();document.cookie=`${t}=;domain=.${window.location.hostname};path=/;expires=${e};`}deleteLocalStorage(t){window.localStorage.removeItem(t)}getChannel(t){return[{"name":"cross-network","test":(v) => new RegExp(".*cross-network.*", "i").test(v.utmCampaign)},{"name":"direct","test":(v) => v.utmSource === "" && v.utmMedium === ""},{"name":"paid-shopping","test":(v) => (new RegExp("^(?:Google|IGShopping|aax-us-east\.amazon-adsystem\.com|aax\.amazon-adsystem\.com|alibaba|alibaba\.com|amazon|amazon\.co\.uk|amazon\.com|apps\.shopify\.com|checkout\.shopify\.com|checkout\.stripe\.com|cr\.shopping\.naver\.com|cr2\.shopping\.naver\.com|ebay|ebay\.co\.uk|ebay\.com|ebay\.com\.au|ebay\.de|etsy|etsy\.com|m\.alibaba\.com|m\.shopping\.naver\.com|mercadolibre|mercadolibre\.com|mercadolibre\.com\.ar|mercadolibre\.com\.mx|message\.alibaba\.com|msearch\.shopping\.naver\.com|nl\.shopping\.net|no\.shopping\.net|offer\.alibaba\.com|one\.walmart\.com|order\.shopping\.yahoo\.co\.jp|partners\.shopify\.com|s3\.amazonaws\.com|se\.shopping\.net|shop\.app|shopify|shopify\.com|shopping\.naver\.com|shopping\.yahoo\.co\.jp|shopping\.yahoo\.com|shopzilla|shopzilla\.com|simplycodes\.com|store\.shopping\.yahoo\.co\.jp|stripe|stripe\.com|uk\.shopping\.net|walmart|walmart\.com)$", "i").test(v.utmSource) || new RegExp("^(.*(([^a-df-z]|^)shop|shopping).*)$", "i").test(v.utmCampaign)) && new RegExp("^(.*cp.*|ppc|retargeting|paid.*)$", "i").test(v.utmMedium)},{"name":"paid-search","test":(v) => new RegExp("^(?:360\.cn|alice|aol|ar\.search\.yahoo\.com|ask|at\.search\.yahoo\.com|au\.search\.yahoo\.com|auone|avg|babylon|baidu|biglobe|biglobe\.co\.jp|biglobe\.ne\.jp|bing|br\.search\.yahoo\.com|ca\.search\.yahoo\.com|centrum\.cz|ch\.search\.yahoo\.com|cl\.search\.yahoo\.com|cn\.bing\.com|cnn|co\.search\.yahoo\.com|comcast|conduit|daum|daum\.net|de\.search\.yahoo\.com|dk\.search\.yahoo\.com|dogpile|dogpile\.com|duckduckgo|ecosia\.org|email\.seznam\.cz|eniro|es\.search\.yahoo\.com|espanol\.search\.yahoo\.com|exalead\.com|excite\.com|fi\.search\.yahoo\.com|firmy\.cz|fr\.search\.yahoo\.com|globo|go\.mail\.ru|google|google-play|hk\.search\.yahoo\.com|id\.search\.yahoo\.com|in\.search\.yahoo\.com|incredimail|it\.search\.yahoo\.com|kvasir|lens\.google\.com|lite\.qwant\.com|lycos|m\.baidu\.com|m\.naver\.com|m\.search\.naver\.com|m\.sogou\.com|mail\.rambler\.ru|mail\.yandex\.ru|malaysia\.search\.yahoo\.com|msn|msn\.com|mx\.search\.yahoo\.com|najdi|naver|naver\.com|news\.google\.com|nl\.search\.yahoo\.com|no\.search\.yahoo\.com|ntp\.msn\.com|nz\.search\.yahoo\.com|onet|onet\.pl|pe\.search\.yahoo\.com|ph\.search\.yahoo\.com|pl\.search\.yahoo\.com|play\.google\.com|qwant|qwant\.com|rakuten|rakuten\.co\.jp|rambler|rambler\.ru|se\.search\.yahoo\.com|search-results|search\.aol\.co\.uk|search\.aol\.com|search\.google\.com|search\.smt\.docomo\.ne\.jp|search\.ukr\.net|secureurl\.ukr\.net|seznam|seznam\.cz|sg\.search\.yahoo\.com|so\.com|sogou|sogou\.com|sp-web\.search\.auone\.jp|startsiden|startsiden\.no|suche\.aol\.de|terra|th\.search\.yahoo\.com|tr\.search\.yahoo\.com|tut\.by|tw\.search\.yahoo\.com|uk\.search\.yahoo\.com|ukr|us\.search\.yahoo\.com|virgilio|vn\.search\.yahoo\.com|wap\.sogou\.com|webmaster\.yandex\.ru|websearch\.rakuten\.co\.jp|yahoo|yahoo\.co\.jp|yahoo\.com|yandex|yandex\.by|yandex\.com|yandex\.com\.tr|yandex\.fr|yandex\.kz|yandex\.ru|yandex\.ua|yandex\.uz|zen\.yandex\.ru)$", "i").test(v.utmSource) && new RegExp("^(.*cp.*|ppc|retargeting|paid.*)$", "i").test(v.utmMedium)},{"name":"paid-social","test":(v) => new RegExp("^(?:43things|43things\.com|51\.com|5ch\.net|Hatena|ImageShack|academia\.edu|activerain|activerain\.com|activeworlds|activeworlds\.com|addthis|addthis\.com|airg\.ca|allnurses\.com|allrecipes\.com|alumniclass|alumniclass\.com|ameba\.jp|ameblo\.jp|americantowns|americantowns\.com|amp\.reddit\.com|ancestry\.com|anobii|anobii\.com|answerbag|answerbag\.com|answers\.yahoo\.com|aolanswers|aolanswers\.com|apps\.facebook\.com|ar\.pinterest\.com|artstation\.com|askubuntu|askubuntu\.com|asmallworld\.com|athlinks|athlinks\.com|away\.vk\.com|awe\.sm|b\.hatena\.ne\.jp|baby-gaga|baby-gaga\.com|babyblog\.ru|badoo|badoo\.com|bebo|bebo\.com|beforeitsnews|beforeitsnews\.com|bharatstudent|bharatstudent\.com|biip\.no|biswap\.org|bit\.ly|blackcareernetwork\.com|blackplanet|blackplanet\.com|blip\.fm|blog\.com|blog\.feedspot\.com|blog\.goo\.ne\.jp|blog\.naver\.com|blog\.yahoo\.co\.jp|blogg\.no|bloggang\.com|blogger|blogger\.com|blogher|blogher\.com|bloglines|bloglines\.com|blogs\.com|blogsome|blogsome\.com|blogspot|blogspot\.com|blogster|blogster\.com|blurtit|blurtit\.com|bookmarks\.yahoo\.co\.jp|bookmarks\.yahoo\.com|br\.pinterest\.com|brightkite|brightkite\.com|brizzly|brizzly\.com|business\.facebook\.com|buzzfeed|buzzfeed\.com|buzznet|buzznet\.com|cafe\.naver\.com|cafemom|cafemom\.com|camospace|camospace\.com|canalblog\.com|care\.com|care2|care2\.com|caringbridge\.org|catster|catster\.com|cbnt\.io|cellufun|cellufun\.com|centerblog\.net|chat\.zalo\.me|chegg\.com|chicagonow|chicagonow\.com|chiebukuro\.yahoo\.co\.jp|classmates|classmates\.com|classquest|classquest\.com|co\.pinterest\.com|cocolog-nifty|cocolog-nifty\.com|copainsdavant\.linternaute\.com|couchsurfing\.org|cozycot|cozycot\.com|cross\.tv|crunchyroll|crunchyroll\.com|cyworld|cyworld\.com|cz\.pinterest\.com|d\.hatena\.ne\.jp|dailystrength\.org|deluxe\.com|deviantart|deviantart\.com|dianping|dianping\.com|digg|digg\.com|diigo|diigo\.com|discover\.hubpages\.com|disqus|disqus\.com|dogster|dogster\.com|dol2day|dol2day\.com|doostang|doostang\.com|dopplr|dopplr\.com|douban|douban\.com|draft\.blogger\.com|draugiem\.lv|drugs-forum|drugs-forum\.com|dzone|dzone\.com|edublogs\.org|elftown|elftown\.com|epicurious\.com|everforo\.com|exblog\.jp|extole|extole\.com|facebook|facebook\.com|faceparty|faceparty\.com|fandom\.com|fanpop|fanpop\.com|fark|fark\.com|fb|fb\.me|fc2|fc2\.com|feedspot|feministing|feministing\.com|filmaffinity|filmaffinity\.com|flickr|flickr\.com|flipboard|flipboard\.com|folkdirect|folkdirect\.com|foodservice|foodservice\.com|forums\.androidcentral\.com|forums\.crackberry\.com|forums\.imore\.com|forums\.nexopia\.com|forums\.webosnation\.com|forums\.wpcentral\.com|fotki|fotki\.com|fotolog|fotolog\.com|foursquare|foursquare\.com|free\.facebook\.com|friendfeed|friendfeed\.com|fruehstueckstreff\.org|fubar|fubar\.com|gaiaonline|gaiaonline\.com|gamerdna|gamerdna\.com|gather\.com|geni\.com|getpocket\.com|glassboard|glassboard\.com|glassdoor|glassdoor\.com|godtube|godtube\.com|goldenline\.pl|goldstar|goldstar\.com|goo\.gl|gooblog|goodreads|goodreads\.com|google\+|googlegroups\.com|googleplus|govloop|govloop\.com|gowalla|gowalla\.com|gree\.jp|groups\.google\.com|gulli\.com|gutefrage\.net|habbo|habbo\.com|hi5|hi5\.com|hootsuite|hootsuite\.com|houzz|houzz\.com|hoverspot|hoverspot\.com|hr\.com|hu\.pinterest\.com|hubculture|hubculture\.com|hubpages\.com|hyves\.net|hyves\.nl|ibibo|ibibo\.com|id\.pinterest\.com|identi\.ca|ig|imageshack\.com|imageshack\.us|imvu|imvu\.com|in\.pinterest\.com|insanejournal|insanejournal\.com|instagram|instagram\.com|instapaper|instapaper\.com|internations\.org|interpals\.net|intherooms|intherooms\.com|irc-galleria\.net|is\.gd|italki|italki\.com|jammerdirect|jammerdirect\.com|jappy\.com|jappy\.de|kaboodle\.com|kakao|kakao\.com|kakaocorp\.com|kaneva|kaneva\.com|kin\.naver\.com|l\.facebook\.com|l\.instagram\.com|l\.messenger\.com|last\.fm|librarything|librarything\.com|lifestream\.aol\.com|line|line\.me|linkedin|linkedin\.com|listal|listal\.com|listography|listography\.com|livedoor\.com|livedoorblog|livejournal|livejournal\.com|lm\.facebook\.com|lnkd\.in|m\.blog\.naver\.com|m\.cafe\.naver\.com|m\.facebook\.com|m\.kin\.naver\.com|m\.vk\.com|m\.yelp\.com|mbga\.jp|medium\.com|meetin\.org|meetup|meetup\.com|meinvz\.net|meneame\.net|menuism\.com|messages\.google\.com|messages\.yahoo\.co\.jp|messenger|messenger\.com|mix\.com|mixi\.jp|mobile\.facebook\.com|mocospace|mocospace\.com|mouthshut|mouthshut\.com|movabletype|movabletype\.com|mubi|mubi\.com|my\.opera\.com|myanimelist\.net|myheritage|myheritage\.com|mylife|mylife\.com|mymodernmet|mymodernmet\.com|myspace|myspace\.com|netvibes|netvibes\.com|news\.ycombinator\.com|newsshowcase|nexopia|ngopost\.org|niconico|nicovideo\.jp|nightlifelink|nightlifelink\.com|ning|ning\.com|nl\.pinterest\.com|odnoklassniki\.ru|odnoklassniki\.ua|okwave\.jp|old\.reddit\.com|oneworldgroup\.org|onstartups|onstartups\.com|opendiary|opendiary\.com|oshiete\.goo\.ne\.jp|out\.reddit\.com|over-blog\.com|overblog\.com|paper\.li|partyflock\.nl|photobucket|photobucket\.com|pinboard|pinboard\.in|pingsta|pingsta\.com|pinterest|pinterest\.at|pinterest\.ca|pinterest\.ch|pinterest\.cl|pinterest\.co\.kr|pinterest\.co\.uk|pinterest\.com|pinterest\.com\.au|pinterest\.com\.mx|pinterest\.de|pinterest\.es|pinterest\.fr|pinterest\.it|pinterest\.jp|pinterest\.nz|pinterest\.ph|pinterest\.pt|pinterest\.ru|pinterest\.se|pixiv\.net|pl\.pinterest\.com|playahead\.se|plurk|plurk\.com|plus\.google\.com|plus\.url\.google\.com|pocket\.co|posterous|posterous\.com|pro\.homeadvisor\.com|pulse\.yahoo\.com|qapacity|qapacity\.com|quechup|quechup\.com|quora|quora\.com|qzone\.qq\.com|ravelry|ravelry\.com|reddit|reddit\.com|redux|redux\.com|renren|renren\.com|researchgate\.net|reunion|reunion\.com|reverbnation|reverbnation\.com|rtl\.de|ryze|ryze\.com|salespider|salespider\.com|scoop\.it|screenrant|screenrant\.com|scribd|scribd\.com|scvngr|scvngr\.com|secondlife|secondlife\.com|serverfault|serverfault\.com|shareit|sharethis|sharethis\.com|shvoong\.com|sites\.google\.com|skype|skyrock|skyrock\.com|slashdot\.org|slideshare\.net|smartnews\.com|snapchat|snapchat\.com|social|sociallife\.com\.br|socialvibe|socialvibe\.com|spaces\.live\.com|spoke|spoke\.com|spruz|spruz\.com|ssense\.com|stackapps|stackapps\.com|stackexchange|stackexchange\.com|stackoverflow|stackoverflow\.com|stardoll\.com|stickam|stickam\.com|studivz\.net|suomi24\.fi|superuser|superuser\.com|sweeva|sweeva\.com|t\.co|t\.me|tagged|tagged\.com|taggedmail|taggedmail\.com|talkbiznow|talkbiznow\.com|taringa\.net|techmeme|techmeme\.com|tencent|tencent\.com|tiktok|tiktok\.com|tinyurl|tinyurl\.com|toolbox|toolbox\.com|touch\.facebook\.com|tr\.pinterest\.com|travellerspoint|travellerspoint\.com|tripadvisor|tripadvisor\.com|trombi|trombi\.com|trustpilot|tudou|tudou\.com|tuenti|tuenti\.com|tumblr|tumblr\.com|tweetdeck|tweetdeck\.com|twitter|twitter\.com|twoo\.com|typepad|typepad\.com|unblog\.fr|urbanspoon\.com|ushareit\.com|ushi\.cn|vampirefreaks|vampirefreaks\.com|vampirerave|vampirerave\.com|vg\.no|video\.ibm\.com|vk\.com|vkontakte\.ru|wakoopa|wakoopa\.com|wattpad|wattpad\.com|web\.facebook\.com|web\.skype\.com|webshots|webshots\.com|wechat|wechat\.com|weebly|weebly\.com|weibo|weibo\.com|wer-weiss-was\.de|weread|weread\.com|whatsapp|whatsapp\.com|wiki\.answers\.com|wikihow\.com|wikitravel\.org|woot\.com|wordpress|wordpress\.com|wordpress\.org|xanga|xanga\.com|xing|xing\.com|yahoo-mbga\.jp|yammer|yammer\.com|yelp|yelp\.co\.uk|yelp\.com|youroom\.in|za\.pinterest\.com|zalo|zoo\.gr|zooppa|zooppa\.com)$", "i").test(v.utmSource) && new RegExp("^(.*cp.*|ppc|retargeting|paid.*)$", "i").test(v.utmMedium)},{"name":"paid-video","test":(v) => new RegExp("^(?:blog\.twitch\.tv|crackle|crackle\.com|curiositystream|curiositystream\.com|d\.tube|dailymotion|dailymotion\.com|dashboard\.twitch\.tv|disneyplus|disneyplus\.com|fast\.wistia\.net|help\.hulu\.com|help\.netflix\.com|hulu|hulu\.com|id\.twitch\.tv|iq\.com|iqiyi|iqiyi\.com|jobs\.netflix\.com|justin\.tv|m\.twitch\.tv|m\.youtube\.com|music\.youtube\.com|netflix|netflix\.com|player\.twitch\.tv|player\.vimeo\.com|ted|ted\.com|twitch|twitch\.tv|utreon|utreon\.com|veoh|veoh\.com|viadeo\.journaldunet\.com|vimeo|vimeo\.com|wistia|wistia\.com|youku|youku\.com|youtube|youtube\.com)$", "i").test(v.utmSource) && new RegExp("^(.*cp.*|ppc|retargeting|paid.*)$", "i").test(v.utmMedium)},{"name":"display","test":(v) => new RegExp("^(?:display|banner|expandable|interstitial|cpm)$", "i").test(v.utmMedium)},{"name":"paid-other","test":(v) => new RegExp("^(.*cp.*|ppc|retargeting|paid.*)$", "i").test(v.utmMedium)},{"name":"organic-shopping","test":(v) => new RegExp("^(?:360\.cn|alice|aol|ar\.search\.yahoo\.com|ask|at\.search\.yahoo\.com|au\.search\.yahoo\.com|auone|avg|babylon|baidu|biglobe|biglobe\.co\.jp|biglobe\.ne\.jp|bing|br\.search\.yahoo\.com|ca\.search\.yahoo\.com|centrum\.cz|ch\.search\.yahoo\.com|cl\.search\.yahoo\.com|cn\.bing\.com|cnn|co\.search\.yahoo\.com|comcast|conduit|daum|daum\.net|de\.search\.yahoo\.com|dk\.search\.yahoo\.com|dogpile|dogpile\.com|duckduckgo|ecosia\.org|email\.seznam\.cz|eniro|es\.search\.yahoo\.com|espanol\.search\.yahoo\.com|exalead\.com|excite\.com|fi\.search\.yahoo\.com|firmy\.cz|fr\.search\.yahoo\.com|globo|go\.mail\.ru|google|google-play|hk\.search\.yahoo\.com|id\.search\.yahoo\.com|in\.search\.yahoo\.com|incredimail|it\.search\.yahoo\.com|kvasir|lens\.google\.com|lite\.qwant\.com|lycos|m\.baidu\.com|m\.naver\.com|m\.search\.naver\.com|m\.sogou\.com|mail\.rambler\.ru|mail\.yandex\.ru|malaysia\.search\.yahoo\.com|msn|msn\.com|mx\.search\.yahoo\.com|najdi|naver|naver\.com|news\.google\.com|nl\.search\.yahoo\.com|no\.search\.yahoo\.com|ntp\.msn\.com|nz\.search\.yahoo\.com|onet|onet\.pl|pe\.search\.yahoo\.com|ph\.search\.yahoo\.com|pl\.search\.yahoo\.com|play\.google\.com|qwant|qwant\.com|rakuten|rakuten\.co\.jp|rambler|rambler\.ru|se\.search\.yahoo\.com|search-results|search\.aol\.co\.uk|search\.aol\.com|search\.google\.com|search\.smt\.docomo\.ne\.jp|search\.ukr\.net|secureurl\.ukr\.net|seznam|seznam\.cz|sg\.search\.yahoo\.com|so\.com|sogou|sogou\.com|sp-web\.search\.auone\.jp|startsiden|startsiden\.no|suche\.aol\.de|terra|th\.search\.yahoo\.com|tr\.search\.yahoo\.com|tut\.by|tw\.search\.yahoo\.com|uk\.search\.yahoo\.com|ukr|us\.search\.yahoo\.com|virgilio|vn\.search\.yahoo\.com|wap\.sogou\.com|webmaster\.yandex\.ru|websearch\.rakuten\.co\.jp|yahoo|yahoo\.co\.jp|yahoo\.com|yandex|yandex\.by|yandex\.com|yandex\.com\.tr|yandex\.fr|yandex\.kz|yandex\.ru|yandex\.ua|yandex\.uz|zen\.yandex\.ru)$", "i").test(v.utmSource) || new RegExp("^(.*(([^a-df-z]|^)shop|shopping).*)$", "i").test(v.utmCampaign)},{"name":"organic-social","test":(v) => new RegExp("^(?:43things|43things\.com|51\.com|5ch\.net|Hatena|ImageShack|academia\.edu|activerain|activerain\.com|activeworlds|activeworlds\.com|addthis|addthis\.com|airg\.ca|allnurses\.com|allrecipes\.com|alumniclass|alumniclass\.com|ameba\.jp|ameblo\.jp|americantowns|americantowns\.com|amp\.reddit\.com|ancestry\.com|anobii|anobii\.com|answerbag|answerbag\.com|answers\.yahoo\.com|aolanswers|aolanswers\.com|apps\.facebook\.com|ar\.pinterest\.com|artstation\.com|askubuntu|askubuntu\.com|asmallworld\.com|athlinks|athlinks\.com|away\.vk\.com|awe\.sm|b\.hatena\.ne\.jp|baby-gaga|baby-gaga\.com|babyblog\.ru|badoo|badoo\.com|bebo|bebo\.com|beforeitsnews|beforeitsnews\.com|bharatstudent|bharatstudent\.com|biip\.no|biswap\.org|bit\.ly|blackcareernetwork\.com|blackplanet|blackplanet\.com|blip\.fm|blog\.com|blog\.feedspot\.com|blog\.goo\.ne\.jp|blog\.naver\.com|blog\.yahoo\.co\.jp|blogg\.no|bloggang\.com|blogger|blogger\.com|blogher|blogher\.com|bloglines|bloglines\.com|blogs\.com|blogsome|blogsome\.com|blogspot|blogspot\.com|blogster|blogster\.com|blurtit|blurtit\.com|bookmarks\.yahoo\.co\.jp|bookmarks\.yahoo\.com|br\.pinterest\.com|brightkite|brightkite\.com|brizzly|brizzly\.com|business\.facebook\.com|buzzfeed|buzzfeed\.com|buzznet|buzznet\.com|cafe\.naver\.com|cafemom|cafemom\.com|camospace|camospace\.com|canalblog\.com|care\.com|care2|care2\.com|caringbridge\.org|catster|catster\.com|cbnt\.io|cellufun|cellufun\.com|centerblog\.net|chat\.zalo\.me|chegg\.com|chicagonow|chicagonow\.com|chiebukuro\.yahoo\.co\.jp|classmates|classmates\.com|classquest|classquest\.com|co\.pinterest\.com|cocolog-nifty|cocolog-nifty\.com|copainsdavant\.linternaute\.com|couchsurfing\.org|cozycot|cozycot\.com|cross\.tv|crunchyroll|crunchyroll\.com|cyworld|cyworld\.com|cz\.pinterest\.com|d\.hatena\.ne\.jp|dailystrength\.org|deluxe\.com|deviantart|deviantart\.com|dianping|dianping\.com|digg|digg\.com|diigo|diigo\.com|discover\.hubpages\.com|disqus|disqus\.com|dogster|dogster\.com|dol2day|dol2day\.com|doostang|doostang\.com|dopplr|dopplr\.com|douban|douban\.com|draft\.blogger\.com|draugiem\.lv|drugs-forum|drugs-forum\.com|dzone|dzone\.com|edublogs\.org|elftown|elftown\.com|epicurious\.com|everforo\.com|exblog\.jp|extole|extole\.com|facebook|facebook\.com|faceparty|faceparty\.com|fandom\.com|fanpop|fanpop\.com|fark|fark\.com|fb|fb\.me|fc2|fc2\.com|feedspot|feministing|feministing\.com|filmaffinity|filmaffinity\.com|flickr|flickr\.com|flipboard|flipboard\.com|folkdirect|folkdirect\.com|foodservice|foodservice\.com|forums\.androidcentral\.com|forums\.crackberry\.com|forums\.imore\.com|forums\.nexopia\.com|forums\.webosnation\.com|forums\.wpcentral\.com|fotki|fotki\.com|fotolog|fotolog\.com|foursquare|foursquare\.com|free\.facebook\.com|friendfeed|friendfeed\.com|fruehstueckstreff\.org|fubar|fubar\.com|gaiaonline|gaiaonline\.com|gamerdna|gamerdna\.com|gather\.com|geni\.com|getpocket\.com|glassboard|glassboard\.com|glassdoor|glassdoor\.com|godtube|godtube\.com|goldenline\.pl|goldstar|goldstar\.com|goo\.gl|gooblog|goodreads|goodreads\.com|google\+|googlegroups\.com|googleplus|govloop|govloop\.com|gowalla|gowalla\.com|gree\.jp|groups\.google\.com|gulli\.com|gutefrage\.net|habbo|habbo\.com|hi5|hi5\.com|hootsuite|hootsuite\.com|houzz|houzz\.com|hoverspot|hoverspot\.com|hr\.com|hu\.pinterest\.com|hubculture|hubculture\.com|hubpages\.com|hyves\.net|hyves\.nl|ibibo|ibibo\.com|id\.pinterest\.com|identi\.ca|ig|imageshack\.com|imageshack\.us|imvu|imvu\.com|in\.pinterest\.com|insanejournal|insanejournal\.com|instagram|instagram\.com|instapaper|instapaper\.com|internations\.org|interpals\.net|intherooms|intherooms\.com|irc-galleria\.net|is\.gd|italki|italki\.com|jammerdirect|jammerdirect\.com|jappy\.com|jappy\.de|kaboodle\.com|kakao|kakao\.com|kakaocorp\.com|kaneva|kaneva\.com|kin\.naver\.com|l\.facebook\.com|l\.instagram\.com|l\.messenger\.com|last\.fm|librarything|librarything\.com|lifestream\.aol\.com|line|line\.me|linkedin|linkedin\.com|listal|listal\.com|listography|listography\.com|livedoor\.com|livedoorblog|livejournal|livejournal\.com|lm\.facebook\.com|lnkd\.in|m\.blog\.naver\.com|m\.cafe\.naver\.com|m\.facebook\.com|m\.kin\.naver\.com|m\.vk\.com|m\.yelp\.com|mbga\.jp|medium\.com|meetin\.org|meetup|meetup\.com|meinvz\.net|meneame\.net|menuism\.com|messages\.google\.com|messages\.yahoo\.co\.jp|messenger|messenger\.com|mix\.com|mixi\.jp|mobile\.facebook\.com|mocospace|mocospace\.com|mouthshut|mouthshut\.com|movabletype|movabletype\.com|mubi|mubi\.com|my\.opera\.com|myanimelist\.net|myheritage|myheritage\.com|mylife|mylife\.com|mymodernmet|mymodernmet\.com|myspace|myspace\.com|netvibes|netvibes\.com|news\.ycombinator\.com|newsshowcase|nexopia|ngopost\.org|niconico|nicovideo\.jp|nightlifelink|nightlifelink\.com|ning|ning\.com|nl\.pinterest\.com|odnoklassniki\.ru|odnoklassniki\.ua|okwave\.jp|old\.reddit\.com|oneworldgroup\.org|onstartups|onstartups\.com|opendiary|opendiary\.com|oshiete\.goo\.ne\.jp|out\.reddit\.com|over-blog\.com|overblog\.com|paper\.li|partyflock\.nl|photobucket|photobucket\.com|pinboard|pinboard\.in|pingsta|pingsta\.com|pinterest|pinterest\.at|pinterest\.ca|pinterest\.ch|pinterest\.cl|pinterest\.co\.kr|pinterest\.co\.uk|pinterest\.com|pinterest\.com\.au|pinterest\.com\.mx|pinterest\.de|pinterest\.es|pinterest\.fr|pinterest\.it|pinterest\.jp|pinterest\.nz|pinterest\.ph|pinterest\.pt|pinterest\.ru|pinterest\.se|pixiv\.net|pl\.pinterest\.com|playahead\.se|plurk|plurk\.com|plus\.google\.com|plus\.url\.google\.com|pocket\.co|posterous|posterous\.com|pro\.homeadvisor\.com|pulse\.yahoo\.com|qapacity|qapacity\.com|quechup|quechup\.com|quora|quora\.com|qzone\.qq\.com|ravelry|ravelry\.com|reddit|reddit\.com|redux|redux\.com|renren|renren\.com|researchgate\.net|reunion|reunion\.com|reverbnation|reverbnation\.com|rtl\.de|ryze|ryze\.com|salespider|salespider\.com|scoop\.it|screenrant|screenrant\.com|scribd|scribd\.com|scvngr|scvngr\.com|secondlife|secondlife\.com|serverfault|serverfault\.com|shareit|sharethis|sharethis\.com|shvoong\.com|sites\.google\.com|skype|skyrock|skyrock\.com|slashdot\.org|slideshare\.net|smartnews\.com|snapchat|snapchat\.com|social|sociallife\.com\.br|socialvibe|socialvibe\.com|spaces\.live\.com|spoke|spoke\.com|spruz|spruz\.com|ssense\.com|stackapps|stackapps\.com|stackexchange|stackexchange\.com|stackoverflow|stackoverflow\.com|stardoll\.com|stickam|stickam\.com|studivz\.net|suomi24\.fi|superuser|superuser\.com|sweeva|sweeva\.com|t\.co|t\.me|tagged|tagged\.com|taggedmail|taggedmail\.com|talkbiznow|talkbiznow\.com|taringa\.net|techmeme|techmeme\.com|tencent|tencent\.com|tiktok|tiktok\.com|tinyurl|tinyurl\.com|toolbox|toolbox\.com|touch\.facebook\.com|tr\.pinterest\.com|travellerspoint|travellerspoint\.com|tripadvisor|tripadvisor\.com|trombi|trombi\.com|trustpilot|tudou|tudou\.com|tuenti|tuenti\.com|tumblr|tumblr\.com|tweetdeck|tweetdeck\.com|twitter|twitter\.com|twoo\.com|typepad|typepad\.com|unblog\.fr|urbanspoon\.com|ushareit\.com|ushi\.cn|vampirefreaks|vampirefreaks\.com|vampirerave|vampirerave\.com|vg\.no|video\.ibm\.com|vk\.com|vkontakte\.ru|wakoopa|wakoopa\.com|wattpad|wattpad\.com|web\.facebook\.com|web\.skype\.com|webshots|webshots\.com|wechat|wechat\.com|weebly|weebly\.com|weibo|weibo\.com|wer-weiss-was\.de|weread|weread\.com|whatsapp|whatsapp\.com|wiki\.answers\.com|wikihow\.com|wikitravel\.org|woot\.com|wordpress|wordpress\.com|wordpress\.org|xanga|xanga\.com|xing|xing\.com|yahoo-mbga\.jp|yammer|yammer\.com|yelp|yelp\.co\.uk|yelp\.com|youroom\.in|za\.pinterest\.com|zalo|zoo\.gr|zooppa|zooppa\.com)$", "i").test(v.utmSource) || new RegExp("^(?:social|social-network|social-media|sm|social network|social media)$", "i").test(v.utmMedium)},{"name":"organic-video","test":(v) => new RegExp("^(?:blog\.twitch\.tv|crackle|crackle\.com|curiositystream|curiositystream\.com|d\.tube|dailymotion|dailymotion\.com|dashboard\.twitch\.tv|disneyplus|disneyplus\.com|fast\.wistia\.net|help\.hulu\.com|help\.netflix\.com|hulu|hulu\.com|id\.twitch\.tv|iq\.com|iqiyi|iqiyi\.com|jobs\.netflix\.com|justin\.tv|m\.twitch\.tv|m\.youtube\.com|music\.youtube\.com|netflix|netflix\.com|player\.twitch\.tv|player\.vimeo\.com|ted|ted\.com|twitch|twitch\.tv|utreon|utreon\.com|veoh|veoh\.com|viadeo\.journaldunet\.com|vimeo|vimeo\.com|wistia|wistia\.com|youku|youku\.com|youtube|youtube\.com)$", "i").test(v.utmSource) || new RegExp("^(.*video.*)$", "i").test(v.utmMedium)},{"name":"organic-search","test":(v) => new RegExp("^(?:360\.cn|alice|aol|ar\.search\.yahoo\.com|ask|at\.search\.yahoo\.com|au\.search\.yahoo\.com|auone|avg|babylon|baidu|biglobe|biglobe\.co\.jp|biglobe\.ne\.jp|bing|br\.search\.yahoo\.com|ca\.search\.yahoo\.com|centrum\.cz|ch\.search\.yahoo\.com|cl\.search\.yahoo\.com|cn\.bing\.com|cnn|co\.search\.yahoo\.com|comcast|conduit|daum|daum\.net|de\.search\.yahoo\.com|dk\.search\.yahoo\.com|dogpile|dogpile\.com|duckduckgo|ecosia\.org|email\.seznam\.cz|eniro|es\.search\.yahoo\.com|espanol\.search\.yahoo\.com|exalead\.com|excite\.com|fi\.search\.yahoo\.com|firmy\.cz|fr\.search\.yahoo\.com|globo|go\.mail\.ru|google|google-play|hk\.search\.yahoo\.com|id\.search\.yahoo\.com|in\.search\.yahoo\.com|incredimail|it\.search\.yahoo\.com|kvasir|lens\.google\.com|lite\.qwant\.com|lycos|m\.baidu\.com|m\.naver\.com|m\.search\.naver\.com|m\.sogou\.com|mail\.rambler\.ru|mail\.yandex\.ru|malaysia\.search\.yahoo\.com|msn|msn\.com|mx\.search\.yahoo\.com|najdi|naver|naver\.com|news\.google\.com|nl\.search\.yahoo\.com|no\.search\.yahoo\.com|ntp\.msn\.com|nz\.search\.yahoo\.com|onet|onet\.pl|pe\.search\.yahoo\.com|ph\.search\.yahoo\.com|pl\.search\.yahoo\.com|play\.google\.com|qwant|qwant\.com|rakuten|rakuten\.co\.jp|rambler|rambler\.ru|se\.search\.yahoo\.com|search-results|search\.aol\.co\.uk|search\.aol\.com|search\.google\.com|search\.smt\.docomo\.ne\.jp|search\.ukr\.net|secureurl\.ukr\.net|seznam|seznam\.cz|sg\.search\.yahoo\.com|so\.com|sogou|sogou\.com|sp-web\.search\.auone\.jp|startsiden|startsiden\.no|suche\.aol\.de|terra|th\.search\.yahoo\.com|tr\.search\.yahoo\.com|tut\.by|tw\.search\.yahoo\.com|uk\.search\.yahoo\.com|ukr|us\.search\.yahoo\.com|virgilio|vn\.search\.yahoo\.com|wap\.sogou\.com|webmaster\.yandex\.ru|websearch\.rakuten\.co\.jp|yahoo|yahoo\.co\.jp|yahoo\.com|yandex|yandex\.by|yandex\.com|yandex\.com\.tr|yandex\.fr|yandex\.kz|yandex\.ru|yandex\.ua|yandex\.uz|zen\.yandex\.ru)$", "i").test(v.utmSource) || v.utmMedium.toLowerCase() === "organic"},{"name":"referral","test":(v) => new RegExp("^(?:referral|app|link)$", "i").test(v.utmMedium)},{"name":"email","test":(v) => new RegExp("^(?:email|e-mail|e_mail|e mail)$", "i").test(v.utmMedium) || new RegExp("^(?:email|e-mail|e_mail|e mail)$", "i").test(v.utmSource)},{"name":"affiliate","test":(v) => v.utmMedium.toLowerCase() === "affiliate"},{"name":"audio","test":(v) => v.utmMedium.toLowerCase() === "audio"},{"name":"sms","test":(v) => v.utmSource.toLowerCase() === "sms" || v.utmMedium.toLowerCase() === "sms"},{"name":"mobile-push-notification","test":(v) => v.utmSource.toLowerCase() === "firebase" || new RegExp("(?:.*mobile.*|.*notification.*|push$)", "i").test(v.utmMedium)}].find(i=>i.test(t))?.name??"other"}getShopifyAnalyticsId(){return this.getCookie("_shopify_y")}legacyGetCookieVisitor(){const t=this.getCookie("SHOPLIFT");return t===null?null:JSON.parse(t,_)}getCookie(t){const e=this.cookie.split("; ").filter(i=>i.split("=").at(0)===t).at(0);return e===void 0?null:e.split("=").slice(1).join("=")}monitorConsentChange(){document.addEventListener("visitorConsentCollected",t=>{(async()=>await this.onConsentChange(t.detail.analyticsAllowed,!0))()}),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>this.loadShopifyConsentApiWithRetry()):this.loadShopifyConsentApiWithRetry()}loadShopifyConsentApiWithRetry(){let t=0;const e=()=>{this.loadShopifyConsentApi()||t++<10&&window.setTimeout(e,100)};e()}loadShopifyConsentApi(){if(window.Shopify){this.log("Loading Shopify features");const t=async()=>{if(!window.Shopify){this.log("Shopify object missing... suddenly?");return}if(window.Shopify.customerPrivacy===void 0){this.log("Shopify CustomerPrivacy api still missing, trying again in 1000ms"),e=window.setTimeout(()=>{(async()=>await t())()},1e3);return}const i=window.Shopify.customerPrivacy.getTrackingConsent();await this.onConsentChange(window.Shopify.customerPrivacy.analyticsProcessingAllowed(),i==="yes")};let e=window.setTimeout(()=>{(async()=>await t())()},5e3);return window.Shopify.loadFeatures([{name:"consent-tracking-api",version:"0.1"}],i=>{(async()=>{if(window.clearTimeout(e),i){this.log("Error loading consent tracking",i);return}await t()})()}),!0}return!1}async onConsentChange(t,e){try{if(this.log("Consent change detected",t,e),this.state.essential.consentApproved=t,this.state.essential.hasConsentInteraction=e,!this.state.essential.consentApproved){this.state.essential.hasConsentInteraction&&(this.state.analytics.queue.length=0),this.saveState();return}this.cookie=document.cookie,this.shopifyAnalyticsId=this.getShopifyAnalyticsId();for(const i of this.state.analytics.queue.filter(s=>s.type===1||s.type===2)){const s=i;s.shopifyAnalyticsId=this.shopifyAnalyticsId}this.saveState(),await this.syncAllEvents()}catch(i){this.log("Error syncing on consent change",i)}}isThemePreview(){return isThemePreview||themeRole!=="main"}clearThemeBar(t,e,i){const s=structuredClone(i);this.log("Looking for theme bar"),this.waitForElement(null,"body").then(r=>this.waitForElement(r,"#preview-bar-iframe, #PBarNextFrameWrapper").then(o=>(this.log("Found theme bar"),e&&(this.log("Removing theme bar"),o.remove()),t?this.makeRequest({url:`${this.eventHost}/api/v0/logs`,method:"post",data:JSON.stringify({...this.debugState(),stateAtEvaluation:s},O)}):Promise.resolve(null)))).catch(r=>console.error(r))}waitForElement(t,e){return new Promise(i=>{const s=document.querySelector(e);if(s){i(s);return}const r=new MutationObserver(o=>{const n=document.querySelector(e);if(n){r.disconnect(),i(n);return}});r.observe(t??document.documentElement,{childList:!0})})}setDebug(t){this.state.essential.debugMode=t,this.saveState()}log(t,...e){let i=0;const s=t.replace(/%[sdoOfF]/g,r=>{if(i>=e.length)return r;const o=e[i++];return r==="%o"||r==="%O"?JSON.stringify(o):String(o)});this.logHistory.push(`[${new Date().toISOString()}][SL] ${s}`),!(!this.state.essential.debugMode&&!this.shopliftDebug)&&console.debug(`[SL] ${t}`,...e)}debugState(){return{state:this.state,storage:{essential:this.loadLocalStorage(this.essentialSessionKey),analytics:this.loadLocalStorage(this.analyticsSessionKey)},params:{shop:this.shop,host:this.host,eventHost:this.eventHost,cssHideClass:this.cssHideClass,testConfigs:this.testConfigs,inactiveTestConfigs:this.inactiveTestConfigs,sendPageView:this.sendPageView,isShopifyMerchantCookie:this.getCookie("is_shopify_merchant"),themeId,url:window.location.href,isThemePreview,themeRole,gaConfig:this.gaConfig},logHistory:this.logHistory}}createViewportObserver(t,e={}){const{threshold:i=this.VIEWPORT_TRACK_THRESHOLD,triggerOnce:s=!0}=e,r=new Set;return new IntersectionObserver(o=>{o.forEach(n=>{if(n.isIntersecting&&!r.has(n.target)){const a=n.target,c=a.getAttribute(this.DATA_SL_TEST_ID);c&&(t(c,a),s&&r.add(a))}})},{threshold:i})}applyChangesWithViewport(t,e,i,s){const r=e.selectorsForViewportTracking??e.selectors,o=n=>{if(this.state.essential.visitorTests.some(p=>p.testId===n)||this.activeViewportObservers.has(n))return;const a=[];if(r.forEach(p=>{t.querySelectorAll(p.cssSelector).forEach(v=>a.push(v))}),a.length===0)return;let c=!1;const h=()=>{c||(c=!0,i(n),u.disconnect(),this.activeViewportObservers.delete(n))},u=this.createViewportObserver(()=>{h()},{triggerOnce:!0,...s});this.activeViewportObservers.set(n,u),this.log(`Created viewport observer for test ${n}, observing ${a.length} elements`),a.forEach(p=>{p.setAttribute(this.DATA_SL_TEST_ID,String(n)),u.observe(p)}),setTimeout(()=>{c||a.forEach(p=>{const d=p.getBoundingClientRect(),v=s?.threshold??this.VIEWPORT_TRACK_THRESHOLD,T=Math.min(d.bottom,window.innerHeight)-Math.max(d.top,0),m=Math.min(d.right,window.innerWidth)-Math.max(d.left,0);d.top<window.innerHeight&&d.bottom>0&&d.left<window.innerWidth&&d.right>0&&T>0&&m>0&&T>=d.height*v&&(this.log(`Price element already visible in viewport for test ${n}:`,p),h())})},100)};e.selectors.length>0&&x(t,e,()=>{}),Z(t,{testId:e.testId,hypothesisId:e.hypothesisId,selectors:r},n=>{o(n)})}applyPriceTestWithMapLookup(t,e,i,s){if(!e.priceData){this.log("No price data for hypothesis '%s'",e.id);return}this.log("Hypothesis '%s' isControl=%s, priceData has %d variants",e.id,e.isControl,e.priceData.v.length);const r=e.priceData.v.slice(0,3);for(const[m,S,I]of r)this.log(" Sample priceData: variant=%s, price=%d, compareAt=%d",m,S,I);const o=ct(e.priceData),n=new Set;for(const m of i)if(m.priceData)for(const[S]of m.priceData.v)n.add(S);this.log("Price test Map lookup: %d products in hypothesis, %d total products to track",o.size,n.size);const a=e.priceData,c=new WeakSet;let h=!1;const u="[data-sl-attribute-p], [data-sl-attribute-cap], [data-sl-attribute-discount]",p=m=>{if(c.has(m))return;const S=m.getAttribute("data-sl-attribute-p"),I=m.getAttribute("data-sl-attribute-cap"),y=m.getAttribute("data-sl-attribute-discount"),f=S||I||y;if(!f||!n.has(f))return;c.add(m);const w=o.get(f);w&&(this.log("Applying price for product %s: %d cents (compare at: %d cents)",f,w.priceInCents,w.compareAtPriceInCents),dt(m,f,w,a),this.log("Applied price to element for product %s",f)),!h&&!this.state.essential.visitorTests.some(g=>g.testId===t)&&(m.setAttribute(this.DATA_SL_TEST_ID,String(t)),this.setupElementViewportTracking(m,t,()=>{h||(h=!0,s(t))}))},d=()=>{const m=document.querySelectorAll(u);this.log("Scanning for price elements, found: %d",m.length),m.forEach(p)},v=new MutationObserver(m=>{for(const S of m)S.type==="childList"&&S.addedNodes.forEach(I=>{if(I.nodeType===Node.ELEMENT_NODE){const y=I;(y.hasAttribute("data-sl-attribute-p")||y.hasAttribute("data-sl-attribute-cap")||y.hasAttribute("data-sl-attribute-discount"))&&p(y),y.querySelectorAll(u).forEach(p)}}),S.type==="attributes"&&S.target instanceof Element&&p(S.target)}),T=document.body||document.documentElement;v.observe(T,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["data-sl-attribute-p","data-sl-attribute-cap","data-sl-attribute-discount"]}),this.log("MutationObserver started for price elements"),d(),document.readyState==="loading"&&document.addEventListener("DOMContentLoaded",()=>{this.log("DOMContentLoaded - rescanning for price elements"),d()}),setTimeout(()=>{this.log("Delayed rescan for price elements"),d()},100),setTimeout(()=>{this.log("Final rescan for price elements"),d()},500)}setupElementViewportTracking(t,e,i){const s=this.VIEWPORT_TRACK_THRESHOLD,r=t.getBoundingClientRect(),o=Math.min(r.bottom,window.innerHeight)-Math.max(r.top,0),n=Math.min(r.right,window.innerWidth)-Math.max(r.left,0);if(r.top<window.innerHeight&&r.bottom>0&&r.left<window.innerWidth&&r.right>0&&o>0&&n>0&&o>=r.height*s){this.log("Price element already visible for test %s",e),i();return}const c=new IntersectionObserver(h=>{for(const u of h)if(u.isIntersecting&&u.intersectionRatio>=s){this.log("Price element entered viewport for test %s",e),c.disconnect(),i();break}},{threshold:s});c.observe(t)}debug(){const t=this.debugState();console.log(JSON.stringify(t,O,2))}}(async function(){window.shopliftInstance||(window.shopliftInstance=new pt("contractor-training-center.myshopify.com","https://app.shoplift.ai","https://events.shoplift.ai",true,false,false,{"sendEvents":false,"mode":"gtag"},false,1000,[{"id":"019bbd9c-5160-7d56-919e-fd93f9165564","startAt":"2026-01-14T17:44:56.927938Z","requiresCountry":false,"bayesianRevision":5,"device":"all","status":"active","visitorOption":"all","ignoreTestViewParameterEnforcement":false,"statusHistory":[{"status":"active","createdAt":"2026-01-14T17:44:56.931875Z"}],"hypotheses":[{"visitorCount":127,"trafficPercentage":0.5,"title":"California General Building (B) Contractor Exam","domSelectors":[],"priceData":null,"id":"019bb8f1-cb33-7077-9cb9-bbbc6e8bd20a","type":"urlRedirect","themeId":142801010765,"affix":"","isControl":true,"redirectPath":"/collections/california-general-building-b-contractor-exam-prep-courses"},{"visitorCount":127,"trafficPercentage":0.5,"title":"California General Building (B) Contractor Exam (B)","domSelectors":[],"priceData":null,"id":"019bb8f8-5d0e-714f-bf11-d937b6144780","type":"urlRedirect","themeId":142801010765,"affix":"","isControl":false,"redirectPath":"/collections/california-general-building-b-contractor-exam-b"}],"targetAudiences":[],"title":"[CTC] California Product Test (Jan26) "}],[{"id":"d62fd5ff-8d97-4bc3-966c-6b375eb4b4e3","bayesianRevision":3,"status":"paused","hypotheses":[{"id":"a07829a9-8cdb-49b1-bb5b-9d0e280710dc","type":"urlRedirect","themeId":142801010765,"affix":"","isControl":true,"redirectPath":"/collections/tennessee-nascla"},{"id":"e7266e3f-8b6b-4b83-a3c5-3705462ad8b4","type":"urlRedirect","themeId":142801010765,"affix":"","isControl":false,"redirectPath":"/collections/tennessee-nascla-commercial-builder-exam-a-b"}],"ignoreTestViewParameterEnforcement":false},{"id":"32b871a1-74c5-454d-bbfa-cda5c76a18db","bayesianRevision":3,"status":"paused","hypotheses":[{"id":"50bddbeb-5e51-4216-8718-7785dad51deb","type":"urlRedirect","themeId":142801010765,"affix":"","isControl":true,"redirectPath":"/collections/alabama-nascla"},{"id":"0a96febd-f8f3-4ba6-8223-68755448a3f6","type":"urlRedirect","themeId":142801010765,"affix":"","isControl":false,"redirectPath":"/collections/alabama-nascla-commercial-builder-exam-a-b"}],"ignoreTestViewParameterEnforcement":false},{"id":"e2b17d40-8734-4b2e-9ea3-c3b43c2730ef","bayesianRevision":3,"status":"paused","hypotheses":[{"id":"2b61976f-e98f-4a7b-a267-d40831319a41","type":"urlRedirect","themeId":142801010765,"affix":"","isControl":true,"redirectPath":"/blogs/news/how-to-become-a-general-contractor-in-florida"},{"id":"0446231e-5f9f-40f9-a947-1797aed3d376","type":"urlRedirect","themeId":142801010765,"affix":"","isControl":false,"redirectPath":"/blogs/news/how-to-become-a-general-contractor-in-florida-2"}],"ignoreTestViewParameterEnforcement":false},{"id":"a236d4df-032d-451d-b812-930a9cfdbde1","bayesianRevision":3,"status":"paused","hypotheses":[{"id":"88c451bc-07e9-4ce6-983a-06bc0da3b993","type":"urlRedirect","themeId":142801010765,"affix":"","isControl":true,"redirectPath":"/collections/national-nascla"},{"id":"3d13597d-fa1f-4b2c-ac75-d8c1ce2f12ba","type":"urlRedirect","themeId":142801010765,"affix":"","isControl":false,"redirectPath":"/collections/national-nascla-commercial-builder-exam-a-b"}],"ignoreTestViewParameterEnforcement":false},{"id":"83fd2840-50f0-4708-ab19-88c16f26e16f","bayesianRevision":3,"status":"paused","hypotheses":[{"id":"88ad32a4-0b96-4baa-b2d2-ac86fcdfd2ed","type":"urlRedirect","themeId":142801010765,"affix":"","isControl":true,"redirectPath":"/collections/north-carolina-nascla"},{"id":"e59d1630-be2c-4e7f-8a66-a25fc673d139","type":"urlRedirect","themeId":142801010765,"affix":"","isControl":false,"redirectPath":"/collections/north-carolina-nascla-commercial-builder-exam-a-b"}],"ignoreTestViewParameterEnforcement":false},{"id":"f5f70c72-fa17-40a1-a617-5948c6a12b72","bayesianRevision":3,"status":"paused","hypotheses":[{"id":"112e32ad-9da0-4cd0-b437-2d5e8353ee2b","type":"urlRedirect","themeId":142801010765,"affix":"","isControl":true,"redirectPath":"/collections/florida-nascla"},{"id":"3e21781a-734b-4f11-b199-de47c857052a","type":"urlRedirect","themeId":142801010765,"affix":"","isControl":false,"redirectPath":"/collections/florida-nascla-commercial-builder-exam-a-b"}],"ignoreTestViewParameterEnforcement":false},{"id":"b1f7d851-d996-4dbf-94a4-e38457d3d7e9","bayesianRevision":3,"status":"paused","hypotheses":[{"id":"0843b1af-e47e-4ee7-abe1-64e43169e314","type":"urlRedirect","themeId":142801010765,"affix":"","isControl":true,"redirectPath":"/collections/south-carolina-unlimited"},{"id":"fefad671-6f8b-43fc-81ea-dfde7d8d21ac","type":"urlRedirect","themeId":142801010765,"affix":"","isControl":false,"redirectPath":"/collections/south-carolina-unlimited-builder-nascla-exam-a-b"}],"ignoreTestViewParameterEnforcement":false},{"id":"8d4ca658-f904-42a3-bcce-c1acce4b70ad","bayesianRevision":3,"status":"paused","hypotheses":[{"id":"5fa2e4b9-8ca5-45b0-8bd5-1910c33b45e9","type":"urlRedirect","themeId":142801010765,"affix":"","isControl":true,"redirectPath":"/collections/virginia-nascla"},{"id":"0144f64d-a6ae-4119-bba5-1e08d9c2e34b","type":"urlRedirect","themeId":142801010765,"affix":"","isControl":false,"redirectPath":"/collections/virginia-nascla-commercial-builder-exam-a-b"}],"ignoreTestViewParameterEnforcement":false},{"id":"6cdd87fb-6dd9-4539-be55-efb3c150cd7b","bayesianRevision":3,"status":"paused","hypotheses":[{"id":"d20ec80d-336a-4cf7-b2e0-d6e9498322fc","type":"urlRedirect","themeId":142801010765,"affix":"","isControl":true,"redirectPath":"/collections/national-nascla"},{"id":"c8f20010-bd9d-4b62-b138-e6e14ba074cc","type":"urlRedirect","themeId":142801010765,"affix":"","isControl":false,"redirectPath":"/collections/national-nascla-2"}],"ignoreTestViewParameterEnforcement":false},{"id":"cf472a25-ce5a-4616-a960-c0a6d4586b63","bayesianRevision":3,"status":"paused","hypotheses":[{"id":"d5ec812b-b1fc-43de-bb17-07a4bb8f276e","type":"urlRedirect","themeId":142801010765,"affix":"","isControl":true,"redirectPath":"/collections/louisiana-nascla"},{"id":"7f4fe4ed-4479-448d-a38f-69531ebe8f18","type":"urlRedirect","themeId":142801010765,"affix":"","isControl":false,"redirectPath":"/collections/louisiana-nascla-commercial-builder-exam-a-b"}],"ignoreTestViewParameterEnforcement":false},{"id":"17d394b1-be8b-4451-9035-0b05e44e7cb7","bayesianRevision":3,"status":"paused","hypotheses":[{"id":"55a72a3f-6f92-4f40-9e8f-5d63e220310c","type":"urlRedirect","themeId":142801010765,"affix":"","isControl":true,"redirectPath":"/collections/arizona-nascla"},{"id":"a0c03de7-234b-4e3b-8bd6-76ac1680c2ab","type":"urlRedirect","themeId":142801010765,"affix":"","isControl":false,"redirectPath":"/collections/arizona-nascla-commercial-builder-exam-a-b"}],"ignoreTestViewParameterEnforcement":false},{"id":"686d7f35-217c-42b7-9bad-4551e103e78b","bayesianRevision":3,"status":"paused","hypotheses":[{"id":"f83e155d-f09f-45b5-809e-a06694622823","type":"urlRedirect","themeId":142801010765,"affix":"","isControl":true,"redirectPath":"/collections/georgia-nascla"},{"id":"286fdf32-bc6a-4a3f-8c21-bb7c0833b068","type":"urlRedirect","themeId":142801010765,"affix":"","isControl":false,"redirectPath":"/collections/georgia-nascla-general-contractor-exam-a-b"}],"ignoreTestViewParameterEnforcement":false}]),await window.shopliftInstance.init())})()})(); })("/", { suffix: "sticky-nav", type: "article" }, "main", 142801010765, false)</script>
A heating, ventilation, and air conditioning (HVAC) technician or contractor keeps you warm in the winter and cool in the summer—and in North Carolina, where winter temps dip into the 20s and summer soars into the90s, their job is important. Â
To work as an HVAC technician or contractor in North Carolina, you must be licensed. To obtain your license, you’ll need to gain experience and pass an exam. HVAC technicians and contractors install, maintain, and repair heating and cooling systems along with the ventilation systems for both. Â
HVAC workers work with wet and forced air systems and are licensed in North Carolina by groups depending on the type and size of HVAC systems: Heating Groups 1 (H1), 2 (H2), and3 (H3).Within each group, there are two classes. Class I allows you to work on systems in residential, commercial, and industrial buildings, and Class II is for residential only. Â
Here is all the information you need to get started in a rewarding career as a Licensed HVAC technician or contractor in North Carolina. Â
Education and Training RequirementsÂ
Those who excel as HVAC technicians and contractors like to work in varied environments. They’re excellent problem solvers and have a mechanical aptitude. HVAC contractors work with different people, whether those are homeowners, general contractors, or subcontractors.  Â
Your first step is to earn a formal HVAC diploma or attend a certificate program, or you can earn your two-year Associate’s degree. You can also fulfill this requirement with a formal apprenticeship with a local union or trade organization, or through an informal apprenticeship with a sponsoring employer as an entry-level employee supervised by a licensed contractor.Â
HVAC Technician License Â
Full-time, on-the-job experience in installation, maintenance, service or repair of heating and cooling systems related to the license category include:Â Â
Class I: 18 months or 3,000 hours Class II: 15 months or 2,500 hoursÂ
HVAC Contractor License Â
To become a licensed contractor, you also need direct, hands-on experience specific to the license you want. All contractors for all groups and classes must have two(2) years or 4,000 hours of documented experience. Up to half of the requirement (2,000 hours) can come from an academic or technical training collegedirectly related to the field (45 quarter hours or 30 semester hours)Â
Benefits of Formal TrainingÂ
HVAC systems are complex with a lot of moving parts. For that reason, many employers prefer to hire HVAC licensees who have some formal training from a vocational or technical school along with on-the-job experience.Apprenticeship programs offer a chance to earn while you learn and include field experience and education. Your apprenticeship will also count toward the required hours to obtain your HVAC technician or contractor license. Â
Certificate programs take three to six months to complete. An associate degree takes two years, and a bachelor’s degree takes four years. Apprenticeship programs can take three to four years, butthey meet the full experience requirement so that you can take the exam.Â
EPA Certification RequirementÂ
The EPA Section 608 certification is required for anyone who handles refrigerants, whether that is installing, maintaining, or disposing of equipment.Apprentices are exempt from this; however, licensed technicians and contractors are required to pass an EPA-approved test. Â
The EPA defines technician [or contractor] as anyone who:Â
Attaches and detaches hoses and gauges to and from an appliance to measure pressure within the appliance. Â
Adds refrigerant to or removes refrigerant from an appliance.Â
Any other activity that violates the integrity of a motor vehicle air conditioner (MVAC)-like appliance or small appliance (other than disposal). Â
Licensing Requirements for HVAC Technicians in NCÂ
Following approval, you have 90 days to take the exam and 45 days after passing the exam to activate your license.Â
Apply for the ExamÂ
On the application you will have to provide:Â Â
The application fee Â
W-2s or detailed description of earningsÂ
Documented proof of experience under a licensed HVAC contractor, including total number of hours worked and percentage allocated to specified tasksÂ
Criminal background check and, when applicable, statements describing any criminal charges, conviction, incarcerations, paroles, and probationsÂ
Determine Your License TypeÂ
North Carolina has three licenses: H1, H2, and H3. Within groups H1 and H3, there are two classes. The state categorizes the work you can perform based on the license you hold. Â
Heating Group 1 (H1)Â
Heating Group 1-Class I (H1-I): “Wet” or “water-based” comfort heating systems in any residential, commercial, or industrial building.Â
Heating Group 1-Class II (H1-II): “Wet” or “water-based” comfort heating systems in single-family detached dwellings only. Â
Heating Group 2 (H2): Forced air heating and cooling systems with a cooling capacity in excess of fifteen tons in any residential, commercial, or industrial building.Â
Heating Group 3 (H3)Â
Heating Group 3-Class I (H3-I): Forced air heating and cooling systems with a cooling capacity ofless thanfifteen tons in any residential, commercial, or industrial building.Â
Heating Group 3-Class II (H3-II): Forced air heating and cooling systems with a cooling capacity of less than15 tons in any single-family detached residential building only.Â
Prepare for the ExamÂ
The exam is open book. You’re allowed to bring hard-bound or ring-bound reference materials, manuals, and codebooks in their original condition to use. All tabs or indexes must be permanently fixed. Reference materials may be highlighted; however, no printed, written text, notes, formula, or other alterations may be made or inserted during the exam. No loose papers or printouts are allowed. Â
HVAC technicians and contractors must pass the trade exam. There is a 4-hour time limit for the exam. If you are a licensed residential HVAC contractor in South Carolina, the trade exam is waived.Â
HVAC contractors must take the business and law exam and the trade exam. There is a 1.5-hour time limit to take this test.Â
Continuing Education and License RenewalÂ
HVAC technician and contractor licenses are valid for one year. The annual renewal fee is $75 for technicians and $150 for contractors. Continuing education (CE) is not required to renew, however, staying current with industry trends and best practices makes you more marketable as an employee and helps advance your career. Â
Benefits of Being an HVAC Technician in North CarolinaÂ
There are many benefits to becoming a licensed HVAC technician or contractor, particularly demand. The Bureau of Labor Statisticsreports a 9% growth rate over the next decade, which is faster than most other fields in the construction industry. Â
In North Carolina, HVAC technicians earn between $25,901 and $81,337, with an average of $53,421 annually. HVAC contactors make significantly more. The average HVAC contractor salary in North Carolina is $111,171, and as high as $144,955. HVAC contractors who choose to open their own businesses can earn even more. Â
Why Choose Our HVAC Licensing Exam Prep School?Â
Becoming a Licensed NC HVAC technician or contractor takes a one and a half-to two-year investment, whether it’s on-the-job training only or a combination of classroom and hands-on training. After investing that much time, you want to make sure you pass your exam. Â
Reach out to the Contractor Training Center when you’reready to get started! We’rehere to answer any questions you have and can help you with the application process.Â
Build your knowledge and sharpen your skills—get contractor tips, tools, and updates straight to your inbox. Sign up today!
By providing my personal information, including phone number, I consent to receive email messages, auto-dialed calls, texts, and prerecorded messages from Contractor Training Center with information and offers, including current and possible future services, customer service and billing and agree to the Terms of Service & Privacy Policy. Â If, at any time, you wish to opt out of electronic or text communications, reply STOP to cancel, HELP for help. Msg & data rates may apply. To opt out of email, follow the unsubscribe process on the email communication. I understand that my consent is not required to purchase, and that cancellation of purchase does not automatically revoke this consent.
Choosing a selection results in a full page refresh.