{"version":3,"sources":["/home/ubuntu24-new/Dev/stormcloud-vp/lib/utils/tracking.cjs","../../src/utils/tracking.ts","../../src/utils/mqttConfig.ts","../../src/utils/mqttClient.ts","../../src/utils/vastEnvironmentSignals.ts"],"names":["__create","Object","create","__defProp","defineProperty","__getOwnPropDesc","getOwnPropertyDescriptor","__getOwnPropNames","getOwnPropertyNames","__getProtoOf","getPrototypeOf","__hasOwnProp","prototype","hasOwnProperty","__export","target","all","name","get","enumerable","__copyProps","to","from","except","desc","key","call","__toESM","mod","isNodeMode","__esModule","value","__toCommonJS","tracking_exports","buildAnalyticsContext","getBrowserID","getClientInfo","sendAdDetectTracking","sendAdImpressionTracking","sendAdLoadedTracking","sendHeartbeat","sendInitialTracking","module","exports","DEFAULT_MQTT_CONFIG","enabled","brokerAddress","brokerPort","wsPort","username","password","topicPrefix","qos","mqttConfig","isMQTTEnabled","buildMQTTBrokerUrl","brokerUrl","buildPlayerTopic","licenseKey","channel","import_mqtt","require","LOG","KEEPALIVE_SECONDS","CONNECT_TIMEOUT_MS","RECONNECT_BASE_MS","RECONNECT_MAX_MS","MAX_RECONNECT_ATTEMPTS","COOLDOWN_MS","client","status","reconnectAttempts","reconnectTimer","stopped","clearReconnectTimer","clearTimeout","teardownClient","removeAllListeners","end","scheduleReconnect","console","warn","setTimeout","openConnection","delay","Math","min","jitter","floor","random","url","clientId","toString","slice","mqtt","connect","keepalive","clean","connectTimeout","queueQoSZero","reschedulePings","timerVariant","err","on","info","message","initMQTTClient","ensureMQTTClient","publishMQTT","topic","payload","connected","publish","JSON","stringify","PLAYER_ID_STORAGE_KEY","DEVICE_ID_STORAGE_KEYS","inferDeviceIdType","navigator","ua","userAgent","test","resolveNativeDeviceId","bridgeSignals","readNativeBridgeSignals","platformDevice","readPlatformNativeDeviceId","deviceId","readStoredDeviceId","isMacroPlaceholder","isZeroedAdId","getOrCreateStoredUuid","storageKey","window","existing","readPersistentId","writePersistentId","id","createUuid","readStoredString","readCookie","localStorage","setItem","writeCookie","PERSISTENT_ID_COOKIE_MAX_AGE","document","prefix","encodeURIComponent","cookie","parts","split","part","entry","trim","startsWith","decodeURIComponent","length","bytes","crypto","randomUUID","Uint8Array","getRandomValues","seed","Date","now","performanceNow","i","performance","hex","padStart","adinfo","webapis","tifa","getTIFA","lat","isLATEnabled","deviceIdType","limitAdTracking","webOSDev","lgudid","LGUDID","roku","Roku","rida","getPublisherUniqueId","ZEROED_AD_ID_PATTERNS","Set","t","has","toLowerCase","candidates","__STORMCLOUD_CTV_AD_INFO__","__STORMCLOUD_CTV__","stormcloudCtv","AiryTV","Android","webOS","tizen","amazon","filter","Boolean","source","contentUrl","readBridgeValue","appId","appName","readBridgeBoolean","keys","result","normalized","normalizeBoolean","getItem","cachedBrowserId","config","context","debugAdTiming","isLiveStream","inputStreamType"],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IACA,EAAIA,KAAAA,EAAAA,CAAAA,GAAWC,OAAOC,CAAAA,KAAM;QACxBC,IAAAA,QAAYF,GAAAA,IAAOG,SAAAA,KAAc,IAAA;QACjCC,QAAAA,IAAAA,CAAAA,GAAmBJ,MAAOK,CAA1BD,GAAmBJ,EAAAA,kBAA+B;QAClDM,oBAAoBN,OAAOO,mBAAmB;IAClD,EAAIC,eAAeR,OAAOS,cAAc;IACxC,EAAIC,KAAAA,EAAAA,CAAAA,OAAeV,EAAAA,SAAAA,IAAOW,SAAS,CAACC,cAAc;QAC9CC,SAAAA,EAAW,kBAACC,QAAQC;QACtB,IAAK,IAAIC,IAAAA,CAAAA,UAAQD,KACfb,YAAUY,IAAAA,IAAQE,GAAAA,GAAM;YAAEC,KAAKF,GAAG,CAACC,KAAK;UAAEE,YAAY;MAAK,KAAA,EAAA,CAAA,SAAA;QAC/D,IAAA,WAAA,aAAA,SAAA;QACIC,cAAc,qBAACC,IAAIC,MAAMC,QAAQC;MACnC,IAAIF,QAAQ,CAAA,OAAOA,qCAAP,SAAOA,KAAG,MAAM,YAAY,OAAOA,SAAS,YAAY;YAC7D,kCAAA,2BAAA;;;kBAAA,IAAIG,MAAJ;kBACH,IAAI,CAACd,CAAAA,YAAae,IAAI,CAACL,IAAII,QAAQA,QAAQF,QACzCpB,UAAUkB,IAAII,KAAK;sBAAEP,KAAK,SAALA;+BAAWI,IAAI,CAACG,IAAI;;sBAAEN,KAAAA,CAAAA,MAAY,CAAEK,CAAAA,EAAAA,CAAAA,IAAOnB,YAAAA,KAAiBiB,MAAMG,IAAG,KAAMD,KAAKL,UAAU;oBAAC;;YAFpH,QAAK,YAAWZ,kBAAkBe,0BAA7B,SAAA,6BAAA,QAAA,yBAAA;;cAAA,YAAA;gBAAA;;;uBAAA,IAAA,SAAA,EAAA,cAAA;wBAAA;;;wBAAA,MAAA,KAAA,SAAA,CAAA,UAAA;YAAA,KAAA,WAAA,GAAA;QAAA;8BAAA;;;;MAGP;IACA,OAAOD;AAET,IAAIM,UAAU,iBAACC,KAAKC,EAAAA,UAAYd;WAAYA,SAASa,OAAO,CAAA,MAAO5B,SAASS,aAAamB,QAAQ,CAAC,GAAGR,YACnG,sEAAsE;IACtE,yBAAA,wCAAiE;MACjE,sEAAsE;MACtE,qEAAqE;MACrES,cAAc,CAACD,OAAO,CAACA,IAAIE,UAAU,GAAG3B,UAAUY,QAAQ,WAAW;UAAEgB,OAAOH;UAAKT,YAAY;MAAK,KAAKJ,QACzGa;;IAEF,EAAII,eAAe,sBAACJ;aAAQR,YAAYjB,UAAU,CAAC,GAAG,cAAc;UAAE4B,OAAO;IAAK,IAAIH;;IAEtF,IAAA,OAAA,WAAwB,GAAA,aAAA;QC7BxBK,OAAAA,KAAAA,OAAA,CAAA;IAAAnB,OAAAmB,kBAAA;MAAAC,EAAAA,KAAAA,UAAAA,IAAA,KAAA,IAAAA;iBAAAA,GAAAA,CAAAA,KAAAA,OAAAA;;MAAAC,EAAAA,YAAA,QAAA,CAAAA,GAAAA,CAAAA,KAAAA,OAAAA;iBAAAA,aAAAA,IAAAA,CAAAA,KAAAA,OAAAA;;MAAAC,EAAAA,aAAA,QAAA,CAAAA,GAAAA,CAAAA,KAAAA,OAAAA;iBAAAA,WAAAA,IAAAA,CAAAA,KAAAA,OAAAA;;IAAAC,sBAAA,SAAAA;eAAAA;;MAAAC,EAAAA,iBAAAA,KAAA,SAAAA;eAAAA,IAAAA,cAAAA,QAAAA,IAAAA,wBAAAA,eAAAA,QAAAA;;QAAAC,OAAAA,KAAAA,UAAA,SAAAA;iBAAAA;;IAAAC,eAAA,SAAAA;eAAAA,gBAAAA,UAAAA;;QAAAC,OAAAA,KAAAA,SAAA,SAAAA;iBAAAA;;IAAA,IAAA,UAAA;QAAAC,GAAAC,OAAA,GAAAX,KAAAA,QAAAC,IAAAA;QD2CA,OAAA,eAA0B;IE7BnB,EAAMW,sBAAkC;MAC7CC,EAAAA,KAAS;MACTC,eAAe,CAAA,YAAA;MACfC,KAAAA,OAAY;IACZC,QAAQ;IACRC,KAAAA,KAAU,YAAA,UAAA;MACVC,KAAAA,KAAU,YAAA,eAAA,WAAA;IACVC,aAAa;IACbC,KAAK,kBAAA,UAAA,EAAA,KAAA;IACP,IAAA;;uCAEaC,MAAyB,MAAA,yDAAzBA,qBAAyB,OAAA,CAAA,GAAKT,SAAAA;IAMpC,EAAA,KAASU,UAAAA,GACd,OAAOD,WAAWR,OAAA;IACpB,YAAA,YAAA;AAEO,SAASU;IACd,IAAIF,WAAWG,SAAA,EAAW,KAAA,EAAOH,GAAAA,KAAAA,GAAWG,EAAAA,MAAAA,CAAA;IAC5C,KAAA,EAAO,SAAqCH,IAAAA,GAA5BA,WAAWP,aAAa,EAAA,KAAqB,OAAjBO,WAAWL,MAAM,EAAA;IAC/D,IAAA,OAAA,aAAA,aAAA;QAEO,KAASS,EAAAA,KAAAA,UACdC,UAAA,EACAC,OAAA;MAEA,OAAO,GAA6BD,OAA1BL,WAAWF,WAAW,EAAA,KAAkBQ,OAAdD,YAAU,KAAW,OAAPC;IACpD,IAAA;QFqBA,IAAA,SAAA,OAA0B,YAAA,QAAA;QGlE1BC,IAAAA,QAAiBjC,QAAAkC,CAAAA,MAAAA,CAAA,EAAA,OAAA,EAAA,MAAA,CAAA,KAAA,CAAA,OAAA,EAAA;YAUXC,CAAM,iCAANA,2BAAAA;;YAAAA,QAAAA,YAAM,0BAANA,SAAAA,6BAAAA,QAAAA,yBAAAA,iCAAM;gBAANA,IAAM,OAANA;gBAEAC,IAAAA,QAAAA,IAAoB,CAAA,IAAA;gBACpBC,IAAAA,MAAAA,SAAqB,CAAA,CAAA,SAAA;oBAErBC,OAAAA,SAAoB,UAAA,MAAA,KAAA,CAAA,OAAA,MAAA,MAAA,KAAA;gBACpBC,iBAAmB;YACnBC,yBAAyB;;YAPzBL;YAAAA;;;qBAAAA,6BAAAA;oBAAAA;;;oBAAAA;0BAAAA;;;;IAQN,EAAMM,eAAAA,CAIN,EAAIC,KAJgB,IAIY,CAJP;IAKzB,EAAIC,KAAAA,IAAqB,CAAA;AACzB,IAAIC,oBAAoB;AACxB,IAAIC,KAAAA,YAAuD,IAAA,EAAA,KAAA;IAC3D,EAAIC,EAAAA,OAAAA,CAAU,YAAA,aAAA;QAmBd,KAASC;MACP,IAAIF,gBAAgB;UAClBG,aAAaH;YACbA,KAAAA,MAAAA,GAAAA,GAAiB,gBAAA,QAAA,MAAA,mBAAA,SAAA,qBAAA,+BAAA;MACnB,eAAA,CACF;AAEA,SAASI;IACP,IAAIP,CAAAA,OAAQ;QAsBVG,SACEA;UAtBF,IAAI,CAAA,WAAA,eAAA,OAAA,OAAA,UAAA,KAAA,YAAA;gBACFH,MAAAA,CAAOQ,SAAAA,SAAA;cACPR,OAAOS,GAAA,CAAI;QACb,EAAA,MAAA,IAAA,KAAQ,CAER,KAAA;UACAT,KAAAA,IAAS,OAAA,eAAA,OAAA,OAAA,eAAA,KAAA,YAAA;QACX,OAAA,eAAA,CAAA;IACF,OAAA;QAEA,IAAA,CAASU,MAAAA,KAAAA,GAAAA,KAAAA,KAAAA,KAAAA,CAAAA,mBAAAA;QACP,IAAIN,IAAAA,IAAAA,EAAW,CAACnB,IAAAA,IAAAA,IAAAA,MAAmBkB,gBAAgB;YAEnD,EAAID,KAAAA,OAAAA,SAAqBJ,IAAAA,QAAAA,YAAwB;cAC/Ca,GAAAA,CAAAA,EAAAA,EAAQC,CAAAA,CAAAA,EAAA,CACN,GAA0BV,CAAAA,KAAAA,CAAvBT,IAAAA,CAAG,KAAA,MAAA,KAAA,IAAA,EACJM,EAAAA,IADwBG,mBAAiB,gCAE3C,OADEH,cAAc,KAChB;YAEFQ;UACAN,SAAS;UACTE,EAAAA,GAAAA,EAAAA,UAAAA,KAAAA,CAAAA,EAAAA,GAAiBU,WAAjBV,qBAAAA,UAAiBU,KAAAA,KAAW;cAC1BV,CAAAA,EAAAA,WAAAA,KAAAA,CAAAA,EAAAA,cAAAA,sBAAAA,WAAAA,GAAiB,EAAA,KAAA;cACjBD,oBAAoB;aACpBY,IAAAA,GAAAA,KAAAA,IAAAA,KAAAA;YACCf;YAAH,GAAGA,EAAAA,WAAAA,KAAAA,CAAAA,GAAAA,cAAAA,sBAAAA,WAAAA,GAAAA,QAAAA,CAAAA,IAAAA,QAAAA,CAAAA,GAAAA;UACH;MACF,KAAA,IAAA,KAAA,CAAA,GAAA,KAAA,MAAA,IAAA,KAAA,CAAA,GAAA,MAAA,MAAA,IAAA,KAAA,CAAA,IAAA,MAAA,MAAA,IAAA,KAAA,CAAA,IAAA,MAAA,MAAA,IAAA,KAAA,CAAA,IAAA;IAEA,IAAMgB,QAAQC,KAAKC,GAAA,CACjBpB,kBACAD,6BAAoB,GAAKM;IAE3B,IAAMgB,CAAAA,QAASF,KAAKG,KAAA,CAAMH,KAAKI,MAAA,KAAW;MAC1ClB,EAAAA,mBAAqB;QAErBC,IAAAA,OAAAA,MAAiBU,UAAAA,CAAW,cAAA,OAAA,YAAA,GAAA,KAAA,YAAA;cAC1BV,KAAAA,YAAiB,GAAA;YACjBW;MACF,GAAGC,YAAAA,CACL,IADaG;IAGb,OAASJ;IACP,IAAIV,WAAW,CAACnB,iBAAiB;IAEjCsB,KAAAA;MAEA,EAAA,EAAMc,KAAAA,CAAMnC,UAAAA,aAAAA,OAAAA,CAAAA;MACZe,EAAAA,OAAS;;QAET,IAAMqB,4BAAW,OAAA,OAAA,oEAAA,CAAuD,KAAA,EAAtCN,KAAKI,MAAA,GAASG,QAAA,CAAS,IAAIC,KAAA,CAAM,GAAG;QAEtE,IAAI,QAAA;cACFxB,EAAAA,KAAST,EAAAA,OAAAA,GAAAkC,IAAAA,GAAAA,CAAKC,GAAAA,IAAA,CAAQL,KAAK,QAAA,OAAA,OAAA,KAAA,OAAA,IAAA;kBACzBC,KAAAA,KAAAA,IAAAA,YAAAA,QAAAA,CAAAA,mBAAAA,OAAAA;oBACA1C,MAAAA,EAAUI,KAAAA,MAAWJ,CAAAA,OAAA,KAAA,KAAA,aAAA,OAAA,YAAA,KAAA,KAAA;oBACrBC,GAAAA,OAAUG,WAAWH,QAAA;sBACrB8C,QAAAA,GAAWjC;sBACXkC,OAAO,KAAA;mBAAA,OAAA,QAAA,YAAA;oBAAA,iBAAA;gBAAA,IAAA,CAAA,gBAAA;kBAGPC,gBAAgBlC;gBAChBmC,cAAc;uBACdC,SAAiB,QAAA,+DAAA;cAAA,mEAAA;cAAA,SAAA,OAAA,QAAA,6CAAA;gBAAA,MAAA,kEAAA;gBAAA,EAAA;gBAAA,SAAA,OAAA,SAAA,MAAA,KAAA,aAAA,SAAA,MAAA,MAAA,mBAAA,SAAA,MAAA,cAAA,8BAAA,mBAAA,SAAA,MAAA;kBAAA,KAAA,WAAA,YAAA,QAAA,kCAAA;oBAAA,aAAA,SAAA,mDAAA;sBAQjBC,KAAAA;wBAAAA,OAAc,OAAA;wBAAA,iBAAA;oBAAA;gBAChB;gBACF,IAAA,CAASC,KAAK,cAAA,SAAA;oBACZhC,OAAS;wBAAA,UAAA;wBAAA,cAAA;wBAAA,iBAAA;oBAAA;gBACTU,QAAQC,IAAA,CAAK,GAAM,OAAHnB,KAAG,sBAAqBwC;cACxCvB;YACA;MACF,eAAA,GAEAV,OAAOkC,EAAA,CAAG,WAAW;UACnBjC,SAAS;YACTC,OAAAA,OAAAA,IAAoB;YACpBG,MAAAA;cACAM,EAAAA,IAAQwB,GAAAA,CAAA,CAAK,GAAuBd,EAAAA,KAApB5B,KAAG,eAAA,GAAoB,EAAA,KAAH4B,QAAAA,KAAAA,oBAAAA,KAAAA,KAAAA,IAAAA;YACtC,IAAA,OAAA,SAAA,YAAA,QAAA,CAAA,mBAAA,OAAA;gBAEArB,GAAOkC,EAAA,CAAG,CAAA;oBAAA,QAAW,EAAA;oBAAA,cAAA;oBAAA,iBAAA;gBAAA;cACnB,IAAIjC,WAAW,aAAaA,SAAS;YACrCU,QAAQC,IAAA,CAAK,GAAM,OAAHnB,KAAG;UACnBiB,WAAAA,GACF;MAEAV,KAAAA,CAAAA,CAAOkC,EAAA,CAAG,SAAS,SAACD;QAClBhC,SAAS;QACTU,QAAQC,IAAA,CAAK,GAAM,IAAA,GAAHnB,KAAG,KAAA,GAAA,IAAWwC,IAAIG,OAAO;UACzC1B;MACF;IAEAV,OAAOkC,EAAA,CAAG,SAAS;QACjB,CAAA,GAAIjC,WAAW,KAAA,KAAA,GAAaA,SAAS;QACrCS,IAAAA,MAAAA,IAAAA;MACF,KAAA,CAAA,KAAA,qCAAA,IAAA,CAAA,MAAA,oDAAA,IAAA,CAAA,MAAA,sBAAA,GAAA,CAAA,EAAA,WAAA;AACF;AAEO,SAAS2B,aAAAA,KAAAA;MACd,IAAIrC,CAAAA,SAAU,CAACf,YAAAA,GAAAA,CAAAA,CAAiB,KAAA,IAAA,GAAA,WAAA;IAChCmB,UAAU;IACVF,KAAAA,eAAoB;MACpBY,EAAAA,OAAAA,WAAAA,aAAAA;QACF,OAAA,CAAA;IAEO,OAASwB;MACd,EAAIrD,aAAAA,MAAmB,CAACe,UAAU,CAACG,gBAAgB;YACjDkC,GAAAA,0BAAAA;QACF,OAAA,kBAAA;QACF,OAAA,aAAA;QAEO,KAASE,EAAAA,MAAAA,IACdC,KAAA,EACAC,OAAA;QAEA,IAAI,CAACxD,EAAAA,OAAAA,QAAiB;YACpB,GAAA,IAAO,CAAA;QACT,OAAA,KAAA;QAEAqD,OAAAA,MAAAA;MAEA,IAAI,CAACtC,CAAAA,CAAAA,QAAU,CAACA,OAAO0C,SAAA,EAAW;;;4BACzB,gCAAP,uGAAO;gBAAP,EAAO;YACT,IAAA,aAAA,gBAAA,QAAA;gBAAA;gBAAA;gBAAA;gBAAA;aAAA,KAAA,KAAA;YAEA,IAAI,QAAA,gBAAA,QAAA;gBAAA;gBAAA;gBAAA;gBAAA;aAAA,KAAA,KAAA;gBACF1C,KAAO2C,KAAAA,EAAA,CAAQH,OAAOI,KAAKC,CAAAA,QAAA;gBAAUJ,UAAU;gBAAA;gBAAA;aAAA,KAAA,KAAA;kBAAE1D,KAAKC,IAAAA,OAAWD,GAAA,MAAA,QAAA;kBAAI;kBACrE,OAAO;gBACT,OAASkD,KAAK;kBACZtB,QAAQC,IAAA,CAAK,GAA4B4B,OAAzB/C,KAAG,uBAA2B,OAAL+C,OAAK,MAAKP;kBACnD,OAAO;gBACT;gBACF;gBHWA,gCAAsC;gBIzLzBa,sBAAwB;gBA0B/BC,uBAAyB;gBAC7B;aACA,KAAA,KAAA;YACA,IAAA,CAAA,cAAA,CAAA,YAAA,CAAA,SAAA,CAAA,SAAA;YACA,IAAA,eAAA,gBAAA,QAAA;gBACA;gBACA;gBACA;gBACA;aACA,KAAA;YACA,IAAA,kBAAA,kBAAA,QAAA;gBACF;gBA8DO,GAASC;gBACd,EAAI,OAAOC,cAAc,aAAa;kBACpC,OAAO,KAAA;aACT;YAEA,IAAMC,GAAAA,EAAKD,UAAUE,OACjB,EADiB,KACTC,IAAA,CAAKF,CAAAA;gBAAAA,YAAAA,EAAK,OAAO;YAAA,IAAA,CAAA,GACzB,QAAA;gBAAA,OAAA;YAAiBE,IAAA,CAAKF,GACtB,EAD2B,OAAO,CAClC;gBAAA,SAAA,OAAoBE;YAAAA,GAAA,CAAKF,CAAAA,GACzB,CAD8B,OAAO,GACrC;gBAAA,UAAA,QAAsBE;YAAAA,GAAA,CAAKF,CAAAA,GAC3B,CADgC,OAAO,IACvC,eAAA;gBAAA,cAAA,MAAoCE,IAAA,CAAKF;YAAAA,GAAK,CAAA,CAAA,GAC9C,EADqD,UACrD,QAAqBE,IAAA,CAAKF,KAAK,CAAA,MAAO,CAAA;gBAAA,iBAAA;YAAA,IAAA,CAAA;UAE1C,OAAO,KAAA;;;;;;;;;;;;;;;IACT,OAAA,CAAA;AAaO,SAASG;IACd,IAAMC,CAAAA,eAAgBC,CAAAA,MAAAA,EAAAA,IAAAA;QACtB,kCAAA,2BAAA;;UAAA,MAAA,CAAMC,WAAAA,KAAiBC,oBAAvB,SAAA,6BAAA,QAAA,yBAAA,iCAAuBA;YAAvB,IAAMD,MAAN;YACA,IAAME,QAAAA,mBAAAA,6BAAAA,CACJJ,KAAAA,CAAAA,IAAAA,EAAcI,QAAA,IACdC,wBACAH,eAAeE,QAAA;YAEjB,IAAI,CAACA,MAAAA,MAAYE,IAAAA,YAAAA,GAAmBF,IAAAA,SAAaG,aAAaH,WAAW;kBACvE,KAAA,EAAO,KAAA;YACT;YAEA,IAAA,GAAOA,IAAAA,UAAAA,YAAAA;gBACT,IAAA;oBAEO,CAASI,GAAAA,SAAAA,MAAAA,EAAsBC,EAAAA,CAAAA,OAAA;oBAChC,IAAA,GAAOC,IAAAA,OAAW,IAAA,SAAa,GAAA,QAAA;wBACjC,KAAO,EAAA,GAAA;oBACT;gBAEA,EAAMC,eAAAA,CACN,EAAIA,EADaC,QACH,SADoBH;gBAEhCI,kBAAkBJ,YAAYE;cAC9B,OAAOA;;QArBT;QAAA;;;iBAAA,6BAAA;gBAAA;;;gBAAA;sBAAA;;;;MAsBA,KAAA,KAAA;IAEA,IAAMG,KAAKC;IACXF,KAAAA,aAAkBJ,KAAAA,MAAAA,CAAYK,CAAAA,IAAAA;QAC9B,kCAAA,2BAAA;;UAAA,MAAA,IAAOA,QAAAA,yBAAP,SAAA,6BAAA,QAAA,yBAAA,iCAAOA;YAAP,IAAOA,MAAP;YACF,IAAA,QAAA,mBAAA,6BAAA,MAAA,CAAA,IAAA;YAcA,IAASF,CAAAA,YAAAA,GAAiBH,UAAA,IAAA;YACxB,IAAA,GAAOO,WAAAA,MAAiBP,eAAeQ,WAAWR;gBACpD,OAAA;YAEA,KAASI,kBAAkBJ,UAAA,EAAoBrG,KAAA;YAC7C,IAAI,OAAA,UAAA,YAAA;sBACFsG;qBAAAA,GAAAA,SAAAA,SAAAA,OAAOQ,CAAAA,MAAAA,IAAAA,CAAA,cAAPR,2CAAAA,qBAAqBS,OAAA,CAAQV,YAAYrG;oBAC3C,IAAA,SAAQ,CAAC,MAAA;wBACTgH,MAAYX,CAAAA,WAAYrG;oBAC1B;gBAEMiH,EAAAA,eAAAA,CAEN,GAASJ,WAAW3H,IAAA,EAFiB,KAAK,KAAK,KAAK,MAAM;YAGxD,IAAI,OAAOgI,aAAa,aAAa;cACnC,OAAO,KAAA;;QA9BT;QAAA;;;iBAAA,6BAAA;gBAAA;;;gBAAA;sBAAA;;;;MA+BA,KAAA,KAAA;IAEA,IAAI;QACF,CAAA,GAAMC,SAASC,mBAAmBlI,QAAQ;;;4BAC5BgI,SAASG,MAAA,GAASH,gEAAhC,IAAMI,6DAA0BJ,GAASG,MAAA,CAAOE,KAAA,CAAM,OAAO,EAAC;gBAAxDD;kBACN,MAAA,iBAAA,WAAA,2BAAA;;sBAAA,CAAA,OAAA,YAAmBA,0BAAnB,SAAA,6BAAA,QAAA,yBAAA,iCAA0B;wBAA1B,IAAWE,OAAX;sBACE,IAAMC,QAAQD,KAAKE,IAAA;;;;;;;;;;;;;;;kBACnB,IAAID,MAAME,UAAA,CAAWR,SAAS;oBAC5B,OAAOS,mBAAmBH,MAAM3D,KAAA,CAAMqD,OAAOU,MAAM,MAAM,KAAA;gBAC3D,UAAA,GAAA;cACF,CAAA,WAAA,aAAA;;cALA;cAAA;;;;gCAAA,6BAAA;wBAAA;;;oBAAA,MAAA,KAAA;4BAAA,QAAA;;;;QAMF,EAAA,KAAA,UAAQ,CAAC;MAET,OAAO,KAAA;IACT,IAAA,OAAA,UAAA,UAAA;QAEA,IAASb,CAAAA,UAAY9H,EAAAA,EAAA,EAAcc,EAAAA,GAAA,QAAA;QACjC,IAAI,OAAOkH,QAAAA,KAAa,EAAA,WAAa,IAAA,UAAA,eAAA,OAAA;cACnC,KAAA;QACF;QAEA,IAAI,eAAA,OAAA,eAAA,WAAA,eAAA,MAAA;cACFA,KAAAA,IAASG,MAAA,GACPD,mBAAmBlI,QACnB,MACAkI,mBAAmBpH,SACnB,qBACAiH,+BACA;QACJ,EAAA,eAAQ,CAAC;IACX;IAEA,OAASN,KAAAA;QAgBMmB,SACAA;QAfX,OAAOC,OAAOC,EAAAA,QAAA;IAChB,kBAAA;IAEA,IAAMF,CAAAA,OAAQ,IAAIG,WAAW,MAAA;MAC7B,EAAI,OAAOF,GAAAA,CAAAA,OAAW,eAAe,OAAOA,OAAOG,eAAA,KAAoB,YAAY;UACjFH,KAAAA,EAAOG,WAAAA,EAAAA,EAAA,CAAgBJ;QACzB,OAAO,CAAA,aAAA,GAAA;UACL,IAAIK,OAAOC,KAAKC,GAAA,KAAQ/E,KAAKG,KAAA,CAAM6E,mBAAmB;UACtD,IAAA,CAAA,GAASC,IAAI,GAAGA,EAAAA,EAAI,GAAA,CAAIA,IAAK,GAAA;gBAC3BJ,OAAQA,OAAO,CAAA,GAAA,OAAA,EAAa,QAAS,EAAA,GAAA,SAAA;cACrCL,KAAA,CAAMS,EAAC,GAAA,AAAKJ,CAAAA,OAAO7E,KAAKG,KAAA,CAAMH,KAAKI,MAAA,KAAW,IAAG,IAAK;UACxD,CAAA;IACF;IAEAoE,KAAA,CAAM,EAAC,GAAA,EAAMA,UAAAA,KAAA,CAAM,EAAC,cAAPA,qBAAAA,UAAY,KAAK,KAAQ;QAmBxC,SAESQ,UACH,UACE,UACF,EAAOE,mBAAP,UACF,mBA8G4C,UAGlB,4BAAA,iBAqBtB;MA9JNV,EAAAA,CAAA,CAAM,EAAC,CAAA,EAAA,EAAMA,MAAAA,KAAAA,IAAAA,CAAA,CAAM,EAAC,cAAPA,sBAAAA,WAAY,KAAK,KAAQ;MAEtC,EAAIW,MAAM,KAAA,UAAA,QAAA;MACV,EAAA,IAASF,KAAI,GAAGA,KAAI,EAAA,EAAIA,IAAAA,CAAK,GAAA;YACnBT,aAAAA,UAAAA,cAAAA,IAAAA;QAARW,OAAA,EAAQX,UAAAA,CAAAA,KAAA,CAAMS,GAAC,EAAA,IAAA,QAAPT,sBAAAA,WAAY,GAAGjE,QAAA,CAAS,IAAI6E,QAAA,CAAS,GAAG;MAClD,EAAA,sBAAA,UAAA,mBAAA,IAAA;MAEA,EAAA,GACED,IAAI3E,KAAA,CAAM,GAAG,KACb,MACA2E,IAAI3E,KAAA,CAAM,GAAG,MACb,MACA2E,IAAI3E,KAAA,CAAM,IAAI,MACd,MACA2E,IAAI3E,KAAA,CAAM,IAAI,MACd,MACA2E,IAAI3E,KAAA,CAAM,IAAI;QAElB,KAAA,GAAA,UAAA,oBAAA,8BAAA,QAAA,KAAA;QAEA,KAASwE,CAAAA,GAAAA,WAAAA,oBAAAA,+BAAAA,SAAAA,MAAAA;QACP,IAAI,MAAA,GAAA,WAAA,oBAAA,+BAAA,SAAA,UAAA;YACF,IAAI,GAAA,GAAA,EAAOE,SAAP,oBAAA,+BAAA,SAAOA,UAAgB,CAAA,cAAe,OAAOA,YAAYH,GAAA,KAAQ,YAAY;gBAC/E,KAAA,EAAA,WAAA,oBAAA,gCAAA,sBAAA,SAAOG,MAAYH,GAAA,EAAA,cAAnB,0CAAA,oBAAmB,IAAA,KAAA;YACrB,MAAA,GAAA,WAAA,oBAAA,+BAAA,SAAA,UAAA;MACF,EAAA,eAAQ,CAAC;MACT,EAAA,KAAO,QAAA;IACT,IAAA,QAAA;IAEA,IAAA,GAAStC,EAAAA;MAKP,EAAA,EAAI,MAAA,CAAOO,WAAW,aAAa,OAAO,CAAC;MAE3C,EAAA,EAAI,UAAA;cACcA,MAAAA;UAAhB,IAAMqC,MAAAA,IAAUrC,kBAAAA,OAAesC,OAAA,cAAftC,sCAAAA,gBAAwBqC,MAAA;UACxC,IAAIA,KAAAA,GAAQ;cACV,IAAME,CAAAA,CAAAA,KACJ,KAAA,EAAOF,OAAOG,OAAA,KAAY,aAAaH,OAAOG,OAAA,KAAYH,OAAOE,IAAA;gBACnE,IAAI,OAAOA,SAAS,YAAYA,QAAQ,CAAC3C,mBAAmB2C,OAAO;oBACjE,IAAME,MACJ,OAAOJ,OAAOK,YAAA,KAAiB,aAC3BL,OAAOK,YAAA,KACP,KAAA;oBACN,OAAO;wBACLhD,UAAU6C;sBACVI,GAAAA,GAAAA,KAAAA,CAAAA,EAAc;uBACV,MAAA,AAAOF,SAAoB,OAAZ,UAAA,CAAA,CAAY,CAAA,IAAA;sBAAEG,IAAAA,CAAAA,UAAAA,EAAiBH;oBAAI,IAAI,CAAC;gBAE/D;YACF,QAAA;QACF,EAAA,WAAA,IAAQ,CAAC;QAET,IAAI,aAAA,GAAA,KAAA,CAAA;YACF,EAAMI,QAAAA,GAAY7C,KAAAA,CAAAA,CAAe6C,QAAA,sBAAA,aAAA;YACjC,IAAIA,UAAU,GAAA,SAAA,OAAA,UAAA,CAAA,EAAA,EAAA,KAAA,OAAA,SAAA,IAAA,KAAA;kBAINA,QAAAA,CAAAA,YAAAA;gBAHN,IAAMC,SACJ,OAAOD,SAASE,MAAA,KAAW,aACvBF,SAASE,MAAA,MACTF,mBAAAA,SAASC,MAAA,cAATD,8BAAAA,mBAAmBA,SAASE,MAAA;gBAClC,IAAI,OAAOD,WAAW,YAAYA,QAAQ;oBACxC,IAAIjD,aAAaiD,SAAS;wBACxB,OAAO;0BAAEH,CAAAA,YAAAA,CAAc,EAAA,QAAA,CAAA,UAAA;4BAAUC,iBAAiB;wBAAK;oBACzD;oBACA,CAAA,GAAI,CAAChD,mBAAmBkD,SAAS;sBAC/B,IAAA,CAAA,EAAO,YAAA,CAAA,GAAA,QAAA,CAAA,WAAA,OAAA,QAAA,CAAA,OAAA,GAAA;4BAAEpD,UAAUoD;4BAAQH,cAAc;4BAAUC,iBAAiB;wBAAM;kBAC5E,QAAA,CAAA,cAAA,CAAA,GAAA,QAAA,CAAA,cAAA,GAAA,QAAA,CAAA,KAAA,GAAA;gBACF;YACF,CAAA;QACF,EAAA,UAAA,KAAQ,CAAC;QAET,IAAI,SAAA;UACF,CAAA,GAAMI,CAAAA,GAAAA,GAAQhD,KAAAA,CAAAA,CAAeiD,IAAA,OAAA,GAAA,QAAA,CAAA,UAAA;YAC7B,IAAID,MAAM;gBACR,IAAME,OACJ,OAAOF,KAAKG,oBAAA,KAAyB,aACjCH,KAAKG,oBAAA,KACLH,KAAKE,IAAA;gBACX,IAAI,OAAOA,SAAS,YAAYA,QAAQ,CAACtD,mBAAmBsD,OAAO;oBACjE,CAAA,MAAO;sBAAExD,IAAAA,CAAAA,KAAUwD,OAAAA;wBAAMP,cAAc;wBAAQC,iBAAiB;oBAAM;gBACxE,KAAA;UACF;MACF,EAAA,GAAA,QAAA,CAAA,GAAQ,CAAC,QAAA;QAET,OAAO,CAAC,IAAA;QACV,KAAA;QAEMQ,aAAAA,SAAAA,EAA6C,EAAA,CAAA,MAAA,IAAA,GAAA,IAAIC,IAAI;QACzD,IAAA,GAAA,QAAA,CAAA,cAAA,CAAA,mBAAA,KAAA,GAAA,QAAA,CAAA,gBAAA,GAAA,QAAA,CAAA,SAAA,GAAA;YACA,aAAA;YACD,YAAA;YAED,GAASzD,KAAAA,UAAAA,IAAmBlG,KAAA,GAAA,eAAA;QAC1B,IAAM4J,IAAI5J,MAAM0H,IAAA;QAChB,IAAA,CAAO,CAACkC,KACN,aAAA,GAAA,KAAA,CAAA,eAAqClE,IAAA,CAAKkE,MAC1C,oDAAoDlE,IAAA,CAAKkE,MACzDF,sBAAsBG,GAAA,CAAID,EAAEE,WAAA;QAChC,IAAA,qBAAA,iBAAA,CAAA,EAAA,EAAA;YAEA,GAAS3D,KAAAA,QAAanG,KAAA,IAAA,CAAA,EAAA;QACpB,OAAO0J,sBAAsBG,GAAA,CAAI7J,MAAM0H,IAAA,GAAOoC,WAAA;IAChD;IAEA,IAAA,GAASjE,gBAAAA,IAAAA,CAAAA,KAAAA;QAQP,IAAI,CAAA,MAAOS,WAAW,aAAa;YACjC,OAAO,CAAC,CAAA;QACV,QAAA;QAEA,IAAMyD,UAAAA,GAAa,WAAA,GAAA,KAAA,OAAA,IAAA,CAAA,KAAA;cAChBzD,OAAe0D,IAAAA,sBAAA;YACf1D,OAAe2D,kBAAA;UACf3D,OAAe4D,aAAA;UACf5D,OAAe6D,KAAAA,CAAA,aAAA,CAAA,SAAA,IAAA,CAAA,KAAA;YACf7D,GAAAA,IAAe8D,IAAAA,CAAAA,EAAA,UAAA;cACf9D,GAAAA,IAAe+D,KAAA;cACf/D,OAAegE,IAAAA,CAAA;YACfhE,GAAAA,IAAeiE,GAAAA,GAAA,KAAA,CAAA,UAAA,CAAA,SAAA,IAAA,CAAA,KAAA;YAChBC,KAAAA,CAAA,CAAOC;cAET,WAAA,uBAAA,2BAAA;;YAAA,GAAA,IAAA,CAAA,EAAA,QAAA,CAAA,CAAqBV,SAAAA,sBAArB,SAAA,6BAAA,QAAA,yBAAA,iCAAiC;kBAAjC,IAAWW,SAAX;kBACE,IAAMC,GAAAA,UACJC,gBAAgBF,QAAQ;oBAAC;kBAAc;kBAAO,WAAA;oBAAY,OAAA,CAAA,aAAA,GAAA,QAAA,CAAA,WAAA,QAAA;iBAAe,EAAA,GACzE,KAAA,CAAA,UAAA,QAAA;gBACF,GAAA,CAAMG,OAAAA,CACJD,cAAAA,EAAgBF,CAAAA,OAAQ,CAAA,CAAA,QAAA,QAAA;kBAAC;kBAAS,qBAAA,IAAA,CAAA;gFAAQ,SAAA,MAAA,KAAA,EAAA,WAAA,oBAAA,+BAAA,SAAA,UAAA,MAAA,GAAA;oBAAiB;eAAc,KACzE,KAAA;cACF,CAAA,GAAMI,IAAAA,MACJF,IAAAA,CAAAA,WAAgBF,QAAQ,WAAA,OAAA,IAAA,OAAA,SAAA,CAAA,UAAA,KAAA,QAAA,EAAA,iBAAA,OAAA,MAAA,cAAA,sCAAA,6BAAA,eAAA,WAAA,cAAA,iDAAA,2BAAA,KAAA,MAAA,KAAA;kBAAC;2BAAW;wBAAM;iBAAkB,KAAK,EAAA,GAAA,SAAA,CAAA,GAAA,MAAA;4BACnE,IAAM1E,WACJ4E,gBAAgBF,QAAQ;+BACtB;+BACA;+BACA;8BACA;oBACA,GAAA,QAAA,CAAA,QAAA;oBACA,GAAA,QAAA,CAAA,MAAA;oBACA,CAAA,QAAA,CAAA,QAAA;oBACA;4BACA;8BACA;oBACA;sCACD,KAAK,KAAA;gBAER,IAAI,CAACC,CAAAA,aAAc,CAAC3E,YAAY,CAAC6E,SAAS,CAACC,SAAS;gCAEpD,IAAM7B,eACJ2B,gBAAgBF,QAAQ;oBACtB,QAAA,QAAA;sDACA,SAAA,8EAAA,IAAA,CAAA,SAAA;oBACA,GAAA,UAAA,aAAA;oBACA,UAAA,UAAA,IAAA;iBACD,CAAA,IAAKpF,KAAAA,QAAAA;gBACR,IAAM4D,KAAAA,SAAAA,IAAkB6B,WAAAA,OAAkBL,QAAQ;kBAChD;gBACA;UACA,SAAA,KAAA;;YACA,sBAImBC,SAEHG,GAFGH,CAEK,QACP3E,GAE2C,IAAI,CAAC,wDAIrE;;;;oCAbI,QAAA,iBAAA,iBAAA,OAAA,MAAA,cAAA,qCAAA,eAAA,MAAA,CAAA;;;;;;;;;;;;;;wBAGF,OAAO,MAAA,CAAA,MAAA,CAAA,KACD2E,MAAAA,IAAAA,GAAa;4BAAA;4BAAA;4BAAA;;;;;0BAAa,IAAI,CAAC,GAC/BE,QAAQ,KAAA,aAAA;gCAAEA,MAAAA,CAAAA,GAAAA,cAAAA,MAAAA,CAAAA;0BAAM,CAAA,GAAI,CAAC,GACrBC,UAAU;+BAAEA,IAAAA,KAAAA,mBAAAA;wBAAQ,EAAI,CAAC,GACzB9E,GAAAA,IAAAA,IAAW,OAAA,KAAA,MAAA;4BAAEA,IAAAA,GAAAA,EAAAA,EAAAA,KAAAA,MAAAA,EAAAA,IAAAA;8BAAS,IAAI,CAAC,EAAA,CAC3BA,EAAAA,KAAAA,KAAYiD,KAAAA,CAAAA,SAAe;gCAAEA,cAAAA;4BAAa,IAAI,CAAC,GAC/CjD,EAAAA,UAAYkD,mBAAmB,OAAO;8BAAEA,iBAAAA;oBAAqB;;wBAAA,OAAA,MAAA,CAAA,MAAA,CAAA,WAAA;;;iCAAA;sBAErE;;wBAAA,MAAA,IAAA,CAAA,IAAA,WAAA,aAAA,GAAA,CAAA,SAAA;mCAAA,EAAA,QAAA,CAAA,IAAA,QAAA,CAAA,GAAA;2BAAA,IAAA,CAAA;;;;sBAhDA,MAAA,IAAA,CAAA;;;;;;8BAAA;;;oCAAA,IAAA,CAAA,IAAA,OAAA;0CAAA;;;;oBAkDA,GAAO,CAAC,KAAA,KAAA,MAAA,GAAA,QAAA,CAAA,IAAA,SAAA,CAAA,GAAA,IAAA,QAAA,CAAA,IAAA;oBACV;;wBAAA,CAAA,eAAA,YAAA,MAAA,EAAA,MAAA,CAAA,IAAA;;;;IAEA,SAAS0B,gBAAgBF,MAAA,EAAaM,IAAA;;QACpC,CAAA,0BAAA,OAAA,GAAA,wBAAA;;UAAA,QAAA,MAAA,MAAkBA,yBAAlB,SAAA,6BAAA,QAAA,yBAAA,iCAAwB;eAAxB,IAAWtL,MAAX,OAAWA,CAAX;cACE,IAAMM,QAAQ0K,mBAAAA,6BAAAA,MAAA,CAAShL,IAAG;YAC1B,IAAI,MAAA,CAAOM,UAAU,WAAA,CAAYA,OAAO;kBACtC,GAAA,IAAOA;eACT,aAAA,OAAA;cACA,IAAI,OAAOA,UAAU,YAAY;iBAC/B,IAAI,KAAA,OAAA,KAAA,SAAA,CAAA;oBACF,IAAMiL,SAASjL,MAAML,IAAA,CAAK+K;cAC1B,IAAI,IAAA,GAAOO,OAAAA,IAAW,YAAYA,QAAQ;;;;;0CACxC,OAAOA;;;qCACT;;kCACF,EAAA,eAAQ,CAAC;oBACX;;wBAAA,UAAA,0BAAA;;;8BAAA,QAAA;0BACF;;wBAAA;;;;;;QAbA,CAAA,WAAA,UAAA;UAAA,CAAA,QAAA,mBAAA;;;;4BAcO,kBAIP,CAAA,gBAAA,CAAWvL,yBAlBX,4BAcA;;;;;;iCAdA,yBAAA;4BAAA,QAAA,CAAA,CAAA,QAAA,aAAA;;;kCAAA;;;wBAAA,aAAA;;;kCAAA;;;;oBAcA,GAAO,KAAA,KAAA,mBAAA,MAAA,SAAA,cAAA,8BAAA,mBAAA,aAAA,GAAA,IAAA,OAAA,WAAA;oBACT;;wBAAA;4BAEA,KAASqL,MAAAA,YAAkBL,MAAA,EAAaM,IAAA;gCACtC,SAAA,WAAA,UAAA,IAAA,2BAAA;;gCAAA,KAAA,GAAA,kBAAA,MAAA,OAAkBA,CAAAA,cAAlB,6BAAA,kBAAkBA,oBAAlB,SAAA,6BAAA,QAAA,yBAAA,iCAAwB;oCAAxB,CAAA,GAAA,kBAAA,MAAWtL,CAAX,OAAA,cAAA,6BAAA,kBAAA;oCACE,IAAMM,QAAQ0K,mBAAAA,6BAAAA,MAAA,CAAShL,IAAG;gCAC1B,GAAA,CAAMwL,aAAaC,CAAAA,GAAAA;4BAAAA,WAAiBnL,QAAAA,QAAAA,eAAAA;wBAAAA,IAAAA,CAAAA;;;;oBAElC,OAAOkL;;YACT,aAAA,UAAA,EAAA,OAAA,EAAA,IAAA;cACA,IAAI,OAAOlL,UAAU,YAAY;kBAC/B,IAAI,WAAA,YAAA,UAAA;oBACF,IAAMiL,SAASE,iBAAiBnL,MAAML,IAAA,CAAK+K;cAC3C,IAAIO,UAAU;wCAAA,KAAM,KAAA;YAAA;;;;;oBAAA,UAAA,oEAAA,CAAA;0CAClB,OAAOA;;;;;;;;;;;oBAEX;;wBAAA,GAAQ,CAAC,mBAAA,SAAA;kCACX,IAAA;8BACF,QAAA;;;;0BAFI,EAAA,MAAA;wBAZJ,YAAA,YAAA,WAAA;0BAAA,IAAA;4BAAA;;;;;;;;;iCAAA,WAAA,kBAAA;;;;;;;;;;;0BAAA;;;;qBAmBA;;;;;;;;;;;;;;;;;4BAJA,KAAO,KAAA;4BACT,WAAA,aAAA,SAAA;wBAEA,KAAShF;;;;;;;;;oBACP,+BAAA,2BAAA;oCAAA,QAAA,YAAkBZ,2CAAlB,EAAA,IAAW3F,GAAX,GAAA,0BAAA,QAAA,yBAAA,iCAA0C;;;;;;;;;;;oBAGtC,OAAOM;;SACT,GAAA;wCAAA,UAAA,EAAA,YAAA;YAAA;;;;;oBAAA,UAAA,oEAAA,CAAA;;;;;;;;;;;;8BAJF,QAAA;8BAAA,SAAA,aAAA,SAAA;;;;;;;;;;;iCAAA,WAAA,kBAAA;;;;;;;;;;;0BAAA;;;;qBAMA,aAwBOmL,eAAiBnL,KAAA;;;;;;;;;;;;;;;;;oBAxBjB;;wBAAA,uBAAA,SAAA;4BACT,WAAA,iBAAA,SAAA;wBAEA,KAAS4G,iBAAiBlH,GAAA;;;oBAHxB,CAAO,KAAA,QAAA;oBAIP,IAAI,OAAO4G,KAAAA,MAAW,MAAA,OAAa,MAAA;wBACjC,OAAO,KAAA,YAAA,eAAA;wBACT,MAAA;4BAEI;kCACYA,SAAAA,YAAAA,SAAAA;gCAAd,EAAMtG,SAAQsG,MAAAA,iBAAAA,OAAOQ,YAAA,cAAPR,2CAAAA,qBAAqB8E,OAAA,CAAQ1L;gCAC3C,KAAOM,GAAAA,MAAS,KAAA,MAAA,KAAA;gCAClB,WAAQ,CAAA,iBAAA,SAAA;4BACN,OAAO,KAAA;;oBAEX;;;;;;oBAUSmL;oBACP,IAAI,IAAA,GAAOnL,EAAAA,GACT,KADmB,EACZA,SADuB,+CAEhC;;;;;;;;;;;QAGA;;IACA,IAAI,CAAOA,UAAU;wCAAA,MAAU,IAAA;YAAA,SAAA,sBAK7B;;;;;oBAL6B,UAAA,oEAAA,CAAA,GAAA,QAAA,oEAAA,CAAA;0BAC7B,IAAMkL,MAAAA,OAAalL,MAAM8J,WAAA;;;;;;;;;;;oBAEhB;;wBAAA,uBAAA,SAAA;;;sBAAP,OAAO,OAAA;wBACT,YAAA,YAAA,aAAA;;;;;;oBACA,CAAIoB,eAAe,OAAOA,eAAe,WAAWA,eAAe,MAAM;4BACvE,KAAA,CAAA,CAAO,mDAAA;;;;;;;;;;;QAEX;;IACA,OAAO,KAAA,6CAAA;AACT,KAAA,CAAA,OAAA,OAAA,GAAA;IJZA,uBAAA,sBAAwB;IC3exB,cAAA,EAAIG,kBAAiC;IAE9B,eAAA,OAASlL,sBACdmL,MAAA;4BAEA,IAAMC,UAAkC,CAAC;gCACzC,IAAID,OAAOE,aAAA,EAAe;gCACxBD,QAAQC,aAAA,GAAgB;qBAC1B;2BACA,IAAIF,OAAOG,YAAA,KAAiB,KAAA,GAAW;SACrCF,QAAQG,eAAA,GAAkBJ,OAAOG,YAAA,GAAe,SAAS","sourcesContent":["\"use strict\";\nvar __create = Object.create;\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __getProtoOf = Object.getPrototypeOf;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n  for (var name in all)\n    __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n  if (from && typeof from === \"object\" || typeof from === \"function\") {\n    for (let key of __getOwnPropNames(from))\n      if (!__hasOwnProp.call(to, key) && key !== except)\n        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n  }\n  return to;\n};\nvar __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(\n  // If the importer is in node compatibility mode or this is not an ESM\n  // file that has been converted to a CommonJS file using a Babel-\n  // compatible transform (i.e. \"__esModule\" has not been set), then set\n  // \"default\" to the CommonJS \"module.exports\" for node compatibility.\n  isNodeMode || !mod || !mod.__esModule ? __defProp(target, \"default\", { value: mod, enumerable: true }) : target,\n  mod\n));\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/utils/tracking.ts\nvar tracking_exports = {};\n__export(tracking_exports, {\n  buildAnalyticsContext: () => buildAnalyticsContext,\n  getBrowserID: () => getBrowserID,\n  getClientInfo: () => getClientInfo,\n  sendAdDetectTracking: () => sendAdDetectTracking,\n  sendAdImpressionTracking: () => sendAdImpressionTracking,\n  sendAdLoadedTracking: () => sendAdLoadedTracking,\n  sendHeartbeat: () => sendHeartbeat,\n  sendInitialTracking: () => sendInitialTracking\n});\nmodule.exports = __toCommonJS(tracking_exports);\n\n// src/utils/mqttConfig.ts\nvar DEFAULT_MQTT_CONFIG = {\n  enabled: true,\n  brokerAddress: \"vecbae77.ala.us-east-1.emqxsl.com\",\n  brokerPort: 8883,\n  wsPort: 8084,\n  username: \"for-sonifi\",\n  password: \"sonifi-mqtt\",\n  topicPrefix: \"adstorm/players\",\n  qos: 1\n};\nvar mqttConfig = { ...DEFAULT_MQTT_CONFIG };\nfunction isMQTTEnabled() {\n  return mqttConfig.enabled;\n}\nfunction buildMQTTBrokerUrl() {\n  if (mqttConfig.brokerUrl) return mqttConfig.brokerUrl;\n  return `wss://${mqttConfig.brokerAddress}:${mqttConfig.wsPort}/mqtt`;\n}\nfunction buildPlayerTopic(licenseKey, channel) {\n  return `${mqttConfig.topicPrefix}/${licenseKey}/${channel}`;\n}\n\n// src/utils/mqttClient.ts\nvar import_mqtt = __toESM(require(\"mqtt\"), 1);\nvar LOG = \"[StormcloudVideoPlayer][MQTT]\";\nvar KEEPALIVE_SECONDS = 30;\nvar CONNECT_TIMEOUT_MS = 1e4;\nvar RECONNECT_BASE_MS = 5e3;\nvar RECONNECT_MAX_MS = 6e4;\nvar MAX_RECONNECT_ATTEMPTS = 8;\nvar COOLDOWN_MS = 10 * 6e4;\nvar client = null;\nvar status = \"disconnected\";\nvar reconnectAttempts = 0;\nvar reconnectTimer = null;\nvar stopped = false;\nfunction clearReconnectTimer() {\n  if (reconnectTimer) {\n    clearTimeout(reconnectTimer);\n    reconnectTimer = null;\n  }\n}\nfunction teardownClient() {\n  if (client) {\n    try {\n      client.removeAllListeners();\n      client.end(true);\n    } catch {\n    }\n    client = null;\n  }\n}\nfunction scheduleReconnect() {\n  if (stopped || !isMQTTEnabled() || reconnectTimer) return;\n  if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {\n    console.warn(\n      `${LOG} giving up after ${reconnectAttempts} attempts; cooling down for ${COOLDOWN_MS / 6e4}m`\n    );\n    teardownClient();\n    status = \"disconnected\";\n    reconnectTimer = setTimeout(() => {\n      reconnectTimer = null;\n      reconnectAttempts = 0;\n      openConnection();\n    }, COOLDOWN_MS);\n    return;\n  }\n  const delay = Math.min(\n    RECONNECT_MAX_MS,\n    RECONNECT_BASE_MS * 2 ** reconnectAttempts\n  );\n  const jitter = Math.floor(Math.random() * 1e3);\n  reconnectAttempts += 1;\n  reconnectTimer = setTimeout(() => {\n    reconnectTimer = null;\n    openConnection();\n  }, delay + jitter);\n}\nfunction openConnection() {\n  if (stopped || !isMQTTEnabled()) return;\n  teardownClient();\n  const url = buildMQTTBrokerUrl();\n  status = \"connecting\";\n  const clientId = `stormcloud-vp-${Math.random().toString(36).slice(2, 9)}`;\n  try {\n    client = import_mqtt.default.connect(url, {\n      clientId,\n      username: mqttConfig.username,\n      password: mqttConfig.password,\n      keepalive: KEEPALIVE_SECONDS,\n      clean: true,\n      // Disable MQTT.js internal reconnect; we manage reconnection ourselves.\n      reconnectPeriod: 0,\n      connectTimeout: CONNECT_TIMEOUT_MS,\n      queueQoSZero: false,\n      reschedulePings: true,\n      // Root-cause fix for the Tizen 4.0 \"Keepalive timeout\" loop: MQTT.js's\n      // default timerVariant \"auto\" runs the keepalive interval inside a\n      // Blob-URL Web Worker (via worker-timers). On Samsung Tizen 4.0 (old\n      // WebKit) served from a file:// origin that worker can't tick reliably,\n      // so the keepalive counter trips onKeepaliveTimeout almost immediately\n      // after connect. Force the native setInterval timer instead; the main\n      // thread is free because video is decoded by the native AVPlay pipeline.\n      timerVariant: \"native\"\n    });\n  } catch (err) {\n    status = \"error\";\n    console.warn(`${LOG} connect() threw:`, err);\n    scheduleReconnect();\n    return;\n  }\n  client.on(\"connect\", () => {\n    status = \"connected\";\n    reconnectAttempts = 0;\n    clearReconnectTimer();\n    console.info(`${LOG} connected to ${url}`);\n  });\n  client.on(\"offline\", () => {\n    if (status === \"connected\") status = \"disconnected\";\n    console.warn(`${LOG} offline`);\n    scheduleReconnect();\n  });\n  client.on(\"error\", (err) => {\n    status = \"error\";\n    console.warn(`${LOG} error:`, err.message);\n    scheduleReconnect();\n  });\n  client.on(\"close\", () => {\n    if (status === \"connected\") status = \"disconnected\";\n    scheduleReconnect();\n  });\n}\nfunction initMQTTClient() {\n  if (client || !isMQTTEnabled()) return;\n  stopped = false;\n  reconnectAttempts = 0;\n  openConnection();\n}\nfunction ensureMQTTClient() {\n  if (isMQTTEnabled() && !client && !reconnectTimer) {\n    initMQTTClient();\n  }\n}\nfunction publishMQTT(topic, payload) {\n  if (!isMQTTEnabled()) {\n    return false;\n  }\n  ensureMQTTClient();\n  if (!client || !client.connected) {\n    return false;\n  }\n  try {\n    client.publish(topic, JSON.stringify(payload), { qos: mqttConfig.qos });\n    return true;\n  } catch (err) {\n    console.warn(`${LOG} publish failed on ${topic}:`, err);\n    return false;\n  }\n}\n\n// src/utils/vastEnvironmentSignals.ts\nvar PLAYER_ID_STORAGE_KEY = \"stormcloud.player.id\";\nvar DEVICE_ID_STORAGE_KEYS = [\n  \"rdid\",\n  \"ifa\",\n  \"advertisingId\",\n  \"advertising_id\",\n  \"deviceAdvertisingId\",\n  \"aaid\",\n  \"adid\",\n  \"rida\",\n  \"tifa\",\n  \"lgudid\"\n];\nfunction inferDeviceIdType() {\n  if (typeof navigator === \"undefined\") {\n    return void 0;\n  }\n  const ua = navigator.userAgent;\n  if (/Roku/i.test(ua)) return \"rida\";\n  if (/Tizen|Samsung/i.test(ua)) return \"tifa\";\n  if (/AppleTV|Apple TV/i.test(ua)) return \"tvOS\";\n  if (/AFT|Fire TV|Amazon/i.test(ua)) return \"afai\";\n  if (/Web0S|webOS|LG Browser|LGSTB|LGE/i.test(ua)) return \"lgudid\";\n  if (/Android|Google TV/i.test(ua)) return \"aaid\";\n  if (/iPhone|iPad|iPod/i.test(ua)) return \"idfa\";\n  return void 0;\n}\nfunction resolveNativeDeviceId() {\n  const bridgeSignals = readNativeBridgeSignals();\n  const platformDevice = readPlatformNativeDeviceId();\n  const deviceId = bridgeSignals.deviceId || readStoredDeviceId() || platformDevice.deviceId;\n  if (!deviceId || isMacroPlaceholder(deviceId) || isZeroedAdId(deviceId)) {\n    return void 0;\n  }\n  return deviceId;\n}\nfunction getOrCreateStoredUuid(storageKey) {\n  if (typeof window === \"undefined\") {\n    return void 0;\n  }\n  const existing = readPersistentId(storageKey);\n  if (existing) {\n    writePersistentId(storageKey, existing);\n    return existing;\n  }\n  const id = createUuid();\n  writePersistentId(storageKey, id);\n  return id;\n}\nfunction readPersistentId(storageKey) {\n  return readStoredString(storageKey) || readCookie(storageKey);\n}\nfunction writePersistentId(storageKey, value) {\n  try {\n    window.localStorage?.setItem(storageKey, value);\n  } catch {\n  }\n  writeCookie(storageKey, value);\n}\nvar PERSISTENT_ID_COOKIE_MAX_AGE = 60 * 60 * 24 * 365 * 5;\nfunction readCookie(name) {\n  if (typeof document === \"undefined\") {\n    return void 0;\n  }\n  try {\n    const prefix = encodeURIComponent(name) + \"=\";\n    const parts = document.cookie ? document.cookie.split(\";\") : [];\n    for (const part of parts) {\n      const entry = part.trim();\n      if (entry.startsWith(prefix)) {\n        return decodeURIComponent(entry.slice(prefix.length)) || void 0;\n      }\n    }\n  } catch {\n  }\n  return void 0;\n}\nfunction writeCookie(name, value) {\n  if (typeof document === \"undefined\") {\n    return;\n  }\n  try {\n    document.cookie = encodeURIComponent(name) + \"=\" + encodeURIComponent(value) + \";path=/;max-age=\" + PERSISTENT_ID_COOKIE_MAX_AGE + \";SameSite=Lax\";\n  } catch {\n  }\n}\nfunction createUuid() {\n  if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n    return crypto.randomUUID();\n  }\n  const bytes = new Uint8Array(16);\n  if (typeof crypto !== \"undefined\" && typeof crypto.getRandomValues === \"function\") {\n    crypto.getRandomValues(bytes);\n  } else {\n    let seed = Date.now() ^ Math.floor(performanceNow() * 1e3);\n    for (let i = 0; i < 16; i++) {\n      seed = seed * 1103515245 + 12345 & 2147483647;\n      bytes[i] = (seed ^ Math.floor(Math.random() * 256)) & 255;\n    }\n  }\n  bytes[6] = (bytes[6] ?? 0) & 15 | 64;\n  bytes[8] = (bytes[8] ?? 0) & 63 | 128;\n  let hex = \"\";\n  for (let i = 0; i < 16; i++) {\n    hex += (bytes[i] ?? 0).toString(16).padStart(2, \"0\");\n  }\n  return hex.slice(0, 8) + \"-\" + hex.slice(8, 12) + \"-\" + hex.slice(12, 16) + \"-\" + hex.slice(16, 20) + \"-\" + hex.slice(20, 32);\n}\nfunction performanceNow() {\n  try {\n    if (typeof performance !== \"undefined\" && typeof performance.now === \"function\") {\n      return performance.now();\n    }\n  } catch {\n  }\n  return 0;\n}\nfunction readPlatformNativeDeviceId() {\n  if (typeof window === \"undefined\") return {};\n  try {\n    const adinfo = window.webapis?.adinfo;\n    if (adinfo) {\n      const tifa = typeof adinfo.getTIFA === \"function\" ? adinfo.getTIFA() : adinfo.tifa;\n      if (typeof tifa === \"string\" && tifa && !isMacroPlaceholder(tifa)) {\n        const lat = typeof adinfo.isLATEnabled === \"function\" ? adinfo.isLATEnabled() : void 0;\n        return {\n          deviceId: tifa,\n          deviceIdType: \"tifa\",\n          ...typeof lat === \"boolean\" ? { limitAdTracking: lat } : {}\n        };\n      }\n    }\n  } catch {\n  }\n  try {\n    const webOSDev = window.webOSDev;\n    if (webOSDev) {\n      const lgudid = typeof webOSDev.LGUDID === \"function\" ? webOSDev.LGUDID() : webOSDev.lgudid ?? webOSDev.LGUDID;\n      if (typeof lgudid === \"string\" && lgudid) {\n        if (isZeroedAdId(lgudid)) {\n          return { deviceIdType: \"lgudid\", limitAdTracking: true };\n        }\n        if (!isMacroPlaceholder(lgudid)) {\n          return { deviceId: lgudid, deviceIdType: \"lgudid\", limitAdTracking: false };\n        }\n      }\n    }\n  } catch {\n  }\n  try {\n    const roku = window.Roku;\n    if (roku) {\n      const rida = typeof roku.getPublisherUniqueId === \"function\" ? roku.getPublisherUniqueId() : roku.rida;\n      if (typeof rida === \"string\" && rida && !isMacroPlaceholder(rida)) {\n        return { deviceId: rida, deviceIdType: \"rida\", limitAdTracking: false };\n      }\n    }\n  } catch {\n  }\n  return {};\n}\nvar ZEROED_AD_ID_PATTERNS = /* @__PURE__ */ new Set([\n  \"38400000-8cf0-11bd-b23e-10b96e40000d\",\n  \"00000000-0000-0000-0000-000000000000\"\n]);\nfunction isMacroPlaceholder(value) {\n  const t = value.trim();\n  return !t || /^(\\[[^\\]]*\\]|\\{[^}]*\\}|%%[^%]*%%)$/.test(t) || /^(unknown|null|undefined|none|n\\/a|\\$\\{[^}]+\\})$/i.test(t) || ZEROED_AD_ID_PATTERNS.has(t.toLowerCase());\n}\nfunction isZeroedAdId(value) {\n  return ZEROED_AD_ID_PATTERNS.has(value.trim().toLowerCase());\n}\nfunction readNativeBridgeSignals() {\n  if (typeof window === \"undefined\") {\n    return {};\n  }\n  const candidates = [\n    window.__STORMCLOUD_CTV_AD_INFO__,\n    window.__STORMCLOUD_CTV__,\n    window.stormcloudCtv,\n    window.AiryTV,\n    window.Android,\n    window.webOS,\n    window.tizen,\n    window.amazon\n  ].filter(Boolean);\n  for (const source of candidates) {\n    const contentUrl = readBridgeValue(source, [\"contentUrl\", \"url\", \"videoUrl\", \"canonicalUrl\"]) || void 0;\n    const appId = readBridgeValue(source, [\"appId\", \"msid\", \"applicationId\", \"packageName\"]) || void 0;\n    const appName = readBridgeValue(source, [\"appName\", \"an\", \"applicationName\"]) || void 0;\n    const deviceId = readBridgeValue(source, [\n      \"rdid\",\n      \"ifa\",\n      \"advertisingId\",\n      \"adId\",\n      \"deviceId\",\n      \"lgudid\",\n      \"LGUDID\",\n      \"tifa\",\n      \"rida\",\n      \"afai\",\n      \"aaid\"\n    ]) || void 0;\n    if (!contentUrl && !deviceId && !appId && !appName) continue;\n    const deviceIdType = readBridgeValue(source, [\n      \"idtype\",\n      \"deviceIdType\",\n      \"advertisingIdType\",\n      \"idType\"\n    ]) || inferDeviceIdType();\n    const limitAdTracking = readBridgeBoolean(source, [\n      \"is_lat\",\n      \"limitAdTracking\",\n      \"limitedAdTracking\",\n      \"lat\"\n    ]);\n    return {\n      ...contentUrl ? { contentUrl } : {},\n      ...appId ? { appId } : {},\n      ...appName ? { appName } : {},\n      ...deviceId ? { deviceId } : {},\n      ...deviceId && deviceIdType ? { deviceIdType } : {},\n      ...deviceId && limitAdTracking != null ? { limitAdTracking } : {}\n    };\n  }\n  return {};\n}\nfunction readBridgeValue(source, keys) {\n  for (const key of keys) {\n    const value = source?.[key];\n    if (typeof value === \"string\" && value) {\n      return value;\n    }\n    if (typeof value === \"function\") {\n      try {\n        const result = value.call(source);\n        if (typeof result === \"string\" && result) {\n          return result;\n        }\n      } catch {\n      }\n    }\n  }\n  return void 0;\n}\nfunction readBridgeBoolean(source, keys) {\n  for (const key of keys) {\n    const value = source?.[key];\n    const normalized = normalizeBoolean(value);\n    if (normalized != null) {\n      return normalized;\n    }\n    if (typeof value === \"function\") {\n      try {\n        const result = normalizeBoolean(value.call(source));\n        if (result != null) {\n          return result;\n        }\n      } catch {\n      }\n    }\n  }\n  return void 0;\n}\nfunction readStoredDeviceId() {\n  for (const key of DEVICE_ID_STORAGE_KEYS) {\n    const value = readStoredString(key);\n    if (value) {\n      return value;\n    }\n  }\n  return void 0;\n}\nfunction readStoredString(key) {\n  if (typeof window === \"undefined\") {\n    return void 0;\n  }\n  try {\n    const value = window.localStorage?.getItem(key);\n    return value || void 0;\n  } catch {\n    return void 0;\n  }\n}\nfunction normalizeBoolean(value) {\n  if (typeof value === \"boolean\") {\n    return value;\n  }\n  if (typeof value === \"number\") {\n    return value === 1;\n  }\n  if (typeof value === \"string\") {\n    const normalized = value.toLowerCase();\n    if (normalized === \"1\" || normalized === \"true\" || normalized === \"yes\") {\n      return true;\n    }\n    if (normalized === \"0\" || normalized === \"false\" || normalized === \"no\") {\n      return false;\n    }\n  }\n  return void 0;\n}\n\n// src/utils/tracking.ts\nvar cachedBrowserId = null;\nfunction buildAnalyticsContext(config) {\n  const context = {};\n  if (config.debugAdTiming) {\n    context.debugAdTiming = true;\n  }\n  if (config.isLiveStream !== void 0) {\n    context.inputStreamType = config.isLiveStream ? \"live\" : \"vod\";\n  }\n  return context;\n}\nfunction getClientInfo() {\n  const ua = navigator.userAgent;\n  const platform = navigator.platform;\n  const vendor = navigator.vendor || \"\";\n  const maxTouchPoints = navigator.maxTouchPoints || 0;\n  const memory = navigator.deviceMemory || null;\n  const hardwareConcurrency = navigator.hardwareConcurrency || 1;\n  const screenInfo = {\n    width: screen?.width,\n    height: screen?.height,\n    availWidth: screen?.availWidth,\n    availHeight: screen?.availHeight,\n    orientation: screen?.orientation?.type || \"\",\n    pixelDepth: screen?.pixelDepth\n  };\n  let deviceType = \"desktop\";\n  let brand = \"Unknown\";\n  let os = \"Unknown\";\n  let model = \"\";\n  let isSmartTV = false;\n  let isAndroid = false;\n  let isWebView = false;\n  let isWebApp = false;\n  if (ua.includes(\"Web0S\")) {\n    brand = \"LG\";\n    os = \"webOS\";\n    isSmartTV = true;\n    deviceType = \"tv\";\n    const webosMatch = ua.match(/Web0S\\/([^\\s]+)/);\n    model = webosMatch ? `webOS ${webosMatch[1]}` : \"webOS TV\";\n  } else if (ua.includes(\"Tizen\")) {\n    brand = \"Samsung\";\n    os = \"Tizen\";\n    isSmartTV = true;\n    deviceType = \"tv\";\n    const tizenMatch = ua.match(/Tizen\\/([^\\s]+)/);\n    const tvMatch = ua.match(/(?:Smart-TV|SMART-TV|TV)/i) ? \"Smart TV\" : \"\";\n    model = tizenMatch ? `Tizen ${tizenMatch[1]} ${tvMatch}`.trim() : \"Tizen TV\";\n  } else if (ua.includes(\"Philips\")) {\n    brand = \"Philips\";\n    os = \"Saphi\";\n    isSmartTV = true;\n    deviceType = \"tv\";\n  } else if (ua.includes(\"Sharp\") || ua.includes(\"AQUOS\")) {\n    brand = \"Sharp\";\n    os = \"Android TV\";\n    isSmartTV = true;\n    deviceType = \"tv\";\n  } else if (ua.includes(\"Android\") && (ua.includes(\"Sony\") || vendor.includes(\"Sony\"))) {\n    brand = \"Sony\";\n    os = \"Android TV\";\n    isSmartTV = true;\n    deviceType = \"tv\";\n  } else if (ua.includes(\"Android\") && (ua.includes(\"NetCast\") || ua.includes(\"LG\"))) {\n    brand = \"LG\";\n    os = \"Android TV\";\n    isSmartTV = true;\n    deviceType = \"tv\";\n  } else if (ua.includes(\" Roku\") || ua.includes(\"Roku/\")) {\n    brand = \"Roku\";\n    os = \"Roku OS\";\n    isSmartTV = true;\n    deviceType = \"tv\";\n  } else if (ua.includes(\"AppleTV\")) {\n    brand = \"Apple\";\n    os = \"tvOS\";\n    isSmartTV = true;\n    deviceType = \"tv\";\n  }\n  if (ua.includes(\"Android\")) {\n    isAndroid = true;\n    os = \"Android\";\n    deviceType = /Mobile/.test(ua) ? \"mobile\" : \"tablet\";\n    if (ua.includes(\"Android\") && (maxTouchPoints === 0 || ua.includes(\"Google TV\") || ua.includes(\"XiaoMi\"))) {\n      deviceType = \"tv\";\n      isSmartTV = true;\n      brand = brand === \"Unknown\" ? \"Android TV\" : brand;\n    }\n    const androidModelMatch = ua.match(/\\(([^)]*Android[^)]*)\\)/);\n    if (androidModelMatch && androidModelMatch[1]) {\n      model = androidModelMatch[1];\n    }\n  }\n  if (/iPad|iPhone|iPod/.test(ua)) {\n    os = \"iOS\";\n    deviceType = \"mobile\";\n    brand = \"Apple\";\n    if (navigator.maxTouchPoints > 1 && /iPad/.test(ua)) {\n      deviceType = \"tablet\";\n    }\n  }\n  if (!isAndroid && !isSmartTV && !/Mobile/.test(ua)) {\n    if (ua.includes(\"Windows\")) {\n      os = \"Windows\";\n      deviceType = \"desktop\";\n    } else if (ua.includes(\"Mac\") && !/iPhone/.test(ua)) {\n      os = \"macOS\";\n      deviceType = \"desktop\";\n      if (maxTouchPoints > 1) deviceType = \"tablet\";\n    } else if (ua.includes(\"Linux\")) {\n      os = \"Linux\";\n      deviceType = \"desktop\";\n    }\n  }\n  if (brand === \"Unknown\") {\n    if (vendor.includes(\"Google\") || ua.includes(\"Chrome\")) brand = \"Google\";\n    if (vendor.includes(\"Apple\")) brand = \"Apple\";\n    if (vendor.includes(\"Samsung\") || ua.includes(\"SM-\")) brand = \"Samsung\";\n  }\n  isWebView = /wv|WebView|Linux; U;/.test(ua);\n  if (window?.outerHeight === 0 && window?.outerWidth === 0) {\n    isWebView = true;\n  }\n  isWebApp = window.matchMedia(\"(display-mode: standalone)\").matches || window.navigator.standalone === true || window.screen?.orientation?.angle !== void 0;\n  return {\n    brand,\n    os,\n    model: model || ua.substring(0, 50) + \"...\",\n    deviceType,\n    isSmartTV,\n    isAndroid,\n    isWebView,\n    isWebApp,\n    domain: window.location.hostname,\n    origin: window.location.origin,\n    path: window.location.pathname,\n    userAgent: ua,\n    vendor,\n    platform,\n    screen: screenInfo,\n    hardwareConcurrency,\n    deviceMemory: memory,\n    maxTouchPoints,\n    language: navigator.language,\n    languages: navigator.languages?.join(\",\") || \"\",\n    cookieEnabled: navigator.cookieEnabled,\n    doNotTrack: navigator.doNotTrack || \"\",\n    referrer: document.referrer,\n    visibilityState: document.visibilityState\n  };\n}\nasync function sha256Hex(input) {\n  if (typeof crypto !== \"undefined\" && crypto.subtle?.digest) {\n    try {\n      await crypto.subtle.digest(\"SHA-256\", new Uint8Array([1, 2, 3]));\n      let encodedData;\n      if (typeof TextEncoder !== \"undefined\") {\n        encodedData = new TextEncoder().encode(input);\n      } else {\n        const utf8 = unescape(encodeURIComponent(input));\n        const buffer = new Uint8Array(utf8.length);\n        for (let i = 0; i < utf8.length; i++) {\n          buffer[i] = utf8.charCodeAt(i);\n        }\n        encodedData = buffer;\n      }\n      const hashBuffer = await crypto.subtle.digest(\"SHA-256\", encodedData);\n      return Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n    } catch {\n      console.warn(\n        \"[StormcloudVideoPlayer] crypto.subtle not supported, using fallback hash\"\n      );\n    }\n  }\n  let hash = 0;\n  for (let i = 0; i < input.length; i++) {\n    const char = input.charCodeAt(i);\n    hash = (hash << 5) - hash + char;\n    hash = hash & hash;\n  }\n  const fallbackHash = Math.abs(hash).toString(16).padStart(8, \"0\");\n  const timestamp = Date.now().toString(16).padStart(12, \"0\");\n  const random = Math.random().toString(16).substring(2, 14).padStart(12, \"0\");\n  return (fallbackHash + timestamp + random).padEnd(64, \"0\");\n}\nfunction resolvePlayerIdentitySeed(clientInfo) {\n  const nativeDeviceId = resolveNativeDeviceId();\n  if (nativeDeviceId) {\n    return `device:${nativeDeviceId}`;\n  }\n  const persistedId = getOrCreateStoredUuid(PLAYER_ID_STORAGE_KEY);\n  if (persistedId) {\n    return `persisted:${persistedId}`;\n  }\n  return `fingerprint:${JSON.stringify(clientInfo)}`;\n}\nasync function getBrowserID(clientInfo) {\n  if (cachedBrowserId) {\n    return cachedBrowserId;\n  }\n  cachedBrowserId = await sha256Hex(resolvePlayerIdentitySeed(clientInfo));\n  return cachedBrowserId;\n}\nfunction canPublish(licenseKey) {\n  return Boolean(isMQTTEnabled() && licenseKey);\n}\nasync function buildPlayerMetricEvent(context = {}, flags = {}) {\n  const clientInfo = getClientInfo();\n  const debugAdTiming = !!context.debugAdTiming;\n  if (debugAdTiming) {\n    console.log(\"[StormcloudVideoPlayer] clientInfo: \", JSON.stringify(clientInfo, null, 2));\n  }\n  const playerId = await getBrowserID(clientInfo);\n  if (debugAdTiming) {\n    console.log(\"[StormcloudVideoPlayer] playerId: \", playerId);\n  }\n  const captureAt = flags.captureAt ?? (/* @__PURE__ */ new Date()).toISOString();\n  return {\n    player_id: playerId,\n    device_type: clientInfo.deviceType,\n    os: clientInfo.os.toLowerCase(),\n    ad_loaded: flags.adLoaded ?? false,\n    ad_detect: flags.adDetect ?? false,\n    capture_at: captureAt,\n    ...context.inputStreamType ? { input_stream_type: context.inputStreamType } : {}\n  };\n}\nfunction publishTracking(licenseKey, channel, body) {\n  ensureMQTTClient();\n  publishMQTT(buildPlayerTopic(licenseKey, channel), body);\n}\nasync function sendInitialTracking(licenseKey, context = {}) {\n  if (!canPublish(licenseKey)) return;\n  try {\n    const metricEvent = await buildPlayerMetricEvent(context, {\n      adLoaded: false,\n      adDetect: false\n    });\n    publishTracking(licenseKey, \"metrics\", {\n      events: [metricEvent]\n    });\n  } catch (error) {\n    console.error(\n      \"[StormcloudVideoPlayer] Error sending initial tracking data:\",\n      error\n    );\n  }\n}\nasync function sendAdDetectTracking(licenseKey, adDetectInfo, context = {}) {\n  try {\n    await sendHeartbeat(licenseKey, context, {\n      adDetect: true,\n      captureAt: adDetectInfo.timestamp\n    });\n  } catch (error) {\n    console.error(\n      \"[StormcloudVideoPlayer] Error sending ad detect tracking:\",\n      error\n    );\n  }\n}\nasync function sendAdLoadedTracking(licenseKey, adLoadedInfo, context = {}) {\n  try {\n    await sendHeartbeat(licenseKey, context, {\n      adLoaded: true,\n      captureAt: adLoadedInfo.timestamp\n    });\n  } catch (error) {\n    console.error(\n      \"[StormcloudVideoPlayer] Error sending ad loaded tracking:\",\n      error\n    );\n  }\n}\nasync function sendAdImpressionTracking(licenseKey, adImpressionInfo, context = {}) {\n  if (!canPublish(licenseKey)) return;\n  try {\n    const metricEvent = await buildPlayerMetricEvent(context, {\n      captureAt: adImpressionInfo.timestamp\n    });\n    publishTracking(licenseKey, \"heartbeat\", metricEvent);\n    publishTracking(licenseKey, \"impressions\", {\n      events: [\n        {\n          player_id: metricEvent.player_id,\n          ad_played_count: 1,\n          ad_url: adImpressionInfo.adUrl,\n          capture_at: adImpressionInfo.timestamp\n        }\n      ]\n    });\n  } catch (error) {\n    console.error(\n      \"[StormcloudVideoPlayer] Error sending ad impression tracking:\",\n      error\n    );\n  }\n}\nasync function sendHeartbeat(licenseKey, context = {}, flags = {}) {\n  if (!canPublish(licenseKey)) return;\n  try {\n    const heartbeatData = await buildPlayerMetricEvent(context, flags);\n    publishTracking(licenseKey, \"heartbeat\", heartbeatData);\n  } catch (error) {\n    console.error(\"[StormcloudVideoPlayer] Error sending heartbeat:\", error);\n  }\n}\n// Annotate the CommonJS export names for ESM import in node:\n0 && (module.exports = {\n  buildAnalyticsContext,\n  getBrowserID,\n  getClientInfo,\n  sendAdDetectTracking,\n  sendAdImpressionTracking,\n  sendAdLoadedTracking,\n  sendHeartbeat,\n  sendInitialTracking\n});\n","import type {\n  ClientInfo,\n  AdDetectInfo,\n  AdLoadedInfo,\n  AdImpressionInfo,\n  PlayerAnalyticsContext,\n  StormcloudVideoPlayerConfig,\n} from \"../types\";\n\nimport { buildPlayerTopic, isMQTTEnabled } from \"./mqttConfig\";\nimport { ensureMQTTClient, publishMQTT } from \"./mqttClient\";\nimport {\n  getOrCreateStoredUuid,\n  PLAYER_ID_STORAGE_KEY,\n  resolveNativeDeviceId,\n} from \"./vastEnvironmentSignals\";\n\nlet cachedBrowserId: string | null = null;\n\nexport function buildAnalyticsContext(\n  config: Pick<StormcloudVideoPlayerConfig, \"debugAdTiming\" | \"isLiveStream\">\n): PlayerAnalyticsContext {\n  const context: PlayerAnalyticsContext = {};\n  if (config.debugAdTiming) {\n    context.debugAdTiming = true;\n  }\n  if (config.isLiveStream !== undefined) {\n    context.inputStreamType = config.isLiveStream ? \"live\" : \"vod\";\n  }\n  return context;\n}\n\nexport function getClientInfo(): ClientInfo {\n  const ua = navigator.userAgent;\n  const platform = navigator.platform;\n  const vendor = navigator.vendor || \"\";\n  const maxTouchPoints = navigator.maxTouchPoints || 0;\n  const memory = (navigator as any).deviceMemory || null;\n  const hardwareConcurrency = navigator.hardwareConcurrency || 1;\n\n  const screenInfo = {\n    width: screen?.width,\n    height: screen?.height,\n    availWidth: screen?.availWidth,\n    availHeight: screen?.availHeight,\n    orientation: (screen?.orientation as any)?.type || \"\",\n    pixelDepth: screen?.pixelDepth,\n  };\n\n  let deviceType: \"tv\" | \"mobile\" | \"tablet\" | \"desktop\" = \"desktop\";\n  let brand = \"Unknown\";\n  let os = \"Unknown\";\n  let model = \"\";\n  let isSmartTV = false;\n  let isAndroid = false;\n  let isWebView = false;\n  let isWebApp = false;\n\n  if (ua.includes(\"Web0S\")) {\n    brand = \"LG\";\n    os = \"webOS\";\n    isSmartTV = true;\n    deviceType = \"tv\";\n    const webosMatch = ua.match(/Web0S\\/([^\\s]+)/);\n    model = webosMatch ? `webOS ${webosMatch[1]}` : \"webOS TV\";\n  } else if (ua.includes(\"Tizen\")) {\n    brand = \"Samsung\";\n    os = \"Tizen\";\n    isSmartTV = true;\n    deviceType = \"tv\";\n    const tizenMatch = ua.match(/Tizen\\/([^\\s]+)/);\n    const tvMatch = ua.match(/(?:Smart-TV|SMART-TV|TV)/i) ? \"Smart TV\" : \"\";\n    model = tizenMatch\n      ? `Tizen ${tizenMatch[1]} ${tvMatch}`.trim()\n      : \"Tizen TV\";\n  } else if (ua.includes(\"Philips\")) {\n    brand = \"Philips\";\n    os = \"Saphi\";\n    isSmartTV = true;\n    deviceType = \"tv\";\n  } else if (ua.includes(\"Sharp\") || ua.includes(\"AQUOS\")) {\n    brand = \"Sharp\";\n    os = \"Android TV\";\n    isSmartTV = true;\n    deviceType = \"tv\";\n  } else if (\n    ua.includes(\"Android\") &&\n    (ua.includes(\"Sony\") || vendor.includes(\"Sony\"))\n  ) {\n    brand = \"Sony\";\n    os = \"Android TV\";\n    isSmartTV = true;\n    deviceType = \"tv\";\n  } else if (\n    ua.includes(\"Android\") &&\n    (ua.includes(\"NetCast\") || ua.includes(\"LG\"))\n  ) {\n    brand = \"LG\";\n    os = \"Android TV\";\n    isSmartTV = true;\n    deviceType = \"tv\";\n  } else if (ua.includes(\" Roku\") || ua.includes(\"Roku/\")) {\n    brand = \"Roku\";\n    os = \"Roku OS\";\n    isSmartTV = true;\n    deviceType = \"tv\";\n  } else if (ua.includes(\"AppleTV\")) {\n    brand = \"Apple\";\n    os = \"tvOS\";\n    isSmartTV = true;\n    deviceType = \"tv\";\n  }\n\n  if (ua.includes(\"Android\")) {\n    isAndroid = true;\n    os = \"Android\";\n    deviceType = /Mobile/.test(ua) ? \"mobile\" : \"tablet\";\n\n    if (\n      ua.includes(\"Android\") &&\n      (maxTouchPoints === 0 ||\n        ua.includes(\"Google TV\") ||\n        ua.includes(\"XiaoMi\"))\n    ) {\n      deviceType = \"tv\";\n      isSmartTV = true;\n      brand = brand === \"Unknown\" ? \"Android TV\" : brand;\n    }\n\n    const androidModelMatch = ua.match(/\\(([^)]*Android[^)]*)\\)/);\n    if (androidModelMatch && androidModelMatch[1]) {\n      model = androidModelMatch[1];\n    }\n  }\n\n  if (/iPad|iPhone|iPod/.test(ua)) {\n    os = \"iOS\";\n    deviceType = \"mobile\";\n    brand = \"Apple\";\n    if (navigator.maxTouchPoints > 1 && /iPad/.test(ua)) {\n      deviceType = \"tablet\";\n    }\n  }\n\n  if (!isAndroid && !isSmartTV && !/Mobile/.test(ua)) {\n    if (ua.includes(\"Windows\")) {\n      os = \"Windows\";\n      deviceType = \"desktop\";\n    } else if (ua.includes(\"Mac\") && !/iPhone/.test(ua)) {\n      os = \"macOS\";\n      deviceType = \"desktop\";\n      if (maxTouchPoints > 1) deviceType = \"tablet\";\n    } else if (ua.includes(\"Linux\")) {\n      os = \"Linux\";\n      deviceType = \"desktop\";\n    }\n  }\n\n  if (brand === \"Unknown\") {\n    if (vendor.includes(\"Google\") || ua.includes(\"Chrome\")) brand = \"Google\";\n    if (vendor.includes(\"Apple\")) brand = \"Apple\";\n    if (vendor.includes(\"Samsung\") || ua.includes(\"SM-\")) brand = \"Samsung\";\n  }\n\n  isWebView = /wv|WebView|Linux; U;/.test(ua);\n\n  if (window?.outerHeight === 0 && window?.outerWidth === 0) {\n    isWebView = true;\n  }\n\n  isWebApp =\n    window.matchMedia(\"(display-mode: standalone)\").matches ||\n    (window.navigator as any).standalone === true ||\n    window.screen?.orientation?.angle !== undefined;\n\n  return {\n    brand,\n    os,\n    model: model || ua.substring(0, 50) + \"...\",\n    deviceType,\n    isSmartTV,\n    isAndroid,\n    isWebView,\n    isWebApp,\n    domain: window.location.hostname,\n    origin: window.location.origin,\n    path: window.location.pathname,\n    userAgent: ua,\n    vendor,\n    platform,\n    screen: screenInfo,\n    hardwareConcurrency,\n    deviceMemory: memory,\n    maxTouchPoints,\n    language: navigator.language,\n    languages: navigator.languages?.join(\",\") || \"\",\n    cookieEnabled: navigator.cookieEnabled,\n    doNotTrack: navigator.doNotTrack || \"\",\n    referrer: document.referrer,\n    visibilityState: document.visibilityState,\n  };\n}\n\nasync function sha256Hex(input: string): Promise<string> {\n  if (typeof crypto !== \"undefined\" && crypto.subtle?.digest) {\n    try {\n      await crypto.subtle.digest(\"SHA-256\", new Uint8Array([1, 2, 3]));\n\n      let encodedData: BufferSource;\n      if (typeof TextEncoder !== \"undefined\") {\n        encodedData = new TextEncoder().encode(input);\n      } else {\n        const utf8 = unescape(encodeURIComponent(input));\n        const buffer = new Uint8Array(utf8.length);\n        for (let i = 0; i < utf8.length; i++) {\n          buffer[i] = utf8.charCodeAt(i);\n        }\n        encodedData = buffer;\n      }\n\n      const hashBuffer = await crypto.subtle.digest(\"SHA-256\", encodedData);\n      return Array.from(new Uint8Array(hashBuffer))\n        .map((b) => b.toString(16).padStart(2, \"0\"))\n        .join(\"\");\n    } catch {\n      console.warn(\n        \"[StormcloudVideoPlayer] crypto.subtle not supported, using fallback hash\"\n      );\n    }\n  }\n\n  let hash = 0;\n  for (let i = 0; i < input.length; i++) {\n    const char = input.charCodeAt(i);\n    hash = (hash << 5) - hash + char;\n    hash = hash & hash;\n  }\n\n  const fallbackHash = Math.abs(hash).toString(16).padStart(8, \"0\");\n  const timestamp = Date.now().toString(16).padStart(12, \"0\");\n  const random = Math.random().toString(16).substring(2, 14).padStart(12, \"0\");\n\n  return (fallbackHash + timestamp + random).padEnd(64, \"0\");\n}\n\nfunction resolvePlayerIdentitySeed(clientInfo: ClientInfo): string {\n  const nativeDeviceId = resolveNativeDeviceId();\n  if (nativeDeviceId) {\n    return `device:${nativeDeviceId}`;\n  }\n\n  const persistedId = getOrCreateStoredUuid(PLAYER_ID_STORAGE_KEY);\n  if (persistedId) {\n    return `persisted:${persistedId}`;\n  }\n\n  return `fingerprint:${JSON.stringify(clientInfo)}`;\n}\n\nexport async function getBrowserID(clientInfo: ClientInfo): Promise<string> {\n  if (cachedBrowserId) {\n    return cachedBrowserId;\n  }\n\n  cachedBrowserId = await sha256Hex(resolvePlayerIdentitySeed(clientInfo));\n  return cachedBrowserId;\n}\n\ntype PlayerMetricFlags = {\n  adLoaded?: boolean;\n  adDetect?: boolean;\n  captureAt?: string;\n};\n\nfunction canPublish(licenseKey: string | undefined): licenseKey is string {\n  return Boolean(isMQTTEnabled() && licenseKey);\n}\n\nasync function buildPlayerMetricEvent(\n  context: PlayerAnalyticsContext = {},\n  flags: PlayerMetricFlags = {}\n): Promise<Record<string, unknown>> {\n  const clientInfo = getClientInfo();\n\n  const debugAdTiming = !!context.debugAdTiming;\n  if (debugAdTiming) {\n    console.log(\"[StormcloudVideoPlayer] clientInfo: \", JSON.stringify(clientInfo, null, 2));\n  }\n\n  const playerId = await getBrowserID(clientInfo);\n\n  if (debugAdTiming) {\n    console.log(\"[StormcloudVideoPlayer] playerId: \", playerId);\n  }\n\n  const captureAt = flags.captureAt ?? new Date().toISOString();\n\n  return {\n    player_id: playerId,\n    device_type: clientInfo.deviceType,\n    os: clientInfo.os.toLowerCase(),\n    ad_loaded: flags.adLoaded ?? false,\n    ad_detect: flags.adDetect ?? false,\n    capture_at: captureAt,\n    ...(context.inputStreamType\n      ? { input_stream_type: context.inputStreamType }\n      : {}),\n  };\n}\n\nfunction publishTracking(\n  licenseKey: string,\n  channel: \"metrics\" | \"impressions\" | \"heartbeat\",\n  body: Record<string, unknown>\n): void {\n  ensureMQTTClient();\n  publishMQTT(buildPlayerTopic(licenseKey, channel), body);\n}\n\nexport async function sendInitialTracking(\n  licenseKey?: string,\n  context: PlayerAnalyticsContext = {}\n): Promise<void> {\n  if (!canPublish(licenseKey)) return;\n\n  try {\n    const metricEvent = await buildPlayerMetricEvent(context, {\n      adLoaded: false,\n      adDetect: false,\n    });\n\n    publishTracking(licenseKey, \"metrics\", {\n      events: [metricEvent],\n    });\n  } catch (error) {\n    console.error(\n      \"[StormcloudVideoPlayer] Error sending initial tracking data:\",\n      error\n    );\n  }\n}\n\nexport async function sendAdDetectTracking(\n  licenseKey: string | undefined,\n  adDetectInfo: AdDetectInfo,\n  context: PlayerAnalyticsContext = {}\n): Promise<void> {\n  try {\n    await sendHeartbeat(licenseKey, context, {\n      adDetect: true,\n      captureAt: adDetectInfo.timestamp,\n    });\n  } catch (error) {\n    console.error(\n      \"[StormcloudVideoPlayer] Error sending ad detect tracking:\",\n      error\n    );\n  }\n}\n\nexport async function sendAdLoadedTracking(\n  licenseKey: string | undefined,\n  adLoadedInfo: AdLoadedInfo,\n  context: PlayerAnalyticsContext = {}\n): Promise<void> {\n  try {\n    await sendHeartbeat(licenseKey, context, {\n      adLoaded: true,\n      captureAt: adLoadedInfo.timestamp,\n    });\n  } catch (error) {\n    console.error(\n      \"[StormcloudVideoPlayer] Error sending ad loaded tracking:\",\n      error\n    );\n  }\n}\n\nexport async function sendAdImpressionTracking(\n  licenseKey: string | undefined,\n  adImpressionInfo: AdImpressionInfo,\n  context: PlayerAnalyticsContext = {}\n): Promise<void> {\n  if (!canPublish(licenseKey)) return;\n\n  try {\n    const metricEvent = await buildPlayerMetricEvent(context, {\n      captureAt: adImpressionInfo.timestamp,\n    });\n\n    publishTracking(licenseKey, \"heartbeat\", metricEvent);\n    publishTracking(licenseKey, \"impressions\", {\n      events: [\n        {\n          player_id: metricEvent.player_id,\n          ad_played_count: 1,\n          ad_url: adImpressionInfo.adUrl,\n          capture_at: adImpressionInfo.timestamp,\n        },\n      ],\n    });\n  } catch (error) {\n    console.error(\n      \"[StormcloudVideoPlayer] Error sending ad impression tracking:\",\n      error\n    );\n  }\n}\n\nexport async function sendHeartbeat(\n  licenseKey?: string,\n  context: PlayerAnalyticsContext = {},\n  flags: PlayerMetricFlags = {}\n): Promise<void> {\n  if (!canPublish(licenseKey)) return;\n\n  try {\n    const heartbeatData = await buildPlayerMetricEvent(context, flags);\n    publishTracking(licenseKey, \"heartbeat\", heartbeatData);\n  } catch (error) {\n    console.error(\"[StormcloudVideoPlayer] Error sending heartbeat:\", error);\n  }\n}\n","export const MQTT_CA_CERT_FILE = \"src/certs/emqxsl-ca.crt\";\n\nexport type MQTTConfig = {\n  enabled: boolean;\n  brokerAddress: string;\n  brokerPort: number;\n  wsPort: number;\n  username: string;\n  password: string;\n  topicPrefix: string;\n  qos: 0 | 1 | 2;\n  brokerUrl?: string;\n};\n\nexport const DEFAULT_MQTT_CONFIG: MQTTConfig = {\n  enabled: true,\n  brokerAddress: \"vecbae77.ala.us-east-1.emqxsl.com\",\n  brokerPort: 8883,\n  wsPort: 8084,\n  username: \"for-sonifi\",\n  password: \"sonifi-mqtt\",\n  topicPrefix: \"adstorm/players\",\n  qos: 1,\n};\n\nexport const mqttConfig: MQTTConfig = { ...DEFAULT_MQTT_CONFIG };\n\nexport function applyMQTTConfig(overrides: Partial<MQTTConfig>): void {\n  Object.assign(mqttConfig, overrides);\n}\n\nexport function isMQTTEnabled(): boolean {\n  return mqttConfig.enabled;\n}\n\nexport function buildMQTTBrokerUrl(): string {\n  if (mqttConfig.brokerUrl) return mqttConfig.brokerUrl;\n  return `wss://${mqttConfig.brokerAddress}:${mqttConfig.wsPort}/mqtt`;\n}\n\nexport function buildPlayerTopic(\n  licenseKey: string,\n  channel: \"metrics\" | \"impressions\" | \"heartbeat\"\n): string {\n  return `${mqttConfig.topicPrefix}/${licenseKey}/${channel}`;\n}\n","import mqtt from \"mqtt\";\nimport type { MqttClient } from \"mqtt\";\nimport {\n  applyMQTTConfig,\n  buildMQTTBrokerUrl,\n  isMQTTEnabled,\n  mqttConfig,\n} from \"./mqttConfig\";\nimport type { MQTTConfig } from \"./mqttConfig\";\n\nconst LOG = \"[StormcloudVideoPlayer][MQTT]\";\n\nconst KEEPALIVE_SECONDS = 30;\nconst CONNECT_TIMEOUT_MS = 10_000;\n\nconst RECONNECT_BASE_MS = 5_000;\nconst RECONNECT_MAX_MS = 60_000;\nconst MAX_RECONNECT_ATTEMPTS = 8;\nconst COOLDOWN_MS = 10 * 60_000;\n\nexport type MQTTStatus = \"disconnected\" | \"connecting\" | \"connected\" | \"error\";\n\nlet client: MqttClient | null = null;\nlet status: MQTTStatus = \"disconnected\";\nlet reconnectAttempts = 0;\nlet reconnectTimer: ReturnType<typeof setTimeout> | null = null;\nlet stopped = false;\n\nexport function getMQTTStatus(): MQTTStatus {\n  return status;\n}\n\nexport function isMQTTConnected(): boolean {\n  return status === \"connected\" && client !== null && client.connected;\n}\n\nexport function isMQTTConfigured(): boolean {\n  return isMQTTEnabled();\n}\n\nexport function configureMQTT(overrides: Partial<MQTTConfig>): void {\n  applyMQTTConfig(overrides);\n  disconnectMQTT();\n}\n\nfunction clearReconnectTimer(): void {\n  if (reconnectTimer) {\n    clearTimeout(reconnectTimer);\n    reconnectTimer = null;\n  }\n}\n\nfunction teardownClient(): void {\n  if (client) {\n    try {\n      client.removeAllListeners();\n      client.end(true);\n    } catch {\n      // ignore teardown errors\n    }\n    client = null;\n  }\n}\n\nfunction scheduleReconnect(): void {\n  if (stopped || !isMQTTEnabled() || reconnectTimer) return;\n\n  if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {\n    console.warn(\n      `${LOG} giving up after ${reconnectAttempts} attempts; cooling down for ${\n        COOLDOWN_MS / 60_000\n      }m`\n    );\n    teardownClient();\n    status = \"disconnected\";\n    reconnectTimer = setTimeout(() => {\n      reconnectTimer = null;\n      reconnectAttempts = 0;\n      openConnection();\n    }, COOLDOWN_MS);\n    return;\n  }\n\n  const delay = Math.min(\n    RECONNECT_MAX_MS,\n    RECONNECT_BASE_MS * 2 ** reconnectAttempts\n  );\n  const jitter = Math.floor(Math.random() * 1_000);\n  reconnectAttempts += 1;\n\n  reconnectTimer = setTimeout(() => {\n    reconnectTimer = null;\n    openConnection();\n  }, delay + jitter);\n}\n\nfunction openConnection(): void {\n  if (stopped || !isMQTTEnabled()) return;\n\n  teardownClient();\n\n  const url = buildMQTTBrokerUrl();\n  status = \"connecting\";\n\n  const clientId = `stormcloud-vp-${Math.random().toString(36).slice(2, 9)}`;\n\n  try {\n    client = mqtt.connect(url, {\n      clientId,\n      username: mqttConfig.username,\n      password: mqttConfig.password,\n      keepalive: KEEPALIVE_SECONDS,\n      clean: true,\n      // Disable MQTT.js internal reconnect; we manage reconnection ourselves.\n      reconnectPeriod: 0,\n      connectTimeout: CONNECT_TIMEOUT_MS,\n      queueQoSZero: false,\n      reschedulePings: true,\n      // Root-cause fix for the Tizen 4.0 \"Keepalive timeout\" loop: MQTT.js's\n      // default timerVariant \"auto\" runs the keepalive interval inside a\n      // Blob-URL Web Worker (via worker-timers). On Samsung Tizen 4.0 (old\n      // WebKit) served from a file:// origin that worker can't tick reliably,\n      // so the keepalive counter trips onKeepaliveTimeout almost immediately\n      // after connect. Force the native setInterval timer instead; the main\n      // thread is free because video is decoded by the native AVPlay pipeline.\n      timerVariant: \"native\",\n    });\n  } catch (err) {\n    status = \"error\";\n    console.warn(`${LOG} connect() threw:`, err);\n    scheduleReconnect();\n    return;\n  }\n\n  client.on(\"connect\", () => {\n    status = \"connected\";\n    reconnectAttempts = 0;\n    clearReconnectTimer();\n    console.info(`${LOG} connected to ${url}`);\n  });\n\n  client.on(\"offline\", () => {\n    if (status === \"connected\") status = \"disconnected\";\n    console.warn(`${LOG} offline`);\n    scheduleReconnect();\n  });\n\n  client.on(\"error\", (err) => {\n    status = \"error\";\n    console.warn(`${LOG} error:`, err.message);\n    scheduleReconnect();\n  });\n\n  client.on(\"close\", () => {\n    if (status === \"connected\") status = \"disconnected\";\n    scheduleReconnect();\n  });\n}\n\nexport function initMQTTClient(): void {\n  if (client || !isMQTTEnabled()) return;\n  stopped = false;\n  reconnectAttempts = 0;\n  openConnection();\n}\n\nexport function ensureMQTTClient(): void {\n  if (isMQTTEnabled() && !client && !reconnectTimer) {\n    initMQTTClient();\n  }\n}\n\nexport function publishMQTT(\n  topic: string,\n  payload: Record<string, unknown>\n): boolean {\n  if (!isMQTTEnabled()) {\n    return false;\n  }\n\n  ensureMQTTClient();\n\n  if (!client || !client.connected) {\n    return false;\n  }\n\n  try {\n    client.publish(topic, JSON.stringify(payload), { qos: mqttConfig.qos });\n    return true;\n  } catch (err) {\n    console.warn(`${LOG} publish failed on ${topic}:`, err);\n    return false;\n  }\n}\n\nexport function disconnectMQTT(): void {\n  stopped = true;\n  clearReconnectTimer();\n  teardownClient();\n  reconnectAttempts = 0;\n  status = \"disconnected\";\n}\n","export interface VastEnvironmentSignals {\n  isCtv: boolean;\n  contentUrl?: string;\n  appId?: string;\n  appName?: string;\n  sessionId?: string;\n  deviceId?: string;\n  deviceIdType?: string;\n  limitAdTracking?: boolean;\n  deviceTypeHint?: number;\n}\n\nconst AIRY_ANDROID_APP_ID = \"com.freeairytv.android\";\nconst AIRY_WEBOS_APP_ID    = \"com.freeairytv.webos\";\nconst AIRY_TIZEN_APP_ID    = \"com.freeairytv.samsung\";\nconst AIRY_ROKU_APP_ID     = \"com.freeairytv.roku\";\nconst AIRY_APP_NAME = \"AiryTV Movies & TV\";\nconst AIRY_DEFAULT_CONTENT_URL = \"https://live.airy.tv\";\nconst CTV_SESSION_STORAGE_KEY = \"stormcloud.ctv.sid\";\nexport const PLAYER_ID_STORAGE_KEY = \"stormcloud.player.id\";\n\nconst LG_TEST_APP_ID      = \"com.hulu.plus\";\nconst LG_TEST_APP_NAME    = \"Hulu\";\nconst LG_TEST_CONTENT_URL = \"https://www.hulu.com/live-tv\";\n\nlet _lgTestDeviceId: string | undefined;\nfunction getLgTestDeviceId(): string {\n  if (!_lgTestDeviceId) _lgTestDeviceId = createUuid();\n  return _lgTestDeviceId;\n}\n\nfunction isLgWebOS(): boolean {\n  if (typeof navigator === \"undefined\") return false;\n  return /Web0S|webOS|LG Browser|LGSTB|LGE/i.test(navigator.userAgent);\n}\n\nfunction getDefaultAppId(): string {\n  if (typeof navigator === \"undefined\") return AIRY_ANDROID_APP_ID;\n  const ua = navigator.userAgent;\n  if (/Web0S|webOS|LG Browser|LGSTB|LGE/i.test(ua)) return AIRY_WEBOS_APP_ID;\n  if (/Tizen|Samsung/i.test(ua))                       return AIRY_TIZEN_APP_ID;\n  if (/Roku/i.test(ua))                                return AIRY_ROKU_APP_ID;\n  return AIRY_ANDROID_APP_ID;\n}\n\nconst DEVICE_ID_STORAGE_KEYS = [\n  \"rdid\",\n  \"ifa\",\n  \"advertisingId\",\n  \"advertising_id\",\n  \"deviceAdvertisingId\",\n  \"aaid\",\n  \"adid\",\n  \"rida\",\n  \"tifa\",\n  \"lgudid\",\n];\n\nconst ANDROID_ID_TYPES = new Set([\"aaid\", \"adid\"]);\n\nexport function resolveVastEnvironmentSignals(isCtv: boolean): VastEnvironmentSignals {\n  const bridgeSignals  = readNativeBridgeSignals();\n  const platformDevice = readPlatformNativeDeviceId();\n  const lg = isCtv && isLgWebOS();\n\n  const deviceId =\n    bridgeSignals.deviceId  ||\n    readStoredDeviceId()    ||\n    platformDevice.deviceId ||\n    (lg && platformDevice.limitAdTracking !== true ? getLgTestDeviceId() : undefined);\n  const deviceIdType =\n    bridgeSignals.deviceIdType  ||\n    readStoredString(\"deviceIdType\") ||\n    readStoredString(\"idtype\") ||\n    platformDevice.deviceIdType ||\n    inferDeviceIdType() ||\n    (lg ? \"lgudid\" : undefined);\n  const platformLat = bridgeSignals.deviceId\n    ? bridgeSignals.limitAdTracking\n    : platformDevice.limitAdTracking;\n  const limitAdTracking =\n    deviceId != null\n      ? platformLat ?? readStoredLimitAdTracking() ?? false\n      : undefined;\n\n  if (isCtv) {\n    return {\n      isCtv: true,\n      contentUrl:\n        bridgeSignals.contentUrl ||\n        readStoredString(\"contentUrl\") ||\n        (lg ? LG_TEST_CONTENT_URL : AIRY_DEFAULT_CONTENT_URL),\n      appId:\n        bridgeSignals.appId ||\n        readStoredString(\"appId\") ||\n        readStoredString(\"msid\") ||\n        (lg ? LG_TEST_APP_ID : getDefaultAppId()),\n      appName:\n        bridgeSignals.appName ||\n        readStoredString(\"appName\") ||\n        readStoredString(\"an\") ||\n        (lg ? LG_TEST_APP_NAME : AIRY_APP_NAME),\n      sessionId: getOrCreateCtvSessionId(),\n      ...(deviceId ? { deviceId } : {}),\n      ...(deviceIdType ? { deviceIdType } : {}),\n      ...(limitAdTracking != null ? { limitAdTracking } : {}),\n      deviceTypeHint: 5,\n    };\n  }\n\n  return {\n    isCtv: false,\n    ...(deviceId ? { deviceId } : {}),\n    ...(deviceIdType ? { deviceIdType } : {}),\n    ...(limitAdTracking != null ? { limitAdTracking } : {}),\n  };\n}\n\nexport function inferDeviceIdType(): string | undefined {\n  if (typeof navigator === \"undefined\") {\n    return undefined;\n  }\n\n  const ua = navigator.userAgent;\n  if (/Roku/i.test(ua)) return \"rida\";\n  if (/Tizen|Samsung/i.test(ua)) return \"tifa\";\n  if (/AppleTV|Apple TV/i.test(ua)) return \"tvOS\";\n  if (/AFT|Fire TV|Amazon/i.test(ua)) return \"afai\";\n  if (/Web0S|webOS|LG Browser|LGSTB|LGE/i.test(ua)) return \"lgudid\";\n  if (/Android|Google TV/i.test(ua)) return \"aaid\";\n  if (/iPhone|iPad|iPod/i.test(ua)) return \"idfa\";\n  return undefined;\n}\n\nexport function isEquivalentDeviceIdType(\n  tagType: string | undefined,\n  runtimeType: string | undefined\n): boolean {\n  if (!tagType || !runtimeType) return false;\n  const tag = tagType.toLowerCase();\n  const runtime = runtimeType.toLowerCase();\n  if (tag === runtime) return true;\n  return ANDROID_ID_TYPES.has(tag) && ANDROID_ID_TYPES.has(runtime);\n}\n\nexport function resolveNativeDeviceId(): string | undefined {\n  const bridgeSignals = readNativeBridgeSignals();\n  const platformDevice = readPlatformNativeDeviceId();\n  const deviceId =\n    bridgeSignals.deviceId ||\n    readStoredDeviceId() ||\n    platformDevice.deviceId;\n\n  if (!deviceId || isMacroPlaceholder(deviceId) || isZeroedAdId(deviceId)) {\n    return undefined;\n  }\n\n  return deviceId;\n}\n\nexport function getOrCreateStoredUuid(storageKey: string): string | undefined {\n  if (typeof window === \"undefined\") {\n    return undefined;\n  }\n\n  const existing = readPersistentId(storageKey);\n  if (existing) {\n    writePersistentId(storageKey, existing);\n    return existing;\n  }\n\n  const id = createUuid();\n  writePersistentId(storageKey, id);\n  return id;\n}\n\nfunction getOrCreateCtvSessionId(): string {\n  const existing = readPersistentId(CTV_SESSION_STORAGE_KEY);\n  if (existing) {\n    writePersistentId(CTV_SESSION_STORAGE_KEY, existing);\n    return existing;\n  }\n\n  const sessionId = createUuid();\n  writePersistentId(CTV_SESSION_STORAGE_KEY, sessionId);\n  return sessionId;\n}\n\nfunction readPersistentId(storageKey: string): string | undefined {\n  return readStoredString(storageKey) || readCookie(storageKey);\n}\n\nfunction writePersistentId(storageKey: string, value: string): void {\n  try {\n    window.localStorage?.setItem(storageKey, value);\n  } catch {}\n  writeCookie(storageKey, value);\n}\n\nconst PERSISTENT_ID_COOKIE_MAX_AGE = 60 * 60 * 24 * 365 * 5; // ~5 years\n\nfunction readCookie(name: string): string | undefined {\n  if (typeof document === \"undefined\") {\n    return undefined;\n  }\n\n  try {\n    const prefix = encodeURIComponent(name) + \"=\";\n    const parts = document.cookie ? document.cookie.split(\";\") : [];\n    for (const part of parts) {\n      const entry = part.trim();\n      if (entry.startsWith(prefix)) {\n        return decodeURIComponent(entry.slice(prefix.length)) || undefined;\n      }\n    }\n  } catch {}\n\n  return undefined;\n}\n\nfunction writeCookie(name: string, value: string): void {\n  if (typeof document === \"undefined\") {\n    return;\n  }\n\n  try {\n    document.cookie =\n      encodeURIComponent(name) +\n      \"=\" +\n      encodeURIComponent(value) +\n      \";path=/;max-age=\" +\n      PERSISTENT_ID_COOKIE_MAX_AGE +\n      \";SameSite=Lax\";\n  } catch {}\n}\n\nfunction createUuid(): string {\n  if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n    return crypto.randomUUID();\n  }\n\n  const bytes = new Uint8Array(16);\n  if (typeof crypto !== \"undefined\" && typeof crypto.getRandomValues === \"function\") {\n    crypto.getRandomValues(bytes);\n  } else {\n    let seed = Date.now() ^ Math.floor(performanceNow() * 1e3);\n    for (let i = 0; i < 16; i++) {\n      seed = (seed * 1103515245 + 12345) & 0x7fffffff;\n      bytes[i] = (seed ^ Math.floor(Math.random() * 256)) & 0xff;\n    }\n  }\n\n  bytes[6] = ((bytes[6] ?? 0) & 0x0f) | 0x40;\n  bytes[8] = ((bytes[8] ?? 0) & 0x3f) | 0x80;\n\n  let hex = \"\";\n  for (let i = 0; i < 16; i++) {\n    hex += (bytes[i] ?? 0).toString(16).padStart(2, \"0\");\n  }\n\n  return (\n    hex.slice(0, 8) +\n    \"-\" +\n    hex.slice(8, 12) +\n    \"-\" +\n    hex.slice(12, 16) +\n    \"-\" +\n    hex.slice(16, 20) +\n    \"-\" +\n    hex.slice(20, 32)\n  );\n}\n\nfunction performanceNow(): number {\n  try {\n    if (typeof performance !== \"undefined\" && typeof performance.now === \"function\") {\n      return performance.now();\n    }\n  } catch {}\n  return 0;\n}\n\nfunction readPlatformNativeDeviceId(): {\n  deviceId?: string;\n  deviceIdType?: string;\n  limitAdTracking?: boolean;\n} {\n  if (typeof window === \"undefined\") return {};\n\n  try {\n    const adinfo = (window as any).webapis?.adinfo;\n    if (adinfo) {\n      const tifa: unknown =\n        typeof adinfo.getTIFA === \"function\" ? adinfo.getTIFA() : adinfo.tifa;\n      if (typeof tifa === \"string\" && tifa && !isMacroPlaceholder(tifa)) {\n        const lat: unknown =\n          typeof adinfo.isLATEnabled === \"function\"\n            ? adinfo.isLATEnabled()\n            : undefined;\n        return {\n          deviceId: tifa,\n          deviceIdType: \"tifa\",\n          ...(typeof lat === \"boolean\" ? { limitAdTracking: lat } : {}),\n        };\n      }\n    }\n  } catch {}\n\n  try {\n    const webOSDev = (window as any).webOSDev;\n    if (webOSDev) {\n      const lgudid: unknown =\n        typeof webOSDev.LGUDID === \"function\"\n          ? webOSDev.LGUDID()\n          : webOSDev.lgudid ?? webOSDev.LGUDID;\n      if (typeof lgudid === \"string\" && lgudid) {\n        if (isZeroedAdId(lgudid)) {\n          return { deviceIdType: \"lgudid\", limitAdTracking: true };\n        }\n        if (!isMacroPlaceholder(lgudid)) {\n          return { deviceId: lgudid, deviceIdType: \"lgudid\", limitAdTracking: false };\n        }\n      }\n    }\n  } catch {}\n\n  try {\n    const roku = (window as any).Roku;\n    if (roku) {\n      const rida: unknown =\n        typeof roku.getPublisherUniqueId === \"function\"\n          ? roku.getPublisherUniqueId()\n          : roku.rida;\n      if (typeof rida === \"string\" && rida && !isMacroPlaceholder(rida)) {\n        return { deviceId: rida, deviceIdType: \"rida\", limitAdTracking: false };\n      }\n    }\n  } catch {}\n\n  return {};\n}\n\nconst ZEROED_AD_ID_PATTERNS: ReadonlySet<string> = new Set([\n  \"38400000-8cf0-11bd-b23e-10b96e40000d\",\n  \"00000000-0000-0000-0000-000000000000\",\n]);\n\nfunction isMacroPlaceholder(value: string): boolean {\n  const t = value.trim();\n  return !t ||\n    /^(\\[[^\\]]*\\]|\\{[^}]*\\}|%%[^%]*%%)$/.test(t) ||\n    /^(unknown|null|undefined|none|n\\/a|\\$\\{[^}]+\\})$/i.test(t) ||\n    ZEROED_AD_ID_PATTERNS.has(t.toLowerCase());\n}\n\nfunction isZeroedAdId(value: string): boolean {\n  return ZEROED_AD_ID_PATTERNS.has(value.trim().toLowerCase());\n}\n\nfunction readNativeBridgeSignals(): {\n  contentUrl?: string;\n  appId?: string;\n  appName?: string;\n  deviceId?: string;\n  deviceIdType?: string;\n  limitAdTracking?: boolean;\n} {\n  if (typeof window === \"undefined\") {\n    return {};\n  }\n\n  const candidates = [\n    (window as any).__STORMCLOUD_CTV_AD_INFO__,\n    (window as any).__STORMCLOUD_CTV__,\n    (window as any).stormcloudCtv,\n    (window as any).AiryTV,\n    (window as any).Android,\n    (window as any).webOS,\n    (window as any).tizen,\n    (window as any).amazon,\n  ].filter(Boolean);\n\n  for (const source of candidates) {\n    const contentUrl =\n      readBridgeValue(source, [\"contentUrl\", \"url\", \"videoUrl\", \"canonicalUrl\"]) ||\n      undefined;\n    const appId =\n      readBridgeValue(source, [\"appId\", \"msid\", \"applicationId\", \"packageName\"]) ||\n      undefined;\n    const appName =\n      readBridgeValue(source, [\"appName\", \"an\", \"applicationName\"]) || undefined;\n    const deviceId =\n      readBridgeValue(source, [\n        \"rdid\",\n        \"ifa\",\n        \"advertisingId\",\n        \"adId\",\n        \"deviceId\",\n        \"lgudid\",\n        \"LGUDID\",\n        \"tifa\",\n        \"rida\",\n        \"afai\",\n        \"aaid\",\n      ]) || undefined;\n\n    if (!contentUrl && !deviceId && !appId && !appName) continue;\n\n    const deviceIdType =\n      readBridgeValue(source, [\n        \"idtype\",\n        \"deviceIdType\",\n        \"advertisingIdType\",\n        \"idType\",\n      ]) || inferDeviceIdType();\n    const limitAdTracking = readBridgeBoolean(source, [\n      \"is_lat\",\n      \"limitAdTracking\",\n      \"limitedAdTracking\",\n      \"lat\",\n    ]);\n\n    return {\n      ...(contentUrl ? { contentUrl } : {}),\n      ...(appId ? { appId } : {}),\n      ...(appName ? { appName } : {}),\n      ...(deviceId ? { deviceId } : {}),\n      ...(deviceId && deviceIdType ? { deviceIdType } : {}),\n      ...(deviceId && limitAdTracking != null ? { limitAdTracking } : {}),\n    };\n  }\n\n  return {};\n}\n\nfunction readBridgeValue(source: any, keys: string[]): string | undefined {\n  for (const key of keys) {\n    const value = source?.[key];\n    if (typeof value === \"string\" && value) {\n      return value;\n    }\n    if (typeof value === \"function\") {\n      try {\n        const result = value.call(source);\n        if (typeof result === \"string\" && result) {\n          return result;\n        }\n      } catch {}\n    }\n  }\n  return undefined;\n}\n\nfunction readBridgeBoolean(source: any, keys: string[]): boolean | undefined {\n  for (const key of keys) {\n    const value = source?.[key];\n    const normalized = normalizeBoolean(value);\n    if (normalized != null) {\n      return normalized;\n    }\n    if (typeof value === \"function\") {\n      try {\n        const result = normalizeBoolean(value.call(source));\n        if (result != null) {\n          return result;\n        }\n      } catch {}\n    }\n  }\n  return undefined;\n}\n\nfunction readStoredDeviceId(): string | undefined {\n  for (const key of DEVICE_ID_STORAGE_KEYS) {\n    const value = readStoredString(key);\n    if (value) {\n      return value;\n    }\n  }\n  return undefined;\n}\n\nfunction readStoredString(key: string): string | undefined {\n  if (typeof window === \"undefined\") {\n    return undefined;\n  }\n\n  try {\n    const value = window.localStorage?.getItem(key);\n    return value || undefined;\n  } catch {\n    return undefined;\n  }\n}\n\nfunction readStoredLimitAdTracking(): boolean | undefined {\n  return normalizeBoolean(\n    readStoredString(\"limitAdTracking\") ||\n      readStoredString(\"limitedAdTracking\") ||\n      readStoredString(\"is_lat\")\n  );\n}\n\nfunction normalizeBoolean(value: unknown): boolean | undefined {\n  if (typeof value === \"boolean\") {\n    return value;\n  }\n  if (typeof value === \"number\") {\n    return value === 1;\n  }\n  if (typeof value === \"string\") {\n    const normalized = value.toLowerCase();\n    if (normalized === \"1\" || normalized === \"true\" || normalized === \"yes\") {\n      return true;\n    }\n    if (normalized === \"0\" || normalized === \"false\" || normalized === \"no\") {\n      return false;\n    }\n  }\n  return undefined;\n}\n"]}