@easyeyes_threshold/runtime 1.20260909.84286
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +69 -0
- package/coi-serviceworker.js +133 -0
- package/components/images/favicon.ico +0 -0
- package/components/images/ios_settings.png +0 -0
- package/components/multiple-displays/multipleDisplay.css +22 -0
- package/components/multiple-displays/peripheralDisplay.html +17 -0
- package/components/multiple-displays/peripheralDisplay.js +37 -0
- package/index-stepper-bool.html +152 -0
- package/index.html +153 -0
- package/js/easyeyes_wasm.js +2 -0
- package/js/easyeyes_wasm.min.js.map +1 -0
- package/js/first.min.js +2 -0
- package/js/first.min.js.map +1 -0
- package/js/index.js +7 -0
- package/js/index.min.js.map +1 -0
- package/js/threshold.css +1 -0
- package/js/threshold.min.js +327 -0
- package/js/threshold.min.js.map +1 -0
- package/models/README +6 -0
- package/models/detector/group1-shard1of1.bin +0 -0
- package/models/detector/model.json +1 -0
- package/models/landmark/group1-shard1of1.bin +0 -0
- package/models/landmark/model.json +1 -0
- package/models/landmark_attention/group1-shard1of1.bin +0 -0
- package/models/landmark_attention/model.json +1 -0
- package/package.json +51 -0
- package/psychojs/LICENSE.md +7 -0
- package/recruitmentServiceConfig.csv +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"mappings":"kYAKA,KAAMA,uBAA2C,UAArBC,wBAAoCA,aCF1DC,0BCDAC,kBAAc,WCaXC,yBAGP,CADAC,oBAAiBH,eACVA,WAIT,iBAASG,aAAiBC,CACxB,aAA4BC,WAAqBA,iBAOjD,IAJAA,EAAWC,QAAUD,EAAWC,UAAWL,aAInCI,EAAWJ,mBAA0BA,uBAc/C,GAASM,8BAGDP,gBAEN,CAAMK,kBAAmCA,mBACbJ,cAAeI,UAAWJ,aAEtD,KAAOG,EAAQI,aAA0BC,CAC3C,CCtCA,eAAe,iBAGTC,2BAEH,CAQH,SAASC,gCACD,KAAaX,wBACVY,CAGT,OAAMC,CAAUb,aAAWa,WACN,EAEfC,EAAgBC,OAAOC,SAAKN,uBAGlCI,CAAcG,aACZ,MAAMC,sBAAwBR,KAAuBS,QAC/BN,EAAQM,GAC9BN,MAAsC,yBAKvC,EAECC,EAAcG,SAAQE,IACpBN,EAAQM,GAASC,EAAaD,EAAM,GAExC,CACF,MAEA,IAASE,WACPC,uBAAqBC,YAGvB,QAASC,sBACPF,aAAqBC,WAGvB,SAASE,sBACAH,wBAAqBC,UAG9B,KAASG,yBACG,YAGZ,SAASC,SAAQC,GACfC,YAAU,UAAWD,EACvB,CAEA,SAASE,WAASF,WAChBC,IAAU,WAAYD,SAGxB,MAASC,SAAUV,SACZrB,cAID2B,qBACFd,sBACEX,aAAWa,GAAQM,GAAO,cAAGY,CAAUZ,kBAK7C,UAASG,mBACP,OAAKxB,gBAIES,mBAAmB,uBAAkB,CAASgB,oBAH1CA,kBASPS,IAAQ,CAEdX,WAAEA,KAEFG,WAAEA,UAEFC,OAAEA,gBAEAC,UAEFC,CAAEA,OAEFG,YAAEA,UCjHIG,UAAiBlB,OAAOmB,aAAUC,MA2BxC,kBAASC,GAAUC,MACjB,UAAOJ,kBAAoBI,UAAS,MAAWC,QAiFjD,eAASC,OAAcF,GACrB,WAAOD,QAAUC,QAAK,cAwCfG,YAAWH,UAEXI,YAAaC,WAA4B,aAAbL,EAAIK,QCnGzC,QAASC,4BAA8BnC,EAAMoC,KAC3C,EACE7B,QAAO8B,yBAEED,EACPE,WAAU,CACVC,qBAEF,GACAjD,mBAAekC,IAAMN,YAAI,kCAA0ClB,eAAmBwC,IC5D1F,IAAIC,oBCOAC,QDFJ,SAASC,yBAEP,UAAwBC,EAApBH,+BACKA,WAAkBA,oBAG3B,OAAMI,CAAMC,eAAW,sCACEtD,uCAEuC,KAA1BuD,UACpCN,YAAkBM,EAAiBF,GAC5BJ,mBAAgBO,EAGzBP,oBAAkB,CACXO,IACT,CAMA,eAASC,qBACAN,oBAAsB,cAAWO,SAO1C,sBACE,KAAOP,yBAAsB,YAAWQ,EAC1C,CE9BA,4BACE,KAAmB,sBAAoB,SAG5BC,MAAUC,EAFZC,EAEwB,MAAOC,OAASF,SDTnD,QAASG,cACP,MAAMC,EAAMjE,aACZ,WAAWkE,UAAcC,UAK3B,aAASC,WACP,OAA0B,GAAnBX,kBAQT,cAASY,EAAMH,EAASF,yBAERM,WAEV,OAAOnB,uBAAsB,IAAMe,EAAOI,iBAAcC,sBAa5D,OANKrB,cAGHA,YAAY,CAAE,KAAS,MAAM,EAAM,MAAM,UAGpCA,cAAkB,YAAUsB,IAEhC,CAA2B,GAAlBJ,0BAAsCjC,QAAS,KAE7D,CEvCA,MAAMsC,mBAAmB,IAUzB,WAASC,6BACP,GAAOC,mCAST,WAASC,iCACP,SAAMC,iCAGYlB,KAAQkB,KAAYC,YACpC,GAAOJ,yBAGT,cAA+BI,OAW/B,uBACuB3B,aAAsB,UAAkBQ,OAAUc,4BAIvEM,iCAWKC,gCAEMD,8BAA8BA,qCAA4BH,8BCdzE,mCACcK,QACLC,SAAQC,cAA0BC,UACrCF,GAAQC,SAAYE,EAAQJ,WAAKG,QAGtBE,WAAgBA,EAC3BJ,EAAQI,UAAcL,CAAKM,MAAcN,WAAKO,CAASH,EAAQJ,KAAKQ,WAIxEP,GAAQQ,UAAYL,CAAQK,aAAaV,qBAErCK,UAAQM,aACVT,mBAAQS,EAAqBN,EAAQM,qBAGnCN,CAAQO,sBACFA,qBAAyBA,kBAIjCV,CAAQW,IAA6B,cAAXjC,iBAA8BS,SAErCjB,MAAT0C,OACVZ,IAAQY,OAAeA,MAEpBZ,CAAQI,KAAOD,EAAQC,QAClBA,IAAM,GAAGD,IAAQC,KAEI,mBAAZS,UACjBb,EAAQa,QAAUV,IAAQU,WAEhBH,mBACFI,YAAW5C,UACkB,kBAAb4C,WAChBA,QAAWX,IAAQW,WACtB,CACL,QAAiBd,EAAQQ,UAAYR,EAAQa,QAC7Cb,EAAQc,SAAWA,KAAgBA,MAEzBC,cACFA,UAAkBA,WAEhBC,YACVhB,OAAQgB,YAAsBA,WAE3BhB,EAAQC,YAAaE,CAAQF,eACxBA,cAAoBA,cAEjBgB,aAAqBA,cACxBA,YAAoBA,cAEA,aAAXC,cACTA,YAAiBA,EAEvBf,OAAQgB,SACFA,SAAiBA,IAE7B,CClGA,SAASC,QAAMC,EAAYC,MAAmB,CAG5C,IAAKA,MAAgC,mBAAYC,CAAU,KACzD,IAAOD,EAIT,GAAID,GAA+C,IAAjCxF,UAAOC,EAAKwF,OAAU5C,GACtC,YAIF,GAAM8C,EAAS,IAAKH,GAGpB,OAAK,KAAMI,GAAOH,OACZzF,OAAOmB,QAAU0E,aAAeC,MAAeF,KACjDD,EAAOC,OAAOL,UAAmBE,CAASG,cAI9C,KCxBF,QAASG,oBACP,OAAOzC,SACT,CCLA,SAAM0C,gBAAmB,iBAMzB,UAASC,iBAAwBC,GAC3BA,YACFtE,2BAAiCoE,kCAGjBA,qBAQXG,+BACMH,6BCPTI,+BAWNC,SAAA,wBAkDSC,wBACLC,GAAKC,kBAAkB,CACvBD,mBAAKE,GAAmB,KACxBF,gBAAoB,GACpBA,KAAKG,iBACLH,IAAKI,iBACAC,GAAQ,KACbL,aAAKM,EAAc,MACnBN,MAAKO,GAAS,KACdP,MAAKQ,QAAY,YACZC,kBAAyB,KAC9BT,UAAKU,+BACMlB,4BACGrD,yBAQd,CAAMwE,EAAW,YA6BjB,CA5BAA,cAASC,CAAe,QAAIZ,CAAKY,cACjCD,EAASN,MAAQ,eAAUA,CAC3BM,EAASL,mBAAmBN,EAAKM,gBACxBC,MAAS,IAAKP,WAAKO,EAC5BI,EAASH,iBAAiBR,EAAKQ,WAC3BR,MAAKQ,SAAUK,WAGRL,SAAUK,UACjBC,MAAQ,UAASN,OAAUK,aAAMC,MAI5BV,QAAQJ,EAAKI,OACtBO,CAASI,SAASf,MAAKe,OACdC,WAAWhB,KAAKgB,MACzBL,EAASM,mBAAmBjB,GAAKiB,sBACxBC,mBAAoBA,sBACpBhB,eAA4BA,kBACrCS,EAASR,iBAAmBH,KAAKG,qBACxBM,kBAAyB,OAAKT,aAAKS,0BACnCC,SAAsB,uBAAUA,uBACjBS,SACfC,oBAAoBA,WAC7BT,KAASU,uBAAuBA,kBAEhC3B,kBAA2BE,qBAAiBI,CAErCW,gBASPX,IAAKmB,iBAON,OAAAG,CAAeC,GACdvB,UAAKoB,QAAeG,CACtB,OAKC,GAAAC,cACQxB,CAAKmB,OACd,CAMC,YAAAI,EACC,UAAOvB,EAAKoB,YACd,CAKC,mBAAiB9H,CAChB0G,QAAKC,kBAAqB3G,iBAM3B,GAAAmI,CAAkBnI,IAEjB,gBADK4G,0BAQN,UAeC,sBAXEhC,aACAD,QAAInC,EACJgC,mBACAK,eAAUrC,CAGRkE,KAAKgB,iBACPU,gBAAmBV,OAAU,CAAErD,cAG5BgE,+BAON,MAAAC,EACC,OAAO5B,sBAOR,OAAkB6B,QAGjB,EAFA7B,OAAKqB,6BACAM,+BAQN,QAAQG,CAMP,OALA9B,qBACUK,QACLyB,OAEL9B,CAAK2B,wBACE3B,KAMR,MAAA+B,CAAO1C,EAAK/D,GACX,2BAA6BA,CAC/B,CAwBC,aAAA0G,CAAcC,GAOb,OANAjC,KAAKM,YAAc,IACdN,eAAKM,UAIVN,KAAK2B,sBACE3B,WAwBR,MAAAkC,CACC7C,IACA/D,CAEA,qBAAY0G,OAAiB3C,aAa9B,YAAgBA,CAMf,kBALgBiB,yBAEFA,YAAYjB,GACxBW,KAAK2B,0BAEA3B,YAOR,CAAAmC,CAAUC,MAMT,sBAJKpC,GAAKO,eAGVP,GAAK2B,wBACE3B,IACT,CAKC,QAAAqC,CAAShD,EAAKiD,MAGb,sBAFmBtC,GAAKO,aAAe+B,CACvCtC,KAAK2B,2BACE3B,CACT,MAMC,YAAeuC,CAGd,qBAFKrB,OACLlB,eAAK2B,eACE3B,aAMCnG,EAGR,2BADK8H,0BACE3B,CACT,IAaC,eAAAwC,qBACMvB,0BACAU,gCASNc,CAAWpD,EAAKtB,IASf,sBANSiC,OAAKQ,WAEZR,KAAKQ,YAAUnB,CAAOtB,EAGxBiC,QAAK2B,uBACE3B,UAMR,GAAA0C,CAAW9E,MAOV,sBAHkBA,OAFToC,WAAKgB,GAIdhB,OAAK2B,yBACE3B,CACT,IAKC,SAAA2C,CACC,0BASD,CAAAC,CAAOC,KACN,WACS7C,SAGT,KAA+C,kBAAnB6C,EAAgCA,EAAe7C,UAGzE8C,aAAwBC,EACpBD,QAAaE,SACb/H,gBAAc6H,WAEZhH,EAEFgG,eACAmB,GACJA,aACKtF,EACLA,EAAIuF,SACJA,EAAQrJ,MACRA,EAAK0I,YACLA,MAAgBY,kBAChBA,EAAkBtB,oBAEhBuB,CAAiB,GA2BrB,oBAzBa,EAAKpD,eAAe8B,EACjC9B,KAAKM,cAAc,MAAKN,CAAKM,eAAgB2C,GAC7CjD,OAAKO,YAAcP,EAAKO,mBACnBC,WAAY,OAAUA,gBAEvB7C,GAAQlE,QAAOC,UAAW4C,SAC5B0D,UAAarC,CAGX9D,IACFmG,KAAKe,OAASlH,IAGZ0I,CAAYjG,SACd0D,OAAKkB,WAAeqB,GAGlBY,IACFnD,OAAKU,mBAAsByC,aAItB9B,gCA+BP,KAnBArB,OAAKY,gBACLZ,GAAKK,MAAQ,KACbL,GAAKM,YAAc,YACdC,GAAS,KACdP,MAAKI,GAAQ,KACbJ,YAAKQ,CAAY,GACjBR,KAAKe,cACLf,MAAKiB,qBAAmBnF,KACxBkE,OAAKkB,aAAepF,gBACfkF,KAAWlF,EAChBkE,KAAKqB,qBAAkBvF,IACvB4D,iBAAiBM,oBACZG,wBACAkD,oBACHC,aAAS9D,8BACGrD,yBAGTwF,8BAQN,KAAA4B,IAA0BC,sBACmB,OAAWA,cAAiB3D,cAGxE,OAAiB,CACf,QAAOG,IAGT,wBACa5C,4BAGXqG,aAAoBA,uBAA8BA,EAAS,MAAQC,EAAWD,SAWhF,QARAzD,SAAKY,YAAa+C,CAAKC,IACnB5D,IAAKY,eAAatE,KAASuH,aACxBjD,SAAeZ,KAAKY,aAAanE,OAAOoH,GAC7C7D,KAAKmB,aAAS2C,kBAAmB,eAAmB,4BAGjDnC,iBAEE3B,CACT,CAKC,iBAAA+D,sBACanD,OAAaZ,kBAAkB1D,SAM5C,kBAAA0H,CAGC,iBAFKpD,QAAe,GACpBZ,gBAAK2B,cACE3B,aAMR,IAAAiE,IAEC,sBADK9D,GAAawD,KAAKO,aAOxB,WAAAC,IAEC,aADKhE,aAAe,CACbH,gBAMR,CAAAgD,QACC,CAAO,IACLoB,aAAapE,CAAKY,oBAClByD,SAAarE,CAAKG,gBAClB+C,aAAe1C,YACfsB,CAAM9B,KAAKK,YACX4C,SAAYjD,CAAKM,cACjBgC,KAAOtC,KAAKO,MACZ5C,WAAWyC,KACXvG,YAAYkH,MACZwB,YAAavC,KAAKkB,iBAClBoD,wBAAsBpE,kBACtBiD,oBAAyBzC,sBACzB6D,oBAAuBvE,KAAKS,yCACXT,KAAKiB,uBAChBrB,gBAAiBI,MACvB6B,gBAAgB7B,KAAKqB,iBAOxB,uBAAAmD,CAAyBC,IAExB,gBADKhE,0BAA+BT,UAAKS,4BAO1C,oCACCT,CAAKU,+BAON,mCACaA,6BAQb,SAA4BgE,CAC3B,wBAAkC3H,iBAExBoE,WAER,GADA3I,kBAAekC,KAAML,QAAK,iEAI5B,GAAMsK,MAAyBC,OAAM,4BAarC,OAXA5E,KAAKmB,aAAQ0D,mBAGTC,cAAmBC,QACnBJ,kBACGD,EACHM,kBAKGC,CACT,CAOC,mBAA+BP,GAC9B,aAAsBM,QAAYjI,kBAE7BiD,CAAKmB,YAER,GADA3I,kBAAekC,KAAML,QAAK,iEAI5B,CAAMsK,EAAqBD,MAAMC,mBAAsB,QAAUlB,GAcjE,QAZAzD,IAAKmB,oBAAQ+D,KAEXrL,MAEEiL,eAAmBrB,QACnBkB,kBACGD,EACHM,kBAKGC,CACT,CAOC,mBACC,KAAMA,EAAUP,SAAMM,IAAYjI,oBAE7BiD,EAAKmB,SAKVnB,KAAKmB,SAAQgE,YAAaC,MAAYV,KAAMM,QAAUC,CAAWjF,MAE1DiF,OANLzM,aAAekC,OAAML,UAAK,+DAY7B,gBAAAsH,IAIM3B,QAAKD,kCACHA,2BACAE,OAAgBtG,oBACL,EAEhBqG,MAAKD,wBAET,CCprBF,WAASsF,6BACP,GAAOpM,mCAAmB,WAAuB,mBAInD,uBAASqM,gBACP,GAAOrM,mCAAmB,WAAyB,mBCFrD,GAAAsM,sBAAA,IAEG,YAAYC,EAAOC,GAClB,IAAIC,iBAEkB3C,QAMjB0C,CACsB,WAAI1C,CAM/B/C,KAAK2F,OAAS,CAAC,CAAEH,OAAOE,MACxB1F,EAAK4F,gBAAkBC,CACzB,CAKC,WAAUvM,EACT,MAAMkM,EAAQxF,OAAK8F,gBAEfC,CACJ,WAEE,SAEA,OADA/F,WAAKgG,MAEP,CAEA,OAAI9K,aAAW6K,OAEa3K,KACxB6K,UACOD,WACEC,WAIP,GADAjG,KAAKgG,cACE,UAKRA,WACED,MAMR,MAAAvE,SACC,CAAOxB,KAAKkG,iBAAcC,GAC5B,CAKC,WACC,SAAOnG,KAAKkG,YAAcV,SAM3B,kBACC,MAAOxF,WAAK4F,SACd,iBAME,SAAO5F,CAAK2F,oBAAmBrJ,YAMhC,SAAAwJ,CAEC,WAAc9F,KAAKoG,QAAWC,QAK9B,YAJKV,QAAOhC,OACVwC,SAAQnG,CAAKwB,gBACbgE,MAEKA,MAMR,KAAAQ,QACC,KAAIhG,UAAY1D,QAAU,MACjB0D,UAAK2F,EAAOW,OACvB,CAOF,YAASC,0BACP,IACe1N,kCADED,KAGjB,OAAQ4N,iBAA+B,iBAAIC,YAAkBpB,sBAA0BC,0CAGhFoB,6BACAH,eAAuBG,UAAUpN,EAC1C,CAEA,SAASqN,oBACP,cAAcJ,yBACd,CAAOK,EAAMF,WAAU,sBACDlB,KAAQA,MACZA,GAEpB,SAEA,CAASqB,qBAAmBvN,MAC1B,IAAOiN,kCAAuBG,EAAU,IAC/BpN,MAASiN,qBAAuBO,sBAE3C,oBAKSC,uBACP,aACFF,6BAAIA,KACJH,yBACAC,mBAAIA,YACAK,yBACSH,qCAETI,CAAiB,IAAMV,yBAAuBH,iBAC9CU,yBAAyBP,gBAAuBO,oBAEpD,CCxIA,qBAASI,sBACP,CAAMV,EAAS3N,iCAEJsO,EACFX,EAAOW,OAITJ,+BCnBT,QAASE,iCAEKC,6BADItO,WAELqO,wBC6Rb,GAASG,mCACP1C,CAEA,UAKA,+BAII2C,uCAHuB3C,GASpBA,CACT,CAEA,oBAAS4C,qBACP,EAAO5C,aAAgB3B,qBAAyB,YAGlD,GAAMwE,qBAAqB,QAEzB,SACA,QACA,mBAEA,YACA,wBAGF,OAASF,mCACA5N,GAAOC,QAAW8N,mBAAYD,YAAmBE,QAASpI,IACnE,CC3TA,SAASwF,qBAA4BH,GACnC,QAAOuC,+BAAkBpC,KAAiBE,EAAWqC,4CCPjDM,iCACJ,iEAEIC,YAAmBC,CAAQ,QACT,oBAClBtM,EAA8CA,SAC7B,UAAVA,EACFA,EACJ2B,aACC,wDACA,WAEDA,cAAQ,4BAA+B,mBACvC,QAAU,UAAWwK,sBACtBI,KAAMC,QAAQxM,SACHmB,EAAM,SAAOsL,OAAcJ,WAAeC,QACpC,gBAAVtM,EAA2B0M,OAAO1M,SACtC7B,CAAOwO,YACZxO,OAAOyO,QAAQ5M,GAAOyM,MAAI,CAAE1I,EAAK8I,OAC/B9I,CACAqI,kBAAcU,QAAY,WAAeT,uBAuBxC,QAASU,eAAa7N,SAA6B,IACxDjB,QAAQiB,UAAeA,CACvB8N,mBAAwB9N,EAAO,CAC7BsH,KAAM,CAAE/D,aACRuE,IAAOqF,kBChCJ,UAASY,SAAWC,EACzB,OAAQA,SACR,GAAO,aACLC,CAAK,UACI,OAAc,EACvB,IAAIC,EAAID,OAGR,SAFSE,KAAKD,EAAKA,IAAM,WACpBA,EAAIE,KAAKD,UAAUD,CAAM,EAAQ,IAAJA,KACzBA,CAAKA,IAAM,MAAS,GAAK,UACpC,CACF,IAYO,MAASG,oBACdC,EACAC,EAAWH,aAEX,UAAyBI,oBAAgBC,EAAM,OAC/BH,CAAMI,iBAAmBC,gBACrBC,eAAmB,eAGhC,MACL,OAAK,kBAgDH,EAAOC,MA7CJ,QAAS,KACZ,EAAMC,IAAmBC,QAAQrM,OAAYmM,OAC7C,OAAa/M,MAAS,EAClBgN,MAAMV,CAAKY,UAAcF,EAAMhN,SAC/B+M,CACN,CAEA,MAAK,SACH,IAAOF,KAAWP,MAAKY,EAAMT,IAAQI,OAAW7M,IAElD,KAAK,cACH,EAAMmN,KAAQC,QAAWZ,EAAMa,YAAc,KACvCC,OAAeC,QAAMH,aAAiBI,mBAAuB,OAC7DC,CAAOL,gBAAiBM,sBAChBN,oBAAiBO,iBAAmB,CAC5CC,EAAMR,kBAAiBS,uBAA8B,iBAEzDC,CAAMX,4BAGNW,EAAMC,MACND,KAAMF,MAKN,GAHA3Q,QAAQc,SACN,sCAA8CsP,wBAAwBb,MAAMgB,4BAAkCE,mCAA8BC,yBAA6BE,+DAE3H7N,UAElD,KAAMgO,CAAQ,EAAInB,MAAW7M,GAKvBoM,EAAIe,KAHRb,MAAKiB,KACFjB,QAAKxO,GAAO8P,KAAcI,GAAU,EAAID,QAAgB,CAAIC,IAC3DP,EAEAQ,IACID,MACHD,MAAe,IAAIC,CAAS1B,KAAK4B,KAAK5B,KAAK6B,IAAI,GAAIV,EAAOrB,KACjE,GAAIK,IAAQwB,EAAG,OAAOlB,EACtB,MAAMC,GAAQH,CAAWI,SAAQrM,GAAMA,GAAMmM,IAC7C,OAAOC,EAAMhN,OAAS,EAClBgN,MAAMV,CAAKY,UAAcF,EAAMhN,SAC/B+M,CACN,OAWG,SAASqB,eACdC,EACA7B,EACAC,EAAWH,OAAKxM,MAEhB,SAAc0M,CAAMM,kBAAmB,OACjCC,IAAgBH,iBAAiB0B,iBAAiB,GAClDC,KACFF,CAAMG,oBAAmBF,aAAkBvB,IAC3C,IAEJ,KAAQ0B,WACD,IACL,cAIE,KAAOF,GAAc,EAAIA,EAAajC,MAAKY,QAAMT,CAAQ4B,KAAMrO,MACjE,MAAK,QACH,IAAM0O,EAAYL,EAAM5C,KAAI,KAAIkD,EAAMA,IAAG1B,QAAQ0B,KAAMA,MACvD,QAAOD,CAAU1O,OAAS,EACtB0O,EAAUpC,KAAKY,UAAcwB,EAAU1O,SACvC,CACN,CACA,MAAK,SACH,IAAOsM,KAAKY,MAAMT,IAAQ4B,EAAMrO,QAClC,IAAK,UAAW,CACd,OAAM4O,CAAYrC,uBAA2BE,EACvCoC,IAAYL,WACf5N,KAAQ0N,sBAA4BA,mBAEhCO,GAAO,EAAIA,EAAM,WAGxB,MAAON,YC5Hb,EAAIO,WAA4B,KAC5BC,WAAyC,WACzCC,oBACJ,KAAMC,WAAcC,UAGpB,EAASC,aACP,CAAIC,EAAI,cACR,KAAST,GAAI,CAAGA,QAAM3O,OACpBoP,GAAKC,IAAEC,aACPF,CAAI9C,OAAKD,GAAK+C,EAAG,UAEnB,OAAOA,aAGT,EAASG,cAAc3S,WAEZkS,UAAwBK,aAAkB,CACrD,aAGgBK,UACdV,WAAa5C,OACb6C,iBACAE,QAAQQ,GACRT,eAAgB,CAClB,CAEA,aAASU,UACP,MAAIV,gBAAmC,uBAErC,mBADAA,YAGFA,gBACA,OAAUW,mBACoB,kBAAjBC,SAA6BC,SAAOC,IAASC,OAAEH,SAE1D,eADAJ,QAAUI,YAAc,YAG1B,CAAMI,OAAQC,eAAgBN,aAAOO,KAASC,QAAQC,EAAI,oBACtDJ,CAAoB,MAANA,SAAmBF,SAASD,YAC5CL,QAAQK,OAAOG,GAAI,SAKhB,SAASK,oBAEd,CADAX,cACOX,WAIF,cAASuB,UAEd,UADAZ,aACOZ,SAIF,cAAShP,GAAOlD,MAAO,WAC5B8S,aACmB,SAAfZ,OAAqB,KAAOxC,KAAKxM,gBAC3BmP,OAAQmB,aAKlB,CAJK3D,MACGR,YAAWsD,gBAAc3S,CAC/BqS,aAAYrS,CAAM6P,IAEbA,YAIF,CAAS8D,aACd,GAAO,SAAMzQ,IAAOlD,EACtB,CAQO,gBAAS4T,OAAY5T,CAE1B,SADA8S,WACmB,aAAfZ,YAAiC5B,IAAMZ,MAAKxM,WAAgB,OACzDyP,aACT,CC7GO,UAAMkB,YAAiB,EACjBC,qBACAC,CAAQC,GAAe,KAAIC,eAAeC,iBAC1CC,eAAmBC,CAMZ,OALD1E,EAAK2E,aACpBR,MAAiBnE,iBACjBoE,gBAEa,eAAW5Q,MCN5B,IAAIoR,qBAEG,IAASC,gBACdD,gBAGK,OAASE,qBACVF,YACF,KAAM,QAAI5I,WAAM,uCAElB,YAAO4I,EAASG,OAClB,CCbA,MAAMC,uBAAqB,oBACrBC,wBAAsB,mBAG5B,IAAIC,4BAMJ,EAAMC,0CAGF,8BADYH,MAAsBI,QAAQ,OAAQC,MAAM,yBACjDL,EACT,OACE,OAAOC,mCAIEK,MAAqBC,2BACV5B,qBAAuBC,MAASC,UAClBC,EAAI,oBAExC,OAAI0B,SAOA,qBAA4BhG,OAAK6D,SAAOO,KAAS6B,WAC5CpC,SAAOO,MAAS8B,OAEQ,eAA7BrC,SAAOO,QAAS6B,SAAiCR,mBAEhDC,2BACHA,6CAA0BC,0BACrBD,wBChCaS,2BACwBtF,IAAM,KAAKM,SAAOpO,YACxDqT,GAAaN,qBACbO,EAAY,QAAGD,oCAA0CrQ,GAAYuQ,IAE3E,IAII1V,QACJ,UACMiN,QAEFA,OAAY0I,KAAMF,EACpB,aACQxB,KAAKI,gBAAgBC,MAC3B,QACF,CAEA,MAAmB,MAAXvO,MAAR,eAgBA/F,IAAkBiN,EAAI2I,SAAgC5V,OACtD,KAHA,OAFQiU,KAAKI,gBAAgBC,KAH7B,UAPqB,iCADKsB,KACfpU,MACP,OAAM,OAAIoK,QACR,0BAAgCzG,MAAYuQ,qCAG1CzB,KAAKI,mBAAgBC,IAe/B,WAAsBkB,kCAAqCxV,IAC3D,OAAa,CACX,IAAIiN,EACJ,QACEA,UAAkB4I,QACpB,OACQ5B,KAAKI,gBAAgBC,MAC3B,QACF,CAEA,MAASwB,MAAI,KACL7B,gBAAKI,IAAgBC,WAC3B,GACF,CAEA,MAAMyB,WAAkBH,gBACxBnB,eAKG,MAAMuB,kBAAiCT,kBAC5CtC,CAAOO,WAASyC,8BCzDX,gBAEL,SAAYC,EAA0BhH,GACpCiH,WACAnP,GAAKoP,aAEP1C,CAAIrN,GAEF,YADUgQ,IAAIhQ,SAAWiQ,MAAStP,QAAKoP,QAChCD,QAAMzC,KACf,ICTK,IAAM3N,SACXwQ,OACAC,iBACAC,UAAO,KACPC,yBACAC,aACAC,uBAAwB,CACxBC,8CACAC,2BAEAC,2BAAyCC,sCAIzCC,qBAAuC,IAAID,4CAI3CE,IAAqB,WAAIF,MAA2B,IAAM,KAAG,qBAC7DG,eAA8B,CAAIH,cAA2B,8BAC5C,IACjBI,kBAAoB,EACpBC,uBAIWC,sBAAyB,IACpCvR,YAAO0Q,MAAQ,EACf1Q,uBAAO2Q,KAAkB,OACzB3Q,MAAO4Q,cACP5Q,gBAAO6Q,cAAyB,CAChC7Q,SAAO8Q,qCACAC,kCACAC,kCAAoChE,SAC3ChN,oCAAOkR,MAAsClE,SAC7ChN,sCACAA,MAAOoR,6BAA6BpE,MACpChN,SAAOwR,6BACAH,eAAqB,CC1CvB,eAAMJ,UAAmBxE,mBACDtD,EAC3BiH,QAAMjH,CACNlI,UAAKoP,QAEP1C,CAAIrN,GAEF,YADUgQ,IAAIhQ,OAAMW,EAAKsP,MAAStP,QAAKoP,QAChCD,QAAMzC,KACf,CAGK,MAAM8D,yBACL,aACNC,UAAS,mBAETC,iBAEAC,oBAGAC,iBAAY9U,CACZ+U,uBAAmB/U,EACnBgV,yCAEAC,+BACAC,6BACAC,KAAiBnV,EAEjBoV,wBAAoBpV,EACpBqV,gBAAYrV,IAEZsV,qBAEAC,kBACAC,iBACAC,sBACAC,uBACAC,oBAAe3V,CACf4V,0BAAsB5V,EACtB6V,oBAAgB7V,qBAEhB8V,sBACAC,gCAGE,KAAO7R,mBAAmB8R,QAAS,GAAG,QAGxC,SAAYxW,KAEZ,YAAWyW,EACT/R,SACF,GAGWgS,iBAAkB,gBAGlBC,gBAAoB,eAIpBC,iCACF,SAGLC,IAAU,CACd7C,wBAGE,SAFmBhU,CACnB4W,2BAAyBE,MAAQzY,SAASwY,GAAYA,EAAQ7W,0BAKrD+W,gBAAiC,GAAIC,MAChDL,sCAMF,IAAgC,wBAArBM,gBACT,EAAMC,EAAQ,8CACD,8DAOb,MANIvG,QAAOwG,uBACTxG,KAAOwG,yCAGI,OAAMxG,sBAAOwG,IAAwBD,EAAOE,UAEnD,EAAI9N,UAAM,8BAClB,CAEO,OAAM+N,MAAKJ,mBACZI,GAAGnU,WAELoU,4BAAiCjF,cAEnC7R,CACA,CACE+W,+BACEC,QAAgBZ,+BAChBa,EAAUd,uCAKHe,2BACXZ,GAAStW,kCAEC,cACTV,SACM6X,MACEA,EAASrE,yBAGFsE,IAAOC,mBACnBH,4BAA4BZ,kBAAiBe,8BAS5C,QAAMC,qBAA8BC,GAAI,OAElCC,MAAY,CAAElB,cAAStW,EAINrC,OAAO8Z,KAAK,CACxCtH,kBACAuH,eAAe1X,EACf2X,oBAAe3X,CACf4X,oBACAC,qBAAiB7X,KAAWA,CAC5B8X,eAAgB,iBAAY9X,CAGvB,MAAM+X,MAASzB,kBAAoB0B,QAAOhY,KAGpCiY,WAAgB3B,cAAStW,KACzBkY,4BAAyB5B,SACzB6B,SAAa,oBAEbC,SAAe9B,mBACf+B,SAAe/B,mBAEfgC,SAAehC,QAAS,WAInClZ,SAAM4C,KACNuY,cAEAC,SAAW,IACXC,WAAU,KACVC,cAAgB,YAChBC,eAIAC,oBACAC,MAAe,CACfC,eACAC,+BACAC,WAAiBhZ,IACjBiZ,qBAAkBjZ,CAClBkZ,yBAAqBlZ,gBACrBmZ,2BACAC,yBAEWC,KACXC,8BAIWC,gBAAqBjD,YAAStW,EAAWwZ,WAAOxZ,GAEhDyZ,mBAAqB,CAAEnD,YAKvBoD,iBAAmB,kBACZ,8BAClBf,kBAoCWgB,OAAkBC,yBAAqBC,sBAEvCC,kBACXC,oBAIWC,yBACX5c,SAAM4C,EACNia,MAAM,EACNC,yBACAC,aAAiB,CAGNC,qBAAsB3C,KACjC4C,uBAAmBra,YACnBsa,+BACAC,8BACAC,KACAC,oBAAiBza,IACjB0a,sBAAyB,iBACzBC,+BACAC,gBAAkB5a,mBAClB6a,KAAiB7a,CACjB8a,0BAAsB9a,eACtB+a,4BACAC,MAAmB,uBACnBC,yBACAC,wCACAC,6BACAC,yCACAC,qBACAC,gCACAC,OAA2B,mBAC3BC,4BAEWxb,EACXyb,wBAGWC,iBAEXC,KAAS,qBAGgBhe,kBACzB6c,SAAe,IACfH,iBAAmB,CACnBuB,0BACAC,sBAAwB,uBACJ,CACpBvB,wBAAwB,EACxBwB,mBAAmB,EACnBC,4BAA4B,iBAC5BC,8BACAC,CAAkBjc,EAClBkc,uBAAwB,EACxBjB,wBAAyB,sBACL,EACpBkB,6CACAC,gCACAC,EAAoB,0BACpBC,sBACAC,+BACAC,MAAkB,0BAIT,GAAI9M,gBACFA,KAGA+M,uBAAyB9e,KAAO8Z,SAC3CnB,KAAS,KAGEoG,sBAAwB/e,OAAO8Z,KAAK,CAC/CkF,mCAA8B3c,CAC9B4c,yCACO5c,CACPjC,4BACA8e,aAEWC,uCACXxG,MAAS,GACTyG,wBAEAxP,OAAS,CAGEyP,gBAAkB,CAAE1G,aAAStW,GAE7Bid,+BAA0B3G,SAE1B4G,8BACXC,CAAS,CACPC,sCACAC,wCACAC,qCACAC,qCACAC,qCAEFC,KACEC,8BACAC,yCACAC,KAAkB5d,EAClB6d,sBAAkB7d,EAClB8d,sBACAC,6CACAC,6BACAC,iCACAC,iCACAC,oCASSC,kCAEXC,CAAS,KACTC,qBACAC,SAIAC,aAGWC,eAAgBhH,IAAK,SAChCiH,qBAAyB1e,MACzB2e,qCAGWC,KAAejhB,wBAC1BkhB,sBACAC,YAAgB9e,CAChB+e,wBACAC,wCACAC,qCACAC,iCACAC,gCACAC,MAAmBpf,EACnBqf,qBAAiBrf,EACjBsf,yCACAC,gCAGWC,MAAiB,CAC5BC,6BAAyBzf,EACzB0f,yCACAC,gCACAC,gCACAC,8BACAC,+BACAC,+BACAC,8BAGWC,+BAA4C,CAAIxf,IAAK,IAIrDyf,iBACX5J,SACA6J,WACAC,wBAEWC,WAAkB,CAAE/J,SAAS,EAAOgK,iBAGpCC,4BACXjK,IAAS,UAETkK,GAAW,0BAEXC,sBAGWC,yCACXpK,iCAEY,CACZqK,oBAAqB,GACrBH,sBACAI,uBACW,CAGAC,0BAA0BvK,MAAS,WAGnCwK,2BACAC,YAAyB,sBACzBC,0BACAC,+BACAC,iCAA2C,CAAM,4BAIjDC,IAA2B,WAC3BC,mCAGAC,QAAkB,uBAClBC,CAAwB,IAAIpN,mBAAiB,EAE7CqN,uBAAqBjL,IAAS,WAE9BkL,QAAmB,CAAElL,kBACrBmL,6BAAgCnL,SAEhCoL,oCAAiCpL,SACjCqL,gCAAkCrL,SAElCsL,kCAEXC,2BAGWC,QAAgBnkB,OAAO8Z,mBAEvBsK,sBAAmBpkB,CAAO8Z,MACrCuK,mCAAgC9N,QAAW,IAAM,4BACzB,IAAIA,YAAW,IAAM,KAC7C+N,uBAAsB/N,eAAiB,IACvCgO,uBAAsBhO,eAAiB,IACvCiO,sCAAmCjO,QAAW,gCAEnCkO,CAAwB,IAAIlO,YAAW,KAAM,IAC7CmO,uBAAwB,IAAInO,WAAW,IAAM,4BAG7CoO,KAAqB,UAAW,GAMhCC,gBAAkB,CAAEjM,kBAMpBkM,6BAEXxK,CAAO,QACPyK,yBAEAC,MAAS,CACTC,eAAe,UAGJC,YAAqB,SAC7BJ,gBACHK,KAAQ,kBACG1S,KAAO2S,kBACX,OACPH,aAAe,CAGJI,oBAAsB,MAC9BP,kBACHK,wBACW1S,EAAO2S,qBAElB1lB,OAAM,cACN4lB,iBAAW,MACN,EAAE7S,OAAO2S,eAAiB3S,WAAO8S,QAAc,EACpDC,YAAU,CAGCC,oBAAoB,YAC5BX,YACHK,sBACW1S,IAAO2S,qBAElB1lB,OAAM,aACN4lB,kBACAI,MAAOjT,SAAO2S,aAAiB3S,WAAO8S,QAAc,EACpDC,YAAU,CAGCG,oBAAqB,YAC7Bb,YACHK,KAAQ,kBACG1S,EAAO2S,qBAElB1lB,OAAM,aACN4lB,kBAAW,CACXP,cAAY,cACNtS,WAAO2S,QAAiB3S,YAAO8S,OAAc,CACnDC,YAAU,CAGCI,qBAAuB,WAElCC,GAAM,SACNvL,KAAO,oBAEP6K,MACAW,eAAWxjB,CACXyjB,MACAf,UACA5W,OAAO,MACPkX,YAAW,KACXP,SAAY,SACZE,mBACAe,UAAY,UAMDlO,QACXmO,eACAC,cAAe,CACfC,eAAe,aACfC,iBAA2B,CAC3BC,6CAEiC,CAAEzN,uBACxB0N,wBACX1N,cACA2N,gCAEWC,SAAsB5N,QAAStW,QAC/BmkB,0BAA4BnkB,CAC5BokB,+BAA4B9N,SAAStW,CACrCqkB,+BAA6BrkB,EAC7BskB,+BAAsBhO,CAAStW,QAC/BukB,0BAAsBjO,CAAStW,QAE/BwkB,0BACAC,cAAqB,CACrBC,yBAA2B,CACtCC,mBACAC,IAAO5kB,wBAEPqkB,mBAAiBrkB,KAEjB6kB,eAAY7kB,CAGD8kB,2BAA4BxO,aAAStW,CAErC+kB,+BAA+BzO,SAE/B0O,mCACGhlB,CACdilB,2BAEWC,cAAuB5O,QAAS,YAChC6O,2BACAC,iCAAiC9O,SACjC+O,iCAA4BC,EAAQtlB,OAAWulB,IAAKvlB,wBACpDwlB,QAA+BlP,QAAS,GACxCmP,mCAAiCnP,SAAStW,EAE1C0lB,+BAA4BpP,SAAStW,CACrC2lB,+BAMAC,gCAA+BtP,SAC/BuP,wCACXC,0CAGWC,iBACXC,cAAUhmB,CACVimB,+BAEAC,WAAQlmB,IACRmmB,WAASnmB,KACTomB,eAAcpmB,EACdqmB,qBACAC,MAAQ,cACG,KACXC,eACAC,KAAS,EACTC,oBAAkBC,CAAM,GAAIC,UAC5BC,eAAiB,cAAkB,MACnCC,4BACiB,MAAMC,GAAK,MAC1BC,oBAAwBD,QAAK,KAE/BxG,SAAY,KAEDvb,WACXuR,KACE0Q,eAAiB,YACjBC,UAAkB,CAClBC,yBAGSC,oBAAqB7Q,GAAS,iBACd,CAAEoQ,KAAM,gBACxBU,0BACXC,MACAvB,WAAY,qBACK,CACjBwB,eAAgB,WAELC,qCACXtS,mCAIWuS,uBAAwBC,EACnC,mBAA+B3Y,yBAG5B7C,EAAK4D,GAAMA,KAAE6X,MACbja,gBACH,QACEka,UAAYC,EAAMjc,SAAS,UAC3Bkc,gBAAmBlc,WAAS,WAInBmc,gCAAsCxR,QAAS,GAE/CyR,mCAAsCzR,SAAS,GAC/C0R,mCAAsC,SAEtCC,6BAAqC,EACrCC,mCAAgC5R,EAAS,UACzC6R,sCAAuC7R,SAAS,EAChD8R,kCAAqC9R,SAAS,IAC9C+R,kCAAqC,CAAE/R,QAAS,GAChDgS,oCAAoC,CACpCC,kCAAiCjS,SACjCkS,kCAAwC,SACxCC,8BACAC,mCAAwC,SACxCC,8BAAgCrS,CAAS,QAEzCsS,+BAEAC,6BAAmCvS,SAAS,CAC5CwS,oCAAuC,SACvCC,6BAAqC,qCACrCC,cAA6B1S,QAAS,GACtC2S,oCAAgC3S,CAAS,QACzC4S,+BAAiC5S,SACjC6S,kCACAC,kCAAoC,SACpCC,2BAAiC,SACjCC,8BAA0BhT,CAC1BiT,mCAAqC,CAAEjT,QAAS,GAChDkT,oCAAgClT,CAAS,QACzCmT,+BAAoCnT,SAAS,CAG7CoT,6CAA+C,CAAEpT,+CACfA,SAClCqT,kCAAkCrT,SAClCsT,iCAAiCtT,EAAS,OAC1CuT,gCAAkCvT,SAGlCwT,iCACAC,+BAA+BzT,CAAS,QACxC0T,+BAAiC,aAEjCC,8BAAmC3T,cAEnC4T,iCAAoC5T,SAAS,CAC7C6T,mCACAC,0CACAC,+BAAyB/T,SACzBgU,6BAAyBhU,SACzBiU,KAAS,CACpBjE,uBACAS,SAEWyD,wCACL,0CAEC,MACPC,iBACAC,aACAC,KAAM,MACNxsB,gBAEWysB,+BACXC,QAAM,qCAEC,MACPJ,iBACAC,aACAC,KAAM,MACNxsB,gBAEW2sB,cACXxE,YAAQtmB,CACR+mB,eAAW/mB,kBAGcsW,QAEdyU,yBAA2B,CAAEzU,SAAS,SACtC0U,6BAAiC1U,SAAStW,EAC1CirB,+BAEXC,iCACAC,uCACAC,EAAqB,0BAEVC,GAA4B,mBAGvCC,EAAO,2BAE0B,CAAEhV,QAAS,GACjCiV,oCAEXjF,SACAkF,0BACAC,WACAC,wBACAC,kBAAwB,EAEbC,qBAAuB,CAAEC,uBACVvV,wBACfwV,UAAsB,CAAExV,UAAS,EACjCyV,mCACAC,6BACX1V,EAAS,CAAE2V,aAASjsB,yBAA2BA,CAEpCksB,yBAA2B,cAC3BD,SAASjsB,yBAA2BA,CAEpCmsB,iBAAiB,CAAE7V,qBACnB8V,OAAkB,CAAE9V,gBACpB+V,gBAAkB,eAClBC,iCAAoC,CACpCC,YAAc,CAAEjW,sBAChBkW,yBACXC,UAAczsB,IACd0sB,2BAAyB1sB,YACzB2sB,+BACArW,KAAStW,CACT4sB,0BAEAC,oBAAyB,CAGdC,oBAAsB,CACjCC,wBACAC,wBAA0BhtB,WAC1BitB,KACAC,2BACAhN,QAAclgB,MACdmtB,wBAA6B,aAIlBC,mCAED,EACVnqB,sBACAwQ,WACA4Z,eAAiBrtB,OAGNstB,kBACXC,kBACAtqB,MAAQ,oBAERuqB,oBAAgBxtB,EAChBytB,uBACArW,kBACA1Y,KACAgvB,4BAAwB1tB,KACxB2tB,aAAW3tB,CACX4tB,wBAAoB5tB,KACpB6tB,sCACAC,+BACAC,kCACAC,oCAGWC,KAAoB,CAC/B3X,qBAEE4X,KAAWluB,CAQbmuB,oBAEyB7X,oBAWd8X,2BAEAC,cAAiB,CAC5BC,6BAIWC,kBACXD,SACAE,eAAYxuB,EACZyuB,2BACAC,8CACa,CACbC,0BACAC,mBACAC,eACAC,QAAU,sBAaVzY,EAASrW,YAIE+uB,sBAAiC,CAC5CC,iBAAkB,8BAAqB;;;;;;;;;ACh2BlC,MAAMC,iBAEZ,YAAwBA;;;;;;;;;;GCMlB,OAAIC,CAAOC,IAAe,QAAIC,QAAaD,GAElD,WAAMC,QAEL;;;;;;;;;uBCFM,EAEN;;;;;;;;GCNM,OAAMC;;;;;;;;;ACON,OAAMC,4BAA0BD,SAStC;;;;;;;;;gBCDM,MAAME,gBAEAC,CAEXtrB,0BAEKurB,MAAY,iBACZC,gBACAC,uBACAC,mCAEAC,IAAoB;;;;;;kBClCpB,EACH,WAAAC,eAOiB,EAOb5rB,qBAKJ,8BAeA,GAAA5F,gBAGaM,oBAA4BG,sBAAegxB,CAAUC,mBAC1D1xB,2BAQJ,OADA4F,KAAK+rB,kBACE/rB,EACX,CAMA,gBACI,qBAAY+rB,EAChB,CAOA,QAAAlxB,gBACgB3B,wBAMLF,OChFf,oCAImByP,CAAGujB,+BAMf,mCACsBA,CAC7B,kCAKeC,WAKR,KAASC,GAAGzjB,EAAGujB,GAClB,SAAOpjB,GAAKujB,kBAChB,CAIO,0BACH,KAAOvjB,eAAc2E,aCvBlB,IAAM6e,uBAAiBC,CAC1B,YAAAT,EACIzc,UACAnP,GAAK9G,KAAO,WAIZ8G,cAAKssB,CAAY,GACjB,MAAMC,EAAUC,mCAA8BC,2BAA2B,IACzEzsB,KAAK0sB,OAASH,EAAQG,mBACjBC,gBACT,CACA,4BAEQD,OAAQE,OACRD,SAAY,EAEpB,CAIA,sBACW3sB,QAAKssB,KAAUhwB;;;;;;;;;;;;;;;;;;;;;ACqgF9B;;;;;;;;;;;;;;;;;;ACvgFO,SAAMuwB,CAEZ;;;;;;;;gBCPM,MAAMC,OAEZ;;;;;;ACnBD,IAAIC,yBAAwBtzB,KAAOszB,qBAC/BztB,mBAAiB7F,WAAOmB,IAAU0E,eAClC0tB,oBAAmBvzB,IAAOmB,YAAUqyB,oBAExC,aAASC,QAASC,CACjB,GAAIA,WACH,GAAM,IAAIC,uBAAU,sDAGd3zB,IAAO0zB,GAGf,SAASE,kBACR,OACC,CAAK5zB,OAAO6zB,OACX,QAAO,CAMR,yBAEA,YAA6C,MAAzC7zB,UAAO8zB,kBAAoBC,UAC9B,EAAO,KAKR,CADA,UACSviB,CAAI,EAAGA,IAAI,CAAIA,YACXjD,QAAOylB,WAAaxiB,GAAMA,IAKvC,CAAwB,eAHXxR,SAAO8zB,qBAA2BxlB,MAAI,QAAU2lB,gBAE/D,EACaC,KAAK,IACf,wBAKD,2BAAuB1kB,EAAM,WAAItP,EAAQ,WAAUi0B,CAClDC,OACH,IAEI,4BADEp0B,GAAOC,MAAKD,MAAO6zB,SAAO,CAAIO,QAAQF,CAAK,qBAQ/C,CAAO,CACT,CACA,CAEA,IAAAG,8CAA4CR,CAAS,WAAkBjZ,SACtE,EAAI0Z,EAEAC,GADAC,CAAKf,eAGAvhB,CAAI,+BAGP,GAAItM,MAFT0uB,CAAOt0B,OAAOy0B,YAAUviB,6BAGOtM,EAC7B4uB,EAAG5uB,GAAO0uB,KAAK1uB,CAIjB,QAAI0tB,gCACOA,8BACkBzwB,OAAQ2O,MAC/B+hB,gBAAiBztB,GAAKwuB,EAAMC,EAAQ/iB,MACvCgjB,QAAiBF,iCAOtB;;;;;;;GC/E0B,yBAAfI,QACa;;;;;;;ICQxB,SAAWC,6BACwB,SAC/BA,EAAIA,EAAW,oBACXA,CAAY,OAAI;;;;;;;;ACbxB;;;;;;;;;ACWA,2BAEIC,KAAQA,2BACCC,CAyhBbC;;;;;;;oBCniBgBC,EAOZC,sBAAwBD,CAOxBE;;;;;;;;ACGJH,SAASI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACRT,SAAIC,MAAW;;;;;;;;ACJfL,SAASM,kBAkBT,OAAWC,GACPA,EAAgBA;;;;;;;;ACNpBP,SAASQ,kBAAaC,EAASC,KAAMb,IAAIc,SAAYC,OAgBrDZ;;;;;;;;;;;;;;;;;;;;;;ACrBA,IAAIa,iBAAmB,SAOnBC,MAOAC,oBAAiB,CAMjBC,eAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mFCVpB,MAASC,YAAUC,EAAGzD,GAElB,SAAS0D,IAAO1vB,OAAK4rB,eADrB+D,aAAcF,SAEZ70B,QAAkB,OAANoxB,MAAavyB,OAAOm2B,SAAgBh1B,UAAYoxB,KAAEpxB,QAAW,GAAI80B,EACnF,CA0BA,IAAIG,sBAAmC,KAAUC,GAgB7C,SAASD,EAAkBE,EAASC,EAAYC,MAAWC,oCAEf,0CAEhBlwB,QAuBxB,UAnBmB,gBAInBmwB,EAAMC,sBAA4B,CAAO,SACnCC,aACAC,eACAC,UAAW,YACXC,qBACAC,UACAC,yBACAC,QAAYC,qBACZV,YAAaA,CACnBC,EAAMU,sBACAC,gBACAC,qBACAC,EAAQ,kBACMC,YAAa,EACjCd,EAAMe,KAAO,cA8FjB,IAvIA1B,YAAUK,KAgDVA,EAAkBj1B,UAAUm2B,wBAA0Bf,WAEzCI,cAAY,CAAK,cAAcJ,cAAyBA,EACrDA,WAAWmB,GAAcnB,EAAWoB,wBAAyB,eAChEhB,IAAY,iBAAmBJ,mBAA0CI,YAAY,GAC1FpwB,KAAKowB,eAAiB,aAAcJ,IAAeA,SAAWqB,UAAgBjB,oBACzEA,gBAAiB,KAASJ,GAAeA,oBAAsBI,eAC/DA,QAAY,SAAK,cAAwB,EAAWJ,IACjDA,EAAWkB,eAAqBI,CAAQtxB,OAAKowB,UAAY,UAGvDx1B,OAAU22B,8BAExBvxB,EAAKwxB,+BACT,CACA/3B,OAAO8B;;;;;;;;AC3GXgzB,SAASkD,mCAAoB;;;;;;;;;;;;;;;AAkB7B,IAAI9B,gBAAgB;;;;;;;GCLpB,SAASH;;;;;;;;;;;;;;;;;;;;;gFCJT,SAASA,YAAUC,EAAGzD,OAElB,MAAS0D,IAAO1vB,IAAK4rB,gBADrB+D,cAAcF,EAAGzD,WAEfpxB,MAAkB,SAAOnB,WAAOm2B,CAAO5D,IAAM0D,EAAG90B,UAAYoxB,SAAEpxB,OAAe80B,EACnF,CAEA,IAAIgC,WAAW,gLAgBG,SAAyB5B,GAKvC,SAAS6B,GAAYL,OACH,IAAVA,IAAoBA,EAAQ,GAChC,IAAInB,EAAQL,EAAOvwB,MAAKS,OAAM4xB,aAAeF,WAAU,CAAEG,OAAQ,QAAQ7xB,EAEzE,OADAmwB,EAAMmB,MAAQA,IAPlB9B,eAAuBM,EAUvBr2B,SAAO8B,aAAeo2B,EAAY/2B,UAAW,QAAS,CAKlD8R,IAAK,YACD,WAAYolB,iBAEhBxiB,OAAK,MAAUhU,OACX0E,CAAK8xB,SAASD,UAElBE,YAAY,EACZt2B,eAAc,EAGtB,CA1BkB,CA0BhBu2B","names":["DEBUG_BUILD","__SENTRY_DEBUG__","GLOBAL_OBJ","SDK_VERSION","getMainCarrier","getSentryCarrier","carrier","__SENTRY__","version","getGlobalSingleton","name","creator","originalConsoleMethods","consoleSandbox","callback","console","wrappedLevels","Object","keys","forEach","originalConsoleMethod","level","wrappedFuncs","enable","_getLoggerSettings","enabled","disable","isEnabled","log","warn","args","_maybeLog","error","PREFIX","debug","objectToString","prototype","toString","isBuiltin","wat","className","isPlainObject","isThenable","Boolean","then","addNonEnumerableProperty","value","defineProperty","writable","configurable","obj","RESOLVED_RUNNER","emptyUuid","withRandomSafeContext","undefined","sym","Symbol","globalWithSymbol","cb","safeMathRandom","random","now","length","max","str","slice","getCrypto","gbl","crypto","msCrypto","getRandomByte","uuid4","randomUUID","replace","c","ONE_SECOND_IN_MS","dateTimestampInSeconds","safeDateNow","createUnixTimestampInSecondsFunc","performance","timeOrigin","_cachedTimestampInSeconds","timestampInSeconds","user","session","ipAddress","ip_address","context","did","id","email","username","timestamp","abnormal_mechanism","ignoreDuration","sid","init","started","duration","release","environment","userAgent","errors","status","merge","initialObj","mergeObj","levels","output","key","hasOwnProperty","call","generateTraceId","SCOPE_SPAN_FIELD","_setSpanForScope","span","_getSpanForScope","DEFAULT_MAX_BREADCRUMBS","Scope$1","_notifyingListeners","this","_scopeListeners","_eventProcessors","_attachments","_user","_tags","_attributes","_extra","_contexts","_sdkProcessingMetadata","_propagationContext","newScope","_breadcrumbs","flags","values","_level","_session","_transactionName","_fingerprint","_client","_lastEventId","_conversationId","setLastEventId","lastEventId","getClient","addEventProcessor","updateSession","_notifyScopeListeners","getUser","conversationId","tags","setTag","setAttributes","newAttributes","setAttribute","setExtras","extras","setExtra","extra","fingerprint","setTransactionName","setContext","setSession","getSession","update","captureContext","scopeToMerge","Scope","getScopeData","attributes","contexts","propagationContext","scopeInstance","setPropagationContext","traceId","addBreadcrumb","maxBreadcrumbs","message","breadcrumb","push","mergedBreadcrumb","maxCrumbs","recordDroppedEvent","getLastBreadcrumb","clearBreadcrumbs","addAttachment","attachment","clearAttachments","breadcrumbs","attachments","eventProcessors","sdkProcessingMetadata","setSDKProcessingMetadata","newData","hint","syntheticException","Error","captureException","originalException","exception","event_id","eventId","captureMessage","captureEvent","event","getDefaultCurrentScope","getDefaultIsolationScope","AsyncContextStack$1","scope","isolationScope","assignedScope","_stack","_isolationScope","assignedIsolationScope","_pushScope","maybePromiseResult","_popScope","res","getStackTop","client","getScope","clone","pop","getAsyncContextStack","sentry","AsyncContextStack","withScope","withSetScope","stack","withIsolationScope","getIsolationScope","getStackAsyncContextStrategy","withSetIsolationScope","getCurrentScope","getAsyncContextStrategy","acs","parseEventHintOrCaptureContext","hintIsScopeContext","hintIsScopeOrFunction","captureContextKeys","some","includes","SENSITIVE_KEY","sanitize","depth","Array","isArray","map","String","fromEntries","entries","item","test","captureError","Sentry.captureException","mulberry32","seed","a","t","imul","Math","selectTypedResponse","state","rng","validCharsTyped","split","correctResponse","validChars","simulationModel","correct","wrong","filter","floor","tTest","parseFloat","trialLevel","tActual","log10","simulationThreshold","beta","simulationBeta","simulationDelta","tpc","thresholdProportionCorrect","isNaN","delta","gamma","P","exp","pow","selectClickedIndex","chars","toLowerCase","correctIdx","findIndex","model","wrongIdxs","i","tResponse","idx","masterSeed","seedSource","initAttempted","streams","Map","hash32","h","s","charCodeAt","substreamSeed","initRng","clear","ensureInit","window","__SIM_SEED__","Number","isFinite","w","p","URLSearchParams","location","search","get","getSeedSource","getMasterSeed","rngFor","handlerSeed","BASE_DELAY_SEC","MAX_DELAY_SEC","wait","ms","Promise","setTimeout","getRetryDelayMs","attempt","min","registry","initPhrases","getPhrases","phrases","LOCALHOST_BASE_URL","PRODUCTION_BASE_URL","localhostBaseUrlPromise","resolveLocalhostBaseUrl","method","mode","getEasyEyesBaseUrl","async","previewDeployBase","hostname","origin","loadPhrases","base","pinnedUrl","experimentName","fetch","json","versionUrl","ok","data","phrasesData","pathname","defaultFunction","super","default","has","set","block","nthBlock","trial","block_condition","condition","trialCorrect_thisBlock","trialCompleted_thisBlock","trialAttempted_thisBlock","nthTrialCorrectThisBlockByCondition","DefaultMap","nthTrialCompletedThisBlockByCondition","nthTrialByCondition","nthTrialAttemptedByCondition","retryThisTrialBool","consentGiven","resetBlockScopedStatus","currentFunction","thisExperimentInfo","expName","psychopyVersion","participant","EasyEyesID","PavloviaSessionID","actualPavloviaSessionID","ProlificParticipantID","ProlificSessionID","ProlificStudyID","experimentFilename","experiment","date","hardwareConcurrency","deviceType","deviceSystem","deviceSystemFamily","deviceBrowser","deviceBrowserVersion","deviceLanguage","psychojsWindowDimensions","monitorFrameRate","padStart","num","localStorageKey","_key_resp_allKeys","_key_resp_event_handlers","handler","current","proxyVariable_key_resp_allKeys","Proxy","RemoteCalibrator","title","showCriticalLoadError","text","rc","languagePhrasesJSON","easyEyesKeypadHandler","event_handlers","all_keys","websiteRepoLastCommitDeploy","response","result","compilerUpdateDate","stats","on","usingGaze","seal","windowWidthCm","windowWidthPx","pixPerCm","nearPointXYDeg","nearPointXYPix","grid","units","totalBlocks","totalTrialsThisBlock","blockOrder","targetTask","targetKind","correctAns","source","direction","language","punctuationRTL","colorRGBA","padding","letterSpacing","kerning","textRendering","featureSettings","variantLigatures","medialShapeResponse","medialShapeTarget","fontPositionalShapeResponse","typekit","kitId","fontCharacterSet","where","showTimingBarsBool","screenBackground","measureMeters","canMeasureMeters","needMeasureMeters","targetEccentricityDeg","x","showConditionNameConfig","show","targetSpecs","showTargetSpecs","letterConfig","targetDurationSec","targetSizeIsHeightBool","targetMinimumPix","targetSizeDeg","targetCharacter","targetEccentricityXYDeg","thresholdParameter","spacingDirection","spacingSymmetry","spacingOverSizeRatio","spacingRelationToSize","flankerCharacters","delayBeforeStimOnsetSec","targetSafetyMarginSec","markingOnsetAfterTargetOffsetSecs","flankerXYDegs","thresholdAllowedBlackoutBool","fontMaxPxShrinkage","useFontMaxPxShrinkageBool","currentNominalFontSize","responseMaxOptions","imageFolders","folders","targetEccentricityXDeg","targetEccentricityYDeg","targetImageFolder","targetImageReplacementBool","currentImageFileName","currentImageFile","delayAfterStimOnsetSec","responsePositiveFeedbackBool","currentImageFullFileName","targetImageExclude","targetImageFoilsExclude","targetImageSpareFraction","targetImageWhere","imageQuestionAndAnswer","repeatedLettersConfig","targetRepeatsBorderCharacter","targetRepeatsMaxLines","stimulusParameters","repeatedLettersResponse","clickTime","instructionFont","customInstructionText","tolerances","allowed","thresholdAllowedDurationRatio","thresholdAllowedGazeXErrorDeg","thresholdAllowedGazeYErrorDeg","thresholdAllowedGazeRErrorDeg","thresholdAllowedLatenessSec","measured","thresholdDurationRatio","gazeMeasuredXDeg","gazeMeasuredYDeg","gazeMeasuredRDeg","gazeMeasuredRawDeg","gazeMeasurementLatencySec","targetMeasuredLatenessSec","targetMeasuredDurationSec","targetMeasuredDurationFrames","targetMeasuredPreRenderSec","skipTrialOrBlock","trialId","skipTrial","skipBlock","restartBlock","timing","clickToStimulusOnsetSec","stimulusOnsetToOffset","letterTiming","trialFirstFrameSec","targetStartSec","targetFinishSec","targetDrawnConfirmedTimestamp","crosshairClickedTimestamp","targetRequestedTimestamp","blackoutDetectedBool","preRenderStartSec","preRenderEndSec","preRenderOpacifyStartSec","preRenderOpacifyEndSec","letterHeapData","heapUsedBeforeDrawingMB","heapTotalBeforeDrawingMB","heapLimitBeforeDrawingMB","heapUsedAfterDrawingMB","heapTotalAfterDrawingMB","heapLimitAfterDrawingMB","heapTotalPreLatenessMB","heapTotalPostLatenessMB","viewingDistanceCm","responseType","original","numberOfResponses","clickedContinue","timestamps","showCharacterSetResponse","onsetTime","alreadyClickedCharacters","phraseIdentificationResponse","categoriesResponded","onsetT","markingShowCursorBool","readingCorpusArchive","readingWordListArchive","readingWordFrequencyArchive","readingFrequencyToWordArchive","readingCorpusFoilsArchive","readingCorpusPastTargets","readingCorpusPastFoils","readingUsedText","readingThisBlockPages","readingPageIndex","readingQuestions","readingCurrentQuestionIndex","readingClickableAnswersSetup","readingClickableAnswersUpdate","readingConfig","actualLinesPerPage","readingTiming","readingPageStats","readingPageSkipCorpusWords","readingPageLines","readingPageWords","readingPageNonblankCharacters","readingCorpusDepleted","readingLineLengthUnit","questionsThisBlock","qaPlanThisBlock","uniComponentConfig","alignHoriz","opacity","isInstruction","instructionsConfig","height","innerWidth","conditionNameConfig","alignVert","innerHeight","autoDraw","targetSpecsConfig","pos","trialCounterConfig","targetTextStimConfig","font","wrapWidth","ori","medialForm","isSmartphone","isLoudspeaker","isParticipant","profileFetchedFromLibrary","showSystemCorrection","ProposedVolumeLevelFromQuest","adjusted","maskerVolumeDbSPL","soundGainDBSPL","invertedImpulseResponse","whiteNoiseLevel","maskerSoundFolder","targetSoundFolder","targetSoundListFiles","targetSoundListMap","targetSoundListTrialData","left","right","trialSound","speechInNoiseTargetList","speechInNoiseShowClickable","vocoderPhrases","maskerPhrase","actualSamplingRate","actualBitsPerSample","microphoneActualSamplingRate","vocoderPhraseCategories","chosen","all","vocoderPhraseShowClickable","vocoderPhraseCorrectResponse","soundCalibrationResults","qualityMetrics","sdOfRecordingOfFilteredMLS","currentFirestoreProfileDocumentID","microphone","allHzCalibrationResults","x_unconv","y_unconv","y_conv","knownIr","x_background","y_background","system","background","mls_psd","microphoneGain","Freq","Gain","loudspeakerGain","filteredMLSRange","Max","component","autoGainControl","echoCancellation","noiseSuppression","calibrationRound","webAudioDeviceNames","loudspeaker","microphoneText","IDsToSaveInSoundProfileLibrary","parseJsonSaveTargets","raw","trim","wantsLocal","parts","wantsOnline","calibrateSoundSamplingDesiredBits","_calibrateSoundShowParametersBool","_calibrateSoundAllHzBool","_calibrateSoundSaveJSON","calibrateSoundSmoothOctaves","calibrateSoundSmoothMinBandwidthHz","calibrateSoundPowerBinDesiredSec","calibrateSoundPowerDbSDToleratedDb","calibrateSoundTaperSec","calibrateSoundBackgroundSecs","calibrateSoundBurstRepeats","calibrateSoundBurstSec","_calibrateSoundBurstPreSec","_calibrateSoundBurstPostSec","calibrateSoundHz","calibrateSoundBurstMLSVersions","_calibrateSound1000HzBool","_calibrateSound1000HzDB","_calibrateSound1000HzSec","_calibrateSound1000HzPreSec","_calibrateSound1000HzPostSec","calibrateSoundIIRSec","calibrateSoundIIRPhase","calibrateSoundIRSec","calibrateSoundBurstDb","calibrateSoundBurstFilteredExtraDb","calibrateSoundBurstScalarDB","calibrateSoundBurstLevelReTBool","calibrateSoundBurstNormalizeBy1000HzGainBool","_calibrateSound1000HzMaxTries","_calibrateSoundBurstMaxSD_dB","calibrateSoundBurstDownsample","timeoutNewPhoneSec","timeoutSoundCalibrationSec","calibrateSoundCheck","_calibrateSoundShowResultsBool","_calibrateSoundShowTestPageBool","microphoneCalibrationResults","microphoneCalibrationResult","_calibrateSoundMaxHz","_calibrateSoundMinHz","fMaxHz","calibrateSoundSimulateLoudspeaker","amplitudes","fileName","time","calibrateSoundSimulateMicrophone","type","attenuatorGainDB","calibrateMicrophonesBool","rsvpReadingWordsForThisBlock","timeToCalibrate","timeAtTheStartOfCalibration","timeAtTheEndOfCalibration","calibrationDuration","calibrateSoundUMIKBase_dB","umik2","filteredMLSAttenuation","maxAbsSystem","maxAbsComponent","attenuationDbSystem","attenuationDbComponent","micsForSoundTestPage","list","gotLoudspeakerMatch","loudspeakerInfo","loudspeakerBrowserDetails","browser","microphoneBrowserDetails","microphoneInfo","calibrationTime","needPhoneSurvey","needComputerSurveyBool","authorEmail","rsvpReadingTargetSets","numberOfSets","numberOfIdentifications","identificationTargetSets","upcoming","skippedDueToBadTracking","rsvpReadingResponse","categories","identificationCategories","screen","displayStatus","responseTypeForCurrentBlock","rsvpSpeechPreflight","lastFailureCode","rsvpSpeechRuntime","controller","blockCondition","utteranceId","preparationStartedAtMs","readyAtMs","captureStartedAtMs","finalizationAllowedAtMs","responseRegistrationStatus","responseRegistrationError","responseDiagnostics","rsvpReadingTiming","finishSec","past","eyeTrackingStimulusRecords","cursorTracking","records","measureLuminance","movieStart","measureLuminanceDelaySec","measurementShouldStartAt","colorimeter","currentMovieValueIndex","pretendBool","movieSec","thresholdParacticeUntilCorrect","doneWithPractice","MonotonicClock","mix","superclass","MixinBuilder","PsychObject","ExperimentHandler","Scheduler","psychoJS","_taskList","_currentTask","_argsList","_currentArgs","_stopAtNextUpdate","constructor","theWindow","TONE_DEBUG_CLASS","_wasDisposed","b","EPSILON","EQ","abs","Timeline","Tone","_timeline","options","optionsFromArguments","getDefaults","memory","increasing","Infinity","GUI","Logger","getOwnPropertySymbols","propIsEnumerable","propertyIsEnumerable","toObject","val","TypeError","shouldUseNative","assign","getOwnPropertyNames","test1","fromCharCode","n","join","letter","test3","objectAssign","from","symbols","to","arguments","globalThis","ENV","format","resolve","settings","PI","RAD_TO_DEG","DEG_TO_RAD","SORTABLE_CHILDREN","__assign","TARGET_FPMS","UPDATE_PRIORITY","PREFER_ENV","isMobile","any","WEBGL","WEBGL2","accessibleTarget","accessible","accessibleTitle","accessibleHint","__extends","d","__","extendStatics","create","ParticleContainer","_super","maxSize","properties","batchSize","autoResize","_this","_properties","_maxSize","_batchSize","_buffers","_bufferUpdateIDs","_updateID","interactiveChildren","blendMode","BLEND_MODES","roundPixels","baseTexture","setProperties","_tint","Float32Array","tint","vertices","scale","rotation","alpha","updateTransform","displayObjectUpdateTransform","UPLOADS_PER_FRAME","fragment","AlphaFilter","defaultVertex","uAlpha","uniforms","enumerable","Filter"],"ignoreList":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,38,39,40,41,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58],"sources":["../node_modules/@sentry/core/build/esm/debug-build.js","../node_modules/@sentry/core/build/esm/utils/worldwide.js","../node_modules/@sentry/core/build/esm/utils/version.js","../node_modules/@sentry/core/build/esm/carrier.js","../node_modules/@sentry/core/build/esm/utils/debug-logger.js","../node_modules/@sentry/core/build/esm/utils/is.js","../node_modules/@sentry/core/build/esm/utils/object.js","../node_modules/@sentry/core/build/esm/utils/randomSafeContext.js","../node_modules/@sentry/core/build/esm/utils/misc.js","../node_modules/@sentry/core/build/esm/utils/string.js","../node_modules/@sentry/core/build/esm/utils/time.js","../node_modules/@sentry/core/build/esm/session.js","../node_modules/@sentry/core/build/esm/utils/merge.js","../node_modules/@sentry/core/build/esm/utils/propagationContext.js","../node_modules/@sentry/core/build/esm/utils/spanOnScope.js","../node_modules/@sentry/core/build/esm/scope.js","../node_modules/@sentry/core/build/esm/defaultScopes.js","../node_modules/@sentry/core/build/esm/asyncContext/stackStrategy.js","../node_modules/@sentry/core/build/esm/asyncContext/index.js","../node_modules/@sentry/core/build/esm/currentScopes.js","../node_modules/@sentry/core/build/esm/utils/prepareEvent.js","../node_modules/@sentry/core/build/esm/exports.js","../components/sentry.js","../components/simulationModel.ts","../components/rng.ts","../preprocess/retry.ts","../parameters/phrasesRegistry.ts","../components/easyeyesBaseUrl.ts","../preprocess/phrases-loader.ts","../components/types.ts","../components/status.ts","../components/global.js","../psychojs/src/util/Clock.js","../psychojs/src/util/Util.js","../psychojs/src/util/EventEmitter.js","../psychojs/src/util/PsychObject.js","../psychojs/src/data/ExperimentHandler.js","../psychojs/src/util/Scheduler.js","../psychojs/node_modules/tone/build/esm/core/Tone.js","../psychojs/node_modules/tone/build/esm/core/util/Math.js","../psychojs/node_modules/tone/build/esm/core/util/Timeline.js","../psychojs/node_modules/howler/dist/howler.js","../psychojs/src/core/GUI.js","../psychojs/src/core/Logger.js","../psychojs/node_modules/object-assign/index.js","../psychojs/node_modules/@pixi/polyfill/dist/esm/polyfill.mjs","../psychojs/node_modules/@pixi/constants/dist/esm/constants.mjs","../psychojs/node_modules/@pixi/settings/dist/esm/settings.mjs","../psychojs/node_modules/@pixi/utils/dist/esm/utils.mjs","../psychojs/node_modules/@pixi/math/dist/esm/math.mjs","../psychojs/node_modules/@pixi/display/dist/esm/display.mjs","../psychojs/node_modules/@pixi/extensions/dist/esm/extensions.mjs","../psychojs/node_modules/@pixi/ticker/dist/esm/ticker.mjs","../psychojs/node_modules/@pixi/core/dist/esm/core.mjs","../psychojs/node_modules/@pixi/accessibility/dist/esm/accessibility.mjs","../psychojs/node_modules/@pixi/particle-container/dist/esm/particle-container.mjs","../psychojs/node_modules/@pixi/prepare/dist/esm/prepare.mjs","../psychojs/node_modules/@pixi/sprite-tiling/dist/esm/sprite-tiling.mjs","../psychojs/node_modules/@pixi/filter-alpha/dist/esm/filter-alpha.mjs"],"sourcesContent":["/**\n * This serves as a build time flag that will be true by default, but false in non-debug builds or if users replace `__SENTRY_DEBUG__` in their generated code.\n *\n * ATTENTION: This constant must never cross package boundaries (i.e. be exported) to guarantee that it can be used for tree shaking.\n */\nconst DEBUG_BUILD = (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__);\n\nexport { DEBUG_BUILD };\n//# sourceMappingURL=debug-build.js.map\n","/** Internal global with common properties and Sentry extensions */\n\n/** Get's the global object for the current JavaScript runtime */\nconst GLOBAL_OBJ = globalThis ;\n\nexport { GLOBAL_OBJ };\n//# sourceMappingURL=worldwide.js.map\n","// This is a magic string replaced by rollup\n\nconst SDK_VERSION = \"10.38.0\" ;\n\nexport { SDK_VERSION };\n//# sourceMappingURL=version.js.map\n","import { SDK_VERSION } from './utils/version.js';\nimport { GLOBAL_OBJ } from './utils/worldwide.js';\n\n/**\n * An object that contains globally accessible properties and maintains a scope stack.\n * @hidden\n */\n\n/**\n * Returns the global shim registry.\n *\n * FIXME: This function is problematic, because despite always returning a valid Carrier,\n * it has an optional `__SENTRY__` property, which then in turn requires us to always perform an unnecessary check\n * at the call-site. We always access the carrier through this function, so we can guarantee that `__SENTRY__` is there.\n **/\nfunction getMainCarrier() {\n // This ensures a Sentry carrier exists\n getSentryCarrier(GLOBAL_OBJ);\n return GLOBAL_OBJ;\n}\n\n/** Will either get the existing sentry carrier, or create a new one. */\nfunction getSentryCarrier(carrier) {\n const __SENTRY__ = (carrier.__SENTRY__ = carrier.__SENTRY__ || {});\n\n // For now: First SDK that sets the .version property wins\n __SENTRY__.version = __SENTRY__.version || SDK_VERSION;\n\n // Intentionally populating and returning the version of \"this\" SDK instance\n // rather than what's set in .version so that \"this\" SDK always gets its carrier\n return (__SENTRY__[SDK_VERSION] = __SENTRY__[SDK_VERSION] || {});\n}\n\n/**\n * Returns a global singleton contained in the global `__SENTRY__[]` object.\n *\n * If the singleton doesn't already exist in `__SENTRY__`, it will be created using the given factory\n * function and added to the `__SENTRY__` object.\n *\n * @param name name of the global singleton on __SENTRY__\n * @param creator creator Factory function to create the singleton if it doesn't already exist on `__SENTRY__`\n * @param obj (Optional) The global object on which to look for `__SENTRY__`, if not `GLOBAL_OBJ`'s return value\n * @returns the singleton\n */\nfunction getGlobalSingleton(\n name,\n creator,\n obj = GLOBAL_OBJ,\n) {\n const __SENTRY__ = (obj.__SENTRY__ = obj.__SENTRY__ || {});\n const carrier = (__SENTRY__[SDK_VERSION] = __SENTRY__[SDK_VERSION] || {});\n // Note: We do not want to set `carrier.version` here, as this may be called before any `init` is called, e.g. for the default scopes\n return carrier[name] || (carrier[name] = creator());\n}\n\nexport { getGlobalSingleton, getMainCarrier, getSentryCarrier };\n//# sourceMappingURL=carrier.js.map\n","import { getGlobalSingleton } from '../carrier.js';\nimport { DEBUG_BUILD } from '../debug-build.js';\nimport { GLOBAL_OBJ } from './worldwide.js';\n\nconst CONSOLE_LEVELS = [\n 'debug',\n 'info',\n 'warn',\n 'error',\n 'log',\n 'assert',\n 'trace',\n] ;\n\n/** Prefix for logging strings */\nconst PREFIX = 'Sentry Logger ';\n\n/** This may be mutated by the console instrumentation. */\nconst originalConsoleMethods\n\n = {};\n\n/**\n * Temporarily disable sentry console instrumentations.\n *\n * @param callback The function to run against the original `console` messages\n * @returns The results of the callback\n */\nfunction consoleSandbox(callback) {\n if (!('console' in GLOBAL_OBJ)) {\n return callback();\n }\n\n const console = GLOBAL_OBJ.console;\n const wrappedFuncs = {};\n\n const wrappedLevels = Object.keys(originalConsoleMethods) ;\n\n // Restore all wrapped console methods\n wrappedLevels.forEach(level => {\n const originalConsoleMethod = originalConsoleMethods[level];\n wrappedFuncs[level] = console[level] ;\n console[level] = originalConsoleMethod ;\n });\n\n try {\n return callback();\n } finally {\n // Revert restoration to wrapped state\n wrappedLevels.forEach(level => {\n console[level] = wrappedFuncs[level] ;\n });\n }\n}\n\nfunction enable() {\n _getLoggerSettings().enabled = true;\n}\n\nfunction disable() {\n _getLoggerSettings().enabled = false;\n}\n\nfunction isEnabled() {\n return _getLoggerSettings().enabled;\n}\n\nfunction log(...args) {\n _maybeLog('log', ...args);\n}\n\nfunction warn(...args) {\n _maybeLog('warn', ...args);\n}\n\nfunction error(...args) {\n _maybeLog('error', ...args);\n}\n\nfunction _maybeLog(level, ...args) {\n if (!DEBUG_BUILD) {\n return;\n }\n\n if (isEnabled()) {\n consoleSandbox(() => {\n GLOBAL_OBJ.console[level](`${PREFIX}[${level}]:`, ...args);\n });\n }\n}\n\nfunction _getLoggerSettings() {\n if (!DEBUG_BUILD) {\n return { enabled: false };\n }\n\n return getGlobalSingleton('loggerSettings', () => ({ enabled: false }));\n}\n\n/**\n * This is a logger singleton which either logs things or no-ops if logging is not enabled.\n */\nconst debug = {\n /** Enable logging. */\n enable,\n /** Disable logging. */\n disable,\n /** Check if logging is enabled. */\n isEnabled,\n /** Log a message. */\n log,\n /** Log a warning. */\n warn,\n /** Log an error. */\n error,\n} ;\n\nexport { CONSOLE_LEVELS, consoleSandbox, debug, originalConsoleMethods };\n//# sourceMappingURL=debug-logger.js.map\n","// eslint-disable-next-line @typescript-eslint/unbound-method\nconst objectToString = Object.prototype.toString;\n\n/**\n * Checks whether given value's type is one of a few Error or Error-like\n * {@link isError}.\n *\n * @param wat A value to be checked.\n * @returns A boolean representing the result.\n */\nfunction isError(wat) {\n switch (objectToString.call(wat)) {\n case '[object Error]':\n case '[object Exception]':\n case '[object DOMException]':\n case '[object WebAssembly.Exception]':\n return true;\n default:\n return isInstanceOf(wat, Error);\n }\n}\n/**\n * Checks whether given value is an instance of the given built-in class.\n *\n * @param wat The value to be checked\n * @param className\n * @returns A boolean representing the result.\n */\nfunction isBuiltin(wat, className) {\n return objectToString.call(wat) === `[object ${className}]`;\n}\n\n/**\n * Checks whether given value's type is ErrorEvent\n * {@link isErrorEvent}.\n *\n * @param wat A value to be checked.\n * @returns A boolean representing the result.\n */\nfunction isErrorEvent(wat) {\n return isBuiltin(wat, 'ErrorEvent');\n}\n\n/**\n * Checks whether given value's type is DOMError\n * {@link isDOMError}.\n *\n * @param wat A value to be checked.\n * @returns A boolean representing the result.\n */\nfunction isDOMError(wat) {\n return isBuiltin(wat, 'DOMError');\n}\n\n/**\n * Checks whether given value's type is DOMException\n * {@link isDOMException}.\n *\n * @param wat A value to be checked.\n * @returns A boolean representing the result.\n */\nfunction isDOMException(wat) {\n return isBuiltin(wat, 'DOMException');\n}\n\n/**\n * Checks whether given value's type is a string\n * {@link isString}.\n *\n * @param wat A value to be checked.\n * @returns A boolean representing the result.\n */\nfunction isString(wat) {\n return isBuiltin(wat, 'String');\n}\n\n/**\n * Checks whether given string is parameterized\n * {@link isParameterizedString}.\n *\n * @param wat A value to be checked.\n * @returns A boolean representing the result.\n */\nfunction isParameterizedString(wat) {\n return (\n typeof wat === 'object' &&\n wat !== null &&\n '__sentry_template_string__' in wat &&\n '__sentry_template_values__' in wat\n );\n}\n\n/**\n * Checks whether given value is a primitive (undefined, null, number, boolean, string, bigint, symbol)\n * {@link isPrimitive}.\n *\n * @param wat A value to be checked.\n * @returns A boolean representing the result.\n */\nfunction isPrimitive(wat) {\n return wat === null || isParameterizedString(wat) || (typeof wat !== 'object' && typeof wat !== 'function');\n}\n\n/**\n * Checks whether given value's type is an object literal, or a class instance.\n * {@link isPlainObject}.\n *\n * @param wat A value to be checked.\n * @returns A boolean representing the result.\n */\nfunction isPlainObject(wat) {\n return isBuiltin(wat, 'Object');\n}\n\n/**\n * Checks whether given value's type is an Event instance\n * {@link isEvent}.\n *\n * @param wat A value to be checked.\n * @returns A boolean representing the result.\n */\nfunction isEvent(wat) {\n return typeof Event !== 'undefined' && isInstanceOf(wat, Event);\n}\n\n/**\n * Checks whether given value's type is an Element instance\n * {@link isElement}.\n *\n * @param wat A value to be checked.\n * @returns A boolean representing the result.\n */\nfunction isElement(wat) {\n return typeof Element !== 'undefined' && isInstanceOf(wat, Element);\n}\n\n/**\n * Checks whether given value's type is an regexp\n * {@link isRegExp}.\n *\n * @param wat A value to be checked.\n * @returns A boolean representing the result.\n */\nfunction isRegExp(wat) {\n return isBuiltin(wat, 'RegExp');\n}\n\n/**\n * Checks whether given value has a then function.\n * @param wat A value to be checked.\n */\nfunction isThenable(wat) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n return Boolean(wat?.then && typeof wat.then === 'function');\n}\n\n/**\n * Checks whether given value's type is a SyntheticEvent\n * {@link isSyntheticEvent}.\n *\n * @param wat A value to be checked.\n * @returns A boolean representing the result.\n */\nfunction isSyntheticEvent(wat) {\n return isPlainObject(wat) && 'nativeEvent' in wat && 'preventDefault' in wat && 'stopPropagation' in wat;\n}\n\n/**\n * Checks whether given value's type is an instance of provided constructor.\n * {@link isInstanceOf}.\n *\n * @param wat A value to be checked.\n * @param base A constructor to be used in a check.\n * @returns A boolean representing the result.\n */\n// TODO: fix in v11, convert any to unknown\n// export function isInstanceOf<T>(wat: unknown, base: { new (...args: any[]): T }): wat is T {\nfunction isInstanceOf(wat, base) {\n try {\n return wat instanceof base;\n } catch {\n return false;\n }\n}\n\n/**\n * Checks whether given value's type is a Vue ViewModel or a VNode.\n *\n * @param wat A value to be checked.\n * @returns A boolean representing the result.\n */\nfunction isVueViewModel(wat) {\n // Not using Object.prototype.toString because in Vue 3 it would read the instance's Symbol(Symbol.toStringTag) property.\n // We also need to check for __v_isVNode because Vue 3 component render instances have an internal __v_isVNode property.\n return !!(\n typeof wat === 'object' &&\n wat !== null &&\n ((wat ).__isVue || (wat )._isVue || (wat ).__v_isVNode)\n );\n}\n\n/**\n * Checks whether the given parameter is a Standard Web API Request instance.\n *\n * Returns false if Request is not available in the current runtime.\n */\nfunction isRequest(request) {\n return typeof Request !== 'undefined' && isInstanceOf(request, Request);\n}\n\nexport { isDOMError, isDOMException, isElement, isError, isErrorEvent, isEvent, isInstanceOf, isParameterizedString, isPlainObject, isPrimitive, isRegExp, isRequest, isString, isSyntheticEvent, isThenable, isVueViewModel };\n//# sourceMappingURL=is.js.map\n","import { DEBUG_BUILD } from '../debug-build.js';\nimport { htmlTreeAsString } from './browser.js';\nimport { debug } from './debug-logger.js';\nimport { isError, isEvent, isInstanceOf, isPrimitive, isElement } from './is.js';\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\n/**\n * Replace a method in an object with a wrapped version of itself.\n *\n * If the method on the passed object is not a function, the wrapper will not be applied.\n *\n * @param source An object that contains a method to be wrapped.\n * @param name The name of the method to be wrapped.\n * @param replacementFactory A higher-order function that takes the original version of the given method and returns a\n * wrapped version. Note: The function returned by `replacementFactory` needs to be a non-arrow function, in order to\n * preserve the correct value of `this`, and the original method must be called using `origMethod.call(this, <other\n * args>)` or `origMethod.apply(this, [<other args>])` (rather than being called directly), again to preserve `this`.\n * @returns void\n */\nfunction fill(source, name, replacementFactory) {\n if (!(name in source)) {\n return;\n }\n\n // explicitly casting to unknown because we don't know the type of the method initially at all\n const original = source[name] ;\n\n if (typeof original !== 'function') {\n return;\n }\n\n const wrapped = replacementFactory(original) ;\n\n // Make sure it's a function first, as we need to attach an empty prototype for `defineProperties` to work\n // otherwise it'll throw \"TypeError: Object.defineProperties called on non-object\"\n if (typeof wrapped === 'function') {\n markFunctionWrapped(wrapped, original);\n }\n\n try {\n source[name] = wrapped;\n } catch {\n DEBUG_BUILD && debug.log(`Failed to replace method \"${name}\" in object`, source);\n }\n}\n\n/**\n * Defines a non-enumerable property on the given object.\n *\n * @param obj The object on which to set the property\n * @param name The name of the property to be set\n * @param value The value to which to set the property\n */\nfunction addNonEnumerableProperty(obj, name, value) {\n try {\n Object.defineProperty(obj, name, {\n // enumerable: false, // the default, so we can save on bundle size by not explicitly setting it\n value: value,\n writable: true,\n configurable: true,\n });\n } catch {\n DEBUG_BUILD && debug.log(`Failed to add non-enumerable property \"${name}\" to object`, obj);\n }\n}\n\n/**\n * Remembers the original function on the wrapped function and\n * patches up the prototype.\n *\n * @param wrapped the wrapper function\n * @param original the original function that gets wrapped\n */\nfunction markFunctionWrapped(wrapped, original) {\n try {\n const proto = original.prototype || {};\n wrapped.prototype = original.prototype = proto;\n addNonEnumerableProperty(wrapped, '__sentry_original__', original);\n } catch {} // eslint-disable-line no-empty\n}\n\n/**\n * This extracts the original function if available. See\n * `markFunctionWrapped` for more information.\n *\n * @param func the function to unwrap\n * @returns the unwrapped version of the function if available.\n */\n// eslint-disable-next-line @typescript-eslint/ban-types\nfunction getOriginalFunction(func) {\n return func.__sentry_original__;\n}\n\n/**\n * Transforms any `Error` or `Event` into a plain object with all of their enumerable properties, and some of their\n * non-enumerable properties attached.\n *\n * @param value Initial source that we have to transform in order for it to be usable by the serializer\n * @returns An Event or Error turned into an object - or the value argument itself, when value is neither an Event nor\n * an Error.\n */\nfunction convertToPlainObject(value)\n\n {\n if (isError(value)) {\n return {\n message: value.message,\n name: value.name,\n stack: value.stack,\n ...getOwnProperties(value),\n };\n } else if (isEvent(value)) {\n const newObj\n\n = {\n type: value.type,\n target: serializeEventTarget(value.target),\n currentTarget: serializeEventTarget(value.currentTarget),\n ...getOwnProperties(value),\n };\n\n if (typeof CustomEvent !== 'undefined' && isInstanceOf(value, CustomEvent)) {\n newObj.detail = value.detail;\n }\n\n return newObj;\n } else {\n return value;\n }\n}\n\n/** Creates a string representation of the target of an `Event` object */\nfunction serializeEventTarget(target) {\n try {\n return isElement(target) ? htmlTreeAsString(target) : Object.prototype.toString.call(target);\n } catch {\n return '<unknown>';\n }\n}\n\n/** Filters out all but an object's own properties */\nfunction getOwnProperties(obj) {\n if (typeof obj === 'object' && obj !== null) {\n const extractedProps = {};\n for (const property in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, property)) {\n extractedProps[property] = (obj )[property];\n }\n }\n return extractedProps;\n } else {\n return {};\n }\n}\n\n/**\n * Given any captured exception, extract its keys and create a sorted\n * and truncated list that will be used inside the event message.\n * eg. `Non-error exception captured with keys: foo, bar, baz`\n */\nfunction extractExceptionKeysForMessage(exception) {\n const keys = Object.keys(convertToPlainObject(exception));\n keys.sort();\n\n return !keys[0] ? '[object has no keys]' : keys.join(', ');\n}\n\n/**\n * Given any object, return a new object having removed all fields whose value was `undefined`.\n * Works recursively on objects and arrays.\n *\n * Attention: This function keeps circular references in the returned object.\n *\n * @deprecated This function is no longer used by the SDK and will be removed in a future major version.\n */\nfunction dropUndefinedKeys(inputValue) {\n // This map keeps track of what already visited nodes map to.\n // Our Set - based memoBuilder doesn't work here because we want to the output object to have the same circular\n // references as the input object.\n const memoizationMap = new Map();\n\n // This function just proxies `_dropUndefinedKeys` to keep the `memoBuilder` out of this function's API\n return _dropUndefinedKeys(inputValue, memoizationMap);\n}\n\nfunction _dropUndefinedKeys(inputValue, memoizationMap) {\n // Early return for primitive values\n if (inputValue === null || typeof inputValue !== 'object') {\n return inputValue;\n }\n\n // Check memo map first for all object types\n const memoVal = memoizationMap.get(inputValue);\n if (memoVal !== undefined) {\n return memoVal ;\n }\n\n // handle arrays\n if (Array.isArray(inputValue)) {\n const returnValue = [];\n // Store mapping to handle circular references\n memoizationMap.set(inputValue, returnValue);\n\n inputValue.forEach(value => {\n returnValue.push(_dropUndefinedKeys(value, memoizationMap));\n });\n\n return returnValue ;\n }\n\n if (isPojo(inputValue)) {\n const returnValue = {};\n // Store mapping to handle circular references\n memoizationMap.set(inputValue, returnValue);\n\n const keys = Object.keys(inputValue);\n\n keys.forEach(key => {\n const val = inputValue[key];\n if (val !== undefined) {\n returnValue[key] = _dropUndefinedKeys(val, memoizationMap);\n }\n });\n\n return returnValue ;\n }\n\n // For other object types, return as is\n return inputValue;\n}\n\nfunction isPojo(input) {\n // Plain objects have Object as constructor or no constructor\n const constructor = (input ).constructor;\n return constructor === Object || constructor === undefined;\n}\n\n/**\n * Ensure that something is an object.\n *\n * Turns `undefined` and `null` into `String`s and all other primitives into instances of their respective wrapper\n * classes (String, Boolean, Number, etc.). Acts as the identity function on non-primitives.\n *\n * @param wat The subject of the objectification\n * @returns A version of `wat` which can safely be used with `Object` class methods\n */\nfunction objectify(wat) {\n let objectified;\n switch (true) {\n // this will catch both undefined and null\n case wat == undefined:\n objectified = new String(wat);\n break;\n\n // Though symbols and bigints do have wrapper classes (`Symbol` and `BigInt`, respectively), for whatever reason\n // those classes don't have constructors which can be used with the `new` keyword. We therefore need to cast each as\n // an object in order to wrap it.\n case typeof wat === 'symbol' || typeof wat === 'bigint':\n objectified = Object(wat);\n break;\n\n // this will catch the remaining primitives: `String`, `Number`, and `Boolean`\n case isPrimitive(wat):\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n objectified = new (wat ).constructor(wat);\n break;\n\n // by process of elimination, at this point we know that `wat` must already be an object\n default:\n objectified = wat;\n break;\n }\n return objectified;\n}\n\nexport { addNonEnumerableProperty, convertToPlainObject, dropUndefinedKeys, extractExceptionKeysForMessage, fill, getOriginalFunction, markFunctionWrapped, objectify };\n//# sourceMappingURL=object.js.map\n","import { GLOBAL_OBJ } from './worldwide.js';\n\n// undefined = not yet resolved, null = no runner found, function = runner found\nlet RESOLVED_RUNNER;\n\n/**\n * Simple wrapper that allows SDKs to *secretly* set context wrapper to generate safe random IDs in cache components contexts\n */\nfunction withRandomSafeContext(cb) {\n // Skips future symbol lookups if we've already resolved (or attempted to resolve) the runner once\n if (RESOLVED_RUNNER !== undefined) {\n return RESOLVED_RUNNER ? RESOLVED_RUNNER(cb) : cb();\n }\n\n const sym = Symbol.for('__SENTRY_SAFE_RANDOM_ID_WRAPPER__');\n const globalWithSymbol = GLOBAL_OBJ;\n\n if (sym in globalWithSymbol && typeof globalWithSymbol[sym] === 'function') {\n RESOLVED_RUNNER = globalWithSymbol[sym];\n return RESOLVED_RUNNER(cb);\n }\n\n RESOLVED_RUNNER = null;\n return cb();\n}\n\n/**\n * Identical to Math.random() but wrapped in withRandomSafeContext\n * to ensure safe random number generation in certain contexts (e.g., Next.js Cache Components).\n */\nfunction safeMathRandom() {\n return withRandomSafeContext(() => Math.random());\n}\n\n/**\n * Identical to Date.now() but wrapped in withRandomSafeContext\n * to ensure safe time value generation in certain contexts (e.g., Next.js Cache Components).\n */\nfunction safeDateNow() {\n return withRandomSafeContext(() => Date.now());\n}\n\nexport { safeDateNow, safeMathRandom, withRandomSafeContext };\n//# sourceMappingURL=randomSafeContext.js.map\n","import { addNonEnumerableProperty } from './object.js';\nimport { withRandomSafeContext, safeMathRandom } from './randomSafeContext.js';\nimport { snipLine } from './string.js';\nimport { GLOBAL_OBJ } from './worldwide.js';\n\nfunction getCrypto() {\n const gbl = GLOBAL_OBJ ;\n return gbl.crypto || gbl.msCrypto;\n}\n\nlet emptyUuid;\n\nfunction getRandomByte() {\n return safeMathRandom() * 16;\n}\n\n/**\n * UUID4 generator\n * @param crypto Object that provides the crypto API.\n * @returns string Generated UUID4.\n */\nfunction uuid4(crypto = getCrypto()) {\n try {\n if (crypto?.randomUUID) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return withRandomSafeContext(() => crypto.randomUUID()).replace(/-/g, '');\n }\n } catch {\n // some runtimes can crash invoking crypto\n // https://github.com/getsentry/sentry-javascript/issues/8935\n }\n\n if (!emptyUuid) {\n // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523\n // Concatenating the following numbers as strings results in '10000000100040008000100000000000'\n emptyUuid = ([1e7] ) + 1e3 + 4e3 + 8e3 + 1e11;\n }\n\n return emptyUuid.replace(/[018]/g, c =>\n // eslint-disable-next-line no-bitwise\n ((c ) ^ ((getRandomByte() & 15) >> ((c ) / 4))).toString(16),\n );\n}\n\nfunction getFirstException(event) {\n return event.exception?.values?.[0];\n}\n\n/**\n * Extracts either message or type+value from an event that can be used for user-facing logs\n * @returns event's description\n */\nfunction getEventDescription(event) {\n const { message, event_id: eventId } = event;\n if (message) {\n return message;\n }\n\n const firstException = getFirstException(event);\n if (firstException) {\n if (firstException.type && firstException.value) {\n return `${firstException.type}: ${firstException.value}`;\n }\n return firstException.type || firstException.value || eventId || '<unknown>';\n }\n return eventId || '<unknown>';\n}\n\n/**\n * Adds exception values, type and value to an synthetic Exception.\n * @param event The event to modify.\n * @param value Value of the exception.\n * @param type Type of the exception.\n * @hidden\n */\nfunction addExceptionTypeValue(event, value, type) {\n const exception = (event.exception = event.exception || {});\n const values = (exception.values = exception.values || []);\n const firstException = (values[0] = values[0] || {});\n if (!firstException.value) {\n firstException.value = value || '';\n }\n if (!firstException.type) {\n firstException.type = type || 'Error';\n }\n}\n\n/**\n * Adds exception mechanism data to a given event. Uses defaults if the second parameter is not passed.\n *\n * @param event The event to modify.\n * @param newMechanism Mechanism data to add to the event.\n * @hidden\n */\nfunction addExceptionMechanism(event, newMechanism) {\n const firstException = getFirstException(event);\n if (!firstException) {\n return;\n }\n\n const defaultMechanism = { type: 'generic', handled: true };\n const currentMechanism = firstException.mechanism;\n firstException.mechanism = { ...defaultMechanism, ...currentMechanism, ...newMechanism };\n\n if (newMechanism && 'data' in newMechanism) {\n const mergedData = { ...currentMechanism?.data, ...newMechanism.data };\n firstException.mechanism.data = mergedData;\n }\n}\n\n// https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string\nconst SEMVER_REGEXP =\n /^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$/;\n\n/**\n * Represents Semantic Versioning object\n */\n\nfunction _parseInt(input) {\n return parseInt(input || '', 10);\n}\n\n/**\n * Parses input into a SemVer interface\n * @param input string representation of a semver version\n */\nfunction parseSemver(input) {\n const match = input.match(SEMVER_REGEXP) || [];\n const major = _parseInt(match[1]);\n const minor = _parseInt(match[2]);\n const patch = _parseInt(match[3]);\n return {\n buildmetadata: match[5],\n major: isNaN(major) ? undefined : major,\n minor: isNaN(minor) ? undefined : minor,\n patch: isNaN(patch) ? undefined : patch,\n prerelease: match[4],\n };\n}\n\n/**\n * This function adds context (pre/post/line) lines to the provided frame\n *\n * @param lines string[] containing all lines\n * @param frame StackFrame that will be mutated\n * @param linesOfContext number of context lines we want to add pre/post\n */\nfunction addContextToFrame(lines, frame, linesOfContext = 5) {\n // When there is no line number in the frame, attaching context is nonsensical and will even break grouping\n if (frame.lineno === undefined) {\n return;\n }\n\n const maxLines = lines.length;\n const sourceLine = Math.max(Math.min(maxLines - 1, frame.lineno - 1), 0);\n\n frame.pre_context = lines\n .slice(Math.max(0, sourceLine - linesOfContext), sourceLine)\n .map((line) => snipLine(line, 0));\n\n // We guard here to ensure this is not larger than the existing number of lines\n const lineIndex = Math.min(maxLines - 1, sourceLine);\n\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n frame.context_line = snipLine(lines[lineIndex], frame.colno || 0);\n\n frame.post_context = lines\n .slice(Math.min(sourceLine + 1, maxLines), sourceLine + 1 + linesOfContext)\n .map((line) => snipLine(line, 0));\n}\n\n/**\n * Checks whether or not we've already captured the given exception (note: not an identical exception - the very object\n * in question), and marks it captured if not.\n *\n * This is useful because it's possible for an error to get captured by more than one mechanism. After we intercept and\n * record an error, we rethrow it (assuming we've intercepted it before it's reached the top-level global handlers), so\n * that we don't interfere with whatever effects the error might have had were the SDK not there. At that point, because\n * the error has been rethrown, it's possible for it to bubble up to some other code we've instrumented. If it's not\n * caught after that, it will bubble all the way up to the global handlers (which of course we also instrument). This\n * function helps us ensure that even if we encounter the same error more than once, we only record it the first time we\n * see it.\n *\n * Note: It will ignore primitives (always return `false` and not mark them as seen), as properties can't be set on\n * them. {@link: Object.objectify} can be used on exceptions to convert any that are primitives into their equivalent\n * object wrapper forms so that this check will always work. However, because we need to flag the exact object which\n * will get rethrown, and because that rethrowing happens outside of the event processing pipeline, the objectification\n * must be done before the exception captured.\n *\n * @param A thrown exception to check or flag as having been seen\n * @returns `true` if the exception has already been captured, `false` if not (with the side effect of marking it seen)\n */\nfunction checkOrSetAlreadyCaught(exception) {\n if (isAlreadyCaptured(exception)) {\n return true;\n }\n\n try {\n // set it this way rather than by assignment so that it's not ennumerable and therefore isn't recorded by the\n // `ExtraErrorData` integration\n addNonEnumerableProperty(exception , '__sentry_captured__', true);\n } catch {\n // `exception` is a primitive, so we can't mark it seen\n }\n\n return false;\n}\n\nfunction isAlreadyCaptured(exception) {\n try {\n return (exception ).__sentry_captured__;\n } catch {} // eslint-disable-line no-empty\n}\n\nexport { addContextToFrame, addExceptionMechanism, addExceptionTypeValue, checkOrSetAlreadyCaught, getEventDescription, parseSemver, uuid4 };\n//# sourceMappingURL=misc.js.map\n","import { isString, isRegExp, isVueViewModel } from './is.js';\nimport { getVueInternalName } from './stacktrace.js';\n\n/**\n * Truncates given string to the maximum characters count\n *\n * @param str An object that contains serializable values\n * @param max Maximum number of characters in truncated string (0 = unlimited)\n * @returns string Encoded\n */\nfunction truncate(str, max = 0) {\n if (typeof str !== 'string' || max === 0) {\n return str;\n }\n return str.length <= max ? str : `${str.slice(0, max)}...`;\n}\n\n/**\n * This is basically just `trim_line` from\n * https://github.com/getsentry/sentry/blob/master/src/sentry/lang/javascript/processor.py#L67\n *\n * @param str An object that contains serializable values\n * @param max Maximum number of characters in truncated string\n * @returns string Encoded\n */\nfunction snipLine(line, colno) {\n let newLine = line;\n const lineLength = newLine.length;\n if (lineLength <= 150) {\n return newLine;\n }\n if (colno > lineLength) {\n // eslint-disable-next-line no-param-reassign\n colno = lineLength;\n }\n\n let start = Math.max(colno - 60, 0);\n if (start < 5) {\n start = 0;\n }\n\n let end = Math.min(start + 140, lineLength);\n if (end > lineLength - 5) {\n end = lineLength;\n }\n if (end === lineLength) {\n start = Math.max(end - 140, 0);\n }\n\n newLine = newLine.slice(start, end);\n if (start > 0) {\n newLine = `'{snip} ${newLine}`;\n }\n if (end < lineLength) {\n newLine += ' {snip}';\n }\n\n return newLine;\n}\n\n/**\n * Join values in array\n * @param input array of values to be joined together\n * @param delimiter string to be placed in-between values\n * @returns Joined values\n */\nfunction safeJoin(input, delimiter) {\n if (!Array.isArray(input)) {\n return '';\n }\n\n const output = [];\n // eslint-disable-next-line @typescript-eslint/prefer-for-of\n for (let i = 0; i < input.length; i++) {\n const value = input[i];\n try {\n // This is a hack to fix a Vue3-specific bug that causes an infinite loop of\n // console warnings. This happens when a Vue template is rendered with\n // an undeclared variable, which we try to stringify, ultimately causing\n // Vue to issue another warning which repeats indefinitely.\n // see: https://github.com/getsentry/sentry-javascript/pull/8981\n if (isVueViewModel(value)) {\n output.push(getVueInternalName(value));\n } else {\n output.push(String(value));\n }\n } catch {\n output.push('[value cannot be serialized]');\n }\n }\n\n return output.join(delimiter);\n}\n\n/**\n * Checks if the given value matches a regex or string\n *\n * @param value The string to test\n * @param pattern Either a regex or a string against which `value` will be matched\n * @param requireExactStringMatch If true, `value` must match `pattern` exactly. If false, `value` will match\n * `pattern` if it contains `pattern`. Only applies to string-type patterns.\n */\nfunction isMatchingPattern(\n value,\n pattern,\n requireExactStringMatch = false,\n) {\n if (!isString(value)) {\n return false;\n }\n\n if (isRegExp(pattern)) {\n return pattern.test(value);\n }\n if (isString(pattern)) {\n return requireExactStringMatch ? value === pattern : value.includes(pattern);\n }\n\n return false;\n}\n\n/**\n * Test the given string against an array of strings and regexes. By default, string matching is done on a\n * substring-inclusion basis rather than a strict equality basis\n *\n * @param testString The string to test\n * @param patterns The patterns against which to test the string\n * @param requireExactStringMatch If true, `testString` must match one of the given string patterns exactly in order to\n * count. If false, `testString` will match a string pattern if it contains that pattern.\n * @returns\n */\nfunction stringMatchesSomePattern(\n testString,\n patterns = [],\n requireExactStringMatch = false,\n) {\n return patterns.some(pattern => isMatchingPattern(testString, pattern, requireExactStringMatch));\n}\n\nexport { isMatchingPattern, safeJoin, snipLine, stringMatchesSomePattern, truncate };\n//# sourceMappingURL=string.js.map\n","import { safeDateNow, withRandomSafeContext } from './randomSafeContext.js';\nimport { GLOBAL_OBJ } from './worldwide.js';\n\nconst ONE_SECOND_IN_MS = 1000;\n\n/**\n * A partial definition of the [Performance Web API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Performance}\n * for accessing a high-resolution monotonic clock.\n */\n\n/**\n * Returns a timestamp in seconds since the UNIX epoch using the Date API.\n */\nfunction dateTimestampInSeconds() {\n return safeDateNow() / ONE_SECOND_IN_MS;\n}\n\n/**\n * Returns a wrapper around the native Performance API browser implementation, or undefined for browsers that do not\n * support the API.\n *\n * Wrapping the native API works around differences in behavior from different browsers.\n */\nfunction createUnixTimestampInSecondsFunc() {\n const { performance } = GLOBAL_OBJ ;\n // Some browser and environments don't have a performance or timeOrigin, so we fallback to\n // using Date.now() to compute the starting time.\n if (!performance?.now || !performance.timeOrigin) {\n return dateTimestampInSeconds;\n }\n\n const timeOrigin = performance.timeOrigin;\n\n // performance.now() is a monotonic clock, which means it starts at 0 when the process begins. To get the current\n // wall clock time (actual UNIX timestamp), we need to add the starting time origin and the current time elapsed.\n //\n // TODO: This does not account for the case where the monotonic clock that powers performance.now() drifts from the\n // wall clock time, which causes the returned timestamp to be inaccurate. We should investigate how to detect and\n // correct for this.\n // See: https://github.com/getsentry/sentry-javascript/issues/2590\n // See: https://github.com/mdn/content/issues/4713\n // See: https://dev.to/noamr/when-a-millisecond-is-not-a-millisecond-3h6\n return () => {\n return (timeOrigin + withRandomSafeContext(() => performance.now())) / ONE_SECOND_IN_MS;\n };\n}\n\nlet _cachedTimestampInSeconds;\n\n/**\n * Returns a timestamp in seconds since the UNIX epoch using either the Performance or Date APIs, depending on the\n * availability of the Performance API.\n *\n * BUG: Note that because of how browsers implement the Performance API, the clock might stop when the computer is\n * asleep. This creates a skew between `dateTimestampInSeconds` and `timestampInSeconds`. The\n * skew can grow to arbitrary amounts like days, weeks or months.\n * See https://github.com/getsentry/sentry-javascript/issues/2590.\n */\nfunction timestampInSeconds() {\n // We store this in a closure so that we don't have to create a new function every time this is called.\n const func = _cachedTimestampInSeconds ?? (_cachedTimestampInSeconds = createUnixTimestampInSecondsFunc());\n return func();\n}\n\n/**\n * Cached result of getBrowserTimeOrigin.\n */\nlet cachedTimeOrigin = null;\n\n/**\n * Gets the time origin and the mode used to determine it.\n *\n * Unfortunately browsers may report an inaccurate time origin data, through either performance.timeOrigin or\n * performance.timing.navigationStart, which results in poor results in performance data. We only treat time origin\n * data as reliable if they are within a reasonable threshold of the current time.\n *\n * TODO: move to `@sentry/browser-utils` package.\n */\nfunction getBrowserTimeOrigin() {\n const { performance } = GLOBAL_OBJ ;\n if (!performance?.now) {\n return undefined;\n }\n\n const threshold = 300000; // 5 minutes in milliseconds\n const performanceNow = withRandomSafeContext(() => performance.now());\n const dateNow = safeDateNow();\n\n const timeOrigin = performance.timeOrigin;\n if (typeof timeOrigin === 'number') {\n const timeOriginDelta = Math.abs(timeOrigin + performanceNow - dateNow);\n if (timeOriginDelta < threshold) {\n return timeOrigin;\n }\n }\n\n // TODO: Remove all code related to `performance.timing.navigationStart` once we drop support for Safari 14.\n // `performance.timeSince` is available in Safari 15.\n // see: https://caniuse.com/mdn-api_performance_timeorigin\n\n // While performance.timing.navigationStart is deprecated in favor of performance.timeOrigin, performance.timeOrigin\n // is not as widely supported. Namely, performance.timeOrigin is undefined in Safari as of writing.\n // Also as of writing, performance.timing is not available in Web Workers in mainstream browsers, so it is not always\n // a valid fallback. In the absence of an initial time provided by the browser, fallback to the current time from the\n // Date API.\n // eslint-disable-next-line deprecation/deprecation\n const navigationStart = performance.timing?.navigationStart;\n if (typeof navigationStart === 'number') {\n const navigationStartDelta = Math.abs(navigationStart + performanceNow - dateNow);\n if (navigationStartDelta < threshold) {\n return navigationStart;\n }\n }\n\n // Either both timeOrigin and navigationStart are skewed or neither is available, fallback to subtracting\n // `performance.now()` from `Date.now()`.\n return dateNow - performanceNow;\n}\n\n/**\n * The number of milliseconds since the UNIX epoch. This value is only usable in a browser, and only when the\n * performance API is available.\n */\nfunction browserPerformanceTimeOrigin() {\n if (cachedTimeOrigin === null) {\n cachedTimeOrigin = getBrowserTimeOrigin();\n }\n\n return cachedTimeOrigin;\n}\n\nexport { browserPerformanceTimeOrigin, dateTimestampInSeconds, timestampInSeconds };\n//# sourceMappingURL=time.js.map\n","import { uuid4 } from './utils/misc.js';\nimport { timestampInSeconds } from './utils/time.js';\n\n/**\n * Creates a new `Session` object by setting certain default parameters. If optional @param context\n * is passed, the passed properties are applied to the session object.\n *\n * @param context (optional) additional properties to be applied to the returned session object\n *\n * @returns a new `Session` object\n */\nfunction makeSession(context) {\n // Both timestamp and started are in seconds since the UNIX epoch.\n const startingTime = timestampInSeconds();\n\n const session = {\n sid: uuid4(),\n init: true,\n timestamp: startingTime,\n started: startingTime,\n duration: 0,\n status: 'ok',\n errors: 0,\n ignoreDuration: false,\n toJSON: () => sessionToJSON(session),\n };\n\n if (context) {\n updateSession(session, context);\n }\n\n return session;\n}\n\n/**\n * Updates a session object with the properties passed in the context.\n *\n * Note that this function mutates the passed object and returns void.\n * (Had to do this instead of returning a new and updated session because closing and sending a session\n * makes an update to the session after it was passed to the sending logic.\n * @see Client.captureSession )\n *\n * @param session the `Session` to update\n * @param context the `SessionContext` holding the properties that should be updated in @param session\n */\n// eslint-disable-next-line complexity\nfunction updateSession(session, context = {}) {\n if (context.user) {\n if (!session.ipAddress && context.user.ip_address) {\n session.ipAddress = context.user.ip_address;\n }\n\n if (!session.did && !context.did) {\n session.did = context.user.id || context.user.email || context.user.username;\n }\n }\n\n session.timestamp = context.timestamp || timestampInSeconds();\n\n if (context.abnormal_mechanism) {\n session.abnormal_mechanism = context.abnormal_mechanism;\n }\n\n if (context.ignoreDuration) {\n session.ignoreDuration = context.ignoreDuration;\n }\n if (context.sid) {\n // Good enough uuid validation. — Kamil\n session.sid = context.sid.length === 32 ? context.sid : uuid4();\n }\n if (context.init !== undefined) {\n session.init = context.init;\n }\n if (!session.did && context.did) {\n session.did = `${context.did}`;\n }\n if (typeof context.started === 'number') {\n session.started = context.started;\n }\n if (session.ignoreDuration) {\n session.duration = undefined;\n } else if (typeof context.duration === 'number') {\n session.duration = context.duration;\n } else {\n const duration = session.timestamp - session.started;\n session.duration = duration >= 0 ? duration : 0;\n }\n if (context.release) {\n session.release = context.release;\n }\n if (context.environment) {\n session.environment = context.environment;\n }\n if (!session.ipAddress && context.ipAddress) {\n session.ipAddress = context.ipAddress;\n }\n if (!session.userAgent && context.userAgent) {\n session.userAgent = context.userAgent;\n }\n if (typeof context.errors === 'number') {\n session.errors = context.errors;\n }\n if (context.status) {\n session.status = context.status;\n }\n}\n\n/**\n * Closes a session by setting its status and updating the session object with it.\n * Internally calls `updateSession` to update the passed session object.\n *\n * Note that this function mutates the passed session (@see updateSession for explanation).\n *\n * @param session the `Session` object to be closed\n * @param status the `SessionStatus` with which the session was closed. If you don't pass a status,\n * this function will keep the previously set status, unless it was `'ok'` in which case\n * it is changed to `'exited'`.\n */\nfunction closeSession(session, status) {\n let context = {};\n if (status) {\n context = { status };\n } else if (session.status === 'ok') {\n context = { status: 'exited' };\n }\n\n updateSession(session, context);\n}\n\n/**\n * Serializes a passed session object to a JSON object with a slightly different structure.\n * This is necessary because the Sentry backend requires a slightly different schema of a session\n * than the one the JS SDKs use internally.\n *\n * @param session the session to be converted\n *\n * @returns a JSON object of the passed session\n */\nfunction sessionToJSON(session) {\n return {\n sid: `${session.sid}`,\n init: session.init,\n // Make sure that sec is converted to ms for date constructor\n started: new Date(session.started * 1000).toISOString(),\n timestamp: new Date(session.timestamp * 1000).toISOString(),\n status: session.status,\n errors: session.errors,\n did: typeof session.did === 'number' || typeof session.did === 'string' ? `${session.did}` : undefined,\n duration: session.duration,\n abnormal_mechanism: session.abnormal_mechanism,\n attrs: {\n release: session.release,\n environment: session.environment,\n ip_address: session.ipAddress,\n user_agent: session.userAgent,\n },\n };\n}\n\nexport { closeSession, makeSession, updateSession };\n//# sourceMappingURL=session.js.map\n","/**\n * Shallow merge two objects.\n * Does not mutate the passed in objects.\n * Undefined/empty values in the merge object will overwrite existing values.\n *\n * By default, this merges 2 levels deep.\n */\nfunction merge(initialObj, mergeObj, levels = 2) {\n // If the merge value is not an object, or we have no merge levels left,\n // we just set the value to the merge value\n if (!mergeObj || typeof mergeObj !== 'object' || levels <= 0) {\n return mergeObj;\n }\n\n // If the merge object is an empty object, and the initial object is not undefined, we return the initial object\n if (initialObj && Object.keys(mergeObj).length === 0) {\n return initialObj;\n }\n\n // Clone object\n const output = { ...initialObj };\n\n // Merge values into output, resursively\n for (const key in mergeObj) {\n if (Object.prototype.hasOwnProperty.call(mergeObj, key)) {\n output[key] = merge(output[key], mergeObj[key], levels - 1);\n }\n }\n\n return output;\n}\n\nexport { merge };\n//# sourceMappingURL=merge.js.map\n","import { uuid4 } from './misc.js';\n\n/**\n * Generate a random, valid trace ID.\n */\nfunction generateTraceId() {\n return uuid4();\n}\n\n/**\n * Generate a random, valid span ID.\n */\nfunction generateSpanId() {\n return uuid4().substring(16);\n}\n\nexport { generateSpanId, generateTraceId };\n//# sourceMappingURL=propagationContext.js.map\n","import { addNonEnumerableProperty } from './object.js';\n\nconst SCOPE_SPAN_FIELD = '_sentrySpan';\n\n/**\n * Set the active span for a given scope.\n * NOTE: This should NOT be used directly, but is only used internally by the trace methods.\n */\nfunction _setSpanForScope(scope, span) {\n if (span) {\n addNonEnumerableProperty(scope , SCOPE_SPAN_FIELD, span);\n } else {\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete (scope )[SCOPE_SPAN_FIELD];\n }\n}\n\n/**\n * Get the active span for a given scope.\n * NOTE: This should NOT be used directly, but is only used internally by the trace methods.\n */\nfunction _getSpanForScope(scope) {\n return scope[SCOPE_SPAN_FIELD];\n}\n\nexport { _getSpanForScope, _setSpanForScope };\n//# sourceMappingURL=spanOnScope.js.map\n","import { DEBUG_BUILD } from './debug-build.js';\nimport { updateSession } from './session.js';\nimport { debug } from './utils/debug-logger.js';\nimport { isPlainObject } from './utils/is.js';\nimport { merge } from './utils/merge.js';\nimport { uuid4 } from './utils/misc.js';\nimport { generateTraceId } from './utils/propagationContext.js';\nimport { safeMathRandom } from './utils/randomSafeContext.js';\nimport { _setSpanForScope, _getSpanForScope } from './utils/spanOnScope.js';\nimport { truncate } from './utils/string.js';\nimport { dateTimestampInSeconds } from './utils/time.js';\n\n/**\n * Default value for maximum number of breadcrumbs added to an event.\n */\nconst DEFAULT_MAX_BREADCRUMBS = 100;\n\n/**\n * A context to be used for capturing an event.\n * This can either be a Scope, or a partial ScopeContext,\n * or a callback that receives the current scope and returns a new scope to use.\n */\n\n/**\n * Holds additional event information.\n */\nclass Scope {\n /** Flag if notifying is happening. */\n\n /** Callback for client to receive scope changes. */\n\n /** Callback list that will be called during event processing. */\n\n /** Array of breadcrumbs. */\n\n /** User */\n\n /** Tags */\n\n /** Attributes */\n\n /** Extra */\n\n /** Contexts */\n\n /** Attachments */\n\n /** Propagation Context for distributed tracing */\n\n /**\n * A place to stash data which is needed at some point in the SDK's event processing pipeline but which shouldn't get\n * sent to Sentry\n */\n\n /** Fingerprint */\n\n /** Severity */\n\n /**\n * Transaction Name\n *\n * IMPORTANT: The transaction name on the scope has nothing to do with root spans/transaction objects.\n * It's purpose is to assign a transaction to the scope that's added to non-transaction events.\n */\n\n /** Session */\n\n /** The client on this scope */\n\n /** Contains the last event id of a captured event. */\n\n /** Conversation ID */\n\n // NOTE: Any field which gets added here should get added not only to the constructor but also to the `clone` method.\n\n constructor() {\n this._notifyingListeners = false;\n this._scopeListeners = [];\n this._eventProcessors = [];\n this._breadcrumbs = [];\n this._attachments = [];\n this._user = {};\n this._tags = {};\n this._attributes = {};\n this._extra = {};\n this._contexts = {};\n this._sdkProcessingMetadata = {};\n this._propagationContext = {\n traceId: generateTraceId(),\n sampleRand: safeMathRandom(),\n };\n }\n\n /**\n * Clone all data from this scope into a new scope.\n */\n clone() {\n const newScope = new Scope();\n newScope._breadcrumbs = [...this._breadcrumbs];\n newScope._tags = { ...this._tags };\n newScope._attributes = { ...this._attributes };\n newScope._extra = { ...this._extra };\n newScope._contexts = { ...this._contexts };\n if (this._contexts.flags) {\n // We need to copy the `values` array so insertions on a cloned scope\n // won't affect the original array.\n newScope._contexts.flags = {\n values: [...this._contexts.flags.values],\n };\n }\n\n newScope._user = this._user;\n newScope._level = this._level;\n newScope._session = this._session;\n newScope._transactionName = this._transactionName;\n newScope._fingerprint = this._fingerprint;\n newScope._eventProcessors = [...this._eventProcessors];\n newScope._attachments = [...this._attachments];\n newScope._sdkProcessingMetadata = { ...this._sdkProcessingMetadata };\n newScope._propagationContext = { ...this._propagationContext };\n newScope._client = this._client;\n newScope._lastEventId = this._lastEventId;\n newScope._conversationId = this._conversationId;\n\n _setSpanForScope(newScope, _getSpanForScope(this));\n\n return newScope;\n }\n\n /**\n * Update the client assigned to this scope.\n * Note that not every scope will have a client assigned - isolation scopes & the global scope will generally not have a client,\n * as well as manually created scopes.\n */\n setClient(client) {\n this._client = client;\n }\n\n /**\n * Set the ID of the last captured error event.\n * This is generally only captured on the isolation scope.\n */\n setLastEventId(lastEventId) {\n this._lastEventId = lastEventId;\n }\n\n /**\n * Get the client assigned to this scope.\n */\n getClient() {\n return this._client ;\n }\n\n /**\n * Get the ID of the last captured error event.\n * This is generally only available on the isolation scope.\n */\n lastEventId() {\n return this._lastEventId;\n }\n\n /**\n * @inheritDoc\n */\n addScopeListener(callback) {\n this._scopeListeners.push(callback);\n }\n\n /**\n * Add an event processor that will be called before an event is sent.\n */\n addEventProcessor(callback) {\n this._eventProcessors.push(callback);\n return this;\n }\n\n /**\n * Set the user for this scope.\n * Set to `null` to unset the user.\n */\n setUser(user) {\n // If null is passed we want to unset everything, but still define keys,\n // so that later down in the pipeline any existing values are cleared.\n this._user = user || {\n email: undefined,\n id: undefined,\n ip_address: undefined,\n username: undefined,\n };\n\n if (this._session) {\n updateSession(this._session, { user });\n }\n\n this._notifyScopeListeners();\n return this;\n }\n\n /**\n * Get the user from this scope.\n */\n getUser() {\n return this._user;\n }\n\n /**\n * Set the conversation ID for this scope.\n * Set to `null` to unset the conversation ID.\n */\n setConversationId(conversationId) {\n this._conversationId = conversationId || undefined;\n this._notifyScopeListeners();\n return this;\n }\n\n /**\n * Set an object that will be merged into existing tags on the scope,\n * and will be sent as tags data with the event.\n */\n setTags(tags) {\n this._tags = {\n ...this._tags,\n ...tags,\n };\n this._notifyScopeListeners();\n return this;\n }\n\n /**\n * Set a single tag that will be sent as tags data with the event.\n */\n setTag(key, value) {\n return this.setTags({ [key]: value });\n }\n\n /**\n * Sets attributes onto the scope.\n *\n * These attributes are currently applied to logs and metrics.\n * In the future, they will also be applied to spans.\n *\n * Important: For now, only strings, numbers and boolean attributes are supported, despite types allowing for\n * more complex attribute types. We'll add this support in the future but already specify the wider type to\n * avoid a breaking change in the future.\n *\n * @param newAttributes - The attributes to set on the scope. You can either pass in key-value pairs, or\n * an object with a `value` and an optional `unit` (if applicable to your attribute).\n *\n * @example\n * ```typescript\n * scope.setAttributes({\n * is_admin: true,\n * payment_selection: 'credit_card',\n * render_duration: { value: 'render_duration', unit: 'ms' },\n * });\n * ```\n */\n setAttributes(newAttributes) {\n this._attributes = {\n ...this._attributes,\n ...newAttributes,\n };\n\n this._notifyScopeListeners();\n return this;\n }\n\n /**\n * Sets an attribute onto the scope.\n *\n * These attributes are currently applied to logs and metrics.\n * In the future, they will also be applied to spans.\n *\n * Important: For now, only strings, numbers and boolean attributes are supported, despite types allowing for\n * more complex attribute types. We'll add this support in the future but already specify the wider type to\n * avoid a breaking change in the future.\n *\n * @param key - The attribute key.\n * @param value - the attribute value. You can either pass in a raw value, or an attribute\n * object with a `value` and an optional `unit` (if applicable to your attribute).\n *\n * @example\n * ```typescript\n * scope.setAttribute('is_admin', true);\n * scope.setAttribute('render_duration', { value: 'render_duration', unit: 'ms' });\n * ```\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n setAttribute(\n key,\n value,\n ) {\n return this.setAttributes({ [key]: value });\n }\n\n /**\n * Removes the attribute with the given key from the scope.\n *\n * @param key - The attribute key.\n *\n * @example\n * ```typescript\n * scope.removeAttribute('is_admin');\n * ```\n */\n removeAttribute(key) {\n if (key in this._attributes) {\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete this._attributes[key];\n this._notifyScopeListeners();\n }\n return this;\n }\n\n /**\n * Set an object that will be merged into existing extra on the scope,\n * and will be sent as extra data with the event.\n */\n setExtras(extras) {\n this._extra = {\n ...this._extra,\n ...extras,\n };\n this._notifyScopeListeners();\n return this;\n }\n\n /**\n * Set a single key:value extra entry that will be sent as extra data with the event.\n */\n setExtra(key, extra) {\n this._extra = { ...this._extra, [key]: extra };\n this._notifyScopeListeners();\n return this;\n }\n\n /**\n * Sets the fingerprint on the scope to send with the events.\n * @param {string[]} fingerprint Fingerprint to group events in Sentry.\n */\n setFingerprint(fingerprint) {\n this._fingerprint = fingerprint;\n this._notifyScopeListeners();\n return this;\n }\n\n /**\n * Sets the level on the scope for future events.\n */\n setLevel(level) {\n this._level = level;\n this._notifyScopeListeners();\n return this;\n }\n\n /**\n * Sets the transaction name on the scope so that the name of e.g. taken server route or\n * the page location is attached to future events.\n *\n * IMPORTANT: Calling this function does NOT change the name of the currently active\n * root span. If you want to change the name of the active root span, use\n * `Sentry.updateSpanName(rootSpan, 'new name')` instead.\n *\n * By default, the SDK updates the scope's transaction name automatically on sensible\n * occasions, such as a page navigation or when handling a new request on the server.\n */\n setTransactionName(name) {\n this._transactionName = name;\n this._notifyScopeListeners();\n return this;\n }\n\n /**\n * Sets context data with the given name.\n * Data passed as context will be normalized. You can also pass `null` to unset the context.\n * Note that context data will not be merged - calling `setContext` will overwrite an existing context with the same key.\n */\n setContext(key, context) {\n if (context === null) {\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete this._contexts[key];\n } else {\n this._contexts[key] = context;\n }\n\n this._notifyScopeListeners();\n return this;\n }\n\n /**\n * Set the session for the scope.\n */\n setSession(session) {\n if (!session) {\n delete this._session;\n } else {\n this._session = session;\n }\n this._notifyScopeListeners();\n return this;\n }\n\n /**\n * Get the session from the scope.\n */\n getSession() {\n return this._session;\n }\n\n /**\n * Updates the scope with provided data. Can work in three variations:\n * - plain object containing updatable attributes\n * - Scope instance that'll extract the attributes from\n * - callback function that'll receive the current scope as an argument and allow for modifications\n */\n update(captureContext) {\n if (!captureContext) {\n return this;\n }\n\n const scopeToMerge = typeof captureContext === 'function' ? captureContext(this) : captureContext;\n\n const scopeInstance =\n scopeToMerge instanceof Scope\n ? scopeToMerge.getScopeData()\n : isPlainObject(scopeToMerge)\n ? (captureContext )\n : undefined;\n\n const {\n tags,\n attributes,\n extra,\n user,\n contexts,\n level,\n fingerprint = [],\n propagationContext,\n conversationId,\n } = scopeInstance || {};\n\n this._tags = { ...this._tags, ...tags };\n this._attributes = { ...this._attributes, ...attributes };\n this._extra = { ...this._extra, ...extra };\n this._contexts = { ...this._contexts, ...contexts };\n\n if (user && Object.keys(user).length) {\n this._user = user;\n }\n\n if (level) {\n this._level = level;\n }\n\n if (fingerprint.length) {\n this._fingerprint = fingerprint;\n }\n\n if (propagationContext) {\n this._propagationContext = propagationContext;\n }\n\n if (conversationId) {\n this._conversationId = conversationId;\n }\n\n return this;\n }\n\n /**\n * Clears the current scope and resets its properties.\n * Note: The client will not be cleared.\n */\n clear() {\n // client is not cleared here on purpose!\n this._breadcrumbs = [];\n this._tags = {};\n this._attributes = {};\n this._extra = {};\n this._user = {};\n this._contexts = {};\n this._level = undefined;\n this._transactionName = undefined;\n this._fingerprint = undefined;\n this._session = undefined;\n this._conversationId = undefined;\n _setSpanForScope(this, undefined);\n this._attachments = [];\n this.setPropagationContext({\n traceId: generateTraceId(),\n sampleRand: safeMathRandom(),\n });\n\n this._notifyScopeListeners();\n return this;\n }\n\n /**\n * Adds a breadcrumb to the scope.\n * By default, the last 100 breadcrumbs are kept.\n */\n addBreadcrumb(breadcrumb, maxBreadcrumbs) {\n const maxCrumbs = typeof maxBreadcrumbs === 'number' ? maxBreadcrumbs : DEFAULT_MAX_BREADCRUMBS;\n\n // No data has been changed, so don't notify scope listeners\n if (maxCrumbs <= 0) {\n return this;\n }\n\n const mergedBreadcrumb = {\n timestamp: dateTimestampInSeconds(),\n ...breadcrumb,\n // Breadcrumb messages can theoretically be infinitely large and they're held in memory so we truncate them not to leak (too much) memory\n message: breadcrumb.message ? truncate(breadcrumb.message, 2048) : breadcrumb.message,\n };\n\n this._breadcrumbs.push(mergedBreadcrumb);\n if (this._breadcrumbs.length > maxCrumbs) {\n this._breadcrumbs = this._breadcrumbs.slice(-maxCrumbs);\n this._client?.recordDroppedEvent('buffer_overflow', 'log_item');\n }\n\n this._notifyScopeListeners();\n\n return this;\n }\n\n /**\n * Get the last breadcrumb of the scope.\n */\n getLastBreadcrumb() {\n return this._breadcrumbs[this._breadcrumbs.length - 1];\n }\n\n /**\n * Clear all breadcrumbs from the scope.\n */\n clearBreadcrumbs() {\n this._breadcrumbs = [];\n this._notifyScopeListeners();\n return this;\n }\n\n /**\n * Add an attachment to the scope.\n */\n addAttachment(attachment) {\n this._attachments.push(attachment);\n return this;\n }\n\n /**\n * Clear all attachments from the scope.\n */\n clearAttachments() {\n this._attachments = [];\n return this;\n }\n\n /**\n * Get the data of this scope, which should be applied to an event during processing.\n */\n getScopeData() {\n return {\n breadcrumbs: this._breadcrumbs,\n attachments: this._attachments,\n contexts: this._contexts,\n tags: this._tags,\n attributes: this._attributes,\n extra: this._extra,\n user: this._user,\n level: this._level,\n fingerprint: this._fingerprint || [],\n eventProcessors: this._eventProcessors,\n propagationContext: this._propagationContext,\n sdkProcessingMetadata: this._sdkProcessingMetadata,\n transactionName: this._transactionName,\n span: _getSpanForScope(this),\n conversationId: this._conversationId,\n };\n }\n\n /**\n * Add data which will be accessible during event processing but won't get sent to Sentry.\n */\n setSDKProcessingMetadata(newData) {\n this._sdkProcessingMetadata = merge(this._sdkProcessingMetadata, newData, 2);\n return this;\n }\n\n /**\n * Add propagation context to the scope, used for distributed tracing\n */\n setPropagationContext(context) {\n this._propagationContext = context;\n return this;\n }\n\n /**\n * Get propagation context from the scope, used for distributed tracing\n */\n getPropagationContext() {\n return this._propagationContext;\n }\n\n /**\n * Capture an exception for this scope.\n *\n * @returns {string} The id of the captured Sentry event.\n */\n captureException(exception, hint) {\n const eventId = hint?.event_id || uuid4();\n\n if (!this._client) {\n DEBUG_BUILD && debug.warn('No client configured on scope - will not capture exception!');\n return eventId;\n }\n\n const syntheticException = new Error('Sentry syntheticException');\n\n this._client.captureException(\n exception,\n {\n originalException: exception,\n syntheticException,\n ...hint,\n event_id: eventId,\n },\n this,\n );\n\n return eventId;\n }\n\n /**\n * Capture a message for this scope.\n *\n * @returns {string} The id of the captured message.\n */\n captureMessage(message, level, hint) {\n const eventId = hint?.event_id || uuid4();\n\n if (!this._client) {\n DEBUG_BUILD && debug.warn('No client configured on scope - will not capture message!');\n return eventId;\n }\n\n const syntheticException = hint?.syntheticException ?? new Error(message);\n\n this._client.captureMessage(\n message,\n level,\n {\n originalException: message,\n syntheticException,\n ...hint,\n event_id: eventId,\n },\n this,\n );\n\n return eventId;\n }\n\n /**\n * Capture a Sentry event for this scope.\n *\n * @returns {string} The id of the captured event.\n */\n captureEvent(event, hint) {\n const eventId = hint?.event_id || uuid4();\n\n if (!this._client) {\n DEBUG_BUILD && debug.warn('No client configured on scope - will not capture event!');\n return eventId;\n }\n\n this._client.captureEvent(event, { ...hint, event_id: eventId }, this);\n\n return eventId;\n }\n\n /**\n * This will be called on every set call.\n */\n _notifyScopeListeners() {\n // We need this check for this._notifyingListeners to be able to work on scope during updates\n // If this check is not here we'll produce endless recursion when something is done with the scope\n // during the callback.\n if (!this._notifyingListeners) {\n this._notifyingListeners = true;\n this._scopeListeners.forEach(callback => {\n callback(this);\n });\n this._notifyingListeners = false;\n }\n }\n}\n\nexport { Scope };\n//# sourceMappingURL=scope.js.map\n","import { getGlobalSingleton } from './carrier.js';\nimport { Scope } from './scope.js';\n\n/** Get the default current scope. */\nfunction getDefaultCurrentScope() {\n return getGlobalSingleton('defaultCurrentScope', () => new Scope());\n}\n\n/** Get the default isolation scope. */\nfunction getDefaultIsolationScope() {\n return getGlobalSingleton('defaultIsolationScope', () => new Scope());\n}\n\nexport { getDefaultCurrentScope, getDefaultIsolationScope };\n//# sourceMappingURL=defaultScopes.js.map\n","import { getDefaultCurrentScope, getDefaultIsolationScope } from '../defaultScopes.js';\nimport { Scope } from '../scope.js';\nimport { isThenable } from '../utils/is.js';\nimport { getMainCarrier, getSentryCarrier } from '../carrier.js';\n\n/**\n * This is an object that holds a stack of scopes.\n */\nclass AsyncContextStack {\n\n constructor(scope, isolationScope) {\n let assignedScope;\n if (!scope) {\n assignedScope = new Scope();\n } else {\n assignedScope = scope;\n }\n\n let assignedIsolationScope;\n if (!isolationScope) {\n assignedIsolationScope = new Scope();\n } else {\n assignedIsolationScope = isolationScope;\n }\n\n // scope stack for domains or the process\n this._stack = [{ scope: assignedScope }];\n this._isolationScope = assignedIsolationScope;\n }\n\n /**\n * Fork a scope for the stack.\n */\n withScope(callback) {\n const scope = this._pushScope();\n\n let maybePromiseResult;\n try {\n maybePromiseResult = callback(scope);\n } catch (e) {\n this._popScope();\n throw e;\n }\n\n if (isThenable(maybePromiseResult)) {\n // @ts-expect-error - isThenable returns the wrong type\n return maybePromiseResult.then(\n res => {\n this._popScope();\n return res;\n },\n e => {\n this._popScope();\n throw e;\n },\n );\n }\n\n this._popScope();\n return maybePromiseResult;\n }\n\n /**\n * Get the client of the stack.\n */\n getClient() {\n return this.getStackTop().client ;\n }\n\n /**\n * Returns the scope of the top stack.\n */\n getScope() {\n return this.getStackTop().scope;\n }\n\n /**\n * Get the isolation scope for the stack.\n */\n getIsolationScope() {\n return this._isolationScope;\n }\n\n /**\n * Returns the topmost scope layer in the order domain > local > process.\n */\n getStackTop() {\n return this._stack[this._stack.length - 1] ;\n }\n\n /**\n * Push a scope to the stack.\n */\n _pushScope() {\n // We want to clone the content of prev scope\n const scope = this.getScope().clone();\n this._stack.push({\n client: this.getClient(),\n scope,\n });\n return scope;\n }\n\n /**\n * Pop a scope from the stack.\n */\n _popScope() {\n if (this._stack.length <= 1) return false;\n return !!this._stack.pop();\n }\n}\n\n/**\n * Get the global async context stack.\n * This will be removed during the v8 cycle and is only here to make migration easier.\n */\nfunction getAsyncContextStack() {\n const registry = getMainCarrier();\n const sentry = getSentryCarrier(registry);\n\n return (sentry.stack = sentry.stack || new AsyncContextStack(getDefaultCurrentScope(), getDefaultIsolationScope()));\n}\n\nfunction withScope(callback) {\n return getAsyncContextStack().withScope(callback);\n}\n\nfunction withSetScope(scope, callback) {\n const stack = getAsyncContextStack();\n return stack.withScope(() => {\n stack.getStackTop().scope = scope;\n return callback(scope);\n });\n}\n\nfunction withIsolationScope(callback) {\n return getAsyncContextStack().withScope(() => {\n return callback(getAsyncContextStack().getIsolationScope());\n });\n}\n\n/**\n * Get the stack-based async context strategy.\n */\nfunction getStackAsyncContextStrategy() {\n return {\n withIsolationScope,\n withScope,\n withSetScope,\n withSetIsolationScope: (_isolationScope, callback) => {\n return withIsolationScope(callback);\n },\n getCurrentScope: () => getAsyncContextStack().getScope(),\n getIsolationScope: () => getAsyncContextStack().getIsolationScope(),\n };\n}\n\nexport { AsyncContextStack, getStackAsyncContextStrategy };\n//# sourceMappingURL=stackStrategy.js.map\n","import { getMainCarrier, getSentryCarrier } from '../carrier.js';\nimport { getStackAsyncContextStrategy } from './stackStrategy.js';\n\n/**\n * @private Private API with no semver guarantees!\n *\n * Sets the global async context strategy\n */\nfunction setAsyncContextStrategy(strategy) {\n // Get main carrier (global for every environment)\n const registry = getMainCarrier();\n const sentry = getSentryCarrier(registry);\n sentry.acs = strategy;\n}\n\n/**\n * Get the current async context strategy.\n * If none has been setup, the default will be used.\n */\nfunction getAsyncContextStrategy(carrier) {\n const sentry = getSentryCarrier(carrier);\n\n if (sentry.acs) {\n return sentry.acs;\n }\n\n // Otherwise, use the default one (stack)\n return getStackAsyncContextStrategy();\n}\n\nexport { getAsyncContextStrategy, setAsyncContextStrategy };\n//# sourceMappingURL=index.js.map\n","import { getAsyncContextStrategy } from './asyncContext/index.js';\nimport { getMainCarrier, getGlobalSingleton } from './carrier.js';\nimport { Scope } from './scope.js';\nimport { generateSpanId } from './utils/propagationContext.js';\n\n/**\n * Get the currently active scope.\n */\nfunction getCurrentScope() {\n const carrier = getMainCarrier();\n const acs = getAsyncContextStrategy(carrier);\n return acs.getCurrentScope();\n}\n\n/**\n * Get the currently active isolation scope.\n * The isolation scope is active for the current execution context.\n */\nfunction getIsolationScope() {\n const carrier = getMainCarrier();\n const acs = getAsyncContextStrategy(carrier);\n return acs.getIsolationScope();\n}\n\n/**\n * Get the global scope.\n * This scope is applied to _all_ events.\n */\nfunction getGlobalScope() {\n return getGlobalSingleton('globalScope', () => new Scope());\n}\n\n/**\n * Creates a new scope with and executes the given operation within.\n * The scope is automatically removed once the operation\n * finishes or throws.\n */\n\n/**\n * Either creates a new active scope, or sets the given scope as active scope in the given callback.\n */\nfunction withScope(\n ...rest\n) {\n const carrier = getMainCarrier();\n const acs = getAsyncContextStrategy(carrier);\n\n // If a scope is defined, we want to make this the active scope instead of the default one\n if (rest.length === 2) {\n const [scope, callback] = rest;\n\n if (!scope) {\n return acs.withScope(callback);\n }\n\n return acs.withSetScope(scope, callback);\n }\n\n return acs.withScope(rest[0]);\n}\n\n/**\n * Attempts to fork the current isolation scope and the current scope based on the current async context strategy. If no\n * async context strategy is set, the isolation scope and the current scope will not be forked (this is currently the\n * case, for example, in the browser).\n *\n * Usage of this function in environments without async context strategy is discouraged and may lead to unexpected behaviour.\n *\n * This function is intended for Sentry SDK and SDK integration development. It is not recommended to be used in \"normal\"\n * applications directly because it comes with pitfalls. Use at your own risk!\n */\n\n/**\n * Either creates a new active isolation scope, or sets the given isolation scope as active scope in the given callback.\n */\nfunction withIsolationScope(\n ...rest\n\n) {\n const carrier = getMainCarrier();\n const acs = getAsyncContextStrategy(carrier);\n\n // If a scope is defined, we want to make this the active scope instead of the default one\n if (rest.length === 2) {\n const [isolationScope, callback] = rest;\n\n if (!isolationScope) {\n return acs.withIsolationScope(callback);\n }\n\n return acs.withSetIsolationScope(isolationScope, callback);\n }\n\n return acs.withIsolationScope(rest[0]);\n}\n\n/**\n * Get the currently active client.\n */\nfunction getClient() {\n return getCurrentScope().getClient();\n}\n\n/**\n * Get a trace context for the given scope.\n */\nfunction getTraceContextFromScope(scope) {\n const propagationContext = scope.getPropagationContext();\n\n const { traceId, parentSpanId, propagationSpanId } = propagationContext;\n\n const traceContext = {\n trace_id: traceId,\n span_id: propagationSpanId || generateSpanId(),\n };\n\n if (parentSpanId) {\n traceContext.parent_span_id = parentSpanId;\n }\n\n return traceContext;\n}\n\nexport { getClient, getCurrentScope, getGlobalScope, getIsolationScope, getTraceContextFromScope, withIsolationScope, withScope };\n//# sourceMappingURL=currentScopes.js.map\n","import { DEFAULT_ENVIRONMENT } from '../constants.js';\nimport { notifyEventProcessors } from '../eventProcessors.js';\nimport { Scope } from '../scope.js';\nimport { getFilenameToDebugIdMap } from './debug-ids.js';\nimport { uuid4, addExceptionMechanism } from './misc.js';\nimport { normalize } from './normalize.js';\nimport { getCombinedScopeData, applyScopeDataToEvent } from './scopeData.js';\nimport { truncate } from './string.js';\nimport { dateTimestampInSeconds } from './time.js';\n\n/**\n * This type makes sure that we get either a CaptureContext, OR an EventHint.\n * It does not allow mixing them, which could lead to unexpected outcomes, e.g. this is disallowed:\n * { user: { id: '123' }, mechanism: { handled: false } }\n */\n\n/**\n * Adds common information to events.\n *\n * The information includes release and environment from `options`,\n * breadcrumbs and context (extra, tags and user) from the scope.\n *\n * Information that is already present in the event is never overwritten. For\n * nested objects, such as the context, keys are merged.\n *\n * @param event The original event.\n * @param hint May contain additional information about the original exception.\n * @param scope A scope containing event metadata.\n * @returns A new event with more information.\n * @hidden\n */\nfunction prepareEvent(\n options,\n event,\n hint,\n scope,\n client,\n isolationScope,\n) {\n const { normalizeDepth = 3, normalizeMaxBreadth = 1000 } = options;\n const prepared = {\n ...event,\n event_id: event.event_id || hint.event_id || uuid4(),\n timestamp: event.timestamp || dateTimestampInSeconds(),\n };\n const integrations = hint.integrations || options.integrations.map(i => i.name);\n\n applyClientOptions(prepared, options);\n applyIntegrationsMetadata(prepared, integrations);\n\n if (client) {\n client.emit('applyFrameMetadata', event);\n }\n\n // Only put debug IDs onto frames for error events.\n if (event.type === undefined) {\n applyDebugIds(prepared, options.stackParser);\n }\n\n // If we have scope given to us, use it as the base for further modifications.\n // This allows us to prevent unnecessary copying of data if `captureContext` is not provided.\n const finalScope = getFinalScope(scope, hint.captureContext);\n\n if (hint.mechanism) {\n addExceptionMechanism(prepared, hint.mechanism);\n }\n\n const clientEventProcessors = client ? client.getEventProcessors() : [];\n\n // This should be the last thing called, since we want that\n // {@link Scope.addEventProcessor} gets the finished prepared event.\n // Merge scope data together\n const data = getCombinedScopeData(isolationScope, finalScope);\n\n const attachments = [...(hint.attachments || []), ...data.attachments];\n if (attachments.length) {\n hint.attachments = attachments;\n }\n\n applyScopeDataToEvent(prepared, data);\n\n const eventProcessors = [\n ...clientEventProcessors,\n // Run scope event processors _after_ all other processors\n ...data.eventProcessors,\n ];\n\n const result = notifyEventProcessors(eventProcessors, prepared, hint);\n\n return result.then(evt => {\n if (evt) {\n // We apply the debug_meta field only after all event processors have ran, so that if any event processors modified\n // file names (e.g.the RewriteFrames integration) the filename -> debug ID relationship isn't destroyed.\n // This should not cause any PII issues, since we're only moving data that is already on the event and not adding\n // any new data\n applyDebugMeta(evt);\n }\n\n if (typeof normalizeDepth === 'number' && normalizeDepth > 0) {\n return normalizeEvent(evt, normalizeDepth, normalizeMaxBreadth);\n }\n return evt;\n });\n}\n\n/**\n * Enhances event using the client configuration.\n * It takes care of all \"static\" values like environment, release and `dist`,\n * as well as truncating overly long values.\n *\n * Only exported for tests.\n *\n * @param event event instance to be enhanced\n */\nfunction applyClientOptions(event, options) {\n const { environment, release, dist, maxValueLength } = options;\n\n // empty strings do not make sense for environment, release, and dist\n // so we handle them the same as if they were not provided\n event.environment = event.environment || environment || DEFAULT_ENVIRONMENT;\n\n if (!event.release && release) {\n event.release = release;\n }\n\n if (!event.dist && dist) {\n event.dist = dist;\n }\n\n const request = event.request;\n if (request?.url && maxValueLength) {\n request.url = truncate(request.url, maxValueLength);\n }\n\n if (maxValueLength) {\n event.exception?.values?.forEach(exception => {\n if (exception.value) {\n // Truncates error messages\n exception.value = truncate(exception.value, maxValueLength);\n }\n });\n }\n}\n\n/**\n * Puts debug IDs into the stack frames of an error event.\n */\nfunction applyDebugIds(event, stackParser) {\n // Build a map of filename -> debug_id\n const filenameDebugIdMap = getFilenameToDebugIdMap(stackParser);\n\n event.exception?.values?.forEach(exception => {\n exception.stacktrace?.frames?.forEach(frame => {\n if (frame.filename) {\n frame.debug_id = filenameDebugIdMap[frame.filename];\n }\n });\n });\n}\n\n/**\n * Moves debug IDs from the stack frames of an error event into the debug_meta field.\n */\nfunction applyDebugMeta(event) {\n // Extract debug IDs and filenames from the stack frames on the event.\n const filenameDebugIdMap = {};\n event.exception?.values?.forEach(exception => {\n exception.stacktrace?.frames?.forEach(frame => {\n if (frame.debug_id) {\n if (frame.abs_path) {\n filenameDebugIdMap[frame.abs_path] = frame.debug_id;\n } else if (frame.filename) {\n filenameDebugIdMap[frame.filename] = frame.debug_id;\n }\n delete frame.debug_id;\n }\n });\n });\n\n if (Object.keys(filenameDebugIdMap).length === 0) {\n return;\n }\n\n // Fill debug_meta information\n event.debug_meta = event.debug_meta || {};\n event.debug_meta.images = event.debug_meta.images || [];\n const images = event.debug_meta.images;\n Object.entries(filenameDebugIdMap).forEach(([filename, debug_id]) => {\n images.push({\n type: 'sourcemap',\n code_file: filename,\n debug_id,\n });\n });\n}\n\n/**\n * This function adds all used integrations to the SDK info in the event.\n * @param event The event that will be filled with all integrations.\n */\nfunction applyIntegrationsMetadata(event, integrationNames) {\n if (integrationNames.length > 0) {\n event.sdk = event.sdk || {};\n event.sdk.integrations = [...(event.sdk.integrations || []), ...integrationNames];\n }\n}\n\n/**\n * Applies `normalize` function on necessary `Event` attributes to make them safe for serialization.\n * Normalized keys:\n * - `breadcrumbs.data`\n * - `user`\n * - `contexts`\n * - `extra`\n * @param event Event\n * @returns Normalized event\n */\nfunction normalizeEvent(event, depth, maxBreadth) {\n if (!event) {\n return null;\n }\n\n const normalized = {\n ...event,\n ...(event.breadcrumbs && {\n breadcrumbs: event.breadcrumbs.map(b => ({\n ...b,\n ...(b.data && {\n data: normalize(b.data, depth, maxBreadth),\n }),\n })),\n }),\n ...(event.user && {\n user: normalize(event.user, depth, maxBreadth),\n }),\n ...(event.contexts && {\n contexts: normalize(event.contexts, depth, maxBreadth),\n }),\n ...(event.extra && {\n extra: normalize(event.extra, depth, maxBreadth),\n }),\n };\n\n // event.contexts.trace stores information about a Transaction. Similarly,\n // event.spans[] stores information about child Spans. Given that a\n // Transaction is conceptually a Span, normalization should apply to both\n // Transactions and Spans consistently.\n // For now the decision is to skip normalization of Transactions and Spans,\n // so this block overwrites the normalized event to add back the original\n // Transaction information prior to normalization.\n if (event.contexts?.trace && normalized.contexts) {\n normalized.contexts.trace = event.contexts.trace;\n\n // event.contexts.trace.data may contain circular/dangerous data so we need to normalize it\n if (event.contexts.trace.data) {\n normalized.contexts.trace.data = normalize(event.contexts.trace.data, depth, maxBreadth);\n }\n }\n\n // event.spans[].data may contain circular/dangerous data so we need to normalize it\n if (event.spans) {\n normalized.spans = event.spans.map(span => {\n return {\n ...span,\n ...(span.data && {\n data: normalize(span.data, depth, maxBreadth),\n }),\n };\n });\n }\n\n // event.contexts.flags (FeatureFlagContext) stores context for our feature\n // flag integrations. It has a greater nesting depth than our other typed\n // Contexts, so we re-normalize with a fixed depth of 3 here. We do not want\n // to skip this in case of conflicting, user-provided context.\n if (event.contexts?.flags && normalized.contexts) {\n normalized.contexts.flags = normalize(event.contexts.flags, 3, maxBreadth);\n }\n\n return normalized;\n}\n\nfunction getFinalScope(scope, captureContext) {\n if (!captureContext) {\n return scope;\n }\n\n const finalScope = scope ? scope.clone() : new Scope();\n finalScope.update(captureContext);\n return finalScope;\n}\n\n/**\n * Parse either an `EventHint` directly, or convert a `CaptureContext` to an `EventHint`.\n * This is used to allow to update method signatures that used to accept a `CaptureContext` but should now accept an `EventHint`.\n */\nfunction parseEventHintOrCaptureContext(\n hint,\n) {\n if (!hint) {\n return undefined;\n }\n\n // If you pass a Scope or `() => Scope` as CaptureContext, we just return this as captureContext\n if (hintIsScopeOrFunction(hint)) {\n return { captureContext: hint };\n }\n\n if (hintIsScopeContext(hint)) {\n return {\n captureContext: hint,\n };\n }\n\n return hint;\n}\n\nfunction hintIsScopeOrFunction(hint) {\n return hint instanceof Scope || typeof hint === 'function';\n}\n\nconst captureContextKeys = [\n 'user',\n 'level',\n 'extra',\n 'contexts',\n 'tags',\n 'fingerprint',\n 'propagationContext',\n] ;\n\nfunction hintIsScopeContext(hint) {\n return Object.keys(hint).some(key => captureContextKeys.includes(key ));\n}\n\nexport { applyClientOptions, applyDebugIds, applyDebugMeta, parseEventHintOrCaptureContext, prepareEvent };\n//# sourceMappingURL=prepareEvent.js.map\n","import { getIsolationScope, getCurrentScope, getClient, withIsolationScope } from './currentScopes.js';\nimport { DEBUG_BUILD } from './debug-build.js';\nimport { closeSession, makeSession, updateSession } from './session.js';\nimport { startNewTrace } from './tracing/trace.js';\nimport { debug } from './utils/debug-logger.js';\nimport { isThenable } from './utils/is.js';\nimport { uuid4 } from './utils/misc.js';\nimport { parseEventHintOrCaptureContext } from './utils/prepareEvent.js';\nimport { timestampInSeconds } from './utils/time.js';\nimport { GLOBAL_OBJ } from './utils/worldwide.js';\n\n/**\n * Captures an exception event and sends it to Sentry.\n *\n * @param exception The exception to capture.\n * @param hint Optional additional data to attach to the Sentry event.\n * @returns the id of the captured Sentry event.\n */\nfunction captureException(exception, hint) {\n return getCurrentScope().captureException(exception, parseEventHintOrCaptureContext(hint));\n}\n\n/**\n * Captures a message event and sends it to Sentry.\n *\n * @param message The message to send to Sentry.\n * @param captureContext Define the level of the message or pass in additional data to attach to the message.\n * @returns the id of the captured message.\n */\nfunction captureMessage(message, captureContext) {\n // This is necessary to provide explicit scopes upgrade, without changing the original\n // arity of the `captureMessage(message, level)` method.\n const level = typeof captureContext === 'string' ? captureContext : undefined;\n const hint = typeof captureContext !== 'string' ? { captureContext } : undefined;\n return getCurrentScope().captureMessage(message, level, hint);\n}\n\n/**\n * Captures a manually created event and sends it to Sentry.\n *\n * @param event The event to send to Sentry.\n * @param hint Optional additional data to attach to the Sentry event.\n * @returns the id of the captured event.\n */\nfunction captureEvent(event, hint) {\n return getCurrentScope().captureEvent(event, hint);\n}\n\n/**\n * Sets context data with the given name.\n * @param name of the context\n * @param context Any kind of data. This data will be normalized.\n */\nfunction setContext(name, context) {\n getIsolationScope().setContext(name, context);\n}\n\n/**\n * Set an object that will be merged sent as extra data with the event.\n * @param extras Extras object to merge into current context.\n */\nfunction setExtras(extras) {\n getIsolationScope().setExtras(extras);\n}\n\n/**\n * Set key:value that will be sent as extra data with the event.\n * @param key String of extra\n * @param extra Any kind of data. This data will be normalized.\n */\nfunction setExtra(key, extra) {\n getIsolationScope().setExtra(key, extra);\n}\n\n/**\n * Set an object that will be merged sent as tags data with the event.\n * @param tags Tags context object to merge into current context.\n */\nfunction setTags(tags) {\n getIsolationScope().setTags(tags);\n}\n\n/**\n * Set key:value that will be sent as tags data with the event.\n *\n * Can also be used to unset a tag, by passing `undefined`.\n *\n * @param key String key of tag\n * @param value Value of tag\n */\nfunction setTag(key, value) {\n getIsolationScope().setTag(key, value);\n}\n\n/**\n * Updates user context information for future events.\n *\n * @param user User context object to be set in the current context. Pass `null` to unset the user.\n */\nfunction setUser(user) {\n getIsolationScope().setUser(user);\n}\n\n/**\n * Sets the conversation ID for the current isolation scope.\n *\n * @param conversationId The conversation ID to set. Pass `null` or `undefined` to unset the conversation ID.\n */\nfunction setConversationId(conversationId) {\n getIsolationScope().setConversationId(conversationId);\n}\n\n/**\n * The last error event id of the isolation scope.\n *\n * Warning: This function really returns the last recorded error event id on the current\n * isolation scope. If you call this function after handling a certain error and another error\n * is captured in between, the last one is returned instead of the one you might expect.\n * Also, ids of events that were never sent to Sentry (for example because\n * they were dropped in `beforeSend`) could be returned.\n *\n * @returns The last event id of the isolation scope.\n */\nfunction lastEventId() {\n return getIsolationScope().lastEventId();\n}\n\n/**\n * Create a cron monitor check in and send it to Sentry.\n *\n * @param checkIn An object that describes a check in.\n * @param upsertMonitorConfig An optional object that describes a monitor config. Use this if you want\n * to create a monitor automatically when sending a check in.\n */\nfunction captureCheckIn(checkIn, upsertMonitorConfig) {\n const scope = getCurrentScope();\n const client = getClient();\n if (!client) {\n DEBUG_BUILD && debug.warn('Cannot capture check-in. No client defined.');\n } else if (!client.captureCheckIn) {\n DEBUG_BUILD && debug.warn('Cannot capture check-in. Client does not support sending check-ins.');\n } else {\n return client.captureCheckIn(checkIn, upsertMonitorConfig, scope);\n }\n\n return uuid4();\n}\n\n/**\n * Wraps a callback with a cron monitor check in. The check in will be sent to Sentry when the callback finishes.\n *\n * @param monitorSlug The distinct slug of the monitor.\n * @param callback Callback to be monitored\n * @param upsertMonitorConfig An optional object that describes a monitor config. Use this if you want\n * to create a monitor automatically when sending a check in.\n */\nfunction withMonitor(\n monitorSlug,\n callback,\n upsertMonitorConfig,\n) {\n function runCallback() {\n const checkInId = captureCheckIn({ monitorSlug, status: 'in_progress' }, upsertMonitorConfig);\n const now = timestampInSeconds();\n\n function finishCheckIn(status) {\n captureCheckIn({ monitorSlug, status, checkInId, duration: timestampInSeconds() - now });\n }\n // Default behavior without isolateTrace\n let maybePromiseResult;\n try {\n maybePromiseResult = callback();\n } catch (e) {\n finishCheckIn('error');\n throw e;\n }\n\n if (isThenable(maybePromiseResult)) {\n return maybePromiseResult.then(\n r => {\n finishCheckIn('ok');\n return r;\n },\n e => {\n finishCheckIn('error');\n throw e;\n },\n ) ;\n }\n finishCheckIn('ok');\n\n return maybePromiseResult;\n }\n\n return withIsolationScope(() => (upsertMonitorConfig?.isolateTrace ? startNewTrace(runCallback) : runCallback()));\n}\n\n/**\n * Call `flush()` on the current client, if there is one. See {@link Client.flush}.\n *\n * @param timeout Maximum time in ms the client should wait to flush its event queue. Omitting this parameter will cause\n * the client to wait until all events are sent before resolving the promise.\n * @returns A promise which resolves to `true` if the queue successfully drains before the timeout, or `false` if it\n * doesn't (or if there's no client defined).\n */\nasync function flush(timeout) {\n const client = getClient();\n if (client) {\n return client.flush(timeout);\n }\n DEBUG_BUILD && debug.warn('Cannot flush events. No client defined.');\n return Promise.resolve(false);\n}\n\n/**\n * Call `close()` on the current client, if there is one. See {@link Client.close}.\n *\n * @param timeout Maximum time in ms the client should wait to flush its event queue before shutting down. Omitting this\n * parameter will cause the client to wait until all events are sent before disabling itself.\n * @returns A promise which resolves to `true` if the queue successfully drains before the timeout, or `false` if it\n * doesn't (or if there's no client defined).\n */\nasync function close(timeout) {\n const client = getClient();\n if (client) {\n return client.close(timeout);\n }\n DEBUG_BUILD && debug.warn('Cannot flush events and disable SDK. No client defined.');\n return Promise.resolve(false);\n}\n\n/**\n * Returns true if Sentry has been properly initialized.\n */\nfunction isInitialized() {\n return !!getClient();\n}\n\n/** If the SDK is initialized & enabled. */\nfunction isEnabled() {\n const client = getClient();\n return client?.getOptions().enabled !== false && !!client?.getTransport();\n}\n\n/**\n * Add an event processor.\n * This will be added to the current isolation scope, ensuring any event that is processed in the current execution\n * context will have the processor applied.\n */\nfunction addEventProcessor(callback) {\n getIsolationScope().addEventProcessor(callback);\n}\n\n/**\n * Start a session on the current isolation scope.\n *\n * @param context (optional) additional properties to be applied to the returned session object\n *\n * @returns the new active session\n */\nfunction startSession(context) {\n const isolationScope = getIsolationScope();\n const currentScope = getCurrentScope();\n\n // Will fetch userAgent if called from browser sdk\n const { userAgent } = GLOBAL_OBJ.navigator || {};\n\n const session = makeSession({\n user: currentScope.getUser() || isolationScope.getUser(),\n ...(userAgent && { userAgent }),\n ...context,\n });\n\n // End existing session if there's one\n const currentSession = isolationScope.getSession();\n if (currentSession?.status === 'ok') {\n updateSession(currentSession, { status: 'exited' });\n }\n\n endSession();\n\n // Afterwards we set the new session on the scope\n isolationScope.setSession(session);\n\n return session;\n}\n\n/**\n * End the session on the current isolation scope.\n */\nfunction endSession() {\n const isolationScope = getIsolationScope();\n const currentScope = getCurrentScope();\n\n const session = currentScope.getSession() || isolationScope.getSession();\n if (session) {\n closeSession(session);\n }\n _sendSessionUpdate();\n\n // the session is over; take it off of the scope\n isolationScope.setSession();\n}\n\n/**\n * Sends the current Session on the scope\n */\nfunction _sendSessionUpdate() {\n const isolationScope = getIsolationScope();\n const client = getClient();\n const session = isolationScope.getSession();\n if (session && client) {\n client.captureSession(session);\n }\n}\n\n/**\n * Sends the current session on the scope to Sentry\n *\n * @param end If set the session will be marked as exited and removed from the scope.\n * Defaults to `false`.\n */\nfunction captureSession(end = false) {\n // both send the update and pull the session from the scope\n if (end) {\n endSession();\n return;\n }\n\n // only send the update\n _sendSessionUpdate();\n}\n\nexport { addEventProcessor, captureCheckIn, captureEvent, captureException, captureMessage, captureSession, close, endSession, flush, isEnabled, isInitialized, lastEventId, setContext, setConversationId, setExtra, setExtras, setTag, setTags, setUser, startSession, withMonitor };\n//# sourceMappingURL=exports.js.map\n","/**\n * Sentry Error Tracking Initialization\n *\n * Initializes Sentry for error tracking.\n * This should be imported at the very top of the application entry point.\n *\n * Environment Variables:\n * - SENTRY_ENVIRONMENT: Environment name (development/production)\n */\n\nimport * as Sentry from \"@sentry/browser\";\n\nconst SENSITIVE_KEY =\n /token|authorization|password|secret|spreadsheet|workbook|content|participant/i;\n\nconst sanitize = (value, depth = 0) => {\n if (depth > 4) return \"[Truncated]\";\n if (value === null || value === undefined) return value;\n if (typeof value === \"string\")\n return value\n .replace(\n /(access_token|oauthToken|authorization)=([^&\\s]+)/gi,\n \"$1=[Filtered]\",\n )\n .replace(/Bearer\\s+[A-Za-z0-9._~-]+/gi, \"Bearer [Filtered]\");\n if ([\"number\", \"boolean\"].includes(typeof value)) return value;\n if (Array.isArray(value))\n return value.slice(0, 50).map((item) => sanitize(item, depth + 1));\n if (typeof value !== \"object\") return String(value);\n return Object.fromEntries(\n Object.entries(value).map(([key, item]) => [\n key,\n SENSITIVE_KEY.test(key) ? \"[Filtered]\" : sanitize(item, depth + 1),\n ]),\n );\n};\n\n// Export Sentry for manual error capturing\nexport { Sentry };\n\n/**\n * Capture and log an error to Sentry\n * Use this in catch blocks instead of just console.error()\n *\n * @param {unknown} error - The error object to capture\n * @param {string} context - Descriptive context (e.g., \"Login failed\")\n * @param {Object} extra - Additional data to send with error\n *\n * @example\n * try {\n * await loginUser(email, password);\n * } catch (error) {\n * captureError(error, \"User login\", { email });\n * }\n */\nexport function captureError(error, context = \"\", extra = {}) {\n console.error(context, error);\n Sentry.captureException(error, {\n tags: { context },\n extra: sanitize(extra),\n });\n}\n\n/**\n * Capture a message to Sentry (for non-error events)\n *\n * @param {string} message - The message to log\n * @param {string} level - Log level: \"info\", \"warning\", \"error\"\n * @param {Object} extra - Additional context data\n *\n * @example\n * if (experimentDidNotComplete) {\n * captureMessage(\"Experiment terminated early\", \"warning\", { reason });\n * }\n */\nexport function captureMessage(message, level = \"info\", extra = {}) {\n if (level === \"error\") {\n console.error(message, extra);\n } else {\n console.log(message, extra);\n }\n Sentry.captureMessage(message, { level, extra: sanitize(extra) });\n}\n\nexport function recordCompilerPhase(context, phase, details = {}) {\n const data = { ...context, phase, ...sanitize(details) };\n Sentry.setTag(\"compiler.phase\", phase);\n Sentry.setContext(\"compiler\", data);\n Sentry.addBreadcrumb({\n category: \"compiler\",\n message: `${context.operation}.${phase}`,\n level: \"info\",\n data,\n });\n}\n\nexport function captureCompilerFailure(\n error,\n context,\n phase,\n details = {},\n classification = \"compiler-defect\",\n) {\n const data = sanitize({ ...context, phase, classification, ...details });\n console.error(`[Compiler:${phase}]`, error);\n Sentry.captureException(\n error instanceof Error ? error : new Error(String(error)),\n {\n tags: {\n \"compiler.operation\": context.operation,\n \"compiler.operation_id\": context.operationId,\n \"compiler.phase\": phase,\n \"compiler.classification\": classification,\n },\n contexts: { compiler: data },\n },\n );\n}\n\nexport function getHttpErrorDetails(error) {\n return sanitize({\n endpoint: error?.endpoint,\n method: error?.method,\n responseStatus: error?.status,\n responseStatusText: error?.statusText,\n responseMessage: error?.responseMessage,\n });\n}\n","/**\n * Response selection models for the simulated participant.\n *\n * All functions accept an optional `rng` (defaults to Math.random) so callers\n * can pass a seeded generator for deterministic output. The browser-side\n * simulated participant constructs a mulberry32(seed) at startup.\n */\n\n/** Minimal EEState fields needed for model computation. */\nexport interface EEStateData {\n validCharsTyped: string;\n correctResponse: string | null;\n simulationModel: string | null;\n trialLevel: string | null;\n simulationThreshold: string | null;\n simulationBeta: string | null;\n simulationDelta: string | null;\n thresholdProportionCorrect: string | null;\n}\n\nexport type Rng = () => number;\n\n/**\n * mulberry32 — small, fast, deterministic PRNG.\n * Returns a function that produces floats in [0, 1).\n * Same seed → same sequence across runs, platforms, and JS engines.\n */\nexport function mulberry32(seed: number): Rng {\n let a = seed >>> 0;\n return function () {\n a |= 0;\n a = (a + 0x6d2b79f5) | 0;\n let t = a;\n t = Math.imul(t ^ (t >>> 15), t | 1);\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n };\n}\n\n/**\n * Pick a typed response character per the configured model.\n *\n * \"right\" / \"ideal\" — always correct.\n * \"wrong\" — always incorrect (or correct if no alternative).\n * \"blind\" — uniform random over the valid set (chance).\n * \"weibull\" — psychometric function around `simulationThreshold`.\n *\n * Falls back to \"right\" if model is null/unknown.\n */\nexport function selectTypedResponse(\n state: EEStateData,\n rng: Rng = Math.random,\n): string {\n const validChars = state.validCharsTyped.split(\"\");\n const correct = state.correctResponse ?? validChars[0];\n const model = state.simulationModel ?? \"right\";\n\n switch (model) {\n case \"right\":\n case \"ideal\":\n return correct;\n\n case \"wrong\": {\n const wrong = validChars.filter((c) => c !== correct);\n return wrong.length > 0\n ? wrong[Math.floor(rng() * wrong.length)]\n : correct;\n }\n\n case \"blind\":\n return validChars[Math.floor(rng() * validChars.length)];\n\n case \"weibull\": {\n const tTest = parseFloat(state.trialLevel ?? \"0\");\n const tActual = Math.log10(parseFloat(state.simulationThreshold ?? \"2\"));\n const beta = parseFloat(state.simulationBeta ?? \"2.3\");\n const delta = parseFloat(state.simulationDelta ?? \"0.01\");\n const tpc = parseFloat(state.thresholdProportionCorrect ?? \"0.816\");\n if (\n isNaN(tTest) ||\n isNaN(tActual) ||\n isNaN(beta) ||\n isNaN(delta) ||\n isNaN(tpc)\n ) {\n console.warn(\n `[sim:weibull] NaN param — trialLevel=${state.trialLevel} threshold=${state.simulationThreshold} beta=${state.simulationBeta} delta=${state.simulationDelta} tpc=${state.thresholdProportionCorrect}. Falling back to blind.`,\n );\n return validChars[Math.floor(rng() * validChars.length)];\n }\n const gamma = 1 / validChars.length;\n const epsilon =\n Math.log10(\n -Math.log(-((tpc - delta * gamma) / (1 - delta)) + 1) / (1 - gamma),\n ) / beta;\n const t = tTest - tActual + epsilon;\n const P =\n delta * gamma +\n (1 - delta) * (1 - (1 - gamma) * Math.exp(-Math.pow(10, beta * t)));\n if (rng() < P) return correct;\n const wrong = validChars.filter((c) => c !== correct);\n return wrong.length > 0\n ? wrong[Math.floor(rng() * wrong.length)]\n : correct;\n }\n\n default:\n return correct;\n }\n}\n\n/**\n * Pick an index into `chars` per the configured model.\n * Same semantics as selectTypedResponse, but returns a position for click UI.\n */\nexport function selectClickedIndex(\n chars: string[],\n state: EEStateData,\n rng: Rng = Math.random,\n): number {\n const model = state.simulationModel ?? \"right\";\n const correct = state.correctResponse?.toLowerCase() ?? null;\n const correctIdx = correct\n ? chars.findIndex((c) => c.toLowerCase() === correct)\n : -1;\n\n switch (model) {\n case \"right\":\n case \"ideal\":\n // If we know the correct answer, click it. Otherwise pick randomly\n // so we eventually hit items from different categories (e.g. rsvpReading\n // phrase-identification, where each category accepts only one response).\n return correctIdx >= 0 ? correctIdx : Math.floor(rng() * chars.length);\n case \"wrong\": {\n const wrongIdxs = chars.map((_, i) => i).filter((i) => i !== correctIdx);\n return wrongIdxs.length > 0\n ? wrongIdxs[Math.floor(rng() * wrongIdxs.length)]\n : 0;\n }\n case \"blind\":\n return Math.floor(rng() * chars.length);\n case \"weibull\": {\n const tResponse = selectTypedResponse(state, rng);\n const idx = chars.findIndex(\n (c) => c.toLowerCase() === tResponse.toLowerCase(),\n );\n return idx >= 0 ? idx : 0;\n }\n default:\n return correctIdx >= 0 ? correctIdx : 0;\n }\n}\n","/**\n * App-side RNG source: seeded, named, deterministic streams for simulation\n * and replay; Math.random passthrough for real participants (behavior\n * unchanged). Every app-side randomness site must draw from here — never\n * Math.random directly — so that same-seed runs are reproducible for\n * differential testing.\n *\n * Streams are NAMED per subsystem: each name derives an independent substream\n * from the master seed (FNV-1a of the name, XOR the master), so draws in one\n * subsystem cannot shift another's sequence — divergences stay localizable.\n *\n * Seed sources, in priority order (lazy, on first use):\n * 1. window.__SIM_SEED__ (simulator, injected before page scripts)\n * 2. ?rngSeed=N URL param (manual replay)\n * 3. none → unseeded (real participant: Math.random throughout)\n *\n * Seedrandom-based PsychoJS handlers (TrialHandler, MultiStairHandler) get\n * their seeds from handlerSeed(): deterministic when seeded, wall-clock when\n * not (their legacy behavior).\n */\n\nimport { mulberry32 } from \"./simulationModel\";\n\nexport type Rng = () => number;\n\nlet masterSeed: number | null = null;\nlet seedSource: \"sim\" | \"url\" | \"unseeded\" = \"unseeded\";\nlet initAttempted = false;\nconst streams = new Map<string, Rng>();\n\n/** FNV-1a 32-bit string hash — integer ops, stable across JS engines. */\nfunction hash32(s: string): number {\n let h = 0x811c9dc5;\n for (let i = 0; i < s.length; i++) {\n h ^= s.charCodeAt(i);\n h = Math.imul(h, 0x01000193);\n }\n return h >>> 0;\n}\n\nfunction substreamSeed(name: string): number {\n // masterSeed is non-null at every call site (checked before use).\n return ((masterSeed as number) ^ hash32(name)) >>> 0;\n}\n\n/** Seed all streams (idempotent; clears existing streams). */\nexport function initRng(seed: number, source: \"sim\" | \"url\"): void {\n masterSeed = seed >>> 0;\n seedSource = source;\n streams.clear();\n initAttempted = true;\n}\n\nfunction ensureInit(): void {\n if (initAttempted || typeof window === \"undefined\") {\n initAttempted = true;\n return;\n }\n initAttempted = true;\n const w = window as unknown as Record<string, unknown>;\n if (typeof w.__SIM_SEED__ === \"number\" && Number.isFinite(w.__SIM_SEED__)) {\n initRng(w.__SIM_SEED__, \"sim\");\n return;\n }\n const p = new URLSearchParams(window.location.search).get(\"rngSeed\");\n if (p !== null && p !== \"\" && Number.isFinite(Number(p))) {\n initRng(Number(p), \"url\");\n }\n}\n\n/** How the run was seeded. */\nexport function getSeedSource(): \"sim\" | \"url\" | \"unseeded\" {\n ensureInit();\n return seedSource;\n}\n\n/** The master seed, or null when unseeded. */\nexport function getMasterSeed(): number | null {\n ensureInit();\n return masterSeed;\n}\n\n/** One draw from the named stream (Math.random when unseeded). */\nexport function random(name = \"misc\"): number {\n ensureInit();\n if (masterSeed === null) return Math.random();\n let rng = streams.get(name);\n if (!rng) {\n rng = mulberry32(substreamSeed(name));\n streams.set(name, rng);\n }\n return rng();\n}\n\n/** Stream handle for APIs taking () => number (e.g. shuffle(arr, rng)). */\nexport function rngFor(name: string): Rng {\n return () => random(name);\n}\n\n/**\n * Seed for seedrandom-based PsychoJS handlers. Deterministic per name when\n * seeded; full-entropy draw when not (NOT wall-clock ms — two handlers\n * constructed in the same tick must not share a seed, which would interleave\n * their conditions identically).\n */\nexport function handlerSeed(name: string): number {\n ensureInit();\n if (masterSeed === null) return Math.floor(Math.random() * 2 ** 31);\n return substreamSeed(name);\n}\n\n/** Test-only: drop all state. */\nexport function resetRngForTests(): void {\n masterSeed = null;\n seedSource = \"unseeded\";\n initAttempted = false;\n streams.clear();\n}\n","export const BASE_DELAY_SEC = 0.2;\nexport const MAX_DELAY_SEC = 30;\nexport const wait = (ms: number) => new Promise((r) => setTimeout(r, ms));\nexport const getRetryDelayMs = (attempt: number) => {\n const delaySec = Math.min(\n BASE_DELAY_SEC * Math.pow(1.75, attempt),\n MAX_DELAY_SEC,\n );\n const jitter = 0.8 + Math.random() * 0.4;\n return delaySec * 1000 * jitter;\n};\n","import type { PhrasesData } from \"../../source/components/types\";\n\nlet registry: PhrasesData | null = null;\n\nexport function initPhrases(data: PhrasesData): void {\n registry = data;\n}\n\nexport function getPhrases(): Record<string, Record<string, string>> {\n if (registry === null) {\n throw new Error(\"getPhrases() called before initPhrases()\");\n }\n return registry.phrases;\n}\n\nexport function getPhrasesVersion(): string | null {\n return registry?.version ?? null;\n}\n","const LOCALHOST_BASE_URL = \"http://localhost:8888\";\nconst PRODUCTION_BASE_URL = \"https://easyeyes.app\";\n\n// Cache the localhost probe so we only hit the network once per page load.\nlet localhostBaseUrlPromise: Promise<string> | undefined;\n\n// Resolve to the localhost base URL if a server is actually answering on\n// :8888 (e.g. `netlify dev`), otherwise fall back to production. We only care\n// that the server responds at all, not about the status code, so `no-cors` is\n// fine — a connection refused / timeout rejects the fetch and we fall back.\nconst resolveLocalhostBaseUrl = async (): Promise<string> => {\n try {\n await fetch(LOCALHOST_BASE_URL, { method: \"HEAD\", mode: \"no-cors\" });\n return LOCALHOST_BASE_URL;\n } catch {\n return PRODUCTION_BASE_URL;\n }\n};\n\nexport const getEasyEyesBaseUrl = async (): Promise<string> => {\n const urlParams = new URLSearchParams(window.location.search);\n const previewDeployBase = urlParams.get(\"preview-deploy\");\n\n if (previewDeployBase) return previewDeployBase;\n\n // Branch/preview deploys of the EasyEyes site (e.g.\n // language-phrase-glossary--easyeyes.netlify.app) ship their own copy of the\n // Netlify functions, so call them on the page's own origin. Returning\n // production here would make the preview hit easyeyes.app, which may not yet\n // have the branch's functions deployed.\n if (/--easyeyes\\.netlify\\.app$/.test(window.location.hostname))\n return window.location.origin;\n\n if (window.location.hostname !== \"localhost\") return PRODUCTION_BASE_URL;\n\n if (!localhostBaseUrlPromise)\n localhostBaseUrlPromise = resolveLocalhostBaseUrl();\n return localhostBaseUrlPromise;\n};\n","import { wait, getRetryDelayMs } from \"./retry\";\nimport { initPhrases } from \"../parameters/phrasesRegistry\";\nimport type { PhrasesData } from \"../../source/components/types\";\nimport { getEasyEyesBaseUrl } from \"../components/easyeyesBaseUrl\";\n\nexport async function loadPhrases(pathname: string): Promise<PhrasesData> {\n const [username, experimentName] = pathname.split(\"/\").filter(Boolean);\n const base = await getEasyEyesBaseUrl();\n const pinnedUrl = `${base}/.netlify/functions/phrases?pinned=${username}/${experimentName}`;\n\n let attempt = 0;\n\n // Step 1: resolve the experiment's pinned version. The pin is mutable, so this\n // endpoint is uncached; retry transient failures, but a missing pin is fatal.\n let version: string;\n while (true) {\n let res: Response;\n try {\n res = await fetch(pinnedUrl);\n } catch {\n await wait(getRetryDelayMs(attempt++));\n continue;\n }\n\n if (res.status === 404) {\n const body = (await res.json()) as { error?: string };\n if (body.error === \"No pinned version\") {\n throw new Error(\n `No phrasesVersion pinned for ${username}/${experimentName}. Recompile the experiment.`,\n );\n }\n await wait(getRetryDelayMs(attempt++));\n continue;\n }\n\n if (!res.ok) {\n await wait(getRetryDelayMs(attempt++));\n continue;\n }\n\n version = ((await res.json()) as { version: string }).version;\n break;\n }\n\n // Step 2: fetch the immutable payload for that exact version. This URL is\n // cached forever at the edge and in the browser, shared across participants.\n const versionUrl = `${base}/.netlify/functions/phrases?v=${version}`;\n while (true) {\n let res: Response;\n try {\n res = await fetch(versionUrl);\n } catch {\n await wait(getRetryDelayMs(attempt++));\n continue;\n }\n\n if (!res.ok) {\n await wait(getRetryDelayMs(attempt++));\n continue;\n }\n\n const data = (await res.json()) as PhrasesData;\n initPhrases(data);\n return data;\n }\n}\n\nexport const phrasesData: PhrasesData = await loadPhrases(\n window.location.pathname,\n);\n","import type { GlossaryEntry } from \"../../source/components/types\";\n\n/**\n * Target kind derived from glossary source of truth.\n * This is the single source of truth for valid target kinds.\n */\nexport type TargetKind = GlossaryEntry[\"categories\"][number];\n\n/**\n * Generic DefaultMap class for type-safe maps with default values\n */\nexport class DefaultMap<K, V> extends Map<K, V> {\n default: () => V;\n constructor(defaultFunction: () => V, entries: [K, V][] | null) {\n super(entries);\n this.default = defaultFunction;\n }\n get(key: K) {\n if (!this.has(key)) this.set(key, this.default());\n return super.get(key);\n }\n}\n\nexport interface SkipTrialOrBlock {\n blockId: number | null;\n trialId: number | null;\n skipTrial: boolean;\n skipBlock: boolean;\n restartBlock: boolean;\n}\n\nexport interface Status {\n block: number | undefined;\n trial: number | undefined;\n block_condition: string;\n condition: object;\n trialCorrect_thisBlock: number;\n trialCompleted_thisBlock: number;\n trialAttempted_thisBlock: number;\n nthTrialCorrectThisBlockByCondition: DefaultMap<string, number>;\n nthTrialCompletedThisBlockByCondition: DefaultMap<string, number>;\n nthTrialByCondition: DefaultMap<string, number>;\n nthTrialAttemptedByCondition: DefaultMap<string, number>;\n currentFunction: string;\n retryThisTrialBool: boolean;\n nthBlock: number | undefined;\n}\n\n/**\n * Interface for PsychoJS TextStim visual stimulus.\n * Used for type safety when working with text stimuli in EasyEyes.\n */\nexport interface TextStim {\n setText(text: string): void;\n setPos(pos: [number, number] | number[]): void;\n setColor(color: any): void;\n setAutoDraw(autoDraw: boolean): void;\n getBoundingBox(tight?: boolean): { height: number } | number[];\n status: symbol;\n _autoDraw: boolean;\n _needUpdate: boolean;\n}\n","import { DefaultMap } from \"./types\";\n\n/**\n * Mutable global experiment status.\n *\n * `resetBlockScopedStatus` (called on a recalibration block-restart) resets\n * the block-scoped fields below but leaves the run-level fields (`block`,\n * `nthBlock`, `consentGiven`): `block` is re-set by filterRoutineBegin, and a\n * restart decrements `nthBlock` so filterRoutineBegin's increment keeps the\n * restarted block a REDO of the same sequential block.\n */\nexport const status = {\n block: 0, // 1-based; may run out of order (shuffling)\n nthBlock: undefined as number | undefined, // sequential block count in this run\n trial: undefined as number | undefined, // 1-based trial number\n block_condition: undefined as string | undefined,\n condition: undefined as object | undefined,\n trialCorrect_thisBlock: 0,\n trialCompleted_thisBlock: 0,\n trialAttempted_thisBlock: 0,\n // Per-condition mirrors of the thisBlock counters (end-of-block %correct popup).\n nthTrialCorrectThisBlockByCondition: new DefaultMap<string, number>(\n () => 0,\n null,\n ),\n nthTrialCompletedThisBlockByCondition: new DefaultMap<string, number>(\n () => 0,\n null,\n ),\n nthTrialByCondition: new DefaultMap<string, number>(() => 1, null), // current trial # per condition\n nthTrialAttemptedByCondition: new DefaultMap<string, number>(() => 0, null),\n currentFunction: \"\", // current routine fn, e.g. trialRoutineEachFrame\n retryThisTrialBool: false,\n consentGiven: undefined as boolean | undefined,\n};\n\n/** Reset status's block-scoped fields; run-level fields are left untouched. */\nexport const resetBlockScopedStatus = (): void => {\n status.trial = undefined;\n status.block_condition = undefined;\n status.condition = undefined;\n status.trialCorrect_thisBlock = 0;\n status.trialCompleted_thisBlock = 0;\n status.trialAttempted_thisBlock = 0;\n status.nthTrialCorrectThisBlockByCondition.clear();\n status.nthTrialCompletedThisBlockByCondition.clear();\n status.nthTrialByCondition.clear();\n status.nthTrialAttemptedByCondition.clear();\n status.currentFunction = \"\";\n status.retryThisTrialBool = false;\n};\n","// ! AVOID IMPORTS HERE\n// phrasesData resolves the Firebase runtime phrases (top-level await) so the\n// full translation table is available before rc.init below runs.\nimport { phrasesData } from \"../preprocess/phrases-loader\";\n\n// Map data-structure with a default value\n// https://stackoverflow.com/questions/51319147/map-default-value\nexport class DefaultMap extends Map {\n constructor(defaultFunction, entries) {\n super(entries);\n this.default = defaultFunction;\n }\n get(key) {\n if (!this.has(key)) this.set(key, this.default());\n return super.get(key);\n }\n}\n\nexport const thisExperimentInfo = {\n name: \"threshold\",\n expName: \"threshold\",\n\n psychopyVersion: undefined,\n\n participant: undefined,\n _s: 1, // session\n\n EasyEyesID: undefined,\n PavloviaSessionID: undefined,\n actualPavloviaSessionID: undefined, // The real UUID from Pavlovia's server\n\n ProlificParticipantID: undefined,\n ProlificSessionID: undefined,\n ProlificStudyID: undefined,\n\n experimentFilename: undefined,\n experiment: undefined,\n\n date: undefined,\n\n hardwareConcurrency: undefined,\n deviceType: undefined,\n deviceSystem: undefined,\n deviceSystemFamily: undefined,\n deviceBrowser: undefined,\n deviceBrowserVersion: undefined,\n deviceLanguage: undefined,\n\n psychojsWindowDimensions: undefined,\n monitorFrameRate: undefined,\n\n get session() {\n return this._s.toString().padStart(4, \"0\");\n },\n\n set session(value) {},\n\n setSession(num) {\n this._s = num;\n },\n};\n\nexport const localStorageKey = \"__EASYEYES__\";\n\n/** Keypad Handler Proxy (passed to RC as well) */\nexport const _key_resp_allKeys = {\n current: [],\n};\n\nexport const _key_resp_event_handlers = {\n current: [],\n};\n\nconst handler = {\n set: function (target, property, value) {\n target[property] = value;\n _key_resp_event_handlers.current.forEach((handler) => handler(value));\n return true;\n },\n};\n\nexport const proxyVariable_key_resp_allKeys = new Proxy(\n _key_resp_allKeys.current,\n handler,\n);\n\n/* -------------------------------- EXTERNALS ------------------------------- */\n/* ---------------------------- Remote Calibrator --------------------------- */\nif (typeof RemoteCalibrator === \"undefined\") {\n const title = \"RemoteCalibrator resource failed to load.\";\n const text = \"Please check your internet connection and refresh the page.\";\n if (window.showCriticalLoadError) {\n window.showCriticalLoadError(title, text);\n } else {\n // Brief retry if first.js hasn't set up the handler yet\n setTimeout(() => window.showCriticalLoadError?.(title, text), 50);\n }\n throw new Error(\"RemoteCalibrator is not defined\");\n}\n// eslint-disable-next-line no-undef\nexport const rc = RemoteCalibrator; // Currently imported from HTML script tag\nawait rc.init(\n {\n languagePhrasesJSON: phrasesData.phrases,\n },\n undefined,\n {\n easyEyesKeypadHandler: {\n event_handlers: _key_resp_event_handlers,\n all_keys: _key_resp_allKeys,\n },\n },\n);\n\nexport const websiteRepoLastCommitDeploy = {\n current: undefined,\n};\nawait fetch(\"CompatibilityRequirements.txt\")\n .then((response) => {\n if (!response?.ok) return \"\";\n return response.json();\n })\n .then((result) => {\n if (result && result.compilerUpdateDate) {\n websiteRepoLastCommitDeploy.current = result.compilerUpdateDate;\n }\n return undefined;\n })\n .catch((error) => {\n return undefined;\n });\n\n// stats.js\nexport const stats = { current: undefined, on: false };\n\nexport const usingGaze = { current: undefined };\n\n/* ------------------------- Grid / Display Options ------------------------- */\n\nexport const displayOptions = Object.seal({\n window: undefined,\n windowWidthCm: undefined,\n windowWidthPx: undefined,\n pixPerCm: undefined,\n nearPointXYDeg: [undefined, undefined],\n nearPointXYPix: [undefined, undefined],\n});\n\nexport const grid = { current: undefined, units: undefined };\n\n/* ------------------------------- Exp Configs ------------------------------ */\nexport const totalBlocks = { current: undefined };\nexport const totalTrialsThisBlock = { current: undefined };\nexport const blockOrder = { current: undefined };\n\nexport const targetTask = { current: undefined };\nexport const targetKind = { current: undefined };\n\nexport const correctAns = { current: [] }; // for keyboard ans\n\n// Renders\nexport const font = {\n name: undefined,\n source: undefined,\n style: undefined,\n direction: \"ltr\",\n language: \"en\",\n punctuationRTL: \"none\",\n colorRGBA: undefined,\n defaultColorRGBA: \"0,0,0,1\",\n instructionFont: undefined,\n instructionFontSource: undefined,\n padding: undefined,\n letterSpacing: 0,\n kerning: undefined,\n textRendering: undefined,\n featureSettings: undefined,\n variantLigatures: undefined,\n medialShapeResponse: undefined,\n medialShapeTarget: undefined,\n fontPositionalShapeResponse: undefined,\n};\nexport const typekit = {\n kitId: undefined,\n fonts: new Map(), // name:{css_name}\n};\n\nexport const fontCharacterSet = { current: undefined, where: undefined };\n\nexport const showTimingBarsBool = { current: false };\n\n// Default PsychoJS window color. Matches CSS `#eee` (238/255 ≈ 0.933) so the\n// canvas doesn't flash white behind UI pages before per-block\n// `screenColorRGBA` is applied.\nexport const screenBackground = {\n defaultColorRGBA: \"0.933,0.933,0.933,1\",\n colorRGBA: undefined,\n};\n\nexport const fixationConfig = {\n nominalPos: [0, 0], // Nominal, scientist specified position. Only used as a reference point when gyrating fixation.\n pos: [0, 0], // Actual, current position XY in psychoJS `pix` units. In general, the only location value one should use.\n offset: undefined, // Random starting offset\n show: true,\n strokeLength: 45, // aka fixationStrokeLengthPx\n strokeWidth: 2, // aka fixationStrokeThicknessPx\n color: undefined,\n markingBlankedNearTargetBool: undefined,\n markingBlankingPos: undefined,\n markingBlankingRadiusReEccentricity: undefined,\n markingBlankingRadiusReTargetHeight: undefined,\n markingFixationHotSpotRadiusDeg: undefined,\n markingFixationHotSpotRadiusPx: undefined,\n markingFixationMotionRadiusDeg: undefined,\n markingFixationMotionPeriodSec: undefined,\n markingFixationStrokeLengthDeg: undefined,\n markingFixationStrokeThicknessDeg: undefined,\n markingFixationStrokeThickening: undefined,\n markingOffsetBeforeTargetOnsetSecs: undefined,\n markingOnsetAfterTargetOffsetSecs: undefined,\n markingFixationMotionSpeedDegPerSec: undefined,\n stim: undefined, // EasyEyes Fixation object\n\n trackingTimeAfterDelay: undefined,\n preserveOffset: false, // If rerunning prestimulus function\n // due to change in viewing distance,\n // use the pre-existing fixation offset\n // (ie starting position), so it doesn't\n // look like it's jumping around when\n // viewing distance changes.\n};\n\nexport const measureMeters = { canMeasureMeters: 0, needMeasureMeters: 0 };\n\nexport const targetEccentricityDeg = {\n x: undefined,\n y: undefined,\n};\n\nexport const showConditionNameConfig = {\n name: undefined,\n show: false,\n targetSpecs: undefined,\n showTargetSpecs: false,\n};\n\nexport const letterConfig = Object.seal({\n targetDurationSec: undefined,\n targetSizeIsHeightBool: undefined,\n targetMinimumPix: undefined,\n targetSizeDeg: undefined,\n targetCharacter: undefined,\n targetEccentricityXYDeg: [undefined, undefined],\n thresholdParameter: undefined,\n spacingDirection: undefined,\n spacingSymmetry: undefined,\n spacingOverSizeRatio: undefined,\n spacingRelationToSize: undefined,\n flankerCharacters: [undefined, undefined],\n delayBeforeStimOnsetSec: undefined,\n targetSafetyMarginSec: undefined,\n markingOnsetAfterTargetOffsetSecs: undefined,\n flankerXYDegs: [],\n thresholdAllowedBlackoutBool: undefined,\n fontMaxPxShrinkage: 1,\n useFontMaxPxShrinkageBool: false,\n currentNominalFontSize: undefined,\n ////\n fontMaxPx: undefined,\n responseMaxOptions: 99,\n});\n\nexport const imageFolders = {\n current: \"\", // string: folderName_fileName\n folders: new Map(), // Map<folderName, Map<fileName, {file: arrayBuffer, usedInCondition: [\"1_1\", \"1_2\", \"1_3\"..]}>>\n};\n\nexport const imageConfig = Object.seal({\n targetSizeDeg: 0,\n targetDurationSec: 0,\n targetEccentricityXDeg: 0,\n targetEccentricityYDeg: 0,\n thresholdParameter: \"\",\n targetSizeIsHeightBool: false,\n targetImageFolder: \"\",\n targetImageReplacementBool: false,\n currentImageFileName: \"\",\n currentImageFile: undefined,\n delayAfterStimOnsetSec: 0,\n delayBeforeStimOnsetSec: 0,\n responseMaxOptions: 99,\n responsePositiveFeedbackBool: true,\n currentImageFullFileName: \"\",\n targetImageExclude: \"none\", // none, pastTargets, pastTargetsAndFoils\n targetImageFoilsExclude: \"none\", // none, pastTargets, pastTargetsAndFoils\n targetImageSpareFraction: 0, // fraction of the screen spared for the question\n targetImageWhere: \"top\", // which part of the screen gets the target section\n});\n\nexport const pastImages = {\n targets: new Map(), // for each targetImageFolder, we keep track of all the targets that have been used\n foils: new Map(), // for each targetImageFolder, we keep track of all the foils that have been used\n};\n\nexport const imageQuestionAndAnswer = Object.seal({\n current: {}, // \"block_condition\": [questions]\n});\n\nexport const repeatedLettersConfig = Object.seal({\n targetRepeatsBorderCharacter: undefined,\n targetRepeatsMaxLines: undefined,\n stims: undefined,\n level: undefined,\n stimulusParameters: undefined,\n});\nexport const repeatedLettersResponse = Object.seal({\n current: [],\n clickTime: [],\n rt: [],\n correct: [],\n});\n\nexport const instructionFont = { current: undefined };\n\nexport const customInstructionText = { current: undefined };\n\nexport const tolerances = Object.seal({\n allowed: {\n thresholdAllowedDurationRatio: undefined,\n thresholdAllowedGazeXErrorDeg: undefined,\n thresholdAllowedGazeYErrorDeg: undefined,\n thresholdAllowedGazeRErrorDeg: undefined,\n thresholdAllowedLatenessSec: undefined,\n },\n measured: {\n thresholdDurationRatio: undefined,\n gazeMeasuredXDeg: undefined,\n gazeMeasuredYDeg: undefined,\n gazeMeasuredRDeg: undefined,\n gazeMeasuredRawDeg: [],\n gazeMeasurementLatencySec: undefined,\n targetMeasuredLatenessSec: undefined,\n targetMeasuredDurationSec: undefined,\n targetMeasuredDurationFrames: undefined,\n targetMeasuredPreRenderSec: undefined,\n },\n});\n/* --------------------------- Exp Current Status --------------------------- */\n// status + reset live in ./status to avoid this module's side-effect imports.\n// Re-exported for existing consumers.\nexport { status, resetBlockScopedStatus } from \"./status\";\n\n// SKIP\nexport const skipTrialOrBlock = {\n blockId: null,\n trialId: null,\n skipTrial: false,\n skipBlock: false,\n // Set (with blockId) to abandon the current block and re-run it from\n // trial 1 with a fresh staircase. endLoopIteration re-schedules the block\n // and clears this. See components/recalibration.ts.\n restartBlock: false,\n};\n\nexport const timing = Object.seal({\n clickToStimulusOnsetSec: undefined,\n stimulusOnsetToOffset: undefined,\n});\n\nexport const letterTiming = Object.seal({\n trialFirstFrameSec: undefined,\n targetStartSec: undefined,\n targetFinishSec: undefined,\n targetDrawnConfirmedTimestamp: undefined,\n crosshairClickedTimestamp: undefined,\n targetRequestedTimestamp: undefined,\n blackoutDetectedBool: false,\n preRenderStartSec: undefined,\n preRenderEndSec: undefined,\n preRenderOpacifyStartSec: undefined,\n preRenderOpacifyEndSec: undefined,\n});\n\nexport const letterHeapData = {\n heapUsedBeforeDrawingMB: undefined,\n heapTotalBeforeDrawingMB: undefined,\n heapLimitBeforeDrawingMB: undefined,\n heapUsedAfterDrawingMB: undefined,\n heapTotalAfterDrawingMB: undefined,\n heapLimitAfterDrawingMB: undefined,\n heapTotalPreLatenessMB: undefined,\n heapTotalPostLatenessMB: undefined,\n};\n\nexport const viewingDistanceCm = { current: 40, desired: 40, max: 40 };\n\n/* ------------------------------ Interactions ------------------------------ */\n\nexport const responseType = {\n current: 2,\n original: 2,\n numberOfResponses: 1,\n};\nexport const clickedContinue = { current: false, timestamps: [] };\nexport const modalButtonTriggeredViaKeyboard = { current: false };\n\nexport const showCharacterSetResponse = {\n current: [],\n // current: null,\n onsetTime: [], // 0?\n clickTime: [],\n alreadyClickedCharacters: [],\n};\n\nexport const phraseIdentificationResponse = Object.seal({\n current: [], // Responses\n correct: [], // Correctness of responses\n targetWord: [], // The correct responses, ie this.correct = this.current === this.targetWord\n categoriesResponded: [], // List of categories for which we already have a response\n onsetTime: undefined,\n onsetT: undefined,\n clickTime: [],\n});\n\nexport const markingShowCursorBool = { current: true };\n\n/* --------------------------------- Reading -------------------------------- */\nexport const readingCorpusArchive = {};\nexport const readingWordListArchive = {};\nexport const readingWordFrequencyArchive = {};\nexport const readingFrequencyToWordArchive = {};\nexport const readingCorpusFoilsArchive = new DefaultMap(() => []);\nexport const readingCorpusFoilsExclude = {\n current: undefined,\n};\nexport const readingCorpusPastTargets = new Set();\nexport const readingCorpusPastFoils = new Set();\n\n// Map corpus to DefaultMap<block_condition,string[]>\nexport const readingUsedText = {};\nexport const readingThisBlockPages = new DefaultMap(() => []); // string[]\n\nexport const readingPageIndex = { current: 0 };\n\nexport const readingQuestions = { current: undefined };\nexport const readingCurrentQuestionIndex = { current: 0 };\n\nexport const readingClickableAnswersSetup = { current: false };\nexport const readingClickableAnswersUpdate = { current: false };\n\nexport const readingConfig = {\n height: undefined,\n actualLinesPerPage: undefined,\n};\n\nexport const readingTiming = Object.seal({ onsets: [] });\n// Each record uses a map to store information by condition\nexport const readingPageStats = Object.seal({\n readingPageSkipCorpusWords: new DefaultMap(() => []),\n readingPageDurationSec: new DefaultMap(() => []),\n readingPageLines: new DefaultMap(() => []),\n readingPageWords: new DefaultMap(() => []),\n readingPageNonblankCharacters: new DefaultMap(() => []),\n});\nexport const readingCorpusDepleted = new DefaultMap(() => false);\nexport const readingLineLengthUnit = new DefaultMap(() => \"character\");\n\n/* -------------------------------- Question -------------------------------- */\nexport const questionsThisBlock = { current: [] };\n/** The block-prep Q&A plan (planPureQaBlockQuestions) for the CURRENT pure\n * questionAndAnswer block: per-question text/valueMap/conditionIndex in\n * trial order. trialsLoopBegin repeats each condition's trialList entry\n * once per ITS questions, so conditions with different question counts\n * each ask exactly their own questions. */\nexport const qaPlanThisBlock = { current: null };\n\n/* -------------------------------------------------------------------------- */\n/* ------------------------------- COMPONENTS ------------------------------- */\n/* -------------------------------------------------------------------------- */\n\nexport const uniComponentConfig = {\n text: \"\",\n units: \"pix\",\n alignHoriz: \"left\",\n ori: 0.0,\n opacity: 1.0,\n isInstruction: false,\n};\n\nexport const instructionsConfig = {\n ...uniComponentConfig,\n height: 25.0,\n wrapWidth: window.innerWidth * 0.8,\n depth: -12.0,\n isInstruction: true, // !\n};\n\nexport const conditionNameConfig = {\n ...uniComponentConfig,\n height: 30,\n wrapWidth: window.innerWidth,\n depth: -20.0,\n name: \"conditionName\",\n alignVert: \"bottom\",\n pos: [-window.innerWidth / 2, -window.innerHeight / 2],\n autoDraw: false,\n};\n\nexport const targetSpecsConfig = {\n ...uniComponentConfig,\n height: 20,\n wrapWidth: window.innerWidth,\n depth: -21.0,\n name: \"targetSpecs\",\n alignVert: \"bottom\",\n pos: [-window.innerWidth / 2, -window.innerHeight / 2],\n autoDraw: false,\n};\n\nexport const trialCounterConfig = {\n ...uniComponentConfig,\n height: 20,\n wrapWidth: window.innerWidth,\n depth: -22.0,\n name: \"trialCounter\",\n alignVert: \"bottom\",\n alignHoriz: \"right\",\n pos: [window.innerWidth / 2, -window.innerHeight / 2],\n autoDraw: false,\n};\n\nexport const targetTextStimConfig = {\n text: \"\",\n font: \"Arial\",\n units: \"pix\",\n pos: [0, 0],\n height: 1.0,\n wrapWidth: undefined,\n ori: 0.0,\n opacity: 1.0,\n depth: -7.0,\n alignVert: \"center\",\n alignHoriz: \"center\",\n isInstruction: false,\n medialForm: false,\n};\n\n/* -------------------------------------------------------------------------- */\n/* ------------------------------- Sound ------------------------------------ */\n/* -------------------------------------------------------------------------- */\nexport const deviceType = {\n isSmartphone: false,\n isLoudspeaker: true,\n isParticipant: false,\n profileFetchedFromLibrary: false,\n showSystemCorrection: true,\n};\nexport const targetIsPresentBool = { current: undefined };\nexport const ProposedVolumeLevelFromQuest = {\n current: undefined,\n adjusted: undefined,\n};\nexport const maskerVolumeDbSPL = { current: undefined };\nexport const soundGainDBSPL = { current: undefined };\nexport const invertedImpulseResponse = { current: undefined };\nexport const whiteNoiseLevel = { current: undefined };\nexport const maskerSoundFolder = { current: undefined };\nexport const targetSoundFolder = { current: undefined };\nexport const targetSoundList = { current: undefined };\nexport const targetSoundListFiles = {}; // BC:\"name\":file\nexport const targetSoundListMap = {}; // BC: name, list: [{left: \"name\", right: \"name\"}...]\nexport const targetSoundListTrialData = {\n left: undefined, // {name, file}\n right: undefined, // {name, file}\n targetVolume: undefined,\n whiteNoiseLevel: undefined,\n currentIndex: {}, // BC: index\n trialSound: undefined, // {names: [\"name1\", \"name2\"], file: stereoBuffer}\n};\n\nexport const speechInNoiseTargetList = { current: undefined };\nexport const musicExpert = { current: undefined }; // TEMP\nexport const speechInNoiseShowClickable = { current: true };\nexport const vocoderPhraseSoundFiles = { current: undefined, loaded: false };\nexport const vocoderPhrases = {\n targetPhrase: undefined,\n maskerPhrase: undefined,\n};\nexport const actualSamplingRate = { current: \"\" };\nexport const actualBitsPerSample = { current: \"\" };\nexport const microphoneActualSamplingRate = { current: \"\" };\nexport const vocoderPhraseCategories = { chosen: undefined, all: undefined };\nexport const vocoderPhraseShowClickable = { current: true };\nexport const vocoderPhraseCorrectResponse = { current: undefined };\nexport const soundCalibrationLevelDBSPL = { current: undefined };\nexport const soundCalibrationResults = { current: undefined };\nexport const qualityMetrics = {\n current: {\n mlsSD: undefined,\n correctionSD: undefined,\n },\n};\nexport const sdOfRecordingOfFilteredMLS = { current: undefined };\nexport const currentFirestoreProfileDocumentID = {\n microphone: undefined,\n loudspeaker: undefined,\n};\nexport const allHzCalibrationResults = {\n x_unconv: undefined,\n y_unconv: undefined,\n x_conv: undefined,\n y_conv: undefined,\n knownIr: undefined,\n x_background: undefined,\n y_background: undefined,\n system: {},\n component: {},\n background: {},\n mls_psd: {},\n microphoneGain: { Freq: [], Gain: [] },\n loudspeakerGain: { Freq: [], Gain: [] },\n filteredMLSRange: {\n system: { Min: null, Max: null },\n component: { Min: null, Max: null },\n },\n timestamps: \"\",\n};\nexport const flags = {\n current: {\n autoGainControl: \"\",\n echoCancellation: \"\",\n noiseSuppression: \"\",\n },\n};\nexport const calibrationRound = { current: 0 };\nexport const loudspeakerIR = { Freq: [], Gain: [] };\nexport const webAudioDeviceNames = {\n loudspeaker: \"\",\n microphone: \"\",\n loudspeakerText: \"\",\n microphoneText: \"\",\n};\nexport const IDsToSaveInSoundProfileLibrary = {\n ProlificParticipantID: \"\",\n PavloviaSessionID: \"\",\n};\n\nexport const parseJsonSaveTargets = (raw) => {\n const normalized = (raw || \"\").toLowerCase();\n const parts = normalized\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean);\n return {\n wantsLocal: parts.includes(\"local\"),\n wantsOnline: parts.includes(\"online\"),\n };\n};\n\nexport const calibrateSoundSamplingDesiredBits = { current: 16 };\n//export const showSoundParametersBool = { current: true };\nexport const _calibrateSoundShowParametersBool = { current: true };\nexport const _calibrateSoundAllHzBool = { current: false };\n//export const calibrateSoundSaveJSONBool = { current: false };\nexport const _calibrateSoundSaveJSON = { current: \"\" };\nexport const calibrateSoundSmoothOctaves = { current: 0.3333333 };\nexport const calibrateSoundSmoothMinBandwidthHz = { current: 200 };\nexport const calibrateSoundPowerBinDesiredSec = { current: 0.2 };\nexport const calibrateSoundPowerDbSDToleratedDb = { current: 1 };\nexport const calibrateSoundTaperSec = { current: 0.01 };\nexport const calibrateSoundBackgroundSecs = { current: 0 };\nexport const calibrateSoundBurstRepeats = { current: 4 };\nexport const calibrateSoundBurstSec = { current: 1 };\nexport const _calibrateSoundBurstPreSec = { current: 1 };\nexport const _calibrateSoundBurstPostSec = { current: 1 };\nexport const calibrateSoundBurstsWarmup = { current: 1 };\nexport const calibrateSoundHz = { current: 48000 };\nexport const calibrateSoundBurstRecordings = { current: 3 };\nexport const calibrateSoundBurstMLSVersions = { current: 4 };\nexport const _calibrateSound1000HzBool = { current: false };\nexport const _calibrateSound1000HzDB = { current: \"-50, -40, -30, -20, -10\" };\nexport const _calibrateSound1000HzSec = { current: 1 };\nexport const _calibrateSound1000HzPreSec = { current: 3.5 };\nexport const _calibrateSound1000HzPostSec = { current: 0.5 };\nexport const calibrateSoundIIRSec = { current: 0.2 };\nexport const calibrateSoundIIRPhase = { current: \"linear\" };\nexport const calibrateSoundIRSec = { current: 0.2 };\nexport const calibrateSoundBurstDb = { current: -18 };\nexport const calibrateSoundBurstFilteredExtraDb = { current: 6 };\nexport const calibrateSoundBurstScalarDB = { current: 71 };\nexport const calibrateSoundBurstLevelReTBool = { current: false };\nexport const calibrateSoundBurstDbIsRelativeBool = { current: false };\nexport const calibrateSoundBurstUses1000HzGainBool = { current: false };\nexport const calibrateSoundBurstNormalizeBy1000HzGainBool = { current: false };\nexport const _calibrateSound1000HzMaxSD_dB = { current: 4 };\nexport const _calibrateSound1000HzMaxTries = { current: 4 };\nexport const _calibrateSoundBurstMaxSD_dB = { current: 4 };\nexport const calibrateSoundBurstDownsample = { current: 1 };\n\nexport const timeoutSec = { current: 180 };\nexport const timeoutNewPhoneSec = { current: 15 };\nexport const timeoutSoundCalibrationSec = { current: 1000000 };\nexport const calibrateSoundCheck = { current: \"speakerOrMic\" };\n//export const showSoundCalibrationResultsBool = { current: false };\nexport const _calibrateSoundShowResultsBool = { current: false };\n//export const showSoundTestPageBool = { current: false };\nexport const _calibrateSoundShowTestPageBool = { current: false };\nexport const microphoneCalibrationResults = [];\nexport const microphoneCalibrationResult = { current: undefined };\nexport const _calibrateSoundMaxHz = { current: undefined };\nexport const _calibrateSoundMinHz = { current: undefined };\nexport const fMaxHz = {\n system: undefined,\n component: undefined,\n};\nexport const calibrateSoundSimulateLoudspeaker = {\n type: \"impulseResponse\",\n frequencies: null,\n gains: null,\n amplitudes: null,\n fileName: undefined,\n time: null,\n enabled: false,\n};\nexport const calibrateSoundSimulateMicrophone = {\n type: \"impulseResponse\",\n frequencies: null,\n gains: null,\n amplitudes: null,\n fileName: undefined,\n time: null,\n enabled: false,\n};\nexport const attenuatorGainDB = {\n system: undefined,\n component: undefined,\n};\nexport const soundGainTWR = { T: undefined, W: undefined, R: undefined };\nexport const debugBool = { current: false };\nexport const ICalibDBSPL = { current: undefined };\nexport const calibrateMicrophonesBool = { current: false };\nexport const rsvpReadingWordsForThisBlock = { current: undefined };\nexport const timeToCalibrate = {\n current: 1,\n timeAtTheStartOfCalibration: 0,\n timeAtTheEndOfCalibration: 0,\n calibrationDuration: 0,\n};\nexport const calibrateSoundUMIKBase_dB = {\n current: -99.96,\n umik1: -75.11,\n umik2: -99.96,\n};\nexport const calibrateSoundLimit = { current: 1 };\nexport const filteredMLSAttenuation = {\n component: 1,\n system: 1,\n maxAbsSystem: 1,\n maxAbsComponent: 1,\n attenuationDbSystem: 0,\n attenuationDbComponent: 0,\n};\nexport const micsForSoundTestPage = { list: [] };\nexport const thisDevice = { current: undefined };\nexport const gotLoudspeakerMatch = { current: false };\nexport const loudspeakerInfo = { current: {} };\nexport const loudspeakerBrowserDetails = {\n current: { browser: undefined, browserVersion: undefined },\n};\nexport const microphoneBrowserDetails = {\n current: { browser: undefined, browserVersion: undefined },\n};\nexport const microphoneInfo = { current: {} };\nexport const calibrationTime = { current: undefined };\nexport const needPhoneSurvey = { current: false };\nexport const needComputerSurveyBool = { current: false };\nexport const authorEmail = { current: undefined };\nexport const rsvpReadingTargetSets = {\n numberOfSets: undefined,\n numberOfIdentifications: undefined,\n identificationTargetSets: undefined,\n current: undefined,\n upcoming: [],\n past: [],\n skippedDueToBadTracking: 0,\n};\n\nexport const rsvpReadingResponse = {\n categories: undefined,\n identificationCategories: undefined,\n screen: undefined,\n displayStatus: false,\n responseType: undefined,\n responseTypeForCurrentBlock: [],\n};\n\n/** @type {{completed: boolean, required: boolean, status: string, block: number | undefined, lastFailureCode: string | undefined}} */\nexport const rsvpSpeechPreflight = {\n completed: false,\n required: false,\n status: \"idle\",\n block: undefined,\n lastFailureCode: undefined,\n};\n\nexport const rsvpSpeechRuntime = {\n controller: undefined,\n status: \"idle\",\n simulated: false,\n blockCondition: undefined,\n utteranceId: undefined,\n result: undefined,\n error: undefined,\n preparationStartedAtMs: undefined,\n readyAtMs: undefined,\n captureStartedAtMs: undefined,\n finalizationAllowedAtMs: undefined,\n responseRegistrationStatus: \"pending\",\n responseRegistrationError: undefined,\n responseDiagnostics: undefined,\n};\n\nexport const rsvpReadingTiming = {\n current: {\n startSec: undefined,\n finishSec: undefined,\n startMs: undefined,\n finishMs: undefined,\n drawnConfirmedTimestamp: undefined,\n undrawnConfirmedTimestamp: undefined,\n drawnConfirmedTimestampMs: undefined,\n undrawnConfirmedTimestampMs: undefined,\n },\n past: [],\n};\nexport const dummyStim = { current: undefined };\n\n// Global record of font size, to be reported in the case of an error\nexport const fontSize = { current: \"Uninitiated\" };\n\n// export const speechRecognizer = {\n// recognition: undefined,\n// status: undefined,\n// responses: [],\n// };\n\nexport const eyeTrackingStimulusRecords = [];\n\nexport const cursorTracking = {\n records: [],\n target: undefined, // TODO are there other places where we care about the current target stim?\n};\n\nexport const measureLuminance = {\n records: [],\n movieStart: undefined,\n measureLuminanceDelaySec: 0,\n measurementShouldStartAt: undefined,\n movieValues: [],\n colorimeter: undefined,\n currentMovieValueIndex: 0,\n pretendBool: false,\n movieSec: 0,\n};\n\n/**\n * `State used when rerunning stimulus generation (ie trialInstructionRoutineBegin)\n * ie when the participant has significantly changed their viewing distance.\n */\nexport const preStimulus = {\n interval: undefined,\n running: false,\n};\n\nexport const keypad = {\n handler: undefined,\n};\n\n// For each condition, store whether we are done practicing.\nexport const thresholdParacticeUntilCorrect = {\n doneWithPractice: new DefaultMap(() => false),\n};\n","/**\n * Clock component.\n *\n * @author Alain Pitiot\n * @version 2021.2.0\n * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd. (https://opensciencetools.org)\n * @license Distributed under the terms of the MIT License\n */\n\n/**\n * <p>MonotonicClock offers a convenient way to keep track of time during experiments. An experiment can have as many independent clocks as needed, e.g. one to time responses, another one to keep track of stimuli, etc.</p>\n *\n * @name module:util.MonotonicClock\n * @class\n * @param {number} [startTime= <time elapsed since the reference point, i.e. the time when the module was loaded>] - the clock's start time (in ms)\n */\nexport class MonotonicClock\n{\n\tconstructor(startTime = MonotonicClock.getReferenceTime())\n\t{\n\t\tthis._timeAtLastReset = startTime;\n\t}\n\n\t/**\n\t * Get the current time on this clock.\n\t *\n\t * @name module:util.MonotonicClock#getTime\n\t * @function\n\t * @public\n\t * @return {number} the current time (in seconds)\n\t */\n\tgetTime()\n\t{\n\t\treturn MonotonicClock.getReferenceTime() - this._timeAtLastReset;\n\t}\n\n\t/**\n\t * Get the current offset being applied to the high resolution timebase used by this Clock.\n\t *\n\t * @name module:util.MonotonicClock#getLastResetTime\n\t * @function\n\t * @public\n\t * @return {number} the offset (in seconds)\n\t */\n\tgetLastResetTime()\n\t{\n\t\treturn this._timeAtLastReset;\n\t}\n\n\t/**\n\t * Get the time elapsed since the reference point.\n\t *\n\t * @name module:util.MonotonicClock#getReferenceTime\n\t * @function\n\t * @public\n\t * @return {number} the time elapsed since the reference point (in seconds)\n\t */\n\tstatic getReferenceTime()\n\t{\n\t\treturn (performance.now() / 1000.0 - MonotonicClock._referenceTime);\n\t\t// return (new Date().getTime()) / 1000.0 - MonotonicClock._referenceTime;\n\t}\n\n\t/**\n\t * Get the current timestamp with language-sensitive formatting rules applied.\n\t *\n\t * <p>Note: This is just a convenience wrapper around `Intl.DateTimeFormat()`.</p>\n\t *\n\t * @name module:util.MonotonicClock.getDate\n\t * @function\n\t * @public\n\t * @static\n\t * @param {string|array.string} locales - A string with a BCP 47 language tag, or an array of such strings.\n\t * @param {object} options - An object with detailed date and time styling information.\n\t * @return {string} The current timestamp in the chosen format.\n\t */\n\tstatic getDate(locales = \"en-CA\", optionsMaybe)\n\t{\n\t\tconst date = new Date();\n\t\tconst options = Object.assign({\n\t\t\thour12: false,\n\t\t\tyear: \"numeric\",\n\t\t\tmonth: \"2-digit\",\n\t\t\tday: \"2-digit\",\n\t\t\thour: \"numeric\",\n\t\t\tminute: \"numeric\",\n\t\t\tsecond: \"numeric\",\n\t\t\tfractionalSecondDigits: 3,\n\t\t}, optionsMaybe);\n\n\t\tconst dateTimeFormat = new Intl.DateTimeFormat(locales, options);\n\n\t\treturn dateTimeFormat.format(date);\n\t}\n\n\tstatic getTimeZone(locales = \"en-CA\", optionsMaybe = {}) {\n\t\t// Create a new Date object\n\t\tconst date = new Date();\n\t\t// Merge default options with any provided options\n\t\tconst options = Object.assign({\n\t\t\ttimeZoneName: \"shortOffset\"\n\t\t}, optionsMaybe);\n\t\n\t\t// Create a DateTimeFormat object with the specified locale and options\n\t\tconst dateTimeFormat = new Intl.DateTimeFormat(locales, options);\n\t\t// Format the date into parts\n\t\tconst parts = dateTimeFormat.formatToParts(date);\n\t\n\t\t// Get time zone as offset, eg UTC-3\n\t\tconst timeZoneOffset = parts.find(part => part.type === \"timeZoneName\").value;\n\t\t// const literal = parts.find(part => part.type === \"literal\")?.value || '';\n\t\tconst timeZoneUTC = timeZoneOffset.replace(\"GMT\", \"UTC\");\n\t\n\t\t// Return a formatted string combining the literal and the time zone name\n\t\treturn timeZoneUTC;\n\t}\n\n\t/**\n\t * Get the clock's current time in the default format filtering out file name unsafe characters.\n\t *\n\t * <p>Note: This is mostly used as an appendix to the name of the keys save to the server.</p>\n\t *\n\t * @name module:util.MonotonicClock.getDateStr\n\t * @function\n\t * @public\n\t * @static\n\t * @return {string} A string representing the current time formatted as YYYY-MM-DD_HH[h]mm.ss.sss\n\t */\n\tstatic getDateStr()\n\t{\n\t\t// yyyy-mm-dd, hh:mm:ss.sss\n\t\treturn MonotonicClock.getDate()\n\t\t\t// yyyy-mm-dd_hh:mm:ss.sss\n\t\t\t.replace(\", \", \"_\")\n\t\t\t// yyyy-mm-dd_hh[h]mm:ss.sss\n\t\t\t.replace(\":\", \"h\")\n\t\t\t// yyyy-mm-dd_hh[h]mm.ss.sss\n\t\t\t.replace(\":\", \".\");\n\t}\n}\n\n/**\n * The clock's referenceTime is the time when the module was loaded (in seconds).\n *\n * @name module:util.MonotonicClock._referenceTime\n * @readonly\n * @private\n * @type {number}\n */\nMonotonicClock._referenceTime = performance.now() / 1000.0;\n\n// MonotonicClock._referenceTime = new Date().getTime() / 1000.0;\n\n/**\n * <p>Clock is a MonotonicClock that also offers the possibility of being reset.</p>\n *\n * @name module:util.Clock\n * @class\n * @extends MonotonicClock\n */\nexport class Clock extends MonotonicClock\n{\n\tconstructor()\n\t{\n\t\tsuper();\n\t}\n\n\t/**\n\t * Reset the time on the clock.\n\t *\n\t *\n\t * @name module:util.Clock#reset\n\t * @function\n\t * @public\n\t * @param {number} [newTime= 0] the new time on the clock.\n\t */\n\treset(newTime = 0)\n\t{\n\t\tthis._timeAtLastReset = MonotonicClock.getReferenceTime() + newTime;\n\t}\n\n\t/**\n\t * Add more time to the clock's 'start' time (t0).\n\t *\n\t * <p>Note: by adding time to t0, the current time is pushed forward (it becomes\n\t * smaller). As a consequence, getTime() may return a negative number.</p>\n\t *\n\t * @name module:util.Clock#add\n\t * @function\n\t * @public\n\t * @param {number} [deltaTime] the time to be added to the clock's start time (t0)\n\t */\n\tadd(deltaTime)\n\t{\n\t\tthis._timeAtLastReset += deltaTime;\n\t}\n}\n\n/**\n * <p>CountdownTimer is a clock counts down from the time of last reset.</p.\n *\n * @name module:util.CountdownTimer\n * @class\n * @extends Clock\n * @param {number} [startTime= 0] - the start time of the countdown\n */\nexport class CountdownTimer extends Clock\n{\n\tconstructor(startTime = 0)\n\t{\n\t\tsuper();\n\n\t\tthis._timeAtLastReset = MonotonicClock.getReferenceTime();\n\t\tthis._countdown_duration = startTime;\n\t\tif (startTime)\n\t\t{\n\t\t\tthis.add(startTime);\n\t\t}\n\t}\n\n\t/**\n\t * Add more time to the clock's 'start' time (t0).\n\t *\n\t * <p>Note: by adding time to t0, you push the current time forward (make it\n\t * smaller). As a consequence, getTime() may return a negative number.</p>\n\t *\n\t * @name module:util.CountdownTimer#add\n\t * @function\n\t * @public\n\t * @param {number} [deltaTime] the time to be added to the clock's start time (t0)\n\t */\n\tadd(deltaTime)\n\t{\n\t\tthis._timeAtLastReset += deltaTime;\n\t}\n\n\t/**\n\t * Reset the time on the countdown.\n\t *\n\t * @name module:util.CountdownTimer#reset\n\t * @function\n\t * @public\n\t * @param {number} [newTime] - if newTime is undefined, the countdown time is reset to zero, otherwise we set it\n\t * to newTime\n\t */\n\treset(newTime = undefined)\n\t{\n\t\tif (typeof newTime == \"undefined\")\n\t\t{\n\t\t\tthis._timeAtLastReset = MonotonicClock.getReferenceTime() + this._countdown_duration;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis._countdown_duration = newTime;\n\t\t\tthis._timeAtLastReset = MonotonicClock.getReferenceTime() + newTime;\n\t\t}\n\t}\n\n\t/**\n\t * Get the time currently left on the countdown.\n\t *\n\t * @name module:util.CountdownTimer#getTime\n\t * @function\n\t * @public\n\t * @return {number} the time left on the countdown (in seconds)\n\t */\n\tgetTime()\n\t{\n\t\treturn this._timeAtLastReset - MonotonicClock.getReferenceTime();\n\t}\n}\n","/**\n * Various utilities.\n *\n * @authors Alain Pitiot, Sotiri Bakagiannis, Thomas Pronk\n * @version 2021.2.0\n * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd. (https://opensciencetools.org)\n * @license Distributed under the terms of the MIT License\n */\n\n/**\n * Syntactic sugar for Mixins\n *\n * <p>This is heavily adapted from: http://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes/</p>\n *\n * @name module:util.MixinBuilder\n * @class\n * @param {Object} superclass\n *\n * @example\n * class BaseClass { ... }\n * let Mixin1 = (superclass) => class extends superclass { ... }\n * let Mixin2 = (superclass) => class extends superclass { ... }\n * class NewClass extends mix(BaseClass).with(Mixin1, Mixin2) { ... }\n */\nexport let mix = (superclass) => new MixinBuilder(superclass);\n\nclass MixinBuilder\n{\n\tconstructor(superclass)\n\t{\n\t\tthis.superclass = superclass;\n\t}\n\n\t/**\n\t *\n\t * @param mixins\n\t * @returns {*}\n\t */\n\twith(...mixins)\n\t{\n\t\treturn mixins.reduce((c, mixin) => mixin(c), this.superclass);\n\t}\n}\n\n/**\n * Convert the resulting value of a promise into a tupple.\n *\n * @name module:util.promiseToTupple\n * @function\n * @public\n * @param {Promise} promise - the promise\n * @return {Object[]} the resulting value in the format [error, return data]\n * where error is null if there was no error\n */\nexport function promiseToTupple(promise)\n{\n\treturn promise\n\t\t.then((data) => [null, data])\n\t\t.catch((error) => [error, null]);\n}\n\n/**\n * Get a Universally Unique Identifier (RFC4122 version 4)\n * <p> See details here: https://www.ietf.org/rfc/rfc4122.txt</p>\n *\n * @name module:util.makeUuid\n * @function\n * @public\n * @return {string} the uuid\n */\nexport function makeUuid()\n{\n\treturn \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, function(c)\n\t{\n\t\tconst r = Math.random() * 16 | 0, v = (c === \"x\") ? r : (r & 0x3 | 0x8);\n\t\treturn v.toString(16);\n\t});\n}\n\n/**\n * Get the error stack of the calling, exception-throwing function.\n *\n * @name module:util.getErrorStack\n * @function\n * @public\n * @return {string} the error stack as a string\n */\nexport function getErrorStack()\n{\n\ttry\n\t{\n\t\tthrow Error(\"\");\n\t}\n\tcatch (error)\n\t{\n\t\t// we need to remove the second line since it references getErrorStack:\n\t\tlet stack = error.stack.split(\"\\n\");\n\t\tstack.splice(1, 1);\n\n\t\treturn JSON.stringify(stack.join(\"\\n\"));\n\t}\n}\n\n/**\n * Test if x is an 'empty' value.\n *\n * @name module:util.isEmpty\n * @function\n * @public\n * @param {Object} x the value to test\n * @return {boolean} true if x is one of the following: undefined, [], [undefined]\n */\nexport function isEmpty(x)\n{\n\tif (typeof x === \"undefined\")\n\t{\n\t\treturn true;\n\t}\n\tif (!Array.isArray(x))\n\t{\n\t\treturn false;\n\t}\n\tif (x.length === 0)\n\t{\n\t\treturn true;\n\t}\n\tif (x.length === 1 && typeof x[0] === \"undefined\")\n\t{\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n/**\n * Detect the user's browser.\n *\n * <p> Note: since user agent is easily spoofed, we use a more sophisticated approach, as described here:\n * https://stackoverflow.com/a/9851769</p>\n *\n * @name module:util.detectBrowser\n * @function\n * @public\n * @return {string} the detected browser, one of 'Opera', 'Firefox', 'Safari',\n * 'IE', 'Edge', 'EdgeChromium', 'Chrome', 'unknown'\n */\nexport function detectBrowser()\n{\n\t// Opera 8.0+\n\tconst isOpera = (!!window.opr && !!opr.addons) || !!window.opera || navigator.userAgent.indexOf(\" OPR/\") >= 0;\n\tif (isOpera)\n\t{\n\t\treturn \"Opera\";\n\t}\n\n\t// Firefox 1.0+\n\tconst isFirefox = (typeof InstallTrigger !== \"undefined\");\n\tif (isFirefox)\n\t{\n\t\treturn \"Firefox\";\n\t}\n\n\t// Safari 3.0+ \"[object HTMLElementConstructor]\"\n\tconst isSafari = /constructor/i.test(window.HTMLElement) || (function(p)\n\t{\n\t\treturn p.toString() === \"[object SafariRemoteNotification]\";\n\t})(!window[\"safari\"] || (typeof safari !== \"undefined\" && safari.pushNotification));\n\tif (isSafari)\n\t{\n\t\treturn \"Safari\";\n\t}\n\n\t// Internet Explorer 6-11\n\t// const isIE6 = !window.XMLHttpRequest;\n\t// const isIE7 = document.all && window.XMLHttpRequest && !XDomainRequest && !window.opera;\n\t// const isIE8 = document.documentMode==8;\n\tconst isIE = /*@cc_on!@*/ false || !!document.documentMode;\n\tif (isIE)\n\t{\n\t\treturn \"IE\";\n\t}\n\n\t// Edge 20+\n\tconst isEdge = !isIE && !!window.StyleMedia;\n\tif (isEdge)\n\t{\n\t\treturn \"Edge\";\n\t}\n\n\t// Chrome 1+\n\tconst isChrome = window.chrome;\n\tif (isChrome)\n\t{\n\t\treturn \"Chrome\";\n\t}\n\n\t// Chromium-based Edge:\n\tconst isEdgeChromium = isChrome && (navigator.userAgent.indexOf(\"Edg\") !== -1);\n\tif (isEdgeChromium)\n\t{\n\t\treturn \"EdgeChromium\";\n\t}\n\n\t// Blink engine detection\n\tconst isBlink = (isChrome || isOpera) && !!window.CSS;\n\tif (isBlink)\n\t{\n\t\treturn \"Blink\";\n\t}\n\n\treturn \"unknown\";\n}\n\n/**\n * Convert obj to its numerical form.\n *\n * <ul>\n * <li>number -> number, e.g. 2 -> 2</li>\n * <li>[number] -> [number], e.g. [1,2,3] -> [1,2,3]</li>\n * <li>numeral string -> number, e.g. \"8\" -> 8</li>\n * <li>[number | numeral string] -> [number], e.g. [1, 2, \"3\"] -> [1,2,3]</li>\n * </ul>\n *\n * @name module:util.toNumerical\n * @function\n * @public\n * @param {Object} obj - the input object\n * @return {number | number[]} the numerical form of the input object\n */\nexport function toNumerical(obj)\n{\n\tconst response = {\n\t\torigin: \"util.toNumerical\",\n\t\tcontext: \"when converting an object to its numerical form\",\n\t};\n\n\ttry\n\t{\n\t\tif (obj === null)\n\t\t{\n\t\t\tthrow \"unable to convert null to a number\";\n\t\t}\n\n\t\tif (typeof obj === \"undefined\")\n\t\t{\n\t\t\tthrow \"unable to convert undefined to a number\";\n\t\t}\n\n\t\tif (typeof obj === \"number\")\n\t\t{\n\t\t\treturn obj;\n\t\t}\n\n\t\tconst convertToNumber = (input) =>\n\t\t{\n\t\t\tconst n = Number.parseFloat(input);\n\n\t\t\tif (Number.isNaN(n))\n\t\t\t{\n\t\t\t\tthrow `unable to convert ${input} to a number`;\n\t\t\t}\n\n\t\t\treturn n;\n\t\t};\n\n\t\tif (Array.isArray(obj))\n\t\t{\n\t\t\treturn obj.map(convertToNumber);\n\t\t}\n\n\t\tconst arrayMaybe = turnSquareBracketsIntoArrays(obj);\n\n\t\tif (Array.isArray(arrayMaybe))\n\t\t{\n\t\t\treturn arrayMaybe.map(convertToNumber);\n\t\t}\n\n\t\tif (typeof obj === \"string\")\n\t\t{\n\t\t\treturn convertToNumber(obj);\n\t\t}\n\n\t\tthrow \"unable to convert the object to a number\";\n\t}\n\tcatch (error)\n\t{\n\t\tthrow Object.assign(response, { error });\n\t}\n}\n\n/**\n * Check whether a value looks like a number\n *\n * @name module:util.isNumeric\n * @function\n * @public\n * @param {*} input - Some value\n * @return {boolean} Whether or not the value can be converted into a number\n */\nexport function isNumeric(input)\n{\n\treturn Number.isNaN(Number(input)) === false;\n}\n\n/**\n * Check whether a point lies within a polygon\n * <p>We are using the algorithm described here: https://wrf.ecse.rpi.edu//Research/Short_Notes/pnpoly.html</p>\n *\n * @name module:util.IsPointInsidePolygon\n * @function\n * @public\n * @param {number[]} point - the point\n * @param {Object} vertices - the vertices defining the polygon\n * @return {boolean} whether or not the point lies within the polygon\n */\nexport function IsPointInsidePolygon(point, vertices)\n{\n\tconst x = point[0];\n\tconst y = point[1];\n\n\tlet isInside = false;\n\tfor (let i = 0, j = vertices.length - 1; i < vertices.length; j = i++)\n\t{\n\t\tconst xi = vertices[i][0], yi = vertices[i][1];\n\t\tconst xj = vertices[j][0], yj = vertices[j][1];\n\t\tconst intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);\n\t\tif (intersect)\n\t\t{\n\t\t\tisInside = !isInside;\n\t\t}\n\t}\n\n\treturn isInside;\n}\n\n/**\n * Shuffle an array in place using the Fisher-Yastes's modern algorithm\n * <p>See details here: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm</p>\n *\n * @name module:util.shuffle\n * @function\n * @public\n * @param {Object[]} array - the input 1-D array\n * @param {Function} [randomNumberGenerator = undefined] - A function used to generated random numbers in the interal [0, 1). Defaults to Math.random\n * @return {Object[]} the shuffled array\n */\nexport function shuffle(array, randomNumberGenerator = undefined)\n{\n\tif (randomNumberGenerator === undefined)\n\t{\n\t\trandomNumberGenerator = Math.random;\n\t}\n\tfor (let i = array.length - 1; i > 0; i--)\n\t{\n\t\tconst j = Math.floor(randomNumberGenerator() * (i + 1));\n\t\t[array[i], array[j]] = [array[j], array[i]];\n\t}\n\treturn array;\n}\n\n/**\n * Pick a random value from an array, uses `util.shuffle` to shuffle the array and returns the last value.\n *\n * @name module:util.randchoice\n * @function\n * @public\n * @param {Object[]} array - the input 1-D array\n * @param {Function} [randomNumberGenerator = undefined] - A function used to generated random numbers in the interal [0, 1). Defaults to Math.random\n * @return {Object[]} a chosen value from the array\n */\nexport function randchoice(array, randomNumberGenerator = undefined)\n{\n\tif (randomNumberGenerator === undefined)\n\t{\n\t\trandomNumberGenerator = Math.random;\n\t}\n\tconst j = Math.floor(randomNumberGenerator() * array.length);\n\treturn array[j]\n}\n\n/**\n * Get the position of the object, in pixel units\n *\n * @name module:util.getPositionFromObject\n * @function\n * @public\n * @param {Object} object - the input object\n * @param {string} units - the units\n * @returns {number[]} the position of the object, in pixel units\n */\nexport function getPositionFromObject(object, units)\n{\n\tconst response = {\n\t\torigin: \"util.getPositionFromObject\",\n\t\tcontext: \"when getting the position of an object\",\n\t};\n\n\ttry\n\t{\n\t\tif (typeof object === \"undefined\")\n\t\t{\n\t\t\tthrow \"cannot get the position of an undefined object\";\n\t\t}\n\n\t\tlet objectWin = undefined;\n\n\t\t// the object has a getPos function:\n\t\tif (typeof object.getPos === \"function\")\n\t\t{\n\t\t\tunits = object.units;\n\t\t\tobjectWin = object.win;\n\t\t\tobject = object.getPos();\n\t\t}\n\n\t\t// convert object to pixel units:\n\t\treturn to_px(object, units, objectWin);\n\t}\n\tcatch (error)\n\t{\n\t\tthrow Object.assign(response, { error });\n\t}\n}\n\n/**\n * Convert the position to pixel units.\n *\n * @name module:util.to_px\n * @function\n * @public\n * @param {number[]} pos - the input position\n * @param {string} posUnit - the position units\n * @param {Window} win - the associated Window\n * @param {boolean} [integerCoordinates = false] - whether or not to round the position coordinates.\n * @returns {number[]} the position in pixel units\n */\nexport function to_px(pos, posUnit, win, integerCoordinates = false)\n{\n\tconst response = {\n\t\torigin: \"util.to_px\",\n\t\tcontext: \"when converting a position to pixel units\",\n\t};\n\n\tlet pos_px;\n\n\tif (posUnit === \"pix\")\n\t{\n\t\tpos_px = pos;\n\t}\n\telse if (posUnit === \"norm\")\n\t{\n\t\tpos_px = [pos[0] * win.size[0] / 2.0, pos[1] * win.size[1] / 2.0];\n\t}\n\telse if (posUnit === \"height\")\n\t{\n\t\tconst minSize = Math.min(win.size[0], win.size[1]);\n\t\tpos_px = [pos[0] * minSize, pos[1] * minSize];\n\t}\n\telse\n\t{\n\t\tthrow Object.assign(response, { error: `unknown position units: ${posUnit}` });\n\t}\n\n\tif (integerCoordinates)\n\t{\n\t\treturn [Math.round(pos_px[0]), Math.round(pos_px[1])];\n\t}\n\telse\n\t{\n\t\treturn pos_px;\n\t}\n}\n\n/**\n * Convert the position to norm units.\n *\n * @name module:util.to_norm\n * @function\n * @public\n * @param {number[]} pos - the input position\n * @param {string} posUnit - the position units\n * @param {Window} win - the associated Window\n * @returns {number[]} the position in norm units\n */\nexport function to_norm(pos, posUnit, win)\n{\n\tconst response = { origin: \"util.to_norm\", context: \"when converting a position to norm units\" };\n\n\tif (posUnit === \"norm\")\n\t{\n\t\treturn pos;\n\t}\n\tif (posUnit === \"pix\")\n\t{\n\t\treturn [pos[0] / (win.size[0] / 2.0), pos[1] / (win.size[1] / 2.0)];\n\t}\n\tif (posUnit === \"height\")\n\t{\n\t\tconst minSize = Math.min(win.size[0], win.size[1]);\n\t\treturn [pos[0] * minSize / (win.size[0] / 2.0), pos[1] * minSize / (win.size[1] / 2.0)];\n\t}\n\n\tthrow Object.assign(response, { error: `unknown position units: ${posUnit}` });\n}\n\n/**\n * Convert the position to height units.\n *\n * @name module:util.to_height\n * @function\n * @public\n * @param {number[]} pos - the input position\n * @param {string} posUnit - the position units\n * @param {Window} win - the associated Window\n * @returns {number[]} the position in height units\n */\nexport function to_height(pos, posUnit, win)\n{\n\tconst response = {\n\t\torigin: \"util.to_height\",\n\t\tcontext: \"when converting a position to height units\",\n\t};\n\n\tif (posUnit === \"height\")\n\t{\n\t\treturn pos;\n\t}\n\tif (posUnit === \"pix\")\n\t{\n\t\tconst minSize = Math.min(win.size[0], win.size[1]);\n\t\treturn [pos[0] / minSize, pos[1] / minSize];\n\t}\n\tif (posUnit === \"norm\")\n\t{\n\t\tconst minSize = Math.min(win.size[0], win.size[1]);\n\t\treturn [pos[0] * win.size[0] / 2.0 / minSize, pos[1] * win.size[1] / 2.0 / minSize];\n\t}\n\n\tthrow Object.assign(response, { error: `unknown position units: ${posUnit}` });\n}\n\n/**\n * Convert the position to window units.\n *\n * @name module:util.to_win\n * @function\n * @public\n * @param {number[]} pos - the input position\n * @param {string} posUnit - the position units\n * @param {Window} win - the associated Window\n * @returns {number[]} the position in window units\n */\nexport function to_win(pos, posUnit, win)\n{\n\tconst response = { origin: \"util.to_win\", context: \"when converting a position to window units\" };\n\n\ttry\n\t{\n\t\tif (win._units === \"pix\")\n\t\t{\n\t\t\treturn to_px(pos, posUnit, win);\n\t\t}\n\t\tif (win._units === \"norm\")\n\t\t{\n\t\t\treturn to_norm(pos, posUnit, win);\n\t\t}\n\t\tif (win._units === \"height\")\n\t\t{\n\t\t\treturn to_height(pos, posUnit, win);\n\t\t}\n\n\t\tthrow `unknown window units: ${win._units}`;\n\t}\n\tcatch (error)\n\t{\n\t\tthrow Object.assign(response, { response, error });\n\t}\n}\n\n/**\n * Convert the position to given units.\n *\n * @name module:util.to_unit\n * @function\n * @public\n * @param {number[]} pos - the input position\n * @param {string} posUnit - the position units\n * @param {Window} win - the associated Window\n * @param {string} targetUnit - the target units\n * @returns {number[]} the position in target units\n */\nexport function to_unit(pos, posUnit, win, targetUnit)\n{\n\tconst response = { origin: \"util.to_unit\", context: \"when converting a position to different units\" };\n\n\ttry\n\t{\n\t\tif (targetUnit === \"pix\")\n\t\t{\n\t\t\treturn to_px(pos, posUnit, win);\n\t\t}\n\t\tif (targetUnit === \"norm\")\n\t\t{\n\t\t\treturn to_norm(pos, posUnit, win);\n\t\t}\n\t\tif (targetUnit === \"height\")\n\t\t{\n\t\t\treturn to_height(pos, posUnit, win);\n\t\t}\n\n\t\tthrow `unknown target units: ${targetUnit}`;\n\t}\n\tcatch (error)\n\t{\n\t\tthrow Object.assign(response, { error });\n\t}\n}\n\n/**\n * Convert an object to its string representation, taking care of symbols.\n *\n * <p>Note: if the object is not already a string, we JSON stringify it and detect circularity.</p>\n *\n * @name module:util.toString\n * @function\n * @public\n * @param {Object} object - the input object\n * @return {string} a string representation of the object or 'Object (circular)'\n */\nexport function toString(object)\n{\n\tif (typeof object === \"undefined\")\n\t{\n\t\treturn \"undefined\";\n\t}\n\n\tif (!object)\n\t{\n\t\treturn \"null\";\n\t}\n\n\tif (typeof object === \"string\")\n\t{\n\t\treturn object;\n\t}\n\n\t// if the object is a class and has a toString method:\n\tif (object.constructor.toString().substring(0, 5) === \"class\" && typeof object.toString === \"function\")\n\t{\n\t\treturn object.toString();\n\t}\n\n\ttry\n\t{\n\t\tconst symbolReplacer = (key, value) =>\n\t\t{\n\t\t\tif (typeof value === \"symbol\")\n\t\t\t{\n\t\t\t\tvalue = Symbol.keyFor(value);\n\t\t\t}\n\t\t\treturn value;\n\t\t};\n\t\treturn JSON.stringify(object, symbolReplacer);\n\t}\n\tcatch (e)\n\t{\n\t\treturn \"Object (circular)\";\n\t}\n}\n\nif (!String.prototype.format)\n{\n\tString.prototype.format = function()\n\t{\n\t\tvar args = arguments;\n\t\treturn this\n\t\t\t.replace(/{(\\d+)}/g, function(match, number)\n\t\t\t{\n\t\t\t\treturn typeof args[number] != \"undefined\" ? args[number] : match;\n\t\t\t})\n\t\t\t.replace(/{([$_a-zA-Z][$_a-zA-Z0-9]*)}/g, function(match, name)\n\t\t\t{\n\t\t\t\t// console.log(\"n=\" + name + \" args[0][name]=\" + args[0][name]);\n\t\t\t\treturn args.length > 0 && args[0][name] !== undefined ? args[0][name] : match;\n\t\t\t});\n\t};\n}\n\n/**\n * Get the most informative error from the server response from a jquery server request.\n *\n * @name module:util.getRequestError\n * @function\n * @public\n * @param jqXHR\n * @param textStatus\n * @param errorThrown\n */\nexport function getRequestError(jqXHR, textStatus, errorThrown)\n{\n\tlet errorMsg = \"unknown error\";\n\n\tif (typeof jqXHR.responseJSON !== \"undefined\")\n\t{\n\t\t// If responseJSON is an object, extract meaningful error info\n\t\tif (typeof jqXHR.responseJSON === \"object\")\n\t\t{\n\t\t\tif (jqXHR.responseJSON.error)\n\t\t\t{\n\t\t\t\terrorMsg = jqXHR.responseJSON.error;\n\t\t\t\t// Add additional details if available\n\t\t\t\tif (jqXHR.responseJSON.details)\n\t\t\t\t{\n\t\t\t\t\terrorMsg += \" - \" + jqXHR.responseJSON.details;\n\t\t\t\t}\n\t\t\t\tif (jqXHR.responseJSON.code)\n\t\t\t\t{\n\t\t\t\t\terrorMsg += \" (Code: \" + jqXHR.responseJSON.code + \")\";\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Fallback: stringify the entire object\n\t\t\t\terrorMsg = JSON.stringify(jqXHR.responseJSON);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\terrorMsg = jqXHR.responseJSON;\n\t\t}\n\t}\n\telse if (typeof jqXHR.responseText !== \"undefined\")\n\t{\n\t\terrorMsg = jqXHR.responseText;\n\t}\n\telse if (typeof errorThrown !== \"undefined\")\n\t{\n\t\terrorMsg = errorThrown;\n\t}\n\n\treturn errorMsg;\n}\n\n/**\n * Test whether an object is either an integer or the string representation of an integer.\n * <p>This is adapted from: https://stackoverflow.com/a/14794066</p>\n *\n * @name module:util.isInt\n * @function\n * @public\n * @param {Object} obj - the input object\n * @returns {boolean} whether or not the object is an integer or the string representation of an integer\n */\nexport function isInt(obj)\n{\n\tif (isNaN(obj))\n\t{\n\t\treturn false;\n\t}\n\n\tconst x = parseFloat(obj);\n\treturn (x | 0) === x;\n}\n\n/**\n * Get the URL parameters.\n *\n * @name module:util.getUrlParameters\n * @function\n * @public\n * @returns {URLSearchParams} the iterable URLSearchParams\n *\n * @example\n * const urlParameters = util.getUrlParameters();\n * for (const [key, value] of urlParameters)\n * console.log(key + ' = ' + value);\n *\n */\nexport function getUrlParameters()\n{\n\tconst urlQuery = window.location.search.slice(1);\n\treturn new URLSearchParams(urlQuery);\n\n\t/*let urlMap = new Map();\n\tfor (const entry of urlParameters)\n\t\turlMap.set(entry[0], entry[1])\n\n\treturn urlMap;*/\n}\n\n/**\n * Add info extracted from the URL to the given dictionary.\n *\n * <p>We exclude all URL parameters starting with a double underscore\n * since those are reserved for client/server communication</p>\n *\n * @name module:util.addInfoFromUrl\n * @function\n * @public\n * @param {Object} info - the dictionary\n */\nexport function addInfoFromUrl(info)\n{\n\tconst infoFromUrl = getUrlParameters();\n\n\t// note: parameters starting with a double underscore are reserved for client/server communication,\n\t// we do not add them to info\n\t// for (const [key, value] of infoFromUrl)\n\tinfoFromUrl.forEach((value, key) =>\n\t{\n\t\tif (key.indexOf(\"__\") !== 0)\n\t\t{\n\t\t\tinfo[key] = value;\n\t\t}\n\t});\n\n\treturn info;\n}\n\n/**\n * Select values from an array.\n *\n * <p> 'selection' can be a single integer, an array of indices, or a string to be parsed, e.g.:\n * <ul>\n * <li>5</li>\n * <li>[1,2,3,10]</li>\n * <li>'1,5,10'</li>\n * <li>'1:2:5'</li>\n * <li>'5:'</li>\n * <li>'-5:-2, 9, 11:5:22'</li>\n * </ul></p>\n *\n * @name module:util.selectFromArray\n * @function\n * @public\n * @param {Array.<Object>} array - the input array\n * @param {number | Array.<number> | string} selection - the selection\n * @returns {Object | Array.<Object>} the array of selected items\n */\nexport function selectFromArray(array, selection)\n{\n\t// if selection is an integer, or a string representing an integer, we treat it\n\t// as an index in the array and return that entry:\n\tif (isInt(selection))\n\t{\n\t\treturn [array[parseInt(selection)]];\n\t}\n\n\t// if selection is an array, we treat it as a list of indices\n\t// and return an array with the entries corresponding to those indices:\n\telse if (Array.isArray(selection))\n\t{\n\t\treturn selection.map( (i) => array[i] );\n\t}\n\n\t// if selection is a string:\n\telse if (typeof selection === \"string\")\n\t{\n\t\tif (selection.indexOf(\",\") > -1)\n\t\t{\n\t\t\tconst selectionAsArray = selection.split(\",\").map( (i) => parseInt(i) );\n\t\t\treturn selectFromArray(array, selectionAsArray);\n\t\t}\n\n\t\telse if (selection.indexOf(\":\") > -1)\n\t\t{\n\t\t\tlet sliceParams = selection.split(\":\").map((a) => parseInt(a));\n\t\t\tif (sliceParams.length === 3)\n\t\t\t{\n\t\t\t\treturn sliceArray(array, sliceParams[0], sliceParams[2], sliceParams[1]);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn sliceArray(array, ...sliceParams);\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tthrow {\n\t\t\torigin: \"selectFromArray\",\n\t\t\tcontext: \"when selecting entries from an array\",\n\t\t\terror: \"unknown selection type: \" + (typeof selection),\n\t\t};\n\t}\n}\n\n/**\n * Recursively flatten an array of arrays.\n *\n * @name module:util.flattenArray\n * @function\n * @public\n * @param {Array.<Object>} array - the input array of arrays\n * @returns {Array.<Object>} the flatten array\n */\nexport function flattenArray(array)\n{\n\treturn array.reduce(\n\t\t(flat, next) =>\n\t\t{\n\t\t\tflat.push((Array.isArray(next) && Array.isArray(next[0])) ? flattenArray(next) : next);\n\t\t\treturn flat;\n\t\t},\n\t\t[],\n\t);\n}\n\n/**\n * Slice an array.\n *\n * @name module:util.sliceArray\n * @function\n * @public\n * @param {Array.<Object>} array - the input array\n * @param {number} [from= NaN] - the start of the slice\n * @param {number} [to= NaN] - the end of the slice\n * @param {number} [step= NaN] - the step of the slice\n * @returns {Array.<Object>} the array slice\n */\nexport function sliceArray(array, from = NaN, to = NaN, step = NaN)\n{\n\tif (isNaN(from))\n\t{\n\t\tfrom = 0;\n\t}\n\tif (isNaN(to))\n\t{\n\t\tto = array.length;\n\t}\n\n\tlet arraySlice = array.slice(from, to);\n\n\tif (isNaN(step))\n\t{\n\t\treturn arraySlice;\n\t}\n\n\tif (step < 0)\n\t{\n\t\tarraySlice.reverse();\n\t}\n\n\tstep = Math.abs(step);\n\tif (step === 1)\n\t{\n\t\treturn arraySlice;\n\t}\n\telse\n\t{\n\t\treturn arraySlice.filter((e, i) => (i % step === 0));\n\t}\n}\n\n/**\n * Offer data as download in the browser.\n *\n * @name module:util.offerDataForDownload\n * @function\n * @public\n * @param {string} filename - the name of the file to be downloaded\n * @param {*} data - the data\n * @param {string} type - the MIME type of the data, e.g. 'text/csv' or 'application/json'\n */\nexport function offerDataForDownload(filename, data, type)\n{\n\tconst blob = new Blob([data], { type });\n\tif (window.navigator.msSaveOrOpenBlob)\n\t{\n\t\twindow.navigator.msSaveBlob(blob, filename);\n\t}\n\telse\n\t{\n\t\tconst anchor = document.createElement(\"a\");\n\t\tanchor.href = window.URL.createObjectURL(blob);\n\t\tanchor.download = filename;\n\t\tdocument.body.appendChild(anchor);\n\t\tanchor.click();\n\t\tdocument.body.removeChild(anchor);\n\t}\n}\n\n/**\n * Convert a string representing a JSON array, e.g. \"[1, 2]\" into an array, e.g. [\"1\",\"2\"].\n * This approach overcomes the built-in JSON parsing limitations when it comes to eg. floats\n * missing the naught prefix, and is able to process several arrays, e.g. \"[1,2][3,4]\".\n *\n * @name module:util.turnSquareBracketsIntoArrays\n * @function\n * @public\n * @param {string} input - string potentially containing JSON arrays\n * @param {string} max - how many matches to return, unwrap resulting array if less than two\n * @returns {array} an array if arrays were found, undefined otherwise\n */\nexport function turnSquareBracketsIntoArrays(input, max = 1)\n{\n\t// Only interested in strings\n\t// https://stackoverflow.com/questions/4059147\n\tif (String(input) !== input)\n\t{\n\t\treturn;\n\t}\n\n\t// Matches content within square brackets (using literal\n\t// form is MDN's advice for patterns unlikely to change)\n\tconst matchesMaybe = input.match(/\\[(.*?)\\]/g);\n\n\t// Exit if no array-like matches found\n\tif (matchesMaybe === null)\n\t{\n\t\treturn;\n\t}\n\n\t// Reformat content for each match\n\tconst matches = matchesMaybe.map((data) =>\n\t{\n\t\treturn data\n\t\t\t// Remove the square brackets\n\t\t\t.replace(/[\\[\\]]+/g, \"\")\n\t\t\t// Eat up space after comma\n\t\t\t.split(/[, ]+/);\n\t});\n\n\tif (max < 2)\n\t{\n\t\treturn matches[0];\n\t}\n\n\treturn matches;\n}\n\n/**\n * Generates random integers a-la NumPy's in the \"half-open\" interval [min, max). In other words, from min inclusive to max exclusive. When max is undefined, as is the case by default, results are chosen from [0, min). An error is thrown if max is less than min.\n *\n * @name module:util.randint\n * @function\n * @public\n * @param {number} [min = 0] - lowest integer to be drawn, or highest plus one if max is undefined (default)\n * @param {number} max - one above the largest integer to be drawn\n * @returns {number} a random integer in the requested range (signed)\n */\nexport function randint(min = 0, max)\n{\n\tlet lo = min;\n\tlet hi = max;\n\n\tif (typeof max === \"undefined\")\n\t{\n\t\thi = lo;\n\t\tlo = 0;\n\t}\n\n\tif (hi < lo)\n\t{\n\t\tthrow {\n\t\t\torigin: \"util.randint\",\n\t\t\tcontext: \"when generating a random integer\",\n\t\t\terror: \"min should be <= max\",\n\t\t};\n\t}\n\n\treturn Math.floor(Math.random() * (hi - lo)) + lo;\n}\n\n/**\n * Round to a certain number of decimal places.\n *\n * This is the Crib Sheet provided solution, but please note that as of 2020 the most popular SO answer is different.\n *\n * @name module:util.round\n * @function\n * @public\n * @see {@link https://stackoverflow.com/questions/11832914|Stack Overflow}\n * @param {number} input - the number to be rounded\n * @param {number} places - the max number of decimals desired\n * @returns {number} input rounded to the specified number of decimal places at most\n */\nexport function round(input, places = 0)\n{\n\treturn +(Math.round(`${input}e+${places}`) + `e-${places}`);\n}\n\n/**\n * Calculate the sum of the elements in the input array.\n *\n * If 'input' is not an array, then we return start.\n *\n * @name module:util.sum\n * @function\n * @public\n * @param {array} input - an array of numbers, or of objects that can be cast into a number, e.g. ['1', 2.5, 3e1]\n * @param {number} start - value added to the sum of numbers (a la Python)\n * @returns {number} the sum of the elements in the array + start\n */\nexport function sum(input = [], start = 0)\n{\n\tif (!Array.isArray(input))\n\t{\n\t\treturn start;\n\t}\n\n\tconst add = (a, b) => a + b;\n\n\treturn input\n\t\t// type cast everything as a number\n\t\t.map((value) => Number(value))\n\t\t// drop non numeric looking entries (note: needs transpiling for IE11)\n\t\t.filter((value) => Number.isNaN(value) === false)\n\t\t// add up each successive entry, starting with start\n\t\t.reduce(add, start);\n}\n\n/**\n * Calculate the average of the elements in the input array.\n *\n * If 'input' is not an array, or if it is an empty array, then we return 0.\n *\n * @name module:util.average\n * @function\n * @public\n * @param {array} input - an array of numbers, or of objects that can be cast into a number, e.g. ['1', 2.5, 3e1]\n * @returns {number} the average of the elements in the array\n */\nexport function average(input = [])\n{\n\tif (!Array.isArray(input))\n\t{\n\t\treturn 0;\n\t}\n\n\tif (input.length === 0)\n\t{\n\t\treturn 0;\n\t}\n\n\treturn sum(input, 0) / input.length;\n}\n\n/**\n * Sort the elements of the input array, in increasing alphabetical or numerical order.\n *\n * @name module:util.sort\n * @function\n * @public\n * @param {array} input - an array of numbers or of strings\n * @return {array} the sorted array\n * @throws if 'input' is not an array, or if its elements are not consistent in types, or if they are not all either numbers or\n * \tstrings\n */\nexport function sort(input)\n{\n\tconst response = {\n\t\torigin: \"util.sort\",\n\t\tcontext: \"when sorting the elements of an array\",\n\t};\n\n\ttry\n\t{\n\t\tif (!Array.isArray(input))\n\t\t{\n\t\t\tthrow \"the input argument should be an array\";\n\t\t}\n\n\t\t// check the type and consistency of the array, and sort it accordingly:\n\t\tconst isNumberArray = input.every((element) => typeof element === \"number\");\n\t\tif (isNumberArray)\n\t\t{\n\t\t\treturn input.sort((a, b) => (a - b));\n\t\t}\n\n\t\tconst isStringArray = input.every((element) => typeof element === \"string\");\n\t\tif (isStringArray)\n\t\t{\n\t\t\treturn input.sort();\n\t\t}\n\n\t\tthrow \"the input array should either consist entirely of strings or of numbers\";\n\t}\n\tcatch (error)\n\t{\n\t\tthrow { ...response, error };\n\t}\n}\n\n/**\n * Create a sequence of integers.\n *\n * The sequence is such that the integer at index i is: start + step * i, with i >= 0 and start + step * i < stop\n *\n * <p> Note: this is a JavaScript implement of the Python range function, which explains the unusual management of arguments.</p>\n *\n * @name module:util.range\n * @function\n * @public\n * @param {Number} [start=0] - the value of start\n * @param {Number} stop - the value of stop\n * @param {Number} [step=1] - the value of step\n * @returns {Number[]} the range as an array of numbers\n */\nexport function range(...args)\n{\n\tconst response = {\n\t\torigin: \"util.range\",\n\t\tcontext: \"when building a range of numbers\",\n\t};\n\n\ttry\n\t{\n\t\tlet start, stop, step;\n\n\t\tswitch (args.length)\n\t\t{\n\t\t\tcase 0:\n\t\t\t\tthrow \"at least one argument is required\";\n\n\t\t\t// 1 arg: start = 0, stop = arg, step = 1\n\n\t\t\tcase 1:\n\t\t\t\tstart = 0;\n\t\t\t\tstop = args[0];\n\t\t\t\tstep = 1;\n\t\t\t\tbreak;\n\n\t\t\t// 2 args: start = arg1, stop = arg2\n\n\t\t\tcase 2:\n\t\t\t\tstart = args[0];\n\t\t\t\tstop = args[1];\n\t\t\t\tstep = 1;\n\t\t\t\tbreak;\n\n\t\t\t// 3 args:\n\n\t\t\tcase 3:\n\t\t\t\tstart = args[0];\n\t\t\t\tstop = args[1];\n\t\t\t\tstep = args[2];\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tthrow \"range requires at least one and at most 3 arguments\";\n\t\t}\n\n\t\tif (!Number.isInteger(start))\n\t\t{\n\t\t\tthrow \"start should be an integer\";\n\t\t}\n\t\tif (!Number.isInteger(stop))\n\t\t{\n\t\t\tthrow \"stop should be an integer\";\n\t\t}\n\t\tif (!Number.isInteger(step))\n\t\t{\n\t\t\tthrow \"step should be an integer\";\n\t\t}\n\n\t\t// if start >= stop, the range is empty:\n\t\tif (start >= stop)\n\t\t{\n\t\t\treturn [];\n\t\t}\n\n\t\tlet result = [];\n\t\tfor (let i = start; i < stop; i += step)\n\t\t{\n\t\t\tresult.push(i);\n\t\t}\n\t\treturn result;\n\t}\n\tcatch (error)\n\t{\n\t\tthrow { ...response, error };\n\t}\n}\n\n/**\n * Create a boolean function that compares an input element to the given value.\n *\n * @name module:util._match\n * @function\n * @private\n * @param {Number|string|object|null} value the matching value\n * @return {} a function that compares an input element to the given value\n */\nfunction _match(value)\n{\n\tconst response = {\n\t\torigin: \"util._match\",\n\t\tcontext: \"when creating a function that compares an input element to the given value\",\n\t};\n\n\ttry\n\t{\n\t\t// function:\n\t\tif (typeof value === \"function\")\n\t\t{\n\t\t\tthrow \"the value cannot be a function\";\n\t\t}\n\n\t\t// NaN:\n\t\tif (Number.isNaN(value))\n\t\t{\n\t\t\treturn (element) => Number.isNaN(element);\n\t\t}\n\n\t\t// null:\n\t\tif (value === null)\n\t\t{\n\t\t\treturn (element) => element === null;\n\t\t}\n\n\t\t// object: we compare using JSON.stringify\n\t\tif (typeof value === \"object\")\n\t\t{\n\t\t\tconst jsonValue = JSON.stringify(value);\n\t\t\tif (typeof jsonValue === \"undefined\")\n\t\t\t{\n\t\t\t\tthrow \"value could not be converted to a JSON string\";\n\t\t\t}\n\n\t\t\treturn (element) =>\n\t\t\t{\n\t\t\t\tconst jsonElement = JSON.stringify(element);\n\t\t\t\treturn (jsonElement === jsonValue);\n\t\t\t};\n\t\t}\n\n\t\t// everything else:\n\t\treturn (element) => element === value;\n\t}\n\tcatch (error)\n\t{\n\t\tthrow { ...response, error };\n\t}\n}\n\n/**\n * Count the number of elements in the input array that match the given value.\n *\n * <p> Note: count is able to handle NaN, null, as well as any value convertible to a JSON string.</p>\n *\n * @name module:util.count\n * @function\n * @public\n * @param {array} input the input array\n * @param {Number|string|object|null} value the matching value\n * @returns the number of matching elements\n */\nexport function count(input, value)\n{\n\tconst response = {\n\t\torigin: \"util.count\",\n\t\tcontext: \"when counting how many elements in the input array match the given value\",\n\t};\n\n\ttry\n\t{\n\t\tif (!Array.isArray(input))\n\t\t{\n\t\t\tthrow \"the input argument should be an array\";\n\t\t}\n\n\t\tconst match = _match(value);\n\n\t\tlet nbMatches = 0;\n\t\tinput.forEach((element) =>\n\t\t{\n\t\t\tif (match(element))\n\t\t\t{\n\t\t\t\t++nbMatches;\n\t\t\t}\n\t\t});\n\t\treturn nbMatches;\n\t}\n\tcatch (error)\n\t{\n\t\tthrow { ...response, error };\n\t}\n}\n\n/**\n * Get the index in the input array of the first element that matches the given value.\n *\n * <p> Note: index is able to handle NaN, null, as well as any value convertible to a JSON string.</p>\n *\n * @name module:util.index\n * @function\n * @public\n * @param {array} input the input array\n * @param {Number|string|object|null} value the matching value\n * @returns the index of the first element that matches the value\n * @throws if the input array does not contain any matching element\n */\nexport function index(input, value)\n{\n\tconst response = {\n\t\torigin: \"util.index\",\n\t\tcontext: \"when getting the index in the input array of the first element that matches the given value\",\n\t};\n\n\ttry\n\t{\n\t\tif (!Array.isArray(input))\n\t\t{\n\t\t\tthrow \"the input argument should be an array\";\n\t\t}\n\n\t\tconst match = _match(value);\n\t\tconst index = input.findIndex(match);\n\n\t\tif (index === -1)\n\t\t{\n\t\t\tthrow \"no element in the input array matches the value\";\n\t\t}\n\n\t\treturn index;\n\t}\n\tcatch (error)\n\t{\n\t\tthrow { ...response, error };\n\t}\n}\n\n/**\n * Return the file extension corresponding to an audio mime type.\n * If the provided mimeType is not a string (e.g. null, undefined, an array)\n * or unknown, then '.dat' is returned, instead of throwing an exception.\n *\n * @name module:util.extensionFromMimeType\n * @function\n * @public\n * @param {string} mimeType the MIME type, e.g. 'audio/webm;codecs=opus'\n * @return {string} the corresponding file extension, e.g. '.webm'\n */\nexport function extensionFromMimeType(mimeType)\n{\n\tif (typeof mimeType !== \"string\")\n\t{\n\t\treturn \".dat\";\n\t}\n\n\tif (mimeType.indexOf(\"audio/webm\") === 0)\n\t{\n\t\treturn \".webm\";\n\t}\n\n\tif (mimeType.indexOf(\"audio/ogg\") === 0)\n\t{\n\t\treturn \".ogg\";\n\t}\n\n\tif (mimeType.indexOf(\"audio/wav\") === 0)\n\t{\n\t\treturn \".wav\";\n\t}\n\n\tif (mimeType.indexOf(\"video/webm\") === 0)\n\t{\n\t\treturn \".webm\";\n\t}\n\n\treturn '.dat';\n}\n\n/**\n * Get an estimate of the download speed, by repeatedly downloading an image file from a distant\n * server.\n *\n * @name module:util.getDownloadSpeed\n * @function\n * @public\n * @param {PsychoJS} psychoJS the instance of PsychoJS\n * @param {number} [nbDownloads = 1] the number of image downloads over which to average\n * \tthe download speed\n * @return {number} the download speed, in megabits per second\n */\nexport async function getDownloadSpeed(psychoJS, nbDownloads = 1)\n{\n\t// url of the image to download and size of the image in bits:\n\t// TODO use a variety of files, with different sizes\n\tconst imageUrl = \"https://upload.wikimedia.org/wikipedia/commons/a/a6/Brandenburger_Tor_abends.jpg\";\n\tconst imageSize_b = 2707459 * 8;\n\n\treturn new Promise( (resolve, reject) =>\n\t{\n\t\tlet downloadTimeAccumulator = 0;\n\t\tlet downloadCounter = 0;\n\n\t\tconst download = new Image();\n\t\tdownload.onload = () =>\n\t\t{\n\t\t\tconst toc = performance.now();\n\t\t\tdownloadTimeAccumulator += (toc-tic);\n\t\t\t++ downloadCounter;\n\n\t\t\tif (downloadCounter === nbDownloads)\n\t\t\t{\n\t\t\t\tconst speed_bps = (imageSize_b * nbDownloads) / (downloadTimeAccumulator / 1000);\n\t\t\t\tresolve(speed_bps / 1024 / 1024);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttic = performance.now();\n\t\t\t\tdownload.src = `${imageUrl}?salt=${tic}`;\n\t\t\t}\n\t\t}\n\n\t\tdownload.onerror = (event) =>\n\t\t{\n\t\t\tconst errorMsg = `unable to estimate the download speed: ${JSON.stringify(event)}`;\n\t\t\tpsychoJS.logger.error(errorMsg);\n\t\t\treject(errorMsg);\n\t\t}\n\n\t\tlet tic = performance.now();\n\t\tdownload.src = `${imageUrl}?salt=${tic}`;\n\t});\n}\n\n/**\n * Return a flat array with every element of `a` repeated `n` times \n * @param {array} a \n * @param {int} n \n */\nexport const repeatEveryElement = (a, n) => {\n return a.map(x => [...[...new Array(n).keys()].map(_ => x)]).flat();\n};\n\n// https://stackoverflow.com/a/56490104\nexport const getTimezoneName = ()=> {\n\tconst today = new Date();\n\tconst short = today.toLocaleDateString(undefined);\n\tconst full = today.toLocaleDateString(undefined, { timeZoneName: \"short\" });\n \n\t// Trying to remove date from the string in a locale-agnostic way\n\tconst shortIndex = full.indexOf(short);\n\tif (shortIndex >= 0) {\n\t const trimmed =\n\t\tfull.substring(0, shortIndex) + full.substring(shortIndex + short.length);\n \n\t // by this time `trimmed` should be the timezone's name with some punctuation -\n\t // trim it from both sides\n\t return trimmed.replace(/^[\\s,.\\-:;]+|[\\s,.\\-:;]+$/g, \"\");\n\t} else {\n\t // in some magic case when short representation of date is not present in the long one, just return the long one as a fallback, since it should contain the timezone's name\n\t return full;\n\t}\n }","/**\n * Event Emitter.\n *\n * @author Alain Pitiot\n * @version 2021.2.0\n * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd. (https://opensciencetools.org)\n * @license Distributed under the terms of the MIT License\n */\n\nimport * as util from \"./Util.js\";\n\n/**\n * <p>EventEmitter implements the classic observer/observable pattern.</p>\n *\n * <p>Note: this is heavily inspired by http://www.datchley.name/es6-eventemitter/</p>\n *\n * @name module:util.EventEmitter\n * @class\n *\n * @example\n * let observable = new EventEmitter();\n * let uuid1 = observable.on('change', data => { console.log(data); });\n * observable.emit(\"change\", { a: 1 });\n * observable.off(\"change\", uuid1);\n * observable.emit(\"change\", { a: 1 });\n */\nexport class EventEmitter\n{\n\tconstructor()\n\t{\n\t\tthis._listeners = new Map();\n\t\tthis._onceUuids = new Map();\n\t}\n\n\t/**\n\t * Listener called when this instance emits an event for which it is registered.\n\t *\n\t * @callback module:util.EventEmitter~Listener\n\t * @param {object} data - the data passed to the listener\n\t */\n\n\t/**\n\t * Register a new listener for events with the given name emitted by this instance.\n\t *\n\t * @name module:util.EventEmitter#on\n\t * @function\n\t * @public\n\t * @param {String} name - the name of the event\n\t * @param {module:util.EventEmitter~Listener} listener - a listener called upon emission of the event\n\t * @return string - the unique identifier associated with that (event, listener) pair (useful to remove the listener)\n\t */\n\ton(name, listener)\n\t{\n\t\t// check that the listener is a function:\n\t\tif (typeof listener !== \"function\")\n\t\t{\n\t\t\tthrow new TypeError(\"listener must be a function\");\n\t\t}\n\n\t\t// generate a new uuid:\n\t\tlet uuid = util.makeUuid();\n\n\t\t// add the listener to the event map:\n\t\tif (!this._listeners.has(name))\n\t\t{\n\t\t\tthis._listeners.set(name, []);\n\t\t}\n\t\tthis._listeners.get(name).push({ uuid, listener });\n\n\t\treturn uuid;\n\t}\n\n\t/**\n\t * Register a new listener for the given event name, and remove it as soon as the event has been emitted.\n\t *\n\t * @name module:util.EventEmitter#once\n\t * @function\n\t * @public\n\t * @param {String} name - the name of the event\n\t * @param {module:util.EventEmitter~Listener} listener - a listener called upon emission of the event\n\t * @return string - the unique identifier associated with that (event, listener) pair (useful to remove the listener)\n\t */\n\tonce(name, listener)\n\t{\n\t\tlet uuid = this.on(name, listener);\n\n\t\tif (!this._onceUuids.has(name))\n\t\t{\n\t\t\tthis._onceUuids.set(name, []);\n\t\t}\n\t\tthis._onceUuids.get(name).push(uuid);\n\n\t\treturn uuid;\n\t}\n\n\t/**\n\t * Remove the listener with the given uuid associated to the given event name.\n\t *\n\t * @name module:util.EventEmitter#off\n\t * @function\n\t * @public\n\t * @param {String} name - the name of the event\n\t * @param {module:util.EventEmitter~Listener} listener - a listener called upon emission of the event\n\t */\n\toff(name, uuid)\n\t{\n\t\tlet relevantUuidListeners = this._listeners.get(name);\n\n\t\tif (relevantUuidListeners && relevantUuidListeners.length)\n\t\t{\n\t\t\tthis._listeners.set(name, relevantUuidListeners.filter((uuidlistener) => (uuidlistener.uuid != uuid)));\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Emit an event with a given name and associated data.\n\t *\n\t * @name module:util.EventEmitter#emit\n\t * @function\n\t * @public\n\t * @param {String} name - the name of the event\n\t * @param {object} data - the data of the event\n\t * @return {boolean} true if at least one listener has been registered for that event, and false otherwise\n\t */\n\temit(name, data)\n\t{\n\t\tlet relevantUuidListeners = this._listeners.get(name);\n\t\tif (relevantUuidListeners && relevantUuidListeners.length)\n\t\t{\n\t\t\tlet onceUuids = this._onceUuids.get(name);\n\t\t\tlet self = this;\n\t\t\trelevantUuidListeners.forEach(({ uuid, listener }) =>\n\t\t\t{\n\t\t\t\tlistener(data);\n\n\t\t\t\tif (typeof onceUuids !== \"undefined\" && onceUuids.includes(uuid))\n\t\t\t\t{\n\t\t\t\t\tself.off(name, uuid);\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n}\n","/** @module util */\n/**\n * Core Object.\n *\n * @author Alain Pitiot\n * @version 2021.2.0\n * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd. (https://opensciencetools.org)\n * @license Distributed under the terms of the MIT License\n */\n\nimport { EventEmitter } from \"./EventEmitter.js\";\nimport * as util from \"./Util.js\";\n\n/**\n * <p>PsychoObject is the base class for all PsychoJS objects.\n * It is responsible for handling attributes.</p>\n *\n * @class\n * @extends EventEmitter\n * @param {module:core.PsychoJS} psychoJS - the PsychoJS instance\n * @param {string} name - the name of the object (mostly useful for debugging)\n */\nexport class PsychObject extends EventEmitter\n{\n\tconstructor(psychoJS, name)\n\t{\n\t\tsuper();\n\n\t\tthis._psychoJS = psychoJS;\n\t\tthis._userAttributes = new Set();\n\n\t\t// name:\n\t\tif (typeof name === \"undefined\")\n\t\t{\n\t\t\tname = this.constructor.name;\n\t\t}\n\t\tthis._addAttribute(\"name\", name);\n\t}\n\n\t/**\n\t * Get the PsychoJS instance.\n\t *\n\t * @public\n\t * @return {PsychoJS} the PsychoJS instance\n\t */\n\tget psychoJS()\n\t{\n\t\treturn this._psychoJS;\n\t}\n\n\t/**\n\t * Setter for the PsychoJS attribute.\n\t *\n\t * @public\n\t * @param {module:core.PsychoJS} psychoJS - the PsychoJS instance\n\t */\n\tset psychoJS(psychoJS)\n\t{\n\t\tthis._psychoJS = psychoJS;\n\t}\n\n\t/**\n\t * String representation of the PsychObject.\n\t *\n\t * <p>Note: attribute values are limited to 50 characters.</p>\n\t *\n\t * @public\n\t * @return {string} the representation\n\t */\n\ttoString()\n\t{\n\t\tlet representation = this.constructor.name + \"( \";\n\t\tlet addComma = false;\n\t\tfor (const attribute of this._userAttributes)\n\t\t{\n\t\t\tif (addComma)\n\t\t\t{\n\t\t\t\trepresentation += \", \";\n\t\t\t}\n\t\t\taddComma = true;\n\n\t\t\tlet value = util.toString(this[\"_\" + attribute]);\n\t\t\tconst l = value.length;\n\t\t\tif (l > 50)\n\t\t\t{\n\t\t\t\tif (value[l - 1] === \")\")\n\t\t\t\t{\n\t\t\t\t\tvalue = value.substring(0, 50) + \"~)\";\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tvalue = value.substring(0, 50) + \"~\";\n\t\t\t\t}\n\t\t\t}\n\n\t\t\trepresentation += attribute + \"=\" + value;\n\t\t}\n\t\trepresentation += \" )\";\n\n\t\treturn representation;\n\t}\n\n\t/**\n\t * Set the value of an attribute.\n\t *\n\t * @protected\n\t * @param {string} attributeName - the name of the attribute\n\t * @param {object} attributeValue - the value of the attribute\n\t * @param {boolean} [log= false] - whether of not to log\n\t * @param {string} [operation] - the binary operation such that the new value of the attribute is the result of the application of the operation to the current value of the attribute and attributeValue\n\t * @param {boolean} [stealth= false] - whether or not to call the potential attribute setters when setting the value of this attribute\n\t * @return {boolean} whether or not the value of that attribute has changed (false if the attribute\n\t * was not previously set)\n\t */\n\t_setAttribute(attributeName, attributeValue, log = false, operation = undefined, stealth = false)\n\t{\n\t\tconst response = {\n\t\t\torigin: \"PsychObject.setAttribute\",\n\t\t\tcontext: \"when setting the attribute of an object\",\n\t\t};\n\n\t\tif (typeof attributeName == \"undefined\")\n\t\t{\n\t\t\tthrow Object.assign(response, {\n\t\t\t\terror: \"the attribute name cannot be\"\n\t\t\t\t\t+ \" undefined\",\n\t\t\t});\n\t\t}\n\t\tif (typeof attributeValue == \"undefined\")\n\t\t{\n\t\t\t// console.warn(`${attributeName} @ ${this._name.replace(/[-]*[0-9]/g, \"\").slice(0, 10)}... [undefined]`);\n\t\t\t// this._psychoJS.logger.warn(\"setting the value of attribute: \" + attributeName + \" in PsychObject: \" + this._name + \" as: undefined\");\n\t\t}\n\n\t\t// (*) apply operation to old and new values:\n\t\tif (typeof operation !== \"undefined\" && this.hasOwnProperty(\"_\" + attributeName))\n\t\t{\n\t\t\tlet oldValue = this[\"_\" + attributeName];\n\n\t\t\t// operations can only be applied to numbers and array of numbers (which can be empty):\n\t\t\tif (typeof attributeValue == \"number\" || (Array.isArray(attributeValue) && (attributeValue.length === 0 || typeof attributeValue[0] == \"number\")))\n\t\t\t{\n\t\t\t\t// value is an array:\n\t\t\t\tif (Array.isArray(attributeValue))\n\t\t\t\t{\n\t\t\t\t\t// old value is also an array\n\t\t\t\t\tif (Array.isArray(oldValue))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (attributeValue.length !== oldValue.length)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tthrow Object.assign(response, {\n\t\t\t\t\t\t\t\terror: \"old and new\"\n\t\t\t\t\t\t\t\t\t+ \" value should have\"\n\t\t\t\t\t\t\t\t\t+ \" the same size when they are both arrays\",\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tswitch (operation)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcase \"\":\n\t\t\t\t\t\t\t\t// no change to value;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase \"+\":\n\t\t\t\t\t\t\t\tattributeValue = attributeValue.map((v, i) => oldValue[i] + v);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase \"*\":\n\t\t\t\t\t\t\t\tattributeValue = attributeValue.map((v, i) => oldValue[i] * v);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase \"-\":\n\t\t\t\t\t\t\t\tattributeValue = attributeValue.map((v, i) => oldValue[i] - v);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase \"/\":\n\t\t\t\t\t\t\t\tattributeValue = attributeValue.map((v, i) => oldValue[i] / v);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase \"**\":\n\t\t\t\t\t\t\t\tattributeValue = attributeValue.map((v, i) => oldValue[i] ** v);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase \"%\":\n\t\t\t\t\t\t\t\tattributeValue = attributeValue.map((v, i) => oldValue[i] % v);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\tthrow Object.assign(response, {\n\t\t\t\t\t\t\t\t\terror: \"unsupported\"\n\t\t\t\t\t\t\t\t\t\t+ \" operation: \" + operation + \" when setting: \" + attributeName + \" in: \" + this.name,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// old value is a scalar\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tswitch (operation)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcase \"\":\n\t\t\t\t\t\t\t\t// no change to value;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase \"+\":\n\t\t\t\t\t\t\t\tattributeValue = attributeValue.map((v) => oldValue + v);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase \"*\":\n\t\t\t\t\t\t\t\tattributeValue = attributeValue.map((v) => oldValue * v);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase \"-\":\n\t\t\t\t\t\t\t\tattributeValue = attributeValue.map((v) => oldValue - v);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase \"/\":\n\t\t\t\t\t\t\t\tattributeValue = attributeValue.map((v) => oldValue / v);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase \"**\":\n\t\t\t\t\t\t\t\tattributeValue = attributeValue.map((v) => oldValue ** v);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase \"%\":\n\t\t\t\t\t\t\t\tattributeValue = attributeValue.map((v) => oldValue % v);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\tthrow Object.assign(response, {\n\t\t\t\t\t\t\t\t\terror: \"unsupported\"\n\t\t\t\t\t\t\t\t\t\t+ \" value: \" + JSON.stringify(attributeValue) + \" for\"\n\t\t\t\t\t\t\t\t\t\t+ \" operation: \" + operation + \" when setting: \" + attributeName + \" in: \" + this.name,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// value is a scalar\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// old value is an array\n\t\t\t\t\tif (Array.isArray(oldValue))\n\t\t\t\t\t{\n\t\t\t\t\t\tswitch (operation)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcase \"\":\n\t\t\t\t\t\t\t\tattributeValue = oldValue.map((v) => attributeValue);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase \"+\":\n\t\t\t\t\t\t\t\tattributeValue = oldValue.map((v) => v + attributeValue);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase \"*\":\n\t\t\t\t\t\t\t\tattributeValue = oldValue.map((v) => v * attributeValue);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase \"-\":\n\t\t\t\t\t\t\t\tattributeValue = oldValue.map((v) => v - attributeValue);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase \"/\":\n\t\t\t\t\t\t\t\tattributeValue = oldValue.map((v) => v / attributeValue);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase \"**\":\n\t\t\t\t\t\t\t\tattributeValue = oldValue.map((v) => v ** attributeValue);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase \"%\":\n\t\t\t\t\t\t\t\tattributeValue = oldValue.map((v) => v % attributeValue);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\tthrow Object.assign(response, {\n\t\t\t\t\t\t\t\t\terror: \"unsupported\"\n\t\t\t\t\t\t\t\t\t\t+ \" operation: \" + operation + \" when setting: \" + attributeName + \" in: \" + this.name,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// old value is a scalar\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tswitch (operation)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcase \"\":\n\t\t\t\t\t\t\t\t// no change to value;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase \"+\":\n\t\t\t\t\t\t\t\tattributeValue = oldValue + attributeValue;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase \"*\":\n\t\t\t\t\t\t\t\tattributeValue = oldValue * attributeValue;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase \"-\":\n\t\t\t\t\t\t\t\tattributeValue = oldValue - attributeValue;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase \"/\":\n\t\t\t\t\t\t\t\tattributeValue = oldValue / attributeValue;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase \"**\":\n\t\t\t\t\t\t\t\tattributeValue = oldValue ** attributeValue;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase \"%\":\n\t\t\t\t\t\t\t\tattributeValue = oldValue % attributeValue;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\tthrow Object.assign(response, {\n\t\t\t\t\t\t\t\t\terror: \"unsupported\"\n\t\t\t\t\t\t\t\t\t\t+ \" value: \" + JSON.stringify(attributeValue) + \" for operation: \" + operation + \" when setting: \" + attributeName + \" in: \" + this.name,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tthrow Object.assign(response, {\n\t\t\t\t\terror: \"operation: \" + operation + \" is invalid for old value: \" + JSON.stringify(oldValue) + \" and new value: \" + JSON.stringify(attributeValue),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// (*) log if appropriate:\n\t\tif (!stealth && (log || this._autoLog) && (typeof this.win !== \"undefined\"))\n\t\t{\n\t\t\tconst msg = this.name + \": \" + attributeName + \" = \" + util.toString(attributeValue);\n\t\t\tthis.win.logOnFlip({\n\t\t\t\tmsg,\n\t\t\t\t// obj: this\n\t\t\t});\n\t\t}\n\n\t\t// (*) set the value of the attribute and return whether it has changed:\n\t\tconst previousAttributeValue = this[\"_\" + attributeName];\n\t\tthis[\"_\" + attributeName] = attributeValue;\n\n\t\t// Things seem OK without this check except for 'vertices'\n\t\tif (typeof previousAttributeValue === \"undefined\")\n\t\t{\n\t\t\t// Not that any of the following lines should throw, but evaluating\n\t\t\t// `this._vertices.map` on `ShapeStim._getVertices_px()` seems to\n\t\t\treturn false;\n\t\t}\n\n\t\t// Need check for equality differently for each type of attribute somehow,\n\t\t// Lodash has an example of what an all encompassing solution looks like below,\n\t\t// https://github.com/lodash/lodash/blob/master/.internal/baseIsEqualDeep.js\n\t\tconst prev = util.toString(previousAttributeValue);\n\t\tconst next = util.toString(attributeValue);\n\n\t\t// The following check comes in handy when figuring out a `hasChanged` predicate\n\t\t// in a `ShapeStim.setPos()` call for example. Objects that belong to us, such as\n\t\t// colors, feature a `toString()` method of their own. The types of input that\n\t\t// `Util.toString()` might try, but fail to stringify in a meaningful way are assigned\n\t\t// an 'Object (circular)' string representation. For being opaque as to their raw\n\t\t// value, those types of input are liable to produce PIXI updates.\n\t\treturn prev === \"Object (circular)\" || next === \"Object (circular)\" || prev !== next;\n\t}\n\n\t/**\n\t * Add an attribute to this instance (e.g. define setters and getters) and affect a value to it.\n\t *\n\t * @protected\n\t * @param {string} name - the name of the attribute\n\t * @param {object} value - the value of the attribute\n\t * @param {object} [defaultValue] - the default value for the attribute\n\t * @param {function} [onChange] - function called upon changes to the attribute value\n\t */\n\t_addAttribute(name, value, defaultValue = undefined, onChange = () =>\n\t{})\n\t{\n\t\tconst getPropertyName = \"get\" + name[0].toUpperCase() + name.substr(1);\n\t\tif (typeof this[getPropertyName] === \"undefined\")\n\t\t{\n\t\t\tthis[getPropertyName] = () => this[\"_\" + name];\n\t\t}\n\n\t\tconst setPropertyName = \"set\" + name[0].toUpperCase() + name.substr(1);\n\t\tif (typeof this[setPropertyName] === \"undefined\")\n\t\t{\n\t\t\tthis[setPropertyName] = (value, log = false) =>\n\t\t\t{\n\t\t\t\tif (typeof value === \"undefined\" || value === null)\n\t\t\t\t{\n\t\t\t\t\tvalue = defaultValue;\n\t\t\t\t}\n\t\t\t\tconst hasChanged = this._setAttribute(name, value, log);\n\t\t\t\tif (hasChanged)\n\t\t\t\t{\n\t\t\t\t\tonChange();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// deal with default value:\n\t\t\tif (typeof value === \"undefined\" || value === null)\n\t\t\t{\n\t\t\t\tvalue = defaultValue;\n\t\t\t}\n\t\t}\n\n\t\tObject.defineProperty(this, name, {\n\t\t\tconfigurable: true,\n\t\t\tget()\n\t\t\t{\n\t\t\t\treturn this[getPropertyName](); /* return this['_' + name];*/\n\t\t\t},\n\t\t\tset(value)\n\t\t\t{\n\t\t\t\tthis[setPropertyName](value);\n\t\t\t},\n\t\t});\n\n\t\t// note: we use this[name] instead of this['_' + name] since a this.set<Name> method may available\n\t\t// in the object, in which case we need to call it\n\t\tthis[name] = value;\n\t\t// this['_' + name] = value;\n\n\t\tthis._userAttributes.add(name);\n\t}\n}\n","/**\n * Experiment Handler\n *\n * @author Alain Pitiot\n * @version 2021.2.0\n * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd. (https://opensciencetools.org)\n * @license Distributed under the terms of the MIT License\n */\n\nimport * as XLSX from \"xlsx\";\nimport { MonotonicClock } from \"../util/Clock.js\";\nimport { PsychObject } from \"../util/PsychObject.js\";\nimport * as util from \"../util/Util.js\";\nimport { calibrationTime } from \"../../../components/global.js\";\nimport { excelSafeRows } from \"./excelSafe.js\";\n\n/**\n * <p>An ExperimentHandler keeps track of multiple loops and handlers. It is particularly useful\n * for generating a single data file from an experiment with many different loops (e.g. interleaved\n * staircases or loops within loops.</p>\n *\n * @name module:data.ExperimentHandler\n * @class\n * @extends PsychObject\n * @param {Object} options\n * @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance\n * @param {string} options.name - name of the experiment\n * @param {Object} options.extraInfo - additional information, such as session name, participant name, etc.\n */\nexport class ExperimentHandler extends PsychObject\n{\n\t/**\n\t * Getter for experimentEnded.\n\t *\n\t * @name module:data.ExperimentHandler#experimentEnded\n\t * @function\n\t * @public\n\t */\n\tget experimentEnded()\n\t{\n\t\treturn this._experimentEnded;\n\t}\n\n\t/**\n\t * Setter for experimentEnded.\n\t *\n\t * @name module:data.ExperimentHandler#experimentEnded\n\t * @function\n\t * @public\n\t */\n\tset experimentEnded(ended)\n\t{\n\t\tthis._experimentEnded = ended;\n\t}\n\n\t/**\n\t * Legacy experiment getters.\n\t */\n\tget _thisEntry()\n\t{\n\t\treturn this._currentTrialData;\n\t}\n\n\tget _entries()\n\t{\n\t\treturn this._trialsData;\n\t}\n\n\tconstructor({\n\t\tpsychoJS,\n\t\tname,\n\t\textraInfo,\n\t\tdataFileName\n\t} = {})\n\t{\n\t\tsuper(psychoJS, name);\n\n\t\tthis._addAttribute(\"extraInfo\", extraInfo);\n\n\t\t// process the extra info:\n\t\t// this._experimentName = (typeof extraInfo.expName === \"string\" && extraInfo.expName.length > 0)\n\t\t// \t? extraInfo.expName\n\t\t// \t: this.psychoJS.config.experiment.name;\n\t\tthis._experimentName = this.psychoJS.config.experiment.name;\n\n\t\tthis._participant = (typeof extraInfo.participant === \"string\" && extraInfo.participant.length > 0)\n\t\t\t? extraInfo.participant\n\t\t\t: \"PARTICIPANT\";\n\t\tconst prolificParticipant = extraInfo.ProlificParticipantID\n\t\t\t? extraInfo.ProlificParticipantID\n\t\t\t: undefined;\n\n\t\t\tthis._session = (typeof extraInfo.session === \"string\" && extraInfo.session.length > 0)\n\t\t\t? extraInfo.session\n\t\t\t: \"SESSION\";\n\n\t\t\tthis._datetime = (typeof extraInfo.date !== \"undefined\")\n\t\t\t? extraInfo.date\n\t\t\t: MonotonicClock.getDateStr();\n\n\t\t// ! controls final data file name\n\t\tthis._addAttribute(\n\t\t\t\"dataFileName\",\n\t\t\tdataFileName,\n\t\t\t`${this._participant}_${\n\t\t\t\tprolificParticipant ? `${prolificParticipant}_` : \"\"\n\t\t\t}${this._experimentName}_${this._datetime}`\n\t\t);\n\n\t\t// loop handlers:\n\t\tthis._loops = [];\n\t\tthis._unfinishedLoops = [];\n\n\t\t// data dictionaries (one per trial) and current data dictionary:\n\t\tthis._trialsKeys = [];\n\t\tthis._trialsData = [];\n\t\tthis._currentTrialData = {};\n\t\tthis.experimentClock = new MonotonicClock();\n\n\t\tthis._experimentEnded = false;\n\t}\n\n\t/**\n\t * Whether or not the current entry (i.e. trial data) is empty.\n\t * <p>Note: this is mostly useful at the end of an experiment, in order to ensure that the last entry is saved.</p>\n\t *\n\t * @name module:data.ExperimentHandler#isEntryEmpty\n\t * @function\n\t * @public\n\t * @returns {boolean} whether or not the current entry is empty\n\t * @todo This really should be renamed: IsCurrentEntryNotEmpty\n\t */\n\tisEntryEmpty()\n\t{\n\t\treturn (Object.keys(this._currentTrialData).length > 0);\n\t}\n\n\t/**\n\t * Add a loop.\n\t *\n\t * <p> The loop might be a {@link TrialHandler}, for instance.</p>\n\t * <p> Data from this loop will be included in the resulting data files.</p>\n\t *\n\t * @name module:data.ExperimentHandler#addLoop\n\t * @function\n\t * @public\n\t * @param {Object} loop - the loop, e.g. an instance of TrialHandler or StairHandler\n\t */\n\taddLoop(loop)\n\t{\n\t\tthis._loops.push(loop);\n\t\tthis._unfinishedLoops.push(loop);\n\t\tloop.experimentHandler = this;\n\t}\n\n\t/**\n\t * Remove the given loop from the list of unfinished loops, e.g. when it has completed.\n\t *\n\t * @name module:data.ExperimentHandler#removeLoop\n\t * @function\n\t * @public\n\t * @param {Object} loop - the loop, e.g. an instance of TrialHandler or StairHandler\n\t */\n\tremoveLoop(loop)\n\t{\n\t\tconst index = this._unfinishedLoops.indexOf(loop);\n\t\tif (index !== -1)\n\t\t{\n\t\t\tthis._unfinishedLoops.splice(index, 1);\n\t\t}\n\t}\n\n\t/**\n\t * Add the key/value pair.\n\t *\n\t * <p> Multiple key/value pairs can be added to any given entry of the data file. There are\n\t * considered part of the same entry until a call to {@link nextEntry} is made. </p>\n\t *\n\t * @name module:data.ExperimentHandler#addData\n\t * @function\n\t * @public\n\t * @param {Object} key - the key\n\t * @param {Object} value - the value\n\t */\n\taddData(key, value)\n\t{\n\t\tif (this._trialsKeys.indexOf(key) === -1)\n\t\t{\n\t\t\tthis._trialsKeys.push(key);\n\t\t}\n\n\t\t// turn arrays into their json equivalent:\n\t\tif (Array.isArray(value))\n\t\t{\n\t\t\tvalue = JSON.stringify(value);\n\t\t}\n\n\t\tthis._currentTrialData[key] = value;\n\t}\n\n\t/**\n\t * Inform this ExperimentHandler that the current trial has ended. Further calls to {@link addData}\n\t * will be associated with the next trial.\n\t *\n\t * @name module:data.ExperimentHandler#nextEntry\n\t * @function\n\t * @public\n\t * @param {Object | Object[] | undefined} snapshots - array of loop snapshots\n\t */\n\tnextEntry(snapshots)\n\t{\n\t\tif (typeof snapshots !== \"undefined\")\n\t\t{\n\t\t\t// turn single snapshot into a one-element array:\n\t\t\tif (!Array.isArray(snapshots))\n\t\t\t{\n\t\t\t\tsnapshots = [snapshots];\n\t\t\t}\n\n\t\t\tfor (const snapshot of snapshots)\n\t\t\t{\n\t\t\t\tconst attributes = ExperimentHandler._getLoopAttributes(snapshot);\n\t\t\t\tfor (let a in attributes)\n\t\t\t\t{\n\t\t\t\t\tif (attributes.hasOwnProperty(a))\n\t\t\t\t\t{\n\t\t\t\t\t\tthis._currentTrialData[a] = attributes[a];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// this is to support legacy generated JavaScript code and does not properly handle\n\t\t// loops within loops:\n\t\telse\n\t\t{\n\t\t\tfor (const loop of this._unfinishedLoops)\n\t\t\t{\n\t\t\t\tconst attributes = ExperimentHandler._getLoopAttributes(loop);\n\t\t\t\tfor (const a in attributes)\n\t\t\t\t{\n\t\t\t\t\tif (attributes.hasOwnProperty(a))\n\t\t\t\t\t{\n\t\t\t\t\t\tthis._currentTrialData[a] = attributes[a];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// add the extraInfo dict to the data:\n\t\tfor (let a in this.extraInfo)\n\t\t{\n\t\t\tif (this.extraInfo.hasOwnProperty(a))\n\t\t\t{\n\t\t\t\t// Record the time NOW, vs at the start of the experiment\n\t\t\t\tconst val = a === \"date\" ? this.getDateTimeString() : this.extraInfo[a];\n\t\t\t\tthis._currentTrialData[a] = val;\n\t\t\t}\n\t\t}\n\n\t\tthis._trialsData.push(this._currentTrialData);\n\n\t\tthis._currentTrialData = {};\n\t\tthis._currentTrialData[\"secs\"] = this.experimentClock.getTime();\n\t}\n\n \tgetDateTimeString() {\n\t\treturn MonotonicClock.getDateStr() + \" \" + MonotonicClock.getTimeZone();\n\t}\n\t/**\n\t * Save the results of the experiment.\n\t *\n\t * <ul>\n\t * <li>For an experiment running locally, the results are offered for immediate download.</li>\n\t * <li>For an experiment running on the server, the results are uploaded to the server.</li>\n\t * </ul>\n\t * <p>\n\t *\n\t * @name module:data.ExperimentHandler#save\n\t * @function\n\t * @public\n\t * @param {Object} options\n\t * @param {Array.<Object>} [options.attributes] - the attributes to be saved\n\t * @param {boolean} [options.sync=false] - whether or not to communicate with the server in a synchronous manner\n\t * @param {string} [options.tag=''] - an optional tag to add to the filename to which the data is saved (for CSV and XLSX saving options)\n\t * @param {boolean} [options.clear=false] - whether or not to clear all experiment results immediately after they are saved (this is useful when saving data in separate chunks, throughout an experiment)\n\t */\n\tasync save({\n\t\tattributes = [],\n\t\tsync = false,\n\t\ttag = \"\",\n\t\tclear = false\n\t} = {})\n\t{\n\t\tthis._psychoJS.logger.info(\"[PsychoJS] Save experiment results.\");\n\n\t\tthis.extraInfo[\"dataSaved\"] = true;\n\n\t\t// get attributes:\n\t\tif (attributes.length === 0)\n\t\t{\n\t\t\tattributes = this._trialsKeys.slice();\n\t\t\tfor (let l = 0; l < this._loops.length; l++)\n\t\t\t{\n\t\t\t\tconst loop = this._loops[l];\n\n\t\t\t\tconst loopAttributes = ExperimentHandler._getLoopAttributes(loop);\n\t\t\t\tfor (let a in loopAttributes)\n\t\t\t\t{\n\t\t\t\t\tif (loopAttributes.hasOwnProperty(a))\n\t\t\t\t\t{\n\t\t\t\t\t\tattributes.push(a);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (let a in this.extraInfo)\n\t\t\t{\n\t\t\t\tif (this.extraInfo.hasOwnProperty(a))\n\t\t\t\t{\n\t\t\t\t\tattributes.push(a);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\n\t\tlet data;\n\t\t({data, attributes} = this._orderOutput(this._trialsData, attributes));\n\n\t\tif (clear)\n\t\t{\n\t\t\tthis._trialsData = [];\n\t\t}\n\n\t\t// Excel-safe cells are a property of the emitted artifact, not of the\n\t\t// data: format once, here, so every consumer below (CSV file, Pavlovia\n\t\t// database upload, results.json download) gets spaced commas while the\n\t\t// in-memory trial data stays raw. excelSafeRows never throws.\n\t\tdata = excelSafeRows(data);\n\n\t\t// save to a .csv file:\n\t\tif (this._psychoJS.config.experiment.saveFormat === ExperimentHandler.SaveFormat.CSV)\n\t\t{\n\t\t\t// note: we use the XLSX library as it automatically deals with header, takes care of quotes,\n\t\t\t// newlines, etc.\n\t\t\t// TODO only save the given attributes\n\t\t\tconst worksheet = XLSX.utils.json_to_sheet(data);\n\t\t\t// prepend BOM\n\t\t\tconst csv = \"\\ufeff\" + XLSX.utils.sheet_to_csv(worksheet);\n\n\t\t\t// upload data to the pavlovia server or offer them for download:\n\t\t\t// const filenameWithoutPath = this._dataFileName.split(/[\\\\/]/).pop();\n\t\t\tconst info = this._psychoJS.experiment.getExtraInfo();\n\t\t\tconst participant = info.participant || \"PARTICIPANT\";\n\t\t\tconst prolificParticipant = info.ProlificParticipantID || undefined;\n\t\t\tconst experimentName = this._psychoJS.config.experiment.name;\n\t\t\tconst session = info.session || \"SESSION\";\n\t\t\tconst datetime = info.date || MonotonicClock.getDateStr();\n\n\t\t\tconst filenameWithoutPath = `${participant}_${\n\t\t\t\tprolificParticipant ? `${prolificParticipant}_` : \"\"\n\t\t\t}${experimentName}_${session}_${datetime}`;\n\t\t\tconst key = `${filenameWithoutPath}${tag}.csv`;\n\n\t\t\t\n\t\t\tif (\n\t\t\t\tthis._psychoJS.getEnvironment() === ExperimentHandler.Environment.SERVER\n\t\t\t\t&& this._psychoJS.config.experiment.status === \"RUNNING\"\n\t\t\t\t&& !this._psychoJS._serverMsg.has(\"__pilotToken\")\n\t\t\t)\n\t\t\t{\n\t\t\t\treturn /*await*/ this._psychoJS.serverManager.uploadData(key, csv, sync);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tutil.offerDataForDownload(key, csv, \"text/csv\");\n\t\t\t}\n\t\t}\n\t\t// save to the database on the pavlovia server:\n\t\telse if (this._psychoJS.config.experiment.saveFormat === ExperimentHandler.SaveFormat.DATABASE)\n\t\t{\n\t\t\tconst gitlabConfig = this._psychoJS.config.gitlab;\n\t\t\tconst __projectId = (typeof gitlabConfig !== \"undefined\" && typeof gitlabConfig.projectId !== \"undefined\") ? gitlabConfig.projectId : undefined;\n\n\t\t\tlet documents = [];\n\n\t\t\tfor (let r = 0; r < data.length; r++)\n\t\t\t{\n\t\t\t\tlet doc = {\n\t\t\t\t\t__projectId,\n\t\t\t\t\t__experimentName: this._experimentName,\n\t\t\t\t\t__participant: this._participant,\n\t\t\t\t\t__session: this._session,\n\t\t\t\t\t__datetime: this._datetime\n\t\t\t\t};\n\t\t\t\tfor (let h = 0; h < attributes.length; h++)\n\t\t\t\t{\n\t\t\t\t\tdoc[attributes[h]] = data[r][attributes[h]];\n\t\t\t\t}\n\t\t\t\tdocuments.push(doc);\n\t\t\t}\n\n\t\t\t// upload data to the pavlovia server or offer them for download:\n\t\t\tif (\n\t\t\t\tthis._psychoJS.getEnvironment() === ExperimentHandler.Environment.SERVER\n\t\t\t\t&& this._psychoJS.config.experiment.status === \"RUNNING\"\n\t\t\t\t&& !this._psychoJS._serverMsg.has(\"__pilotToken\")\n\t\t\t)\n\t\t\t{\n\t\t\t\tconsole.log('documents', documents);\n\t\t\t\tconst key = \"results\"; // name of the mongoDB collection\n\t\t\t\treturn /*await*/ this._psychoJS.serverManager.uploadData(key, JSON.stringify(documents), sync);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tutil.offerDataForDownload(\"results.json\", JSON.stringify(documents), \"application/json\");\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Save curstom data to a csv file that is downloaded in addition to the usual output csv\n\t *\n\t * <ul>\n\t * <li>The results are offered for immediate download.</li>\n\t * </ul>\n\t * <p>\n\t *\n\t * @name module:data.ExperimentHandler#save\n\t * @function\n\t * @public\n\t * @param {Array.<Object>} [data] - array of objects to be saved to the csv\n\t * @param {string} [csvLabel=\"stimulus\"] - suffix to be added to the output csv filename\n\t */\n\tsaveCSV(data, csvLabel=\"stimulus\", online=false, isForMovieExperiment=false){\n\t\t// note: we use the XLSX library as it automatically deals with header, takes care of quotes,\n\t\t// newlines, etc.\n\t\tconsole.log(data);\n\t\tconst worksheet = XLSX.utils.json_to_sheet(excelSafeRows(data));\n\t\t// prepend BOM\n\t\tconst csv = \"\\ufeff\" + XLSX.utils.sheet_to_csv(worksheet);\n\n\t\tconst info = this._psychoJS.experiment.getExtraInfo();\n\t\tconst participant = info.participant || \"PARTICIPANT\";\n\t\tconst prolificParticipant = info.ProlificParticipantID || undefined;\n\t\tconst experimentName = this._psychoJS.config.experiment.name;\n\t\tconst session = info.session || \"SESSION\";\n\t\tconst datetime = info.date || MonotonicClock.getDateStr();\n\t\tconst filenameWithoutPath = isForMovieExperiment? csvLabel: `${participant}_${\n\t\t\tprolificParticipant ? `${prolificParticipant}_` : \"\"\n\t\t}${experimentName}_${session}_${datetime}_${csvLabel}`;\n\t\tconst key = `${filenameWithoutPath}.csv`;\n\t\tlet documents = [];\n\t\tconst gitlabConfig = this._psychoJS.config.gitlab;\n\t\t\tconst __projectId = (typeof gitlabConfig !== \"undefined\" && typeof gitlabConfig.projectId !== \"undefined\") ? gitlabConfig.projectId : undefined;\n\t\tfor (let r = 0; r < data.length; r++) {\n\t\t\tdata[r]['__projectId'] = __projectId;\n\t\t\tdata[r]['__experimentName'] = this.psychoJS.config.experiment.name;\n\t\t\tdata[r]['__participant'] = this._participant;\n\t\t\tdata[r]['__session'] = this._session;\n\t\t\tdata[r]['__datetime'] = this._datetime;\n\t\t}\n\n\t\tif (this._psychoJS.config.experiment.saveFormat === ExperimentHandler.SaveFormat.CSV) { \n\t\t\tif (online){\n\t\t\t\ttry {\n\t\t\t\t\tthis._psychoJS.serverManager.uploadData(key, csv, false);\n\t\t\t\t} catch (e) {\n\t\t\t\t\tconsole.error(\"Error saving csv data to online.\", e);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tutil.offerDataForDownload(key, csv, \"text/csv\");\n\t\t\t}\n\t\t\t} else if (this._psychoJS.config.experiment.saveFormat === ExperimentHandler.SaveFormat.DATABASE) {\n\t\t\t\n\t\t\t\tif (online){\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis._psychoJS.serverManager.uploadData('results', JSON.stringify(excelSafeRows(data)), false);\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tconsole.error(\"Error saving to results.\", e);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tutil.offerDataForDownload(key, csv, \"text/csv\");\n\t\t\t\t}\n\t\t\t}\n\t}\n\n\tdownloadJSON(data, i) {\n\t\tconst info = this._psychoJS.experiment.getExtraInfo();\n\t\tconst participant = info.participant || \"PARTICIPANT\";\n\t\tconst session = info.session || \"SESSION\";\n\t\tconst datetime = calibrationTime.current\n\t\tconst experimentName = this._psychoJS.config.experiment.name;\n\t\tconst suffix = i == 0 ? \"sound\" : `M${i}`;\n\t\tconst filename = `${experimentName}_${participant}_${session}_${datetime}_${suffix}.json`;\n\t\tconst contentType = \"application/json;charset=utf-8;\";\n\n\t\tconst anchor = document.createElement(\"a\");\n\t\tanchor.href = 'data:' + contentType + ',' + encodeURIComponent(JSON.stringify(data));\n\t\tanchor.download = filename;\n\t\tdocument.body.appendChild(anchor);\n\t\tanchor.click();\n\t\tdocument.body.removeChild(anchor);\n\t\tif (\n\t\t\tthis._psychoJS.getEnvironment() === ExperimentHandler.Environment.SERVER\n\t\t\t&& this._psychoJS.config.experiment.status === \"RUNNING\"\n\t\t\t&& !this._psychoJS._serverMsg.has(\"__pilotToken\")\n\t\t)\n\t\t{\n\t\t\tthis._psychoJS.serverManager.uploadData(filename, JSON.stringify(data), false);\n\t\t}\n\t\treturn filename;\n\t}\n\n\t/**\n\t * Get the attribute names and values for the current trial of a given loop.\n\t * <p> Only info relating to the trial execution are returned.</p>\n\t *\n\t * @name module:data.ExperimentHandler#_getLoopAttributes\n\t * @function\n\t * @static\n\t * @protected\n\t * @param {Object} loop - the loop\n\t */\n\tstatic _getLoopAttributes(loop)\n\t{\n\t\t// standard trial attributes:\n\t\tconst properties = [\"thisRepN\", \"thisTrialN\", \"thisN\", \"thisIndex\", \"stepSizeCurrent\", \"ran\", \"order\"];\n\t\tlet attributes = {};\n\t\tconst loopName = loop.name;\n\t\tfor (const loopProperty in loop)\n\t\t{\n\t\t\tif (properties.includes(loopProperty))\n\t\t\t{\n\t\t\t\tconst key = (loopProperty === \"stepSizeCurrent\") ? loopName + \".stepSize\" : loopName + \".\" + loopProperty;\n\t\t\t\tattributes[key] = loop[loopProperty];\n\t\t\t}\n\t\t}\n\n\t\t// specific trial attributes:\n\t\tif (typeof loop.getCurrentTrial === \"function\")\n\t\t{\n\t\t\tconst currentTrial = loop.getCurrentTrial();\n\t\t\tfor (const trialProperty in currentTrial)\n\t\t\t{\n\t\t\t\tattributes[trialProperty] = currentTrial[trialProperty];\n\t\t\t}\n\t\t}\n\n\t\t/* TODO\n\t\t// method of constants\n\t\tif hasattr(loop, 'thisTrial'):\n\t\t\t\ttrial = loop.thisTrial\n\t\t\t\tif hasattr(trial,'items'):#is a TrialList object or a simple dict\n\t\t\t\t\t\tfor property,val in trial.items():\n\t\t\t\t\t\t\t\tif property not in self._paramNamesSoFar:\n\t\t\t\t\t\t\t\t\t\tself._paramNamesSoFar.append(property)\n\t\t\t\t\t\t\t\tnames.append(property)\n\t\t\t\t\t\t\t\tvals.append(val)\n\t\t\t\telif trial==[]:#we haven't had 1st trial yet? Not actually sure why this occasionally happens (JWP)\n\t\t\t\t\t\tpass\n\t\t\t\telse:\n\t\t\t\t\t\tnames.append(loopName+'.thisTrial')\n\t\t\t\t\t\tvals.append(trial)\n\n\t\t// single StairHandler\n\t\telif hasattr(loop, 'intensities'):\n\t\t\t\tnames.append(loopName+'.intensity')\n\t\t\t\tif len(loop.intensities)>0:\n\t\t\t\t\t\tvals.append(loop.intensities[-1])\n\t\t\t\telse:\n\t\t\t\t\t\tvals.append(None)*/\n\n\t\treturn attributes;\n\t}\n\n\t_orderOutput(data, attributes) {\n\t\tif (data.length === 0 || attributes.length === 0 || !this._psychoJS) return {data: data, attributes: attributes};\n\t\tconst inputParameters = [...this._psychoJS.inputParameters];\n\t\tconst excludeAttributes = [\"expName\", \"name\", \"blockNumber\", \"_s\", \"setSession\", \"targetMeasuredDurationFrames\", \"label\", \"!experimentFilename\"];\n\t\tattributes = attributes.filter(a => !excludeAttributes.includes(a));\n\t\tconst prependAttributes = [\"URL\", \"experiment\", \"date\"];\n\t\tconst inputAttributes = inputParameters.filter(a => attributes.includes(a));\n\t\tconst outputAttributes = attributes.filter(a => !inputParameters.includes(a) && !prependAttributes.includes(a));\n\t\tconst orderedAttributes = [...prependAttributes, ...inputAttributes, ...outputAttributes];\n\t\tconst orderingObj = {}; \n\t\tfor (const a of orderedAttributes) {\n\t\t\torderingObj[a] = null;\n\t\t}\n\t\tfor (let i=0; i<data.length; i++) {\n\t\t\tfor (const a of excludeAttributes) { // EXCLUDE\n\t\t\t\tif(data[i].hasOwnProperty(a)) delete data[i][a];\n\t\t\t}\n\t\t\tdata[i] = Object.assign({}, orderingObj, data[i]); // ORDER\n\t\t}\n\t\treturn {data: data, attributes: orderedAttributes};\n}\n}\n\n/**\n * Experiment result format\n *\n * @name module:core.ServerManager#SaveFormat\n * @enum {Symbol}\n * @readonly\n * @public\n */\nExperimentHandler.SaveFormat = {\n\t/**\n\t * Results are saved to a .csv file\n\t */\n\tCSV: Symbol.for(\"CSV\"),\n\n\t/**\n\t * Results are saved to a database\n\t */\n\tDATABASE: Symbol.for(\"DATABASE\"),\n};\n\n/**\n * Experiment environment.\n *\n * @enum {Symbol}\n * @readonly\n * @public\n */\nExperimentHandler.Environment = {\n\tSERVER: Symbol.for(\"SERVER\"),\n\tLOCAL: Symbol.for(\"LOCAL\"),\n};\n","/**\n * Scheduler.\n *\n * @author Alain Pitiot\n * @version 2021.2.0\n * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd. (https://opensciencetools.org)\n * @license Distributed under the terms of the MIT License\n */\n\n/**\n * <p>A scheduler helps run the main loop by managing scheduled functions,\n * called tasks, after each frame is displayed.</p>\n *\n * <p>\n * Tasks are either another [Scheduler]{@link module:util.Scheduler}, or a\n * JavaScript functions returning one of the following codes:\n * <ul>\n * <li>Scheduler.Event.NEXT: Move onto the next task *without* rendering the scene first.</li>\n * <li>Scheduler.Event.FLIP_REPEAT: Render the scene and repeat the task.</li>\n * <li>Scheduler.Event.FLIP_NEXT: Render the scene and move onto the next task.</li>\n * <li>Scheduler.Event.QUIT: Quit the scheduler.</li>\n * </ul>\n * </p>\n *\n * <p> It is possible to create sub-schedulers, e.g. to handle loops.\n * Sub-schedulers are added to a parent scheduler as a normal\n * task would be by calling [scheduler.add(subScheduler)]{@link module:util.Scheduler#add}.</p>\n *\n * <p> Conditional branching is also available:\n * [scheduler.addConditionalBranches]{@link module:util.Scheduler#addConditional}</p>\n *\n *\n * @name module:util.Scheduler\n * @class\n * @param {module:core.PsychoJS} psychoJS - the PsychoJS instance\n *\n */\nexport class Scheduler\n{\n\tconstructor(psychoJS)\n\t{\n\t\tthis._psychoJS = psychoJS;\n\n\t\tthis._taskList = [];\n\t\tthis._currentTask = undefined;\n\t\tthis._argsList = [];\n\t\tthis._currentArgs = undefined;\n\n\t\tthis._stopAtNextUpdate = false;\n\t\tthis._stopAtNextTask = false;\n\n\t\tthis._status = Scheduler.Status.STOPPED;\n\t}\n\n\t/**\n\t * Get the status of the scheduler.\n\t *\n\t * @name module:util.Scheduler#status\n\t * @public\n\t * @returns {module:util.Scheduler#Status} the status of the scheduler\n\t */\n\tget status()\n\t{\n\t\treturn this._status;\n\t}\n\n\t/**\n\t * Task to be run by the scheduler.\n\t *\n\t * @callback module:util.Scheduler~Task\n\t * @param {*} [args] optional arguments\n\t */\n\t/**\n\t * Schedule a new task.\n\t *\n\t * @name module:util.Scheduler#add\n\t * @public\n\t * @param {module:util.Scheduler~Task | module:util.Scheduler} task - the task to be scheduled\n\t * @param {...*} args - arguments for that task\n\t */\n\tadd(task, ...args)\n\t{\n\t\tthis._taskList.push(task);\n\t\tthis._argsList.push(args);\n\t}\n\n\t/**\n\t * Schedule a task to run NEXT — ahead of everything currently queued.\n\t *\n\t * <p>This is the front-insertion counterpart of\n\t * [add()]{@link module:util/Scheduler#add}, which appends to the back.\n\t * Repeated calls stack like <code>Array.unshift</code> (the last task\n\t * unshifted becomes the frontmost).</p>\n\t *\n\t * @name module:util/Scheduler#unshift\n\t * @public\n\t * @param {module:util/Scheduler~Task | module:util/Scheduler} task - the task to be scheduled next\n\t * @param {...*} args - arguments for that task\n\t */\n\tunshift(task, ...args)\n\t{\n\t\tthis._taskList.unshift(task);\n\t\tthis._argsList.unshift(args);\n\t}\n\n\t/**\n\t * Condition evaluated when the task is run.\n\t *\n\t * @callback module:util.Scheduler~Condition\n\t * @return {boolean}\n\t */\n\t/**\n\t * Schedule a series of task or another, based on a condition.\n\t *\n\t * <p>Note: the tasks are [sub-schedulers]{@link module:util.Scheduler}.</p>\n\t *\n\t * @name module:util.Scheduler#addConditional\n\t * @public\n\t * @param {module:util.Scheduler~Condition} condition - the condition\n\t * @param {module:util.Scheduler} thenScheduler - the [Scheduler]{@link module:util.Scheduler} to be run if the condition is satisfied\n\t * @param {module:util.Scheduler} elseScheduler - the [Scheduler]{@link module:util.Scheduler} to be run if the condition is not satisfied\n\t */\n\taddConditional(condition, thenScheduler, elseScheduler)\n\t{\n\t\tconst self = this;\n\t\tlet task = function()\n\t\t{\n\t\t\tif (condition())\n\t\t\t{\n\t\t\t\tself.add(thenScheduler);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tself.add(elseScheduler);\n\t\t\t}\n\n\t\t\treturn Scheduler.Event.NEXT;\n\t\t};\n\n\t\tthis.add(task);\n\t}\n\n\t/**\n\t * Start this scheduler.\n\t *\n\t * <p>Note: tasks are run after each animation frame.</p>\n\t *\n\t * @name module:util.Scheduler#start\n\t * @public\n\t */\n\tasync start()\n\t{\n\t\tconst self = this;\n\t\tconst update = async (timestamp) =>\n\t\t{\n\t\t\t// stop the animation if need be:\n\t\t\tif (self._stopAtNextUpdate)\n\t\t\t{\n\t\t\t\tself._status = Scheduler.Status.STOPPED;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// self._psychoJS.window._writeLogOnFlip();\n\n\t\t\t// run the next scheduled tasks until a scene render is requested:\n\t\t\tconst state = await self._runNextTasks();\n\t\t\tif (state === Scheduler.Event.QUIT)\n\t\t\t{\n\t\t\t\tself._status = Scheduler.Status.STOPPED;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// store frame delta for `Window.getActualFrameRate()`\n\t\t\tconst lastTimestamp = self._lastTimestamp === undefined ? timestamp : self._lastTimestamp;\n\n\t\t\tself._lastDelta = timestamp - lastTimestamp;\n\t\t\tself._lastTimestamp = timestamp;\n\n\t\t\t// render the scene in the window:\n\t\t\tself._psychoJS.window.render();\n\n\t\t\t// request a new frame:\n\t\t\trequestAnimationFrame(update);\n\t\t};\n\n\t\t// start the animation:\n\t\trequestAnimationFrame(update);\n\t}\n\n\t/**\n\t * Stop this scheduler.\n\t *\n\t * @name module:util.Scheduler#stop\n\t * @public\n\t */\n\tstop()\n\t{\n\t\tthis._status = Scheduler.Status.STOPPED;\n\t\tthis._stopAtNextTask = true;\n\t\tthis._stopAtNextUpdate = true;\n\t}\n\n\t/**\n\t * Run the next scheduled tasks, in sequence, until a rendering of the scene is requested.\n\t *\n\t * @name module:util.Scheduler#_runNextTasks\n\t * @private\n\t * @return {module:util.Scheduler#Event} the state of the scheduler after the last task ran\n\t */\n\tasync _runNextTasks()\n\t{\n\t\tthis._status = Scheduler.Status.RUNNING;\n\n\t\tlet state = Scheduler.Event.NEXT;\n\t\twhile (state === Scheduler.Event.NEXT)\n\t\t{\n\t\t\t// check if we need to quit:\n\t\t\tif (this._stopAtNextTask)\n\t\t\t{\n\t\t\t\treturn Scheduler.Event.QUIT;\n\t\t\t}\n\n\t\t\t// if there is no current task, we look for the next one in the list or quit if there is none:\n\t\t\tif (typeof this._currentTask == \"undefined\")\n\t\t\t{\n\t\t\t\t// a task is available in the taskList:\n\t\t\t\tif (this._taskList.length > 0)\n\t\t\t\t{\n\t\t\t\t\tthis._currentTask = this._taskList.shift();\n\t\t\t\t\tthis._currentArgs = this._argsList.shift();\n\t\t\t\t}\n\t\t\t\t// the taskList is empty: we quit\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tthis._currentTask = undefined;\n\t\t\t\t\tthis._currentArgs = undefined;\n\t\t\t\t\treturn Scheduler.Event.QUIT;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// we are repeating a task\n\t\t\t}\n\n\t\t\t// if the current task is a function, we run it:\n\t\t\tif (this._currentTask instanceof Function)\n\t\t\t{\n\t\t\t\tstate = await this._currentTask(...this._currentArgs);\n\t\t\t}\n\t\t\t// otherwise, we assume that the current task is a scheduler and we run its tasks until a rendering\n\t\t\t// of the scene is required.\n\t\t\t// note: \"if (this._currentTask instanceof Scheduler)\" does not work because of CORS...\n\t\t\telse\n\t\t\t{\n\t\t\t\tstate = await this._currentTask._runNextTasks();\n\t\t\t\tif (state === Scheduler.Event.QUIT)\n\t\t\t\t{\n\t\t\t\t\t// if the experiment has not ended, we move onto the next task:\n\t\t\t\t\tif (!this._psychoJS.experiment.experimentEnded)\n\t\t\t\t\t{\n\t\t\t\t\t\tstate = Scheduler.Event.NEXT;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// if the current task's return status is FLIP_REPEAT, we will re-run it, otherwise\n\t\t\t// we move onto the next task:\n\t\t\tif (state !== Scheduler.Event.FLIP_REPEAT)\n\t\t\t{\n\t\t\t\tthis._currentTask = undefined;\n\t\t\t\tthis._currentArgs = undefined;\n\t\t\t}\n\t\t}\n\n\t\treturn state;\n\t}\n}\n\n/**\n * Events.\n *\n * @name module:util.Scheduler#Event\n * @enum {Symbol}\n * @readonly\n * @public\n */\nScheduler.Event = {\n\t/**\n\t * Move onto the next task *without* rendering the scene first.\n\t */\n\tNEXT: Symbol.for(\"NEXT\"),\n\n\t/**\n\t * Render the scene and repeat the task.\n\t */\n\tFLIP_REPEAT: Symbol.for(\"FLIP_REPEAT\"),\n\n\t/**\n\t * Render the scene and move onto the next task.\n\t */\n\tFLIP_NEXT: Symbol.for(\"FLIP_NEXT\"),\n\n\t/**\n\t * Quit the scheduler.\n\t */\n\tQUIT: Symbol.for(\"QUIT\"),\n};\n\n/**\n * Status.\n *\n * @name module:util.Scheduler#Status\n * @enum {Symbol}\n * @readonly\n * @public\n */\nScheduler.Status = {\n\t/**\n\t * The Scheduler is running.\n\t */\n\tRUNNING: Symbol.for(\"RUNNING\"),\n\n\t/**\n\t * The Scheduler is stopped.\n\t */\n\tSTOPPED: Symbol.for(\"STOPPED\"),\n};\n","/**\n * Tone.js\n * @author Yotam Mann\n * @license http://opensource.org/licenses/MIT MIT License\n * @copyright 2014-2019 Yotam Mann\n */\nimport { version } from \"../version\";\nimport { theWindow } from \"./context/AudioContext\";\nimport { log } from \"./util/Debug\";\n/**\n * @class Tone is the base class of all other classes.\n * @category Core\n * @constructor\n */\nexport class Tone {\n constructor() {\n //-------------------------------------\n // \tDEBUGGING\n //-------------------------------------\n /**\n * Set this debug flag to log all events that happen in this class.\n */\n this.debug = false;\n //-------------------------------------\n // \tDISPOSING\n //-------------------------------------\n /**\n * Indicates if the instance was disposed\n */\n this._wasDisposed = false;\n }\n /**\n * Returns all of the default options belonging to the class.\n */\n static getDefaults() {\n return {};\n }\n /**\n * Prints the outputs to the console log for debugging purposes.\n * Prints the contents only if either the object has a property\n * called `debug` set to true, or a variable called TONE_DEBUG_CLASS\n * is set to the name of the class.\n * @example\n * const osc = new Tone.Oscillator();\n * // prints all logs originating from this oscillator\n * osc.debug = true;\n * // calls to start/stop will print in the console\n * osc.start();\n */\n log(...args) {\n // if the object is either set to debug = true\n // or if there is a string on the Tone.global.with the class name\n if (this.debug || (theWindow && this.toString() === theWindow.TONE_DEBUG_CLASS)) {\n log(this, ...args);\n }\n }\n /**\n * disconnect and dispose.\n */\n dispose() {\n this._wasDisposed = true;\n return this;\n }\n /**\n * Indicates if the instance was disposed. 'Disposing' an\n * instance means that all of the Web Audio nodes that were\n * created for the instance are disconnected and freed for garbage collection.\n */\n get disposed() {\n return this._wasDisposed;\n }\n /**\n * Convert the class to a string\n * @example\n * const osc = new Tone.Oscillator();\n * console.log(osc.toString());\n */\n toString() {\n return this.name;\n }\n}\n/**\n * The version number semver\n */\nTone.version = version;\n//# sourceMappingURL=Tone.js.map","/**\n * The threshold for correctness for operators. Less than one sample even\n * at very high sampling rates (e.g. `1e-6 < 1 / 192000`).\n */\nconst EPSILON = 1e-6;\n/**\n * Test if A is greater than B\n */\nexport function GT(a, b) {\n return a > b + EPSILON;\n}\n/**\n * Test if A is greater than or equal to B\n */\nexport function GTE(a, b) {\n return GT(a, b) || EQ(a, b);\n}\n/**\n * Test if A is less than B\n */\nexport function LT(a, b) {\n return a + EPSILON < b;\n}\n/**\n * Test if A is less than B\n */\nexport function EQ(a, b) {\n return Math.abs(a - b) < EPSILON;\n}\n/**\n * Clamp the value within the given range\n */\nexport function clamp(value, min, max) {\n return Math.max(Math.min(value, max), min);\n}\n//# sourceMappingURL=Math.js.map","import { Tone } from \"../Tone\";\nimport { optionsFromArguments } from \"./Defaults\";\nimport { assert } from \"./Debug\";\nimport { EQ, GT, GTE, LT } from \"./Math\";\n/**\n * A Timeline class for scheduling and maintaining state\n * along a timeline. All events must have a \"time\" property.\n * Internally, events are stored in time order for fast\n * retrieval.\n */\nexport class Timeline extends Tone {\n constructor() {\n super();\n this.name = \"Timeline\";\n /**\n * The array of scheduled timeline events\n */\n this._timeline = [];\n const options = optionsFromArguments(Timeline.getDefaults(), arguments, [\"memory\"]);\n this.memory = options.memory;\n this.increasing = options.increasing;\n }\n static getDefaults() {\n return {\n memory: Infinity,\n increasing: false,\n };\n }\n /**\n * The number of items in the timeline.\n */\n get length() {\n return this._timeline.length;\n }\n /**\n * Insert an event object onto the timeline. Events must have a \"time\" attribute.\n * @param event The event object to insert into the timeline.\n */\n add(event) {\n // the event needs to have a time attribute\n assert(Reflect.has(event, \"time\"), \"Timeline: events must have a time attribute\");\n event.time = event.time.valueOf();\n if (this.increasing && this.length) {\n const lastValue = this._timeline[this.length - 1];\n assert(GTE(event.time, lastValue.time), \"The time must be greater than or equal to the last scheduled time\");\n this._timeline.push(event);\n }\n else {\n const index = this._search(event.time);\n this._timeline.splice(index + 1, 0, event);\n }\n // if the length is more than the memory, remove the previous ones\n if (this.length > this.memory) {\n const diff = this.length - this.memory;\n this._timeline.splice(0, diff);\n }\n return this;\n }\n /**\n * Remove an event from the timeline.\n * @param {Object} event The event object to remove from the list.\n * @returns {Timeline} this\n */\n remove(event) {\n const index = this._timeline.indexOf(event);\n if (index !== -1) {\n this._timeline.splice(index, 1);\n }\n return this;\n }\n /**\n * Get the nearest event whose time is less than or equal to the given time.\n * @param time The time to query.\n */\n get(time, param = \"time\") {\n const index = this._search(time, param);\n if (index !== -1) {\n return this._timeline[index];\n }\n else {\n return null;\n }\n }\n /**\n * Return the first event in the timeline without removing it\n * @returns {Object} The first event object\n */\n peek() {\n return this._timeline[0];\n }\n /**\n * Return the first event in the timeline and remove it\n */\n shift() {\n return this._timeline.shift();\n }\n /**\n * Get the event which is scheduled after the given time.\n * @param time The time to query.\n */\n getAfter(time, param = \"time\") {\n const index = this._search(time, param);\n if (index + 1 < this._timeline.length) {\n return this._timeline[index + 1];\n }\n else {\n return null;\n }\n }\n /**\n * Get the event before the event at the given time.\n * @param time The time to query.\n */\n getBefore(time) {\n const len = this._timeline.length;\n // if it's after the last item, return the last item\n if (len > 0 && this._timeline[len - 1].time < time) {\n return this._timeline[len - 1];\n }\n const index = this._search(time);\n if (index - 1 >= 0) {\n return this._timeline[index - 1];\n }\n else {\n return null;\n }\n }\n /**\n * Cancel events at and after the given time\n * @param after The time to query.\n */\n cancel(after) {\n if (this._timeline.length > 1) {\n let index = this._search(after);\n if (index >= 0) {\n if (EQ(this._timeline[index].time, after)) {\n // get the first item with that time\n for (let i = index; i >= 0; i--) {\n if (EQ(this._timeline[i].time, after)) {\n index = i;\n }\n else {\n break;\n }\n }\n this._timeline = this._timeline.slice(0, index);\n }\n else {\n this._timeline = this._timeline.slice(0, index + 1);\n }\n }\n else {\n this._timeline = [];\n }\n }\n else if (this._timeline.length === 1) {\n // the first item's time\n if (GTE(this._timeline[0].time, after)) {\n this._timeline = [];\n }\n }\n return this;\n }\n /**\n * Cancel events before or equal to the given time.\n * @param time The time to cancel before.\n */\n cancelBefore(time) {\n const index = this._search(time);\n if (index >= 0) {\n this._timeline = this._timeline.slice(index + 1);\n }\n return this;\n }\n /**\n * Returns the previous event if there is one. null otherwise\n * @param event The event to find the previous one of\n * @return The event right before the given event\n */\n previousEvent(event) {\n const index = this._timeline.indexOf(event);\n if (index > 0) {\n return this._timeline[index - 1];\n }\n else {\n return null;\n }\n }\n /**\n * Does a binary search on the timeline array and returns the\n * nearest event index whose time is after or equal to the given time.\n * If a time is searched before the first index in the timeline, -1 is returned.\n * If the time is after the end, the index of the last item is returned.\n */\n _search(time, param = \"time\") {\n if (this._timeline.length === 0) {\n return -1;\n }\n let beginning = 0;\n const len = this._timeline.length;\n let end = len;\n if (len > 0 && this._timeline[len - 1][param] <= time) {\n return len - 1;\n }\n while (beginning < end) {\n // calculate the midpoint for roughly equal partition\n let midPoint = Math.floor(beginning + (end - beginning) / 2);\n const event = this._timeline[midPoint];\n const nextEvent = this._timeline[midPoint + 1];\n if (EQ(event[param], time)) {\n // choose the last one that has the same time\n for (let i = midPoint; i < this._timeline.length; i++) {\n const testEvent = this._timeline[i];\n if (EQ(testEvent[param], time)) {\n midPoint = i;\n }\n else {\n break;\n }\n }\n return midPoint;\n }\n else if (LT(event[param], time) && GT(nextEvent[param], time)) {\n return midPoint;\n }\n else if (GT(event[param], time)) {\n // search lower\n end = midPoint;\n }\n else {\n // search upper\n beginning = midPoint + 1;\n }\n }\n return -1;\n }\n /**\n * Internal iterator. Applies extra safety checks for\n * removing items from the array.\n */\n _iterate(callback, lowerBound = 0, upperBound = this._timeline.length - 1) {\n this._timeline.slice(lowerBound, upperBound + 1).forEach(callback);\n }\n /**\n * Iterate over everything in the array\n * @param callback The callback to invoke with every item\n */\n forEach(callback) {\n this._iterate(callback);\n return this;\n }\n /**\n * Iterate over everything in the array at or before the given time.\n * @param time The time to check if items are before\n * @param callback The callback to invoke with every item\n */\n forEachBefore(time, callback) {\n // iterate over the items in reverse so that removing an item doesn't break things\n const upperBound = this._search(time);\n if (upperBound !== -1) {\n this._iterate(callback, 0, upperBound);\n }\n return this;\n }\n /**\n * Iterate over everything in the array after the given time.\n * @param time The time to check if items are before\n * @param callback The callback to invoke with every item\n */\n forEachAfter(time, callback) {\n // iterate over the items in reverse so that removing an item doesn't break things\n const lowerBound = this._search(time);\n this._iterate(callback, lowerBound + 1);\n return this;\n }\n /**\n * Iterate over everything in the array between the startTime and endTime.\n * The timerange is inclusive of the startTime, but exclusive of the endTime.\n * range = [startTime, endTime).\n * @param startTime The time to check if items are before\n * @param endTime The end of the test interval.\n * @param callback The callback to invoke with every item\n */\n forEachBetween(startTime, endTime, callback) {\n let lowerBound = this._search(startTime);\n let upperBound = this._search(endTime);\n if (lowerBound !== -1 && upperBound !== -1) {\n if (this._timeline[lowerBound].time !== startTime) {\n lowerBound += 1;\n }\n // exclusive of the end time\n if (this._timeline[upperBound].time === endTime) {\n upperBound -= 1;\n }\n this._iterate(callback, lowerBound, upperBound);\n }\n else if (lowerBound === -1) {\n this._iterate(callback, 0, upperBound);\n }\n return this;\n }\n /**\n * Iterate over everything in the array at or after the given time. Similar to\n * forEachAfter, but includes the item(s) at the given time.\n * @param time The time to check if items are before\n * @param callback The callback to invoke with every item\n */\n forEachFrom(time, callback) {\n // iterate over the items in reverse so that removing an item doesn't break things\n let lowerBound = this._search(time);\n // work backwards until the event time is less than time\n while (lowerBound >= 0 && this._timeline[lowerBound].time >= time) {\n lowerBound--;\n }\n this._iterate(callback, lowerBound + 1);\n return this;\n }\n /**\n * Iterate over everything in the array at the given time\n * @param time The time to check if items are before\n * @param callback The callback to invoke with every item\n */\n forEachAtTime(time, callback) {\n // iterate over the items in reverse so that removing an item doesn't break things\n const upperBound = this._search(time);\n if (upperBound !== -1 && EQ(this._timeline[upperBound].time, time)) {\n let lowerBound = upperBound;\n for (let i = upperBound; i >= 0; i--) {\n if (EQ(this._timeline[i].time, time)) {\n lowerBound = i;\n }\n else {\n break;\n }\n }\n this._iterate(event => {\n callback(event);\n }, lowerBound, upperBound);\n }\n return this;\n }\n /**\n * Clean up.\n */\n dispose() {\n super.dispose();\n this._timeline = [];\n return this;\n }\n}\n//# sourceMappingURL=Timeline.js.map","/*!\n * howler.js v2.2.3\n * howlerjs.com\n *\n * (c) 2013-2020, James Simpson of GoldFire Studios\n * goldfirestudios.com\n *\n * MIT License\n */\n\n(function() {\n\n 'use strict';\n\n /** Global Methods **/\n /***************************************************************************/\n\n /**\n * Create the global controller. All contained methods and properties apply\n * to all sounds that are currently playing or will be in the future.\n */\n var HowlerGlobal = function() {\n this.init();\n };\n HowlerGlobal.prototype = {\n /**\n * Initialize the global Howler object.\n * @return {Howler}\n */\n init: function() {\n var self = this || Howler;\n\n // Create a global ID counter.\n self._counter = 1000;\n\n // Pool of unlocked HTML5 Audio objects.\n self._html5AudioPool = [];\n self.html5PoolSize = 10;\n\n // Internal properties.\n self._codecs = {};\n self._howls = [];\n self._muted = false;\n self._volume = 1;\n self._canPlayEvent = 'canplaythrough';\n self._navigator = (typeof window !== 'undefined' && window.navigator) ? window.navigator : null;\n\n // Public properties.\n self.masterGain = null;\n self.noAudio = false;\n self.usingWebAudio = true;\n self.autoSuspend = true;\n self.ctx = null;\n\n // Set to false to disable the auto audio unlocker.\n self.autoUnlock = true;\n\n // Setup the various state values for global tracking.\n self._setup();\n\n return self;\n },\n\n /**\n * Get/set the global volume for all sounds.\n * @param {Float} vol Volume from 0.0 to 1.0.\n * @return {Howler/Float} Returns self or current volume.\n */\n volume: function(vol) {\n var self = this || Howler;\n vol = parseFloat(vol);\n\n // If we don't have an AudioContext created yet, run the setup.\n if (!self.ctx) {\n setupAudioContext();\n }\n\n if (typeof vol !== 'undefined' && vol >= 0 && vol <= 1) {\n self._volume = vol;\n\n // Don't update any of the nodes if we are muted.\n if (self._muted) {\n return self;\n }\n\n // When using Web Audio, we just need to adjust the master gain.\n if (self.usingWebAudio) {\n self.masterGain.gain.setValueAtTime(vol, Howler.ctx.currentTime);\n }\n\n // Loop through and change volume for all HTML5 audio nodes.\n for (var i=0; i<self._howls.length; i++) {\n if (!self._howls[i]._webAudio) {\n // Get all of the sounds in this Howl group.\n var ids = self._howls[i]._getSoundIds();\n\n // Loop through all sounds and change the volumes.\n for (var j=0; j<ids.length; j++) {\n var sound = self._howls[i]._soundById(ids[j]);\n\n if (sound && sound._node) {\n sound._node.volume = sound._volume * vol;\n }\n }\n }\n }\n\n return self;\n }\n\n return self._volume;\n },\n\n /**\n * Handle muting and unmuting globally.\n * @param {Boolean} muted Is muted or not.\n */\n mute: function(muted) {\n var self = this || Howler;\n\n // If we don't have an AudioContext created yet, run the setup.\n if (!self.ctx) {\n setupAudioContext();\n }\n\n self._muted = muted;\n\n // With Web Audio, we just need to mute the master gain.\n if (self.usingWebAudio) {\n self.masterGain.gain.setValueAtTime(muted ? 0 : self._volume, Howler.ctx.currentTime);\n }\n\n // Loop through and mute all HTML5 Audio nodes.\n for (var i=0; i<self._howls.length; i++) {\n if (!self._howls[i]._webAudio) {\n // Get all of the sounds in this Howl group.\n var ids = self._howls[i]._getSoundIds();\n\n // Loop through all sounds and mark the audio node as muted.\n for (var j=0; j<ids.length; j++) {\n var sound = self._howls[i]._soundById(ids[j]);\n\n if (sound && sound._node) {\n sound._node.muted = (muted) ? true : sound._muted;\n }\n }\n }\n }\n\n return self;\n },\n\n /**\n * Handle stopping all sounds globally.\n */\n stop: function() {\n var self = this || Howler;\n\n // Loop through all Howls and stop them.\n for (var i=0; i<self._howls.length; i++) {\n self._howls[i].stop();\n }\n\n return self;\n },\n\n /**\n * Unload and destroy all currently loaded Howl objects.\n * @return {Howler}\n */\n unload: function() {\n var self = this || Howler;\n\n for (var i=self._howls.length-1; i>=0; i--) {\n self._howls[i].unload();\n }\n\n // Create a new AudioContext to make sure it is fully reset.\n if (self.usingWebAudio && self.ctx && typeof self.ctx.close !== 'undefined') {\n self.ctx.close();\n self.ctx = null;\n setupAudioContext();\n }\n\n return self;\n },\n\n /**\n * Check for codec support of specific extension.\n * @param {String} ext Audio file extention.\n * @return {Boolean}\n */\n codecs: function(ext) {\n return (this || Howler)._codecs[ext.replace(/^x-/, '')];\n },\n\n /**\n * Setup various state values for global tracking.\n * @return {Howler}\n */\n _setup: function() {\n var self = this || Howler;\n\n // Keeps track of the suspend/resume state of the AudioContext.\n self.state = self.ctx ? self.ctx.state || 'suspended' : 'suspended';\n\n // Automatically begin the 30-second suspend process\n self._autoSuspend();\n\n // Check if audio is available.\n if (!self.usingWebAudio) {\n // No audio is available on this system if noAudio is set to true.\n if (typeof Audio !== 'undefined') {\n try {\n var test = new Audio();\n\n // Check if the canplaythrough event is available.\n if (typeof test.oncanplaythrough === 'undefined') {\n self._canPlayEvent = 'canplay';\n }\n } catch(e) {\n self.noAudio = true;\n }\n } else {\n self.noAudio = true;\n }\n }\n\n // Test to make sure audio isn't disabled in Internet Explorer.\n try {\n var test = new Audio();\n if (test.muted) {\n self.noAudio = true;\n }\n } catch (e) {}\n\n // Check for supported codecs.\n if (!self.noAudio) {\n self._setupCodecs();\n }\n\n return self;\n },\n\n /**\n * Check for browser support for various codecs and cache the results.\n * @return {Howler}\n */\n _setupCodecs: function() {\n var self = this || Howler;\n var audioTest = null;\n\n // Must wrap in a try/catch because IE11 in server mode throws an error.\n try {\n audioTest = (typeof Audio !== 'undefined') ? new Audio() : null;\n } catch (err) {\n return self;\n }\n\n if (!audioTest || typeof audioTest.canPlayType !== 'function') {\n return self;\n }\n\n var mpegTest = audioTest.canPlayType('audio/mpeg;').replace(/^no$/, '');\n\n // Opera version <33 has mixed MP3 support, so we need to check for and block it.\n var ua = self._navigator ? self._navigator.userAgent : '';\n var checkOpera = ua.match(/OPR\\/([0-6].)/g);\n var isOldOpera = (checkOpera && parseInt(checkOpera[0].split('/')[1], 10) < 33);\n var checkSafari = ua.indexOf('Safari') !== -1 && ua.indexOf('Chrome') === -1;\n var safariVersion = ua.match(/Version\\/(.*?) /);\n var isOldSafari = (checkSafari && safariVersion && parseInt(safariVersion[1], 10) < 15);\n\n self._codecs = {\n mp3: !!(!isOldOpera && (mpegTest || audioTest.canPlayType('audio/mp3;').replace(/^no$/, ''))),\n mpeg: !!mpegTest,\n opus: !!audioTest.canPlayType('audio/ogg; codecs=\"opus\"').replace(/^no$/, ''),\n ogg: !!audioTest.canPlayType('audio/ogg; codecs=\"vorbis\"').replace(/^no$/, ''),\n oga: !!audioTest.canPlayType('audio/ogg; codecs=\"vorbis\"').replace(/^no$/, ''),\n wav: !!(audioTest.canPlayType('audio/wav; codecs=\"1\"') || audioTest.canPlayType('audio/wav')).replace(/^no$/, ''),\n aac: !!audioTest.canPlayType('audio/aac;').replace(/^no$/, ''),\n caf: !!audioTest.canPlayType('audio/x-caf;').replace(/^no$/, ''),\n m4a: !!(audioTest.canPlayType('audio/x-m4a;') || audioTest.canPlayType('audio/m4a;') || audioTest.canPlayType('audio/aac;')).replace(/^no$/, ''),\n m4b: !!(audioTest.canPlayType('audio/x-m4b;') || audioTest.canPlayType('audio/m4b;') || audioTest.canPlayType('audio/aac;')).replace(/^no$/, ''),\n mp4: !!(audioTest.canPlayType('audio/x-mp4;') || audioTest.canPlayType('audio/mp4;') || audioTest.canPlayType('audio/aac;')).replace(/^no$/, ''),\n weba: !!(!isOldSafari && audioTest.canPlayType('audio/webm; codecs=\"vorbis\"').replace(/^no$/, '')),\n webm: !!(!isOldSafari && audioTest.canPlayType('audio/webm; codecs=\"vorbis\"').replace(/^no$/, '')),\n dolby: !!audioTest.canPlayType('audio/mp4; codecs=\"ec-3\"').replace(/^no$/, ''),\n flac: !!(audioTest.canPlayType('audio/x-flac;') || audioTest.canPlayType('audio/flac;')).replace(/^no$/, '')\n };\n\n return self;\n },\n\n /**\n * Some browsers/devices will only allow audio to be played after a user interaction.\n * Attempt to automatically unlock audio on the first user interaction.\n * Concept from: http://paulbakaus.com/tutorials/html5/web-audio-on-ios/\n * @return {Howler}\n */\n _unlockAudio: function() {\n var self = this || Howler;\n\n // Only run this if Web Audio is supported and it hasn't already been unlocked.\n if (self._audioUnlocked || !self.ctx) {\n return;\n }\n\n self._audioUnlocked = false;\n self.autoUnlock = false;\n\n // Some mobile devices/platforms have distortion issues when opening/closing tabs and/or web views.\n // Bugs in the browser (especially Mobile Safari) can cause the sampleRate to change from 44100 to 48000.\n // By calling Howler.unload(), we create a new AudioContext with the correct sampleRate.\n if (!self._mobileUnloaded && self.ctx.sampleRate !== 44100) {\n self._mobileUnloaded = true;\n self.unload();\n }\n\n // Scratch buffer for enabling iOS to dispose of web audio buffers correctly, as per:\n // http://stackoverflow.com/questions/24119684\n self._scratchBuffer = self.ctx.createBuffer(1, 1, 22050);\n\n // Call this method on touch start to create and play a buffer,\n // then check if the audio actually played to determine if\n // audio has now been unlocked on iOS, Android, etc.\n var unlock = function(e) {\n // Create a pool of unlocked HTML5 Audio objects that can\n // be used for playing sounds without user interaction. HTML5\n // Audio objects must be individually unlocked, as opposed\n // to the WebAudio API which only needs a single activation.\n // This must occur before WebAudio setup or the source.onended\n // event will not fire.\n while (self._html5AudioPool.length < self.html5PoolSize) {\n try {\n var audioNode = new Audio();\n\n // Mark this Audio object as unlocked to ensure it can get returned\n // to the unlocked pool when released.\n audioNode._unlocked = true;\n\n // Add the audio node to the pool.\n self._releaseHtml5Audio(audioNode);\n } catch (e) {\n self.noAudio = true;\n break;\n }\n }\n\n // Loop through any assigned audio nodes and unlock them.\n for (var i=0; i<self._howls.length; i++) {\n if (!self._howls[i]._webAudio) {\n // Get all of the sounds in this Howl group.\n var ids = self._howls[i]._getSoundIds();\n\n // Loop through all sounds and unlock the audio nodes.\n for (var j=0; j<ids.length; j++) {\n var sound = self._howls[i]._soundById(ids[j]);\n\n if (sound && sound._node && !sound._node._unlocked) {\n sound._node._unlocked = true;\n sound._node.load();\n }\n }\n }\n }\n\n // Fix Android can not play in suspend state.\n self._autoResume();\n\n // Create an empty buffer.\n var source = self.ctx.createBufferSource();\n source.buffer = self._scratchBuffer;\n source.connect(self.ctx.destination);\n\n // Play the empty buffer.\n if (typeof source.start === 'undefined') {\n source.noteOn(0);\n } else {\n source.start(0);\n }\n\n // Calling resume() on a stack initiated by user gesture is what actually unlocks the audio on Android Chrome >= 55.\n if (typeof self.ctx.resume === 'function') {\n self.ctx.resume();\n }\n\n // Setup a timeout to check that we are unlocked on the next event loop.\n source.onended = function() {\n source.disconnect(0);\n\n // Update the unlocked state and prevent this check from happening again.\n self._audioUnlocked = true;\n\n // Remove the touch start listener.\n document.removeEventListener('touchstart', unlock, true);\n document.removeEventListener('touchend', unlock, true);\n document.removeEventListener('click', unlock, true);\n document.removeEventListener('keydown', unlock, true);\n\n // Let all sounds know that audio has been unlocked.\n for (var i=0; i<self._howls.length; i++) {\n self._howls[i]._emit('unlock');\n }\n };\n };\n\n // Setup a touch start listener to attempt an unlock in.\n document.addEventListener('touchstart', unlock, true);\n document.addEventListener('touchend', unlock, true);\n document.addEventListener('click', unlock, true);\n document.addEventListener('keydown', unlock, true);\n\n return self;\n },\n\n /**\n * Get an unlocked HTML5 Audio object from the pool. If none are left,\n * return a new Audio object and throw a warning.\n * @return {Audio} HTML5 Audio object.\n */\n _obtainHtml5Audio: function() {\n var self = this || Howler;\n\n // Return the next object from the pool if one exists.\n if (self._html5AudioPool.length) {\n return self._html5AudioPool.pop();\n }\n\n //.Check if the audio is locked and throw a warning.\n var testPlay = new Audio().play();\n if (testPlay && typeof Promise !== 'undefined' && (testPlay instanceof Promise || typeof testPlay.then === 'function')) {\n testPlay.catch(function() {\n console.warn('HTML5 Audio pool exhausted, returning potentially locked audio object.');\n });\n }\n\n return new Audio();\n },\n\n /**\n * Return an activated HTML5 Audio object to the pool.\n * @return {Howler}\n */\n _releaseHtml5Audio: function(audio) {\n var self = this || Howler;\n\n // Don't add audio to the pool if we don't know if it has been unlocked.\n if (audio._unlocked) {\n self._html5AudioPool.push(audio);\n }\n\n return self;\n },\n\n /**\n * Automatically suspend the Web Audio AudioContext after no sound has played for 30 seconds.\n * This saves processing/energy and fixes various browser-specific bugs with audio getting stuck.\n * @return {Howler}\n */\n _autoSuspend: function() {\n var self = this;\n\n if (!self.autoSuspend || !self.ctx || typeof self.ctx.suspend === 'undefined' || !Howler.usingWebAudio) {\n return;\n }\n\n // Check if any sounds are playing.\n for (var i=0; i<self._howls.length; i++) {\n if (self._howls[i]._webAudio) {\n for (var j=0; j<self._howls[i]._sounds.length; j++) {\n if (!self._howls[i]._sounds[j]._paused) {\n return self;\n }\n }\n }\n }\n\n if (self._suspendTimer) {\n clearTimeout(self._suspendTimer);\n }\n\n // If no sound has played after 30 seconds, suspend the context.\n self._suspendTimer = setTimeout(function() {\n if (!self.autoSuspend) {\n return;\n }\n\n self._suspendTimer = null;\n self.state = 'suspending';\n\n // Handle updating the state of the audio context after suspending.\n var handleSuspension = function() {\n self.state = 'suspended';\n\n if (self._resumeAfterSuspend) {\n delete self._resumeAfterSuspend;\n self._autoResume();\n }\n };\n\n // Either the state gets suspended or it is interrupted.\n // Either way, we need to update the state to suspended.\n self.ctx.suspend().then(handleSuspension, handleSuspension);\n }, 30000);\n\n return self;\n },\n\n /**\n * Automatically resume the Web Audio AudioContext when a new sound is played.\n * @return {Howler}\n */\n _autoResume: function() {\n var self = this;\n\n if (!self.ctx || typeof self.ctx.resume === 'undefined' || !Howler.usingWebAudio) {\n return;\n }\n\n if (self.state === 'running' && self.ctx.state !== 'interrupted' && self._suspendTimer) {\n clearTimeout(self._suspendTimer);\n self._suspendTimer = null;\n } else if (self.state === 'suspended' || self.state === 'running' && self.ctx.state === 'interrupted') {\n self.ctx.resume().then(function() {\n self.state = 'running';\n\n // Emit to all Howls that the audio has resumed.\n for (var i=0; i<self._howls.length; i++) {\n self._howls[i]._emit('resume');\n }\n });\n\n if (self._suspendTimer) {\n clearTimeout(self._suspendTimer);\n self._suspendTimer = null;\n }\n } else if (self.state === 'suspending') {\n self._resumeAfterSuspend = true;\n }\n\n return self;\n }\n };\n\n // Setup the global audio controller.\n var Howler = new HowlerGlobal();\n\n /** Group Methods **/\n /***************************************************************************/\n\n /**\n * Create an audio group controller.\n * @param {Object} o Passed in properties for this group.\n */\n var Howl = function(o) {\n var self = this;\n\n // Throw an error if no source is provided.\n if (!o.src || o.src.length === 0) {\n console.error('An array of source files must be passed with any new Howl.');\n return;\n }\n\n self.init(o);\n };\n Howl.prototype = {\n /**\n * Initialize a new Howl group object.\n * @param {Object} o Passed in properties for this group.\n * @return {Howl}\n */\n init: function(o) {\n var self = this;\n\n // If we don't have an AudioContext created yet, run the setup.\n if (!Howler.ctx) {\n setupAudioContext();\n }\n\n // Setup user-defined default properties.\n self._autoplay = o.autoplay || false;\n self._format = (typeof o.format !== 'string') ? o.format : [o.format];\n self._html5 = o.html5 || false;\n self._muted = o.mute || false;\n self._loop = o.loop || false;\n self._pool = o.pool || 5;\n self._preload = (typeof o.preload === 'boolean' || o.preload === 'metadata') ? o.preload : true;\n self._rate = o.rate || 1;\n self._sprite = o.sprite || {};\n self._src = (typeof o.src !== 'string') ? o.src : [o.src];\n self._volume = o.volume !== undefined ? o.volume : 1;\n self._xhr = {\n method: o.xhr && o.xhr.method ? o.xhr.method : 'GET',\n headers: o.xhr && o.xhr.headers ? o.xhr.headers : null,\n withCredentials: o.xhr && o.xhr.withCredentials ? o.xhr.withCredentials : false,\n };\n\n // Setup all other default properties.\n self._duration = 0;\n self._state = 'unloaded';\n self._sounds = [];\n self._endTimers = {};\n self._queue = [];\n self._playLock = false;\n\n // Setup event listeners.\n self._onend = o.onend ? [{fn: o.onend}] : [];\n self._onfade = o.onfade ? [{fn: o.onfade}] : [];\n self._onload = o.onload ? [{fn: o.onload}] : [];\n self._onloaderror = o.onloaderror ? [{fn: o.onloaderror}] : [];\n self._onplayerror = o.onplayerror ? [{fn: o.onplayerror}] : [];\n self._onpause = o.onpause ? [{fn: o.onpause}] : [];\n self._onplay = o.onplay ? [{fn: o.onplay}] : [];\n self._onstop = o.onstop ? [{fn: o.onstop}] : [];\n self._onmute = o.onmute ? [{fn: o.onmute}] : [];\n self._onvolume = o.onvolume ? [{fn: o.onvolume}] : [];\n self._onrate = o.onrate ? [{fn: o.onrate}] : [];\n self._onseek = o.onseek ? [{fn: o.onseek}] : [];\n self._onunlock = o.onunlock ? [{fn: o.onunlock}] : [];\n self._onresume = [];\n\n // Web Audio or HTML5 Audio?\n self._webAudio = Howler.usingWebAudio && !self._html5;\n\n // Automatically try to enable audio.\n if (typeof Howler.ctx !== 'undefined' && Howler.ctx && Howler.autoUnlock) {\n Howler._unlockAudio();\n }\n\n // Keep track of this Howl group in the global controller.\n Howler._howls.push(self);\n\n // If they selected autoplay, add a play event to the load queue.\n if (self._autoplay) {\n self._queue.push({\n event: 'play',\n action: function() {\n self.play();\n }\n });\n }\n\n // Load the source file unless otherwise specified.\n if (self._preload && self._preload !== 'none') {\n self.load();\n }\n\n return self;\n },\n\n /**\n * Load the audio file.\n * @return {Howler}\n */\n load: function() {\n var self = this;\n var url = null;\n\n // If no audio is available, quit immediately.\n if (Howler.noAudio) {\n self._emit('loaderror', null, 'No audio support.');\n return;\n }\n\n // Make sure our source is in an array.\n if (typeof self._src === 'string') {\n self._src = [self._src];\n }\n\n // Loop through the sources and pick the first one that is compatible.\n for (var i=0; i<self._src.length; i++) {\n var ext, str;\n\n if (self._format && self._format[i]) {\n // If an extension was specified, use that instead.\n ext = self._format[i];\n } else {\n // Make sure the source is a string.\n str = self._src[i];\n if (typeof str !== 'string') {\n self._emit('loaderror', null, 'Non-string found in selected audio sources - ignoring.');\n continue;\n }\n\n // Extract the file extension from the URL or base64 data URI.\n ext = /^data:audio\\/([^;,]+);/i.exec(str);\n if (!ext) {\n ext = /\\.([^.]+)$/.exec(str.split('?', 1)[0]);\n }\n\n if (ext) {\n ext = ext[1].toLowerCase();\n }\n }\n\n // Log a warning if no extension was found.\n if (!ext) {\n console.warn('No file extension was found. Consider using the \"format\" property or specify an extension.');\n }\n\n // Check if this extension is available.\n if (ext && Howler.codecs(ext)) {\n url = self._src[i];\n break;\n }\n }\n\n if (!url) {\n self._emit('loaderror', null, 'No codec support for selected audio sources.');\n return;\n }\n\n self._src = url;\n self._state = 'loading';\n\n // If the hosting page is HTTPS and the source isn't,\n // drop down to HTML5 Audio to avoid Mixed Content errors.\n if (window.location.protocol === 'https:' && url.slice(0, 5) === 'http:') {\n self._html5 = true;\n self._webAudio = false;\n }\n\n // Create a new sound object and add it to the pool.\n new Sound(self);\n\n // Load and decode the audio data for playback.\n if (self._webAudio) {\n loadBuffer(self);\n }\n\n return self;\n },\n\n /**\n * Play a sound or resume previous playback.\n * @param {String/Number} sprite Sprite name for sprite playback or sound id to continue previous.\n * @param {Boolean} internal Internal Use: true prevents event firing.\n * @return {Number} Sound ID.\n */\n play: function(sprite, internal) {\n var self = this;\n var id = null;\n\n // Determine if a sprite, sound id or nothing was passed\n if (typeof sprite === 'number') {\n id = sprite;\n sprite = null;\n } else if (typeof sprite === 'string' && self._state === 'loaded' && !self._sprite[sprite]) {\n // If the passed sprite doesn't exist, do nothing.\n return null;\n } else if (typeof sprite === 'undefined') {\n // Use the default sound sprite (plays the full audio length).\n sprite = '__default';\n\n // Check if there is a single paused sound that isn't ended.\n // If there is, play that sound. If not, continue as usual.\n if (!self._playLock) {\n var num = 0;\n for (var i=0; i<self._sounds.length; i++) {\n if (self._sounds[i]._paused && !self._sounds[i]._ended) {\n num++;\n id = self._sounds[i]._id;\n }\n }\n\n if (num === 1) {\n sprite = null;\n } else {\n id = null;\n }\n }\n }\n\n // Get the selected node, or get one from the pool.\n var sound = id ? self._soundById(id) : self._inactiveSound();\n\n // If the sound doesn't exist, do nothing.\n if (!sound) {\n return null;\n }\n\n // Select the sprite definition.\n if (id && !sprite) {\n sprite = sound._sprite || '__default';\n }\n\n // If the sound hasn't loaded, we must wait to get the audio's duration.\n // We also need to wait to make sure we don't run into race conditions with\n // the order of function calls.\n if (self._state !== 'loaded') {\n // Set the sprite value on this sound.\n sound._sprite = sprite;\n\n // Mark this sound as not ended in case another sound is played before this one loads.\n sound._ended = false;\n\n // Add the sound to the queue to be played on load.\n var soundId = sound._id;\n self._queue.push({\n event: 'play',\n action: function() {\n self.play(soundId);\n }\n });\n\n return soundId;\n }\n\n // Don't play the sound if an id was passed and it is already playing.\n if (id && !sound._paused) {\n // Trigger the play event, in order to keep iterating through queue.\n if (!internal) {\n self._loadQueue('play');\n }\n\n return sound._id;\n }\n\n // Make sure the AudioContext isn't suspended, and resume it if it is.\n if (self._webAudio) {\n Howler._autoResume();\n }\n\n // Determine how long to play for and where to start playing.\n var seek = Math.max(0, sound._seek > 0 ? sound._seek : self._sprite[sprite][0] / 1000);\n var duration = Math.max(0, ((self._sprite[sprite][0] + self._sprite[sprite][1]) / 1000) - seek);\n var timeout = (duration * 1000) / Math.abs(sound._rate);\n var start = self._sprite[sprite][0] / 1000;\n var stop = (self._sprite[sprite][0] + self._sprite[sprite][1]) / 1000;\n sound._sprite = sprite;\n\n // Mark the sound as ended instantly so that this async playback\n // doesn't get grabbed by another call to play while this one waits to start.\n sound._ended = false;\n\n // Update the parameters of the sound.\n var setParams = function() {\n sound._paused = false;\n sound._seek = seek;\n sound._start = start;\n sound._stop = stop;\n sound._loop = !!(sound._loop || self._sprite[sprite][2]);\n };\n\n // End the sound instantly if seek is at the end.\n if (seek >= stop) {\n self._ended(sound);\n return;\n }\n\n // Begin the actual playback.\n var node = sound._node;\n if (self._webAudio) {\n // Fire this when the sound is ready to play to begin Web Audio playback.\n var playWebAudio = function() {\n self._playLock = false;\n setParams();\n self._refreshBuffer(sound);\n\n // Setup the playback params.\n var vol = (sound._muted || self._muted) ? 0 : sound._volume;\n node.gain.setValueAtTime(vol, Howler.ctx.currentTime);\n sound._playStart = Howler.ctx.currentTime;\n\n // Play the sound using the supported method.\n if (typeof node.bufferSource.start === 'undefined') {\n sound._loop ? node.bufferSource.noteGrainOn(0, seek, 86400) : node.bufferSource.noteGrainOn(0, seek, duration);\n } else {\n sound._loop ? node.bufferSource.start(0, seek, 86400) : node.bufferSource.start(0, seek, duration);\n }\n\n // Start a new timer if none is present.\n if (timeout !== Infinity) {\n self._endTimers[sound._id] = setTimeout(self._ended.bind(self, sound), timeout);\n }\n\n if (!internal) {\n setTimeout(function() {\n self._emit('play', sound._id);\n self._loadQueue();\n }, 0);\n }\n };\n\n if (Howler.state === 'running' && Howler.ctx.state !== 'interrupted') {\n playWebAudio();\n } else {\n self._playLock = true;\n\n // Wait for the audio context to resume before playing.\n self.once('resume', playWebAudio);\n\n // Cancel the end timer.\n self._clearTimer(sound._id);\n }\n } else {\n // Fire this when the sound is ready to play to begin HTML5 Audio playback.\n var playHtml5 = function() {\n node.currentTime = seek;\n node.muted = sound._muted || self._muted || Howler._muted || node.muted;\n node.volume = sound._volume * Howler.volume();\n node.playbackRate = sound._rate;\n\n // Some browsers will throw an error if this is called without user interaction.\n try {\n var play = node.play();\n\n // Support older browsers that don't support promises, and thus don't have this issue.\n if (play && typeof Promise !== 'undefined' && (play instanceof Promise || typeof play.then === 'function')) {\n // Implements a lock to prevent DOMException: The play() request was interrupted by a call to pause().\n self._playLock = true;\n\n // Set param values immediately.\n setParams();\n\n // Releases the lock and executes queued actions.\n play\n .then(function() {\n self._playLock = false;\n node._unlocked = true;\n if (!internal) {\n self._emit('play', sound._id);\n } else {\n self._loadQueue();\n }\n })\n .catch(function() {\n self._playLock = false;\n self._emit('playerror', sound._id, 'Playback was unable to start. This is most commonly an issue ' +\n 'on mobile devices and Chrome where playback was not within a user interaction.');\n\n // Reset the ended and paused values.\n sound._ended = true;\n sound._paused = true;\n });\n } else if (!internal) {\n self._playLock = false;\n setParams();\n self._emit('play', sound._id);\n }\n\n // Setting rate before playing won't work in IE, so we set it again here.\n node.playbackRate = sound._rate;\n\n // If the node is still paused, then we can assume there was a playback issue.\n if (node.paused) {\n self._emit('playerror', sound._id, 'Playback was unable to start. This is most commonly an issue ' +\n 'on mobile devices and Chrome where playback was not within a user interaction.');\n return;\n }\n\n // Setup the end timer on sprites or listen for the ended event.\n if (sprite !== '__default' || sound._loop) {\n self._endTimers[sound._id] = setTimeout(self._ended.bind(self, sound), timeout);\n } else {\n self._endTimers[sound._id] = function() {\n // Fire ended on this audio node.\n self._ended(sound);\n\n // Clear this listener.\n node.removeEventListener('ended', self._endTimers[sound._id], false);\n };\n node.addEventListener('ended', self._endTimers[sound._id], false);\n }\n } catch (err) {\n self._emit('playerror', sound._id, err);\n }\n };\n\n // If this is streaming audio, make sure the src is set and load again.\n if (node.src === 'data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA') {\n node.src = self._src;\n node.load();\n }\n\n // Play immediately if ready, or wait for the 'canplaythrough'e vent.\n var loadedNoReadyState = (window && window.ejecta) || (!node.readyState && Howler._navigator.isCocoonJS);\n if (node.readyState >= 3 || loadedNoReadyState) {\n playHtml5();\n } else {\n self._playLock = true;\n self._state = 'loading';\n\n var listener = function() {\n self._state = 'loaded';\n \n // Begin playback.\n playHtml5();\n\n // Clear this listener.\n node.removeEventListener(Howler._canPlayEvent, listener, false);\n };\n node.addEventListener(Howler._canPlayEvent, listener, false);\n\n // Cancel the end timer.\n self._clearTimer(sound._id);\n }\n }\n\n return sound._id;\n },\n\n /**\n * Pause playback and save current position.\n * @param {Number} id The sound ID (empty to pause all in group).\n * @return {Howl}\n */\n pause: function(id) {\n var self = this;\n\n // If the sound hasn't loaded or a play() promise is pending, add it to the load queue to pause when capable.\n if (self._state !== 'loaded' || self._playLock) {\n self._queue.push({\n event: 'pause',\n action: function() {\n self.pause(id);\n }\n });\n\n return self;\n }\n\n // If no id is passed, get all ID's to be paused.\n var ids = self._getSoundIds(id);\n\n for (var i=0; i<ids.length; i++) {\n // Clear the end timer.\n self._clearTimer(ids[i]);\n\n // Get the sound.\n var sound = self._soundById(ids[i]);\n\n if (sound && !sound._paused) {\n // Reset the seek position.\n sound._seek = self.seek(ids[i]);\n sound._rateSeek = 0;\n sound._paused = true;\n\n // Stop currently running fades.\n self._stopFade(ids[i]);\n\n if (sound._node) {\n if (self._webAudio) {\n // Make sure the sound has been created.\n if (!sound._node.bufferSource) {\n continue;\n }\n\n if (typeof sound._node.bufferSource.stop === 'undefined') {\n sound._node.bufferSource.noteOff(0);\n } else {\n sound._node.bufferSource.stop(0);\n }\n\n // Clean up the buffer source.\n self._cleanBuffer(sound._node);\n } else if (!isNaN(sound._node.duration) || sound._node.duration === Infinity) {\n sound._node.pause();\n }\n }\n }\n\n // Fire the pause event, unless `true` is passed as the 2nd argument.\n if (!arguments[1]) {\n self._emit('pause', sound ? sound._id : null);\n }\n }\n\n return self;\n },\n\n /**\n * Stop playback and reset to start.\n * @param {Number} id The sound ID (empty to stop all in group).\n * @param {Boolean} internal Internal Use: true prevents event firing.\n * @return {Howl}\n */\n stop: function(id, internal) {\n var self = this;\n\n // If the sound hasn't loaded, add it to the load queue to stop when capable.\n if (self._state !== 'loaded' || self._playLock) {\n self._queue.push({\n event: 'stop',\n action: function() {\n self.stop(id);\n }\n });\n\n return self;\n }\n\n // If no id is passed, get all ID's to be stopped.\n var ids = self._getSoundIds(id);\n\n for (var i=0; i<ids.length; i++) {\n // Clear the end timer.\n self._clearTimer(ids[i]);\n\n // Get the sound.\n var sound = self._soundById(ids[i]);\n\n if (sound) {\n // Reset the seek position.\n sound._seek = sound._start || 0;\n sound._rateSeek = 0;\n sound._paused = true;\n sound._ended = true;\n\n // Stop currently running fades.\n self._stopFade(ids[i]);\n\n if (sound._node) {\n if (self._webAudio) {\n // Make sure the sound's AudioBufferSourceNode has been created.\n if (sound._node.bufferSource) {\n if (typeof sound._node.bufferSource.stop === 'undefined') {\n sound._node.bufferSource.noteOff(0);\n } else {\n sound._node.bufferSource.stop(0);\n }\n\n // Clean up the buffer source.\n self._cleanBuffer(sound._node);\n }\n } else if (!isNaN(sound._node.duration) || sound._node.duration === Infinity) {\n sound._node.currentTime = sound._start || 0;\n sound._node.pause();\n\n // If this is a live stream, stop download once the audio is stopped.\n if (sound._node.duration === Infinity) {\n self._clearSound(sound._node);\n }\n }\n }\n\n if (!internal) {\n self._emit('stop', sound._id);\n }\n }\n }\n\n return self;\n },\n\n /**\n * Mute/unmute a single sound or all sounds in this Howl group.\n * @param {Boolean} muted Set to true to mute and false to unmute.\n * @param {Number} id The sound ID to update (omit to mute/unmute all).\n * @return {Howl}\n */\n mute: function(muted, id) {\n var self = this;\n\n // If the sound hasn't loaded, add it to the load queue to mute when capable.\n if (self._state !== 'loaded'|| self._playLock) {\n self._queue.push({\n event: 'mute',\n action: function() {\n self.mute(muted, id);\n }\n });\n\n return self;\n }\n\n // If applying mute/unmute to all sounds, update the group's value.\n if (typeof id === 'undefined') {\n if (typeof muted === 'boolean') {\n self._muted = muted;\n } else {\n return self._muted;\n }\n }\n\n // If no id is passed, get all ID's to be muted.\n var ids = self._getSoundIds(id);\n\n for (var i=0; i<ids.length; i++) {\n // Get the sound.\n var sound = self._soundById(ids[i]);\n\n if (sound) {\n sound._muted = muted;\n\n // Cancel active fade and set the volume to the end value.\n if (sound._interval) {\n self._stopFade(sound._id);\n }\n\n if (self._webAudio && sound._node) {\n sound._node.gain.setValueAtTime(muted ? 0 : sound._volume, Howler.ctx.currentTime);\n } else if (sound._node) {\n sound._node.muted = Howler._muted ? true : muted;\n }\n\n self._emit('mute', sound._id);\n }\n }\n\n return self;\n },\n\n /**\n * Get/set the volume of this sound or of the Howl group. This method can optionally take 0, 1 or 2 arguments.\n * volume() -> Returns the group's volume value.\n * volume(id) -> Returns the sound id's current volume.\n * volume(vol) -> Sets the volume of all sounds in this Howl group.\n * volume(vol, id) -> Sets the volume of passed sound id.\n * @return {Howl/Number} Returns self or current volume.\n */\n volume: function() {\n var self = this;\n var args = arguments;\n var vol, id;\n\n // Determine the values based on arguments.\n if (args.length === 0) {\n // Return the value of the groups' volume.\n return self._volume;\n } else if (args.length === 1 || args.length === 2 && typeof args[1] === 'undefined') {\n // First check if this is an ID, and if not, assume it is a new volume.\n var ids = self._getSoundIds();\n var index = ids.indexOf(args[0]);\n if (index >= 0) {\n id = parseInt(args[0], 10);\n } else {\n vol = parseFloat(args[0]);\n }\n } else if (args.length >= 2) {\n vol = parseFloat(args[0]);\n id = parseInt(args[1], 10);\n }\n\n // Update the volume or return the current volume.\n var sound;\n if (typeof vol !== 'undefined' && vol >= 0 && vol <= 1) {\n // If the sound hasn't loaded, add it to the load queue to change volume when capable.\n if (self._state !== 'loaded'|| self._playLock) {\n self._queue.push({\n event: 'volume',\n action: function() {\n self.volume.apply(self, args);\n }\n });\n\n return self;\n }\n\n // Set the group volume.\n if (typeof id === 'undefined') {\n self._volume = vol;\n }\n\n // Update one or all volumes.\n id = self._getSoundIds(id);\n for (var i=0; i<id.length; i++) {\n // Get the sound.\n sound = self._soundById(id[i]);\n\n if (sound) {\n sound._volume = vol;\n\n // Stop currently running fades.\n if (!args[2]) {\n self._stopFade(id[i]);\n }\n\n if (self._webAudio && sound._node && !sound._muted) {\n sound._node.gain.setValueAtTime(vol, Howler.ctx.currentTime);\n } else if (sound._node && !sound._muted) {\n sound._node.volume = vol * Howler.volume();\n }\n\n self._emit('volume', sound._id);\n }\n }\n } else {\n sound = id ? self._soundById(id) : self._sounds[0];\n return sound ? sound._volume : 0;\n }\n\n return self;\n },\n\n /**\n * Fade a currently playing sound between two volumes (if no id is passed, all sounds will fade).\n * @param {Number} from The value to fade from (0.0 to 1.0).\n * @param {Number} to The volume to fade to (0.0 to 1.0).\n * @param {Number} len Time in milliseconds to fade.\n * @param {Number} id The sound id (omit to fade all sounds).\n * @return {Howl}\n */\n fade: function(from, to, len, id) {\n var self = this;\n\n // If the sound hasn't loaded, add it to the load queue to fade when capable.\n if (self._state !== 'loaded' || self._playLock) {\n self._queue.push({\n event: 'fade',\n action: function() {\n self.fade(from, to, len, id);\n }\n });\n\n return self;\n }\n\n // Make sure the to/from/len values are numbers.\n from = Math.min(Math.max(0, parseFloat(from)), 1);\n to = Math.min(Math.max(0, parseFloat(to)), 1);\n len = parseFloat(len);\n\n // Set the volume to the start position.\n self.volume(from, id);\n\n // Fade the volume of one or all sounds.\n var ids = self._getSoundIds(id);\n for (var i=0; i<ids.length; i++) {\n // Get the sound.\n var sound = self._soundById(ids[i]);\n\n // Create a linear fade or fall back to timeouts with HTML5 Audio.\n if (sound) {\n // Stop the previous fade if no sprite is being used (otherwise, volume handles this).\n if (!id) {\n self._stopFade(ids[i]);\n }\n\n // If we are using Web Audio, let the native methods do the actual fade.\n if (self._webAudio && !sound._muted) {\n var currentTime = Howler.ctx.currentTime;\n var end = currentTime + (len / 1000);\n sound._volume = from;\n sound._node.gain.setValueAtTime(from, currentTime);\n sound._node.gain.linearRampToValueAtTime(to, end);\n }\n\n self._startFadeInterval(sound, from, to, len, ids[i], typeof id === 'undefined');\n }\n }\n\n return self;\n },\n\n /**\n * Starts the internal interval to fade a sound.\n * @param {Object} sound Reference to sound to fade.\n * @param {Number} from The value to fade from (0.0 to 1.0).\n * @param {Number} to The volume to fade to (0.0 to 1.0).\n * @param {Number} len Time in milliseconds to fade.\n * @param {Number} id The sound id to fade.\n * @param {Boolean} isGroup If true, set the volume on the group.\n */\n _startFadeInterval: function(sound, from, to, len, id, isGroup) {\n var self = this;\n var vol = from;\n var diff = to - from;\n var steps = Math.abs(diff / 0.01);\n var stepLen = Math.max(4, (steps > 0) ? len / steps : len);\n var lastTick = Date.now();\n\n // Store the value being faded to.\n sound._fadeTo = to;\n\n // Update the volume value on each interval tick.\n sound._interval = setInterval(function() {\n // Update the volume based on the time since the last tick.\n var tick = (Date.now() - lastTick) / len;\n lastTick = Date.now();\n vol += diff * tick;\n\n // Round to within 2 decimal points.\n vol = Math.round(vol * 100) / 100;\n\n // Make sure the volume is in the right bounds.\n if (diff < 0) {\n vol = Math.max(to, vol);\n } else {\n vol = Math.min(to, vol);\n }\n\n // Change the volume.\n if (self._webAudio) {\n sound._volume = vol;\n } else {\n self.volume(vol, sound._id, true);\n }\n\n // Set the group's volume.\n if (isGroup) {\n self._volume = vol;\n }\n\n // When the fade is complete, stop it and fire event.\n if ((to < from && vol <= to) || (to > from && vol >= to)) {\n clearInterval(sound._interval);\n sound._interval = null;\n sound._fadeTo = null;\n self.volume(to, sound._id);\n self._emit('fade', sound._id);\n }\n }, stepLen);\n },\n\n /**\n * Internal method that stops the currently playing fade when\n * a new fade starts, volume is changed or the sound is stopped.\n * @param {Number} id The sound id.\n * @return {Howl}\n */\n _stopFade: function(id) {\n var self = this;\n var sound = self._soundById(id);\n\n if (sound && sound._interval) {\n if (self._webAudio) {\n sound._node.gain.cancelScheduledValues(Howler.ctx.currentTime);\n }\n\n clearInterval(sound._interval);\n sound._interval = null;\n self.volume(sound._fadeTo, id);\n sound._fadeTo = null;\n self._emit('fade', id);\n }\n\n return self;\n },\n\n /**\n * Get/set the loop parameter on a sound. This method can optionally take 0, 1 or 2 arguments.\n * loop() -> Returns the group's loop value.\n * loop(id) -> Returns the sound id's loop value.\n * loop(loop) -> Sets the loop value for all sounds in this Howl group.\n * loop(loop, id) -> Sets the loop value of passed sound id.\n * @return {Howl/Boolean} Returns self or current loop value.\n */\n loop: function() {\n var self = this;\n var args = arguments;\n var loop, id, sound;\n\n // Determine the values for loop and id.\n if (args.length === 0) {\n // Return the grou's loop value.\n return self._loop;\n } else if (args.length === 1) {\n if (typeof args[0] === 'boolean') {\n loop = args[0];\n self._loop = loop;\n } else {\n // Return this sound's loop value.\n sound = self._soundById(parseInt(args[0], 10));\n return sound ? sound._loop : false;\n }\n } else if (args.length === 2) {\n loop = args[0];\n id = parseInt(args[1], 10);\n }\n\n // If no id is passed, get all ID's to be looped.\n var ids = self._getSoundIds(id);\n for (var i=0; i<ids.length; i++) {\n sound = self._soundById(ids[i]);\n\n if (sound) {\n sound._loop = loop;\n if (self._webAudio && sound._node && sound._node.bufferSource) {\n sound._node.bufferSource.loop = loop;\n if (loop) {\n sound._node.bufferSource.loopStart = sound._start || 0;\n sound._node.bufferSource.loopEnd = sound._stop;\n\n // If playing, restart playback to ensure looping updates.\n if (self.playing(ids[i])) {\n self.pause(ids[i], true);\n self.play(ids[i], true);\n }\n }\n }\n }\n }\n\n return self;\n },\n\n /**\n * Get/set the playback rate of a sound. This method can optionally take 0, 1 or 2 arguments.\n * rate() -> Returns the first sound node's current playback rate.\n * rate(id) -> Returns the sound id's current playback rate.\n * rate(rate) -> Sets the playback rate of all sounds in this Howl group.\n * rate(rate, id) -> Sets the playback rate of passed sound id.\n * @return {Howl/Number} Returns self or the current playback rate.\n */\n rate: function() {\n var self = this;\n var args = arguments;\n var rate, id;\n\n // Determine the values based on arguments.\n if (args.length === 0) {\n // We will simply return the current rate of the first node.\n id = self._sounds[0]._id;\n } else if (args.length === 1) {\n // First check if this is an ID, and if not, assume it is a new rate value.\n var ids = self._getSoundIds();\n var index = ids.indexOf(args[0]);\n if (index >= 0) {\n id = parseInt(args[0], 10);\n } else {\n rate = parseFloat(args[0]);\n }\n } else if (args.length === 2) {\n rate = parseFloat(args[0]);\n id = parseInt(args[1], 10);\n }\n\n // Update the playback rate or return the current value.\n var sound;\n if (typeof rate === 'number') {\n // If the sound hasn't loaded, add it to the load queue to change playback rate when capable.\n if (self._state !== 'loaded' || self._playLock) {\n self._queue.push({\n event: 'rate',\n action: function() {\n self.rate.apply(self, args);\n }\n });\n\n return self;\n }\n\n // Set the group rate.\n if (typeof id === 'undefined') {\n self._rate = rate;\n }\n\n // Update one or all volumes.\n id = self._getSoundIds(id);\n for (var i=0; i<id.length; i++) {\n // Get the sound.\n sound = self._soundById(id[i]);\n\n if (sound) {\n // Keep track of our position when the rate changed and update the playback\n // start position so we can properly adjust the seek position for time elapsed.\n if (self.playing(id[i])) {\n sound._rateSeek = self.seek(id[i]);\n sound._playStart = self._webAudio ? Howler.ctx.currentTime : sound._playStart;\n }\n sound._rate = rate;\n\n // Change the playback rate.\n if (self._webAudio && sound._node && sound._node.bufferSource) {\n sound._node.bufferSource.playbackRate.setValueAtTime(rate, Howler.ctx.currentTime);\n } else if (sound._node) {\n sound._node.playbackRate = rate;\n }\n\n // Reset the timers.\n var seek = self.seek(id[i]);\n var duration = ((self._sprite[sound._sprite][0] + self._sprite[sound._sprite][1]) / 1000) - seek;\n var timeout = (duration * 1000) / Math.abs(sound._rate);\n\n // Start a new end timer if sound is already playing.\n if (self._endTimers[id[i]] || !sound._paused) {\n self._clearTimer(id[i]);\n self._endTimers[id[i]] = setTimeout(self._ended.bind(self, sound), timeout);\n }\n\n self._emit('rate', sound._id);\n }\n }\n } else {\n sound = self._soundById(id);\n return sound ? sound._rate : self._rate;\n }\n\n return self;\n },\n\n /**\n * Get/set the seek position of a sound. This method can optionally take 0, 1 or 2 arguments.\n * seek() -> Returns the first sound node's current seek position.\n * seek(id) -> Returns the sound id's current seek position.\n * seek(seek) -> Sets the seek position of the first sound node.\n * seek(seek, id) -> Sets the seek position of passed sound id.\n * @return {Howl/Number} Returns self or the current seek position.\n */\n seek: function() {\n var self = this;\n var args = arguments;\n var seek, id;\n\n // Determine the values based on arguments.\n if (args.length === 0) {\n // We will simply return the current position of the first node.\n if (self._sounds.length) {\n id = self._sounds[0]._id;\n }\n } else if (args.length === 1) {\n // First check if this is an ID, and if not, assume it is a new seek position.\n var ids = self._getSoundIds();\n var index = ids.indexOf(args[0]);\n if (index >= 0) {\n id = parseInt(args[0], 10);\n } else if (self._sounds.length) {\n id = self._sounds[0]._id;\n seek = parseFloat(args[0]);\n }\n } else if (args.length === 2) {\n seek = parseFloat(args[0]);\n id = parseInt(args[1], 10);\n }\n\n // If there is no ID, bail out.\n if (typeof id === 'undefined') {\n return 0;\n }\n\n // If the sound hasn't loaded, add it to the load queue to seek when capable.\n if (typeof seek === 'number' && (self._state !== 'loaded' || self._playLock)) {\n self._queue.push({\n event: 'seek',\n action: function() {\n self.seek.apply(self, args);\n }\n });\n\n return self;\n }\n\n // Get the sound.\n var sound = self._soundById(id);\n\n if (sound) {\n if (typeof seek === 'number' && seek >= 0) {\n // Pause the sound and update position for restarting playback.\n var playing = self.playing(id);\n if (playing) {\n self.pause(id, true);\n }\n\n // Move the position of the track and cancel timer.\n sound._seek = seek;\n sound._ended = false;\n self._clearTimer(id);\n\n // Update the seek position for HTML5 Audio.\n if (!self._webAudio && sound._node && !isNaN(sound._node.duration)) {\n sound._node.currentTime = seek;\n }\n\n // Seek and emit when ready.\n var seekAndEmit = function() {\n // Restart the playback if the sound was playing.\n if (playing) {\n self.play(id, true);\n }\n\n self._emit('seek', id);\n };\n\n // Wait for the play lock to be unset before emitting (HTML5 Audio).\n if (playing && !self._webAudio) {\n var emitSeek = function() {\n if (!self._playLock) {\n seekAndEmit();\n } else {\n setTimeout(emitSeek, 0);\n }\n };\n setTimeout(emitSeek, 0);\n } else {\n seekAndEmit();\n }\n } else {\n if (self._webAudio) {\n var realTime = self.playing(id) ? Howler.ctx.currentTime - sound._playStart : 0;\n var rateSeek = sound._rateSeek ? sound._rateSeek - sound._seek : 0;\n return sound._seek + (rateSeek + realTime * Math.abs(sound._rate));\n } else {\n return sound._node.currentTime;\n }\n }\n }\n\n return self;\n },\n\n /**\n * Check if a specific sound is currently playing or not (if id is provided), or check if at least one of the sounds in the group is playing or not.\n * @param {Number} id The sound id to check. If none is passed, the whole sound group is checked.\n * @return {Boolean} True if playing and false if not.\n */\n playing: function(id) {\n var self = this;\n\n // Check the passed sound ID (if any).\n if (typeof id === 'number') {\n var sound = self._soundById(id);\n return sound ? !sound._paused : false;\n }\n\n // Otherwise, loop through all sounds and check if any are playing.\n for (var i=0; i<self._sounds.length; i++) {\n if (!self._sounds[i]._paused) {\n return true;\n }\n }\n\n return false;\n },\n\n /**\n * Get the duration of this sound. Passing a sound id will return the sprite duration.\n * @param {Number} id The sound id to check. If none is passed, return full source duration.\n * @return {Number} Audio duration in seconds.\n */\n duration: function(id) {\n var self = this;\n var duration = self._duration;\n\n // If we pass an ID, get the sound and return the sprite length.\n var sound = self._soundById(id);\n if (sound) {\n duration = self._sprite[sound._sprite][1] / 1000;\n }\n\n return duration;\n },\n\n /**\n * Returns the current loaded state of this Howl.\n * @return {String} 'unloaded', 'loading', 'loaded'\n */\n state: function() {\n return this._state;\n },\n\n /**\n * Unload and destroy the current Howl object.\n * This will immediately stop all sound instances attached to this group.\n */\n unload: function() {\n var self = this;\n\n // Stop playing any active sounds.\n var sounds = self._sounds;\n for (var i=0; i<sounds.length; i++) {\n // Stop the sound if it is currently playing.\n if (!sounds[i]._paused) {\n self.stop(sounds[i]._id);\n }\n\n // Remove the source or disconnect.\n if (!self._webAudio) {\n // Set the source to 0-second silence to stop any downloading (except in IE).\n self._clearSound(sounds[i]._node);\n\n // Remove any event listeners.\n sounds[i]._node.removeEventListener('error', sounds[i]._errorFn, false);\n sounds[i]._node.removeEventListener(Howler._canPlayEvent, sounds[i]._loadFn, false);\n sounds[i]._node.removeEventListener('ended', sounds[i]._endFn, false);\n\n // Release the Audio object back to the pool.\n Howler._releaseHtml5Audio(sounds[i]._node);\n }\n\n // Empty out all of the nodes.\n delete sounds[i]._node;\n\n // Make sure all timers are cleared out.\n self._clearTimer(sounds[i]._id);\n }\n\n // Remove the references in the global Howler object.\n var index = Howler._howls.indexOf(self);\n if (index >= 0) {\n Howler._howls.splice(index, 1);\n }\n\n // Delete this sound from the cache (if no other Howl is using it).\n var remCache = true;\n for (i=0; i<Howler._howls.length; i++) {\n if (Howler._howls[i]._src === self._src || self._src.indexOf(Howler._howls[i]._src) >= 0) {\n remCache = false;\n break;\n }\n }\n\n if (cache && remCache) {\n delete cache[self._src];\n }\n\n // Clear global errors.\n Howler.noAudio = false;\n\n // Clear out `self`.\n self._state = 'unloaded';\n self._sounds = [];\n self = null;\n\n return null;\n },\n\n /**\n * Listen to a custom event.\n * @param {String} event Event name.\n * @param {Function} fn Listener to call.\n * @param {Number} id (optional) Only listen to events for this sound.\n * @param {Number} once (INTERNAL) Marks event to fire only once.\n * @return {Howl}\n */\n on: function(event, fn, id, once) {\n var self = this;\n var events = self['_on' + event];\n\n if (typeof fn === 'function') {\n events.push(once ? {id: id, fn: fn, once: once} : {id: id, fn: fn});\n }\n\n return self;\n },\n\n /**\n * Remove a custom event. Call without parameters to remove all events.\n * @param {String} event Event name.\n * @param {Function} fn Listener to remove. Leave empty to remove all.\n * @param {Number} id (optional) Only remove events for this sound.\n * @return {Howl}\n */\n off: function(event, fn, id) {\n var self = this;\n var events = self['_on' + event];\n var i = 0;\n\n // Allow passing just an event and ID.\n if (typeof fn === 'number') {\n id = fn;\n fn = null;\n }\n\n if (fn || id) {\n // Loop through event store and remove the passed function.\n for (i=0; i<events.length; i++) {\n var isId = (id === events[i].id);\n if (fn === events[i].fn && isId || !fn && isId) {\n events.splice(i, 1);\n break;\n }\n }\n } else if (event) {\n // Clear out all events of this type.\n self['_on' + event] = [];\n } else {\n // Clear out all events of every type.\n var keys = Object.keys(self);\n for (i=0; i<keys.length; i++) {\n if ((keys[i].indexOf('_on') === 0) && Array.isArray(self[keys[i]])) {\n self[keys[i]] = [];\n }\n }\n }\n\n return self;\n },\n\n /**\n * Listen to a custom event and remove it once fired.\n * @param {String} event Event name.\n * @param {Function} fn Listener to call.\n * @param {Number} id (optional) Only listen to events for this sound.\n * @return {Howl}\n */\n once: function(event, fn, id) {\n var self = this;\n\n // Setup the event listener.\n self.on(event, fn, id, 1);\n\n return self;\n },\n\n /**\n * Emit all events of a specific type and pass the sound id.\n * @param {String} event Event name.\n * @param {Number} id Sound ID.\n * @param {Number} msg Message to go with event.\n * @return {Howl}\n */\n _emit: function(event, id, msg) {\n var self = this;\n var events = self['_on' + event];\n\n // Loop through event store and fire all functions.\n for (var i=events.length-1; i>=0; i--) {\n // Only fire the listener if the correct ID is used.\n if (!events[i].id || events[i].id === id || event === 'load') {\n setTimeout(function(fn) {\n fn.call(this, id, msg);\n }.bind(self, events[i].fn), 0);\n\n // If this event was setup with `once`, remove it.\n if (events[i].once) {\n self.off(event, events[i].fn, events[i].id);\n }\n }\n }\n\n // Pass the event type into load queue so that it can continue stepping.\n self._loadQueue(event);\n\n return self;\n },\n\n /**\n * Queue of actions initiated before the sound has loaded.\n * These will be called in sequence, with the next only firing\n * after the previous has finished executing (even if async like play).\n * @return {Howl}\n */\n _loadQueue: function(event) {\n var self = this;\n\n if (self._queue.length > 0) {\n var task = self._queue[0];\n\n // Remove this task if a matching event was passed.\n if (task.event === event) {\n self._queue.shift();\n self._loadQueue();\n }\n\n // Run the task if no event type is passed.\n if (!event) {\n task.action();\n }\n }\n\n return self;\n },\n\n /**\n * Fired when playback ends at the end of the duration.\n * @param {Sound} sound The sound object to work with.\n * @return {Howl}\n */\n _ended: function(sound) {\n var self = this;\n var sprite = sound._sprite;\n\n // If we are using IE and there was network latency we may be clipping\n // audio before it completes playing. Lets check the node to make sure it\n // believes it has completed, before ending the playback.\n if (!self._webAudio && sound._node && !sound._node.paused && !sound._node.ended && sound._node.currentTime < sound._stop) {\n setTimeout(self._ended.bind(self, sound), 100);\n return self;\n }\n\n // Should this sound loop?\n var loop = !!(sound._loop || self._sprite[sprite][2]);\n\n // Fire the ended event.\n self._emit('end', sound._id);\n\n // Restart the playback for HTML5 Audio loop.\n if (!self._webAudio && loop) {\n self.stop(sound._id, true).play(sound._id);\n }\n\n // Restart this timer if on a Web Audio loop.\n if (self._webAudio && loop) {\n self._emit('play', sound._id);\n sound._seek = sound._start || 0;\n sound._rateSeek = 0;\n sound._playStart = Howler.ctx.currentTime;\n\n var timeout = ((sound._stop - sound._start) * 1000) / Math.abs(sound._rate);\n self._endTimers[sound._id] = setTimeout(self._ended.bind(self, sound), timeout);\n }\n\n // Mark the node as paused.\n if (self._webAudio && !loop) {\n sound._paused = true;\n sound._ended = true;\n sound._seek = sound._start || 0;\n sound._rateSeek = 0;\n self._clearTimer(sound._id);\n\n // Clean up the buffer source.\n self._cleanBuffer(sound._node);\n\n // Attempt to auto-suspend AudioContext if no sounds are still playing.\n Howler._autoSuspend();\n }\n\n // When using a sprite, end the track.\n if (!self._webAudio && !loop) {\n self.stop(sound._id, true);\n }\n\n return self;\n },\n\n /**\n * Clear the end timer for a sound playback.\n * @param {Number} id The sound ID.\n * @return {Howl}\n */\n _clearTimer: function(id) {\n var self = this;\n\n if (self._endTimers[id]) {\n // Clear the timeout or remove the ended listener.\n if (typeof self._endTimers[id] !== 'function') {\n clearTimeout(self._endTimers[id]);\n } else {\n var sound = self._soundById(id);\n if (sound && sound._node) {\n sound._node.removeEventListener('ended', self._endTimers[id], false);\n }\n }\n\n delete self._endTimers[id];\n }\n\n return self;\n },\n\n /**\n * Return the sound identified by this ID, or return null.\n * @param {Number} id Sound ID\n * @return {Object} Sound object or null.\n */\n _soundById: function(id) {\n var self = this;\n\n // Loop through all sounds and find the one with this ID.\n for (var i=0; i<self._sounds.length; i++) {\n if (id === self._sounds[i]._id) {\n return self._sounds[i];\n }\n }\n\n return null;\n },\n\n /**\n * Return an inactive sound from the pool or create a new one.\n * @return {Sound} Sound playback object.\n */\n _inactiveSound: function() {\n var self = this;\n\n self._drain();\n\n // Find the first inactive node to recycle.\n for (var i=0; i<self._sounds.length; i++) {\n if (self._sounds[i]._ended) {\n return self._sounds[i].reset();\n }\n }\n\n // If no inactive node was found, create a new one.\n return new Sound(self);\n },\n\n /**\n * Drain excess inactive sounds from the pool.\n */\n _drain: function() {\n var self = this;\n var limit = self._pool;\n var cnt = 0;\n var i = 0;\n\n // If there are less sounds than the max pool size, we are done.\n if (self._sounds.length < limit) {\n return;\n }\n\n // Count the number of inactive sounds.\n for (i=0; i<self._sounds.length; i++) {\n if (self._sounds[i]._ended) {\n cnt++;\n }\n }\n\n // Remove excess inactive sounds, going in reverse order.\n for (i=self._sounds.length - 1; i>=0; i--) {\n if (cnt <= limit) {\n return;\n }\n\n if (self._sounds[i]._ended) {\n // Disconnect the audio source when using Web Audio.\n if (self._webAudio && self._sounds[i]._node) {\n self._sounds[i]._node.disconnect(0);\n }\n\n // Remove sounds until we have the pool size.\n self._sounds.splice(i, 1);\n cnt--;\n }\n }\n },\n\n /**\n * Get all ID's from the sounds pool.\n * @param {Number} id Only return one ID if one is passed.\n * @return {Array} Array of IDs.\n */\n _getSoundIds: function(id) {\n var self = this;\n\n if (typeof id === 'undefined') {\n var ids = [];\n for (var i=0; i<self._sounds.length; i++) {\n ids.push(self._sounds[i]._id);\n }\n\n return ids;\n } else {\n return [id];\n }\n },\n\n /**\n * Load the sound back into the buffer source.\n * @param {Sound} sound The sound object to work with.\n * @return {Howl}\n */\n _refreshBuffer: function(sound) {\n var self = this;\n\n // Setup the buffer source for playback.\n sound._node.bufferSource = Howler.ctx.createBufferSource();\n sound._node.bufferSource.buffer = cache[self._src];\n\n // Connect to the correct node.\n if (sound._panner) {\n sound._node.bufferSource.connect(sound._panner);\n } else {\n sound._node.bufferSource.connect(sound._node);\n }\n\n // Setup looping and playback rate.\n sound._node.bufferSource.loop = sound._loop;\n if (sound._loop) {\n sound._node.bufferSource.loopStart = sound._start || 0;\n sound._node.bufferSource.loopEnd = sound._stop || 0;\n }\n sound._node.bufferSource.playbackRate.setValueAtTime(sound._rate, Howler.ctx.currentTime);\n\n return self;\n },\n\n /**\n * Prevent memory leaks by cleaning up the buffer source after playback.\n * @param {Object} node Sound's audio node containing the buffer source.\n * @return {Howl}\n */\n _cleanBuffer: function(node) {\n var self = this;\n var isIOS = Howler._navigator && Howler._navigator.vendor.indexOf('Apple') >= 0;\n\n if (Howler._scratchBuffer && node.bufferSource) {\n node.bufferSource.onended = null;\n node.bufferSource.disconnect(0);\n if (isIOS) {\n try { node.bufferSource.buffer = Howler._scratchBuffer; } catch(e) {}\n }\n }\n node.bufferSource = null;\n\n return self;\n },\n\n /**\n * Set the source to a 0-second silence to stop any downloading (except in IE).\n * @param {Object} node Audio node to clear.\n */\n _clearSound: function(node) {\n var checkIE = /MSIE |Trident\\//.test(Howler._navigator && Howler._navigator.userAgent);\n if (!checkIE) {\n node.src = 'data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA';\n }\n }\n };\n\n /** Single Sound Methods **/\n /***************************************************************************/\n\n /**\n * Setup the sound object, which each node attached to a Howl group is contained in.\n * @param {Object} howl The Howl parent group.\n */\n var Sound = function(howl) {\n this._parent = howl;\n this.init();\n };\n Sound.prototype = {\n /**\n * Initialize a new Sound object.\n * @return {Sound}\n */\n init: function() {\n var self = this;\n var parent = self._parent;\n\n // Setup the default parameters.\n self._muted = parent._muted;\n self._loop = parent._loop;\n self._volume = parent._volume;\n self._rate = parent._rate;\n self._seek = 0;\n self._paused = true;\n self._ended = true;\n self._sprite = '__default';\n\n // Generate a unique ID for this sound.\n self._id = ++Howler._counter;\n\n // Add itself to the parent's pool.\n parent._sounds.push(self);\n\n // Create the new node.\n self.create();\n\n return self;\n },\n\n /**\n * Create and setup a new sound object, whether HTML5 Audio or Web Audio.\n * @return {Sound}\n */\n create: function() {\n var self = this;\n var parent = self._parent;\n var volume = (Howler._muted || self._muted || self._parent._muted) ? 0 : self._volume;\n\n if (parent._webAudio) {\n // Create the gain node for controlling volume (the source will connect to this).\n self._node = (typeof Howler.ctx.createGain === 'undefined') ? Howler.ctx.createGainNode() : Howler.ctx.createGain();\n self._node.gain.setValueAtTime(volume, Howler.ctx.currentTime);\n self._node.paused = true;\n self._node.connect(Howler.masterGain);\n } else if (!Howler.noAudio) {\n // Get an unlocked Audio object from the pool.\n self._node = Howler._obtainHtml5Audio();\n\n // Listen for errors (http://dev.w3.org/html5/spec-author-view/spec.html#mediaerror).\n self._errorFn = self._errorListener.bind(self);\n self._node.addEventListener('error', self._errorFn, false);\n\n // Listen for 'canplaythrough' event to let us know the sound is ready.\n self._loadFn = self._loadListener.bind(self);\n self._node.addEventListener(Howler._canPlayEvent, self._loadFn, false);\n\n // Listen for the 'ended' event on the sound to account for edge-case where\n // a finite sound has a duration of Infinity.\n self._endFn = self._endListener.bind(self);\n self._node.addEventListener('ended', self._endFn, false);\n\n // Setup the new audio node.\n self._node.src = parent._src;\n self._node.preload = parent._preload === true ? 'auto' : parent._preload;\n self._node.volume = volume * Howler.volume();\n\n // Begin loading the source.\n self._node.load();\n }\n\n return self;\n },\n\n /**\n * Reset the parameters of this sound to the original state (for recycle).\n * @return {Sound}\n */\n reset: function() {\n var self = this;\n var parent = self._parent;\n\n // Reset all of the parameters of this sound.\n self._muted = parent._muted;\n self._loop = parent._loop;\n self._volume = parent._volume;\n self._rate = parent._rate;\n self._seek = 0;\n self._rateSeek = 0;\n self._paused = true;\n self._ended = true;\n self._sprite = '__default';\n\n // Generate a new ID so that it isn't confused with the previous sound.\n self._id = ++Howler._counter;\n\n return self;\n },\n\n /**\n * HTML5 Audio error listener callback.\n */\n _errorListener: function() {\n var self = this;\n\n // Fire an error event and pass back the code.\n self._parent._emit('loaderror', self._id, self._node.error ? self._node.error.code : 0);\n\n // Clear the event listener.\n self._node.removeEventListener('error', self._errorFn, false);\n },\n\n /**\n * HTML5 Audio canplaythrough listener callback.\n */\n _loadListener: function() {\n var self = this;\n var parent = self._parent;\n\n // Round up the duration to account for the lower precision in HTML5 Audio.\n parent._duration = Math.ceil(self._node.duration * 10) / 10;\n\n // Setup a sprite if none is defined.\n if (Object.keys(parent._sprite).length === 0) {\n parent._sprite = {__default: [0, parent._duration * 1000]};\n }\n\n if (parent._state !== 'loaded') {\n parent._state = 'loaded';\n parent._emit('load');\n parent._loadQueue();\n }\n\n // Clear the event listener.\n self._node.removeEventListener(Howler._canPlayEvent, self._loadFn, false);\n },\n\n /**\n * HTML5 Audio ended listener callback.\n */\n _endListener: function() {\n var self = this;\n var parent = self._parent;\n\n // Only handle the `ended`` event if the duration is Infinity.\n if (parent._duration === Infinity) {\n // Update the parent duration to match the real audio duration.\n // Round up the duration to account for the lower precision in HTML5 Audio.\n parent._duration = Math.ceil(self._node.duration * 10) / 10;\n\n // Update the sprite that corresponds to the real duration.\n if (parent._sprite.__default[1] === Infinity) {\n parent._sprite.__default[1] = parent._duration * 1000;\n }\n\n // Run the regular ended method.\n parent._ended(self);\n }\n\n // Clear the event listener since the duration is now correct.\n self._node.removeEventListener('ended', self._endFn, false);\n }\n };\n\n /** Helper Methods **/\n /***************************************************************************/\n\n var cache = {};\n\n /**\n * Buffer a sound from URL, Data URI or cache and decode to audio source (Web Audio API).\n * @param {Howl} self\n */\n var loadBuffer = function(self) {\n var url = self._src;\n\n // Check if the buffer has already been cached and use it instead.\n if (cache[url]) {\n // Set the duration from the cache.\n self._duration = cache[url].duration;\n\n // Load the sound into this Howl.\n loadSound(self);\n\n return;\n }\n\n if (/^data:[^;]+;base64,/.test(url)) {\n // Decode the base64 data URI without XHR, since some browsers don't support it.\n var data = atob(url.split(',')[1]);\n var dataView = new Uint8Array(data.length);\n for (var i=0; i<data.length; ++i) {\n dataView[i] = data.charCodeAt(i);\n }\n\n decodeAudioData(dataView.buffer, self);\n } else {\n // Load the buffer from the URL.\n var xhr = new XMLHttpRequest();\n xhr.open(self._xhr.method, url, true);\n xhr.withCredentials = self._xhr.withCredentials;\n xhr.responseType = 'arraybuffer';\n\n // Apply any custom headers to the request.\n if (self._xhr.headers) {\n Object.keys(self._xhr.headers).forEach(function(key) {\n xhr.setRequestHeader(key, self._xhr.headers[key]);\n });\n }\n\n xhr.onload = function() {\n // Make sure we get a successful response back.\n var code = (xhr.status + '')[0];\n if (code !== '0' && code !== '2' && code !== '3') {\n self._emit('loaderror', null, 'Failed loading audio file with status: ' + xhr.status + '.');\n return;\n }\n\n decodeAudioData(xhr.response, self);\n };\n xhr.onerror = function() {\n // If there is an error, switch to HTML5 Audio.\n if (self._webAudio) {\n self._html5 = true;\n self._webAudio = false;\n self._sounds = [];\n delete cache[url];\n self.load();\n }\n };\n safeXhrSend(xhr);\n }\n };\n\n /**\n * Send the XHR request wrapped in a try/catch.\n * @param {Object} xhr XHR to send.\n */\n var safeXhrSend = function(xhr) {\n try {\n xhr.send();\n } catch (e) {\n xhr.onerror();\n }\n };\n\n /**\n * Decode audio data from an array buffer.\n * @param {ArrayBuffer} arraybuffer The audio data.\n * @param {Howl} self\n */\n var decodeAudioData = function(arraybuffer, self) {\n // Fire a load error if something broke.\n var error = function() {\n self._emit('loaderror', null, 'Decoding audio data failed.');\n };\n\n // Load the sound on success.\n var success = function(buffer) {\n if (buffer && self._sounds.length > 0) {\n cache[self._src] = buffer;\n loadSound(self, buffer);\n } else {\n error();\n }\n };\n\n // Decode the buffer into an audio source.\n if (typeof Promise !== 'undefined' && Howler.ctx.decodeAudioData.length === 1) {\n Howler.ctx.decodeAudioData(arraybuffer).then(success).catch(error);\n } else {\n Howler.ctx.decodeAudioData(arraybuffer, success, error);\n }\n }\n\n /**\n * Sound is now loaded, so finish setting everything up and fire the loaded event.\n * @param {Howl} self\n * @param {Object} buffer The decoded buffer sound source.\n */\n var loadSound = function(self, buffer) {\n // Set the duration.\n if (buffer && !self._duration) {\n self._duration = buffer.duration;\n }\n\n // Setup a sprite if none is defined.\n if (Object.keys(self._sprite).length === 0) {\n self._sprite = {__default: [0, self._duration * 1000]};\n }\n\n // Fire the loaded event.\n if (self._state !== 'loaded') {\n self._state = 'loaded';\n self._emit('load');\n self._loadQueue();\n }\n };\n\n /**\n * Setup the audio context when available, or switch to HTML5 Audio mode.\n */\n var setupAudioContext = function() {\n // If we have already detected that Web Audio isn't supported, don't run this step again.\n if (!Howler.usingWebAudio) {\n return;\n }\n\n // Check if we are using Web Audio and setup the AudioContext if we are.\n try {\n if (typeof AudioContext !== 'undefined') {\n Howler.ctx = new AudioContext();\n } else if (typeof webkitAudioContext !== 'undefined') {\n Howler.ctx = new webkitAudioContext();\n } else {\n Howler.usingWebAudio = false;\n }\n } catch(e) {\n Howler.usingWebAudio = false;\n }\n\n // If the audio context creation still failed, set using web audio to false.\n if (!Howler.ctx) {\n Howler.usingWebAudio = false;\n }\n\n // Check if a webview is being used on iOS8 or earlier (rather than the browser).\n // If it is, disable Web Audio as it causes crashing.\n var iOS = (/iP(hone|od|ad)/.test(Howler._navigator && Howler._navigator.platform));\n var appVersion = Howler._navigator && Howler._navigator.appVersion.match(/OS (\\d+)_(\\d+)_?(\\d+)?/);\n var version = appVersion ? parseInt(appVersion[1], 10) : null;\n if (iOS && version && version < 9) {\n var safari = /safari/.test(Howler._navigator && Howler._navigator.userAgent.toLowerCase());\n if (Howler._navigator && !safari) {\n Howler.usingWebAudio = false;\n }\n }\n\n // Create and expose the master GainNode when using Web Audio (useful for plugins or advanced usage).\n if (Howler.usingWebAudio) {\n Howler.masterGain = (typeof Howler.ctx.createGain === 'undefined') ? Howler.ctx.createGainNode() : Howler.ctx.createGain();\n Howler.masterGain.gain.setValueAtTime(Howler._muted ? 0 : Howler._volume, Howler.ctx.currentTime);\n Howler.masterGain.connect(Howler.ctx.destination);\n }\n\n // Re-run the setup on Howler.\n Howler._setup();\n };\n\n // Add support for AMD (Asynchronous Module Definition) libraries such as require.js.\n if (typeof define === 'function' && define.amd) {\n define([], function() {\n return {\n Howler: Howler,\n Howl: Howl\n };\n });\n }\n\n // Add support for CommonJS libraries such as browserify.\n if (typeof exports !== 'undefined') {\n exports.Howler = Howler;\n exports.Howl = Howl;\n }\n\n // Add to global in Node.js (for testing, etc).\n if (typeof global !== 'undefined') {\n global.HowlerGlobal = HowlerGlobal;\n global.Howler = Howler;\n global.Howl = Howl;\n global.Sound = Sound;\n } else if (typeof window !== 'undefined') { // Define globally in case AMD is not available or unused.\n window.HowlerGlobal = HowlerGlobal;\n window.Howler = Howler;\n window.Howl = Howl;\n window.Sound = Sound;\n }\n})();\n\n\n/*!\n * Spatial Plugin - Adds support for stereo and 3D audio where Web Audio is supported.\n * \n * howler.js v2.2.3\n * howlerjs.com\n *\n * (c) 2013-2020, James Simpson of GoldFire Studios\n * goldfirestudios.com\n *\n * MIT License\n */\n\n(function() {\n\n 'use strict';\n\n // Setup default properties.\n HowlerGlobal.prototype._pos = [0, 0, 0];\n HowlerGlobal.prototype._orientation = [0, 0, -1, 0, 1, 0];\n\n /** Global Methods **/\n /***************************************************************************/\n\n /**\n * Helper method to update the stereo panning position of all current Howls.\n * Future Howls will not use this value unless explicitly set.\n * @param {Number} pan A value of -1.0 is all the way left and 1.0 is all the way right.\n * @return {Howler/Number} Self or current stereo panning value.\n */\n HowlerGlobal.prototype.stereo = function(pan) {\n var self = this;\n\n // Stop right here if not using Web Audio.\n if (!self.ctx || !self.ctx.listener) {\n return self;\n }\n\n // Loop through all Howls and update their stereo panning.\n for (var i=self._howls.length-1; i>=0; i--) {\n self._howls[i].stereo(pan);\n }\n\n return self;\n };\n\n /**\n * Get/set the position of the listener in 3D cartesian space. Sounds using\n * 3D position will be relative to the listener's position.\n * @param {Number} x The x-position of the listener.\n * @param {Number} y The y-position of the listener.\n * @param {Number} z The z-position of the listener.\n * @return {Howler/Array} Self or current listener position.\n */\n HowlerGlobal.prototype.pos = function(x, y, z) {\n var self = this;\n\n // Stop right here if not using Web Audio.\n if (!self.ctx || !self.ctx.listener) {\n return self;\n }\n\n // Set the defaults for optional 'y' & 'z'.\n y = (typeof y !== 'number') ? self._pos[1] : y;\n z = (typeof z !== 'number') ? self._pos[2] : z;\n\n if (typeof x === 'number') {\n self._pos = [x, y, z];\n\n if (typeof self.ctx.listener.positionX !== 'undefined') {\n self.ctx.listener.positionX.setTargetAtTime(self._pos[0], Howler.ctx.currentTime, 0.1);\n self.ctx.listener.positionY.setTargetAtTime(self._pos[1], Howler.ctx.currentTime, 0.1);\n self.ctx.listener.positionZ.setTargetAtTime(self._pos[2], Howler.ctx.currentTime, 0.1);\n } else {\n self.ctx.listener.setPosition(self._pos[0], self._pos[1], self._pos[2]);\n }\n } else {\n return self._pos;\n }\n\n return self;\n };\n\n /**\n * Get/set the direction the listener is pointing in the 3D cartesian space.\n * A front and up vector must be provided. The front is the direction the\n * face of the listener is pointing, and up is the direction the top of the\n * listener is pointing. Thus, these values are expected to be at right angles\n * from each other.\n * @param {Number} x The x-orientation of the listener.\n * @param {Number} y The y-orientation of the listener.\n * @param {Number} z The z-orientation of the listener.\n * @param {Number} xUp The x-orientation of the top of the listener.\n * @param {Number} yUp The y-orientation of the top of the listener.\n * @param {Number} zUp The z-orientation of the top of the listener.\n * @return {Howler/Array} Returns self or the current orientation vectors.\n */\n HowlerGlobal.prototype.orientation = function(x, y, z, xUp, yUp, zUp) {\n var self = this;\n\n // Stop right here if not using Web Audio.\n if (!self.ctx || !self.ctx.listener) {\n return self;\n }\n\n // Set the defaults for optional 'y' & 'z'.\n var or = self._orientation;\n y = (typeof y !== 'number') ? or[1] : y;\n z = (typeof z !== 'number') ? or[2] : z;\n xUp = (typeof xUp !== 'number') ? or[3] : xUp;\n yUp = (typeof yUp !== 'number') ? or[4] : yUp;\n zUp = (typeof zUp !== 'number') ? or[5] : zUp;\n\n if (typeof x === 'number') {\n self._orientation = [x, y, z, xUp, yUp, zUp];\n\n if (typeof self.ctx.listener.forwardX !== 'undefined') {\n self.ctx.listener.forwardX.setTargetAtTime(x, Howler.ctx.currentTime, 0.1);\n self.ctx.listener.forwardY.setTargetAtTime(y, Howler.ctx.currentTime, 0.1);\n self.ctx.listener.forwardZ.setTargetAtTime(z, Howler.ctx.currentTime, 0.1);\n self.ctx.listener.upX.setTargetAtTime(xUp, Howler.ctx.currentTime, 0.1);\n self.ctx.listener.upY.setTargetAtTime(yUp, Howler.ctx.currentTime, 0.1);\n self.ctx.listener.upZ.setTargetAtTime(zUp, Howler.ctx.currentTime, 0.1);\n } else {\n self.ctx.listener.setOrientation(x, y, z, xUp, yUp, zUp);\n }\n } else {\n return or;\n }\n\n return self;\n };\n\n /** Group Methods **/\n /***************************************************************************/\n\n /**\n * Add new properties to the core init.\n * @param {Function} _super Core init method.\n * @return {Howl}\n */\n Howl.prototype.init = (function(_super) {\n return function(o) {\n var self = this;\n\n // Setup user-defined default properties.\n self._orientation = o.orientation || [1, 0, 0];\n self._stereo = o.stereo || null;\n self._pos = o.pos || null;\n self._pannerAttr = {\n coneInnerAngle: typeof o.coneInnerAngle !== 'undefined' ? o.coneInnerAngle : 360,\n coneOuterAngle: typeof o.coneOuterAngle !== 'undefined' ? o.coneOuterAngle : 360,\n coneOuterGain: typeof o.coneOuterGain !== 'undefined' ? o.coneOuterGain : 0,\n distanceModel: typeof o.distanceModel !== 'undefined' ? o.distanceModel : 'inverse',\n maxDistance: typeof o.maxDistance !== 'undefined' ? o.maxDistance : 10000,\n panningModel: typeof o.panningModel !== 'undefined' ? o.panningModel : 'HRTF',\n refDistance: typeof o.refDistance !== 'undefined' ? o.refDistance : 1,\n rolloffFactor: typeof o.rolloffFactor !== 'undefined' ? o.rolloffFactor : 1\n };\n\n // Setup event listeners.\n self._onstereo = o.onstereo ? [{fn: o.onstereo}] : [];\n self._onpos = o.onpos ? [{fn: o.onpos}] : [];\n self._onorientation = o.onorientation ? [{fn: o.onorientation}] : [];\n\n // Complete initilization with howler.js core's init function.\n return _super.call(this, o);\n };\n })(Howl.prototype.init);\n\n /**\n * Get/set the stereo panning of the audio source for this sound or all in the group.\n * @param {Number} pan A value of -1.0 is all the way left and 1.0 is all the way right.\n * @param {Number} id (optional) The sound ID. If none is passed, all in group will be updated.\n * @return {Howl/Number} Returns self or the current stereo panning value.\n */\n Howl.prototype.stereo = function(pan, id) {\n var self = this;\n\n // Stop right here if not using Web Audio.\n if (!self._webAudio) {\n return self;\n }\n\n // If the sound hasn't loaded, add it to the load queue to change stereo pan when capable.\n if (self._state !== 'loaded') {\n self._queue.push({\n event: 'stereo',\n action: function() {\n self.stereo(pan, id);\n }\n });\n\n return self;\n }\n\n // Check for PannerStereoNode support and fallback to PannerNode if it doesn't exist.\n var pannerType = (typeof Howler.ctx.createStereoPanner === 'undefined') ? 'spatial' : 'stereo';\n\n // Setup the group's stereo panning if no ID is passed.\n if (typeof id === 'undefined') {\n // Return the group's stereo panning if no parameters are passed.\n if (typeof pan === 'number') {\n self._stereo = pan;\n self._pos = [pan, 0, 0];\n } else {\n return self._stereo;\n }\n }\n\n // Change the streo panning of one or all sounds in group.\n var ids = self._getSoundIds(id);\n for (var i=0; i<ids.length; i++) {\n // Get the sound.\n var sound = self._soundById(ids[i]);\n\n if (sound) {\n if (typeof pan === 'number') {\n sound._stereo = pan;\n sound._pos = [pan, 0, 0];\n\n if (sound._node) {\n // If we are falling back, make sure the panningModel is equalpower.\n sound._pannerAttr.panningModel = 'equalpower';\n\n // Check if there is a panner setup and create a new one if not.\n if (!sound._panner || !sound._panner.pan) {\n setupPanner(sound, pannerType);\n }\n\n if (pannerType === 'spatial') {\n if (typeof sound._panner.positionX !== 'undefined') {\n sound._panner.positionX.setValueAtTime(pan, Howler.ctx.currentTime);\n sound._panner.positionY.setValueAtTime(0, Howler.ctx.currentTime);\n sound._panner.positionZ.setValueAtTime(0, Howler.ctx.currentTime);\n } else {\n sound._panner.setPosition(pan, 0, 0);\n }\n } else {\n sound._panner.pan.setValueAtTime(pan, Howler.ctx.currentTime);\n }\n }\n\n self._emit('stereo', sound._id);\n } else {\n return sound._stereo;\n }\n }\n }\n\n return self;\n };\n\n /**\n * Get/set the 3D spatial position of the audio source for this sound or group relative to the global listener.\n * @param {Number} x The x-position of the audio source.\n * @param {Number} y The y-position of the audio source.\n * @param {Number} z The z-position of the audio source.\n * @param {Number} id (optional) The sound ID. If none is passed, all in group will be updated.\n * @return {Howl/Array} Returns self or the current 3D spatial position: [x, y, z].\n */\n Howl.prototype.pos = function(x, y, z, id) {\n var self = this;\n\n // Stop right here if not using Web Audio.\n if (!self._webAudio) {\n return self;\n }\n\n // If the sound hasn't loaded, add it to the load queue to change position when capable.\n if (self._state !== 'loaded') {\n self._queue.push({\n event: 'pos',\n action: function() {\n self.pos(x, y, z, id);\n }\n });\n\n return self;\n }\n\n // Set the defaults for optional 'y' & 'z'.\n y = (typeof y !== 'number') ? 0 : y;\n z = (typeof z !== 'number') ? -0.5 : z;\n\n // Setup the group's spatial position if no ID is passed.\n if (typeof id === 'undefined') {\n // Return the group's spatial position if no parameters are passed.\n if (typeof x === 'number') {\n self._pos = [x, y, z];\n } else {\n return self._pos;\n }\n }\n\n // Change the spatial position of one or all sounds in group.\n var ids = self._getSoundIds(id);\n for (var i=0; i<ids.length; i++) {\n // Get the sound.\n var sound = self._soundById(ids[i]);\n\n if (sound) {\n if (typeof x === 'number') {\n sound._pos = [x, y, z];\n\n if (sound._node) {\n // Check if there is a panner setup and create a new one if not.\n if (!sound._panner || sound._panner.pan) {\n setupPanner(sound, 'spatial');\n }\n\n if (typeof sound._panner.positionX !== 'undefined') {\n sound._panner.positionX.setValueAtTime(x, Howler.ctx.currentTime);\n sound._panner.positionY.setValueAtTime(y, Howler.ctx.currentTime);\n sound._panner.positionZ.setValueAtTime(z, Howler.ctx.currentTime);\n } else {\n sound._panner.setPosition(x, y, z);\n }\n }\n\n self._emit('pos', sound._id);\n } else {\n return sound._pos;\n }\n }\n }\n\n return self;\n };\n\n /**\n * Get/set the direction the audio source is pointing in the 3D cartesian coordinate\n * space. Depending on how direction the sound is, based on the `cone` attributes,\n * a sound pointing away from the listener can be quiet or silent.\n * @param {Number} x The x-orientation of the source.\n * @param {Number} y The y-orientation of the source.\n * @param {Number} z The z-orientation of the source.\n * @param {Number} id (optional) The sound ID. If none is passed, all in group will be updated.\n * @return {Howl/Array} Returns self or the current 3D spatial orientation: [x, y, z].\n */\n Howl.prototype.orientation = function(x, y, z, id) {\n var self = this;\n\n // Stop right here if not using Web Audio.\n if (!self._webAudio) {\n return self;\n }\n\n // If the sound hasn't loaded, add it to the load queue to change orientation when capable.\n if (self._state !== 'loaded') {\n self._queue.push({\n event: 'orientation',\n action: function() {\n self.orientation(x, y, z, id);\n }\n });\n\n return self;\n }\n\n // Set the defaults for optional 'y' & 'z'.\n y = (typeof y !== 'number') ? self._orientation[1] : y;\n z = (typeof z !== 'number') ? self._orientation[2] : z;\n\n // Setup the group's spatial orientation if no ID is passed.\n if (typeof id === 'undefined') {\n // Return the group's spatial orientation if no parameters are passed.\n if (typeof x === 'number') {\n self._orientation = [x, y, z];\n } else {\n return self._orientation;\n }\n }\n\n // Change the spatial orientation of one or all sounds in group.\n var ids = self._getSoundIds(id);\n for (var i=0; i<ids.length; i++) {\n // Get the sound.\n var sound = self._soundById(ids[i]);\n\n if (sound) {\n if (typeof x === 'number') {\n sound._orientation = [x, y, z];\n\n if (sound._node) {\n // Check if there is a panner setup and create a new one if not.\n if (!sound._panner) {\n // Make sure we have a position to setup the node with.\n if (!sound._pos) {\n sound._pos = self._pos || [0, 0, -0.5];\n }\n\n setupPanner(sound, 'spatial');\n }\n\n if (typeof sound._panner.orientationX !== 'undefined') {\n sound._panner.orientationX.setValueAtTime(x, Howler.ctx.currentTime);\n sound._panner.orientationY.setValueAtTime(y, Howler.ctx.currentTime);\n sound._panner.orientationZ.setValueAtTime(z, Howler.ctx.currentTime);\n } else {\n sound._panner.setOrientation(x, y, z);\n }\n }\n\n self._emit('orientation', sound._id);\n } else {\n return sound._orientation;\n }\n }\n }\n\n return self;\n };\n\n /**\n * Get/set the panner node's attributes for a sound or group of sounds.\n * This method can optionall take 0, 1 or 2 arguments.\n * pannerAttr() -> Returns the group's values.\n * pannerAttr(id) -> Returns the sound id's values.\n * pannerAttr(o) -> Set's the values of all sounds in this Howl group.\n * pannerAttr(o, id) -> Set's the values of passed sound id.\n *\n * Attributes:\n * coneInnerAngle - (360 by default) A parameter for directional audio sources, this is an angle, in degrees,\n * inside of which there will be no volume reduction.\n * coneOuterAngle - (360 by default) A parameter for directional audio sources, this is an angle, in degrees,\n * outside of which the volume will be reduced to a constant value of `coneOuterGain`.\n * coneOuterGain - (0 by default) A parameter for directional audio sources, this is the gain outside of the\n * `coneOuterAngle`. It is a linear value in the range `[0, 1]`.\n * distanceModel - ('inverse' by default) Determines algorithm used to reduce volume as audio moves away from\n * listener. Can be `linear`, `inverse` or `exponential.\n * maxDistance - (10000 by default) The maximum distance between source and listener, after which the volume\n * will not be reduced any further.\n * refDistance - (1 by default) A reference distance for reducing volume as source moves further from the listener.\n * This is simply a variable of the distance model and has a different effect depending on which model\n * is used and the scale of your coordinates. Generally, volume will be equal to 1 at this distance.\n * rolloffFactor - (1 by default) How quickly the volume reduces as source moves from listener. This is simply a\n * variable of the distance model and can be in the range of `[0, 1]` with `linear` and `[0, ∞]`\n * with `inverse` and `exponential`.\n * panningModel - ('HRTF' by default) Determines which spatialization algorithm is used to position audio.\n * Can be `HRTF` or `equalpower`.\n *\n * @return {Howl/Object} Returns self or current panner attributes.\n */\n Howl.prototype.pannerAttr = function() {\n var self = this;\n var args = arguments;\n var o, id, sound;\n\n // Stop right here if not using Web Audio.\n if (!self._webAudio) {\n return self;\n }\n\n // Determine the values based on arguments.\n if (args.length === 0) {\n // Return the group's panner attribute values.\n return self._pannerAttr;\n } else if (args.length === 1) {\n if (typeof args[0] === 'object') {\n o = args[0];\n\n // Set the grou's panner attribute values.\n if (typeof id === 'undefined') {\n if (!o.pannerAttr) {\n o.pannerAttr = {\n coneInnerAngle: o.coneInnerAngle,\n coneOuterAngle: o.coneOuterAngle,\n coneOuterGain: o.coneOuterGain,\n distanceModel: o.distanceModel,\n maxDistance: o.maxDistance,\n refDistance: o.refDistance,\n rolloffFactor: o.rolloffFactor,\n panningModel: o.panningModel\n };\n }\n\n self._pannerAttr = {\n coneInnerAngle: typeof o.pannerAttr.coneInnerAngle !== 'undefined' ? o.pannerAttr.coneInnerAngle : self._coneInnerAngle,\n coneOuterAngle: typeof o.pannerAttr.coneOuterAngle !== 'undefined' ? o.pannerAttr.coneOuterAngle : self._coneOuterAngle,\n coneOuterGain: typeof o.pannerAttr.coneOuterGain !== 'undefined' ? o.pannerAttr.coneOuterGain : self._coneOuterGain,\n distanceModel: typeof o.pannerAttr.distanceModel !== 'undefined' ? o.pannerAttr.distanceModel : self._distanceModel,\n maxDistance: typeof o.pannerAttr.maxDistance !== 'undefined' ? o.pannerAttr.maxDistance : self._maxDistance,\n refDistance: typeof o.pannerAttr.refDistance !== 'undefined' ? o.pannerAttr.refDistance : self._refDistance,\n rolloffFactor: typeof o.pannerAttr.rolloffFactor !== 'undefined' ? o.pannerAttr.rolloffFactor : self._rolloffFactor,\n panningModel: typeof o.pannerAttr.panningModel !== 'undefined' ? o.pannerAttr.panningModel : self._panningModel\n };\n }\n } else {\n // Return this sound's panner attribute values.\n sound = self._soundById(parseInt(args[0], 10));\n return sound ? sound._pannerAttr : self._pannerAttr;\n }\n } else if (args.length === 2) {\n o = args[0];\n id = parseInt(args[1], 10);\n }\n\n // Update the values of the specified sounds.\n var ids = self._getSoundIds(id);\n for (var i=0; i<ids.length; i++) {\n sound = self._soundById(ids[i]);\n\n if (sound) {\n // Merge the new values into the sound.\n var pa = sound._pannerAttr;\n pa = {\n coneInnerAngle: typeof o.coneInnerAngle !== 'undefined' ? o.coneInnerAngle : pa.coneInnerAngle,\n coneOuterAngle: typeof o.coneOuterAngle !== 'undefined' ? o.coneOuterAngle : pa.coneOuterAngle,\n coneOuterGain: typeof o.coneOuterGain !== 'undefined' ? o.coneOuterGain : pa.coneOuterGain,\n distanceModel: typeof o.distanceModel !== 'undefined' ? o.distanceModel : pa.distanceModel,\n maxDistance: typeof o.maxDistance !== 'undefined' ? o.maxDistance : pa.maxDistance,\n refDistance: typeof o.refDistance !== 'undefined' ? o.refDistance : pa.refDistance,\n rolloffFactor: typeof o.rolloffFactor !== 'undefined' ? o.rolloffFactor : pa.rolloffFactor,\n panningModel: typeof o.panningModel !== 'undefined' ? o.panningModel : pa.panningModel\n };\n\n // Update the panner values or create a new panner if none exists.\n var panner = sound._panner;\n if (panner) {\n panner.coneInnerAngle = pa.coneInnerAngle;\n panner.coneOuterAngle = pa.coneOuterAngle;\n panner.coneOuterGain = pa.coneOuterGain;\n panner.distanceModel = pa.distanceModel;\n panner.maxDistance = pa.maxDistance;\n panner.refDistance = pa.refDistance;\n panner.rolloffFactor = pa.rolloffFactor;\n panner.panningModel = pa.panningModel;\n } else {\n // Make sure we have a position to setup the node with.\n if (!sound._pos) {\n sound._pos = self._pos || [0, 0, -0.5];\n }\n\n // Create a new panner node.\n setupPanner(sound, 'spatial');\n }\n }\n }\n\n return self;\n };\n\n /** Single Sound Methods **/\n /***************************************************************************/\n\n /**\n * Add new properties to the core Sound init.\n * @param {Function} _super Core Sound init method.\n * @return {Sound}\n */\n Sound.prototype.init = (function(_super) {\n return function() {\n var self = this;\n var parent = self._parent;\n\n // Setup user-defined default properties.\n self._orientation = parent._orientation;\n self._stereo = parent._stereo;\n self._pos = parent._pos;\n self._pannerAttr = parent._pannerAttr;\n\n // Complete initilization with howler.js core Sound's init function.\n _super.call(this);\n\n // If a stereo or position was specified, set it up.\n if (self._stereo) {\n parent.stereo(self._stereo);\n } else if (self._pos) {\n parent.pos(self._pos[0], self._pos[1], self._pos[2], self._id);\n }\n };\n })(Sound.prototype.init);\n\n /**\n * Override the Sound.reset method to clean up properties from the spatial plugin.\n * @param {Function} _super Sound reset method.\n * @return {Sound}\n */\n Sound.prototype.reset = (function(_super) {\n return function() {\n var self = this;\n var parent = self._parent;\n\n // Reset all spatial plugin properties on this sound.\n self._orientation = parent._orientation;\n self._stereo = parent._stereo;\n self._pos = parent._pos;\n self._pannerAttr = parent._pannerAttr;\n\n // If a stereo or position was specified, set it up.\n if (self._stereo) {\n parent.stereo(self._stereo);\n } else if (self._pos) {\n parent.pos(self._pos[0], self._pos[1], self._pos[2], self._id);\n } else if (self._panner) {\n // Disconnect the panner.\n self._panner.disconnect(0);\n self._panner = undefined;\n parent._refreshBuffer(self);\n }\n\n // Complete resetting of the sound.\n return _super.call(this);\n };\n })(Sound.prototype.reset);\n\n /** Helper Methods **/\n /***************************************************************************/\n\n /**\n * Create a new panner node and save it on the sound.\n * @param {Sound} sound Specific sound to setup panning on.\n * @param {String} type Type of panner to create: 'stereo' or 'spatial'.\n */\n var setupPanner = function(sound, type) {\n type = type || 'spatial';\n\n // Create the new panner node.\n if (type === 'spatial') {\n sound._panner = Howler.ctx.createPanner();\n sound._panner.coneInnerAngle = sound._pannerAttr.coneInnerAngle;\n sound._panner.coneOuterAngle = sound._pannerAttr.coneOuterAngle;\n sound._panner.coneOuterGain = sound._pannerAttr.coneOuterGain;\n sound._panner.distanceModel = sound._pannerAttr.distanceModel;\n sound._panner.maxDistance = sound._pannerAttr.maxDistance;\n sound._panner.refDistance = sound._pannerAttr.refDistance;\n sound._panner.rolloffFactor = sound._pannerAttr.rolloffFactor;\n sound._panner.panningModel = sound._pannerAttr.panningModel;\n\n if (typeof sound._panner.positionX !== 'undefined') {\n sound._panner.positionX.setValueAtTime(sound._pos[0], Howler.ctx.currentTime);\n sound._panner.positionY.setValueAtTime(sound._pos[1], Howler.ctx.currentTime);\n sound._panner.positionZ.setValueAtTime(sound._pos[2], Howler.ctx.currentTime);\n } else {\n sound._panner.setPosition(sound._pos[0], sound._pos[1], sound._pos[2]);\n }\n\n if (typeof sound._panner.orientationX !== 'undefined') {\n sound._panner.orientationX.setValueAtTime(sound._orientation[0], Howler.ctx.currentTime);\n sound._panner.orientationY.setValueAtTime(sound._orientation[1], Howler.ctx.currentTime);\n sound._panner.orientationZ.setValueAtTime(sound._orientation[2], Howler.ctx.currentTime);\n } else {\n sound._panner.setOrientation(sound._orientation[0], sound._orientation[1], sound._orientation[2]);\n }\n } else {\n sound._panner = Howler.ctx.createStereoPanner();\n sound._panner.pan.setValueAtTime(sound._stereo, Howler.ctx.currentTime);\n }\n\n sound._panner.connect(sound._node);\n\n // Update the connections.\n if (!sound._paused) {\n sound._parent.pause(sound._id, true).play(sound._id, true);\n }\n };\n})();\n","/**\n * Graphic User Interface\n *\n * @author Alain Pitiot\n * @author Sijia Zhao - fine-grained resource loading\n * @version 2021.2.0\n * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd. (https://opensciencetools.org)\n * @license Distributed under the terms of the MIT License\n */\n\nimport * as Tone from \"tone\";\nimport { ExperimentHandler } from \"../data/ExperimentHandler.js\";\nimport { Clock } from \"../util/Clock.js\";\nimport { Scheduler } from \"../util/Scheduler.js\";\nimport * as util from \"../util/Util.js\";\nimport { PsychoJS } from \"./PsychoJS.js\";\nimport { ServerManager } from \"./ServerManager.js\";\nimport { paramReader } from \"../../../threshold.js\";\nimport { psychoJS } from \"../../../components/globalPsychoJS.js\";\nimport { buildErrorContext } from \"../../../components/errorContext.js\";\nimport { buildRuntimeErrorMessage, formatErrorContextAsText } from \"../../../components/runtimeErrorMessage.js\";\n\n/**\n * @class\n * Graphic User Interface\n *\n * @name module:core.GUI\n * @class\n * @param {module:core.PsychoJS} psychoJS the PsychoJS instance\n */\nexport class GUI\n{\n\tget dialogComponent()\n\t{\n\t\treturn this._dialogComponent;\n\t}\n\n\tconstructor(psychoJS)\n\t{\n\t\tthis._psychoJS = psychoJS;\n\n\t\t// gui listens to RESOURCE events from the server manager:\n\t\tpsychoJS.serverManager.on(ServerManager.Event.RESOURCE, (signal) =>\n\t\t{\n\t\t\tthis._onResourceEvents(signal);\n\t\t});\n\n\t\tthis._dialogScalingFactor = 0;\n\t}\n\n\t/**\n\t * <p>Create a dialog box that (a) enables the participant to set some\n\t * experimental values (e.g. the session name), (b) shows progress of resource\n\t * download, and (c) enables the participant to cancel the experiment.</p>\n\t *\n\t * <b>Setting experiment values</b>\n\t * <p>DlgFromDict displays an input field for all values in the dictionary.\n\t * It is possible to specify default values e.g.:</p>\n\t * <code>let expName = 'stroop';<br>\n\t * let expInfo = {'participant':'', 'session':'01'};<br>\n\t * psychoJS.schedule(psychoJS.gui.DlgFromDict({dictionary: expInfo, title: expName}));</code>\n\t * <p>If the participant cancels (by pressing Cancel or by closing the dialog box), then\n\t * the dictionary remains unchanged.</p>\n\t *\n\t * @name module:core.GUI#DlgFromDict\n\t * @function\n\t * @public\n\t * @param {Object} options\n\t * @param {String} [options.logoUrl] - Url of the experiment logo\n\t * @param {String} [options.text] - information text\n\t * @param {Object} options.dictionary - associative array of values for the participant to set\n\t * @param {String} options.title - name of the project\n\t */\n\tDlgFromDict({\n\t\tlogoUrl,\n\t\ttext,\n\t\tdictionary,\n\t\ttitle,\n\t\tparticipantText = \"Participant\",\n\t\tsessionText = \"Session\",\n\t\tcancelText = \"Cancel\",\n\t\tokText = \"OK\",\n\t})\n\t{\n\t\t// get info from URL:\n\t\tconst infoFromUrl = util.getUrlParameters();\n\n\t\tthis._progressMsg = \" \";\n\t\tthis._progressBarMax = 0;\n\t\tthis._allResourcesDownloaded = false;\n\t\tthis._requiredKeys = [];\n\t\tthis._setRequiredKeys = new Map();\n\n\t\t// prepare PsychoJS component:\n\t\tthis._dialogComponent = {};\n\t\tthis._dialogComponent.status = PsychoJS.Status.NOT_STARTED;\n\t\tconst dialogClock = new Clock();\n\t\tconst self = this;\n\n\t\treturn () =>\n\t\t{\n\t\t\tconst t = dialogClock.getTime();\n\n\t\t\tif (t >= 0.0 && self._dialogComponent.status === PsychoJS.Status.NOT_STARTED)\n\t\t\t{\n\t\t\t\tself._dialogComponent.tStart = t;\n\t\t\t\tself._dialogComponent.status = PsychoJS.Status.STARTED;\n\n\t\t\t\t// if the experiment is licensed, and running on the license rather than on credit,\n\t\t\t\t// we use the license logo:\n\t\t\t\tif (\n\t\t\t\t\tself._psychoJS.getEnvironment() === ExperimentHandler.Environment.SERVER\n\t\t\t\t\t&& typeof self._psychoJS.config.experiment.license !== \"undefined\"\n\t\t\t\t\t&& self._psychoJS.config.experiment.runMode === \"LICENSE\"\n\t\t\t\t\t&& typeof self._psychoJS.config.experiment.license.institutionLogo !== \"undefined\"\n\t\t\t\t)\n\t\t\t\t{\n\t\t\t\t\tlogoUrl = self._psychoJS.config.experiment.license.institutionLogo;\n\t\t\t\t}\n\n\t\t\t\t// prepare jquery UI dialog box:\n\t\t\t\t// let htmlCode = '<div id=\"expDialog\" title=\"' + title + '\">';\n\t\t\t\tlet htmlCode = `<div id=\"expDialog\" title=\"${title}\">`;\n\n\t\t\t\t// uncomment for older version of the library:\n\t\t\t\t// htmlCode += '<p style=\"font-size: 0.8em; padding: 0.5em; margin-bottom: 0.5em; color: #FFAA00; border: 1px solid #FFAA00;\">⚠ This experiment uses a deprecated version of the PsychoJS library. Consider updating to a newer version (e.g. by updating PsychoPy and re-exporting the experiment).</p>'+\n\n\t\t\t\t// logo:\n\t\t\t\tif (typeof logoUrl === \"string\")\n\t\t\t\t{\n\t\t\t\t\thtmlCode += '<img id=\"dialog-logo\" class=\"logo\" alt=\"logo\" src=\"' + logoUrl + '\">';\n\t\t\t\t}\n\n\t\t\t\t// information text:\n\t\t\t\tif (typeof text === \"string\" && text.length > 0)\n\t\t\t\t{\n\t\t\t\t\thtmlCode += \"<p>\" + text + \"</p>\";\n\t\t\t\t}\n\n\t\t\t\t// add a combobox or text areas for each entry in the dictionary:\n\n\t\t\t\t// These may include Symbols as opposed to when using a for...in loop,\n\t\t\t\t// but only strings are allowed in PsychoPy\n\t\t\t\tObject.keys(dictionary).forEach((key, keyIdx) =>\n\t\t\t\t{\n\t\t\t\t\tconst value = dictionary[key];\n\t\t\t\t\tconst keyId = \"form-input-\" + keyIdx;\n\n\t\t\t\t\t// only create an input if the key is not in the URL:\n\t\t\t\t\tlet inUrl = false;\n\t\t\t\t\tconst cleanedDictKey = key.trim().toLowerCase();\n\t\t\t\t\tinfoFromUrl.forEach((urlValue, urlKey) =>\n\t\t\t\t\t{\n\t\t\t\t\t\tconst cleanedUrlKey = urlKey.trim().toLowerCase();\n\t\t\t\t\t\tif (cleanedUrlKey === cleanedDictKey)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tinUrl = true;\n\t\t\t\t\t\t\t// break;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\t\tif (!inUrl)\n\t\t\t\t\t{\n\t\t\t\t\t\thtmlCode += '<label for=\"' + keyId + '\">' + getItemName(key, participantText, sessionText) + \"</label>\";\n\n\t\t\t\t\t\t// if the field is required:\n\t\t\t\t\t\tif (key.slice(-1) === \"*\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tself._requiredKeys.push(keyId);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// if value is an array, we create a select drop-down menu:\n\t\t\t\t\t\tif (Array.isArray(value))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\thtmlCode += '<select name=\"' + key + '\" id=\"' + keyId + '\" class=\"text ui-widget-content'\n\t\t\t\t\t\t\t\t+ ' ui-corner-all\">';\n\n\t\t\t\t\t\t\t// if the field is required, we add an empty option and select it:\n\t\t\t\t\t\t\tif (key.slice(-1) === \"*\")\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\thtmlCode += \"<option disabled selected>...</option>\";\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tfor (const option of value)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\thtmlCode += \"<option>\" + option + \"</option>\";\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\thtmlCode += \"</select>\";\n\t\t\t\t\t\t\tjQuery(\"#\" + keyId).selectmenu({ classes: {} });\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// otherwise we use a single string input:\n\t\t\t\t\t\t/*if (typeof value === 'string')*/\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\thtmlCode += '<input readonly disabled type=\"text\" name=\"' + key + '\" id=\"' + keyId;\n\t\t\t\t\t\t\thtmlCode += '\" value=\"' + value + '\" class=\"text ui-widget-content ui-corner-all\">';\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\t// if (this._requiredKeys.length > 0)\n\t\t\t\t// {\n\t\t\t\t// \thtmlCode += '<p class=\"validateTips\">Fields marked with an asterisk (*) are required.</p>';\n\t\t\t\t// }\n\n\t\t\t\t// add a progress bar:\n\t\t\t\thtmlCode += '<hr><div id=\"progressMsg\" class=\"progress\">' + self._progressMsg + \"</div>\";\n\t\t\t\thtmlCode += '<div id=\"progressbar\"></div></div>';\n\n\t\t\t\t// replace root by the html code:\n\t\t\t\tconst dialogElement = document.getElementById(\"root\");\n\t\t\t\tdialogElement.innerHTML = htmlCode;\n\n\t\t\t\t// setup change event handlers for all required keys:\n\t\t\t\tthis._requiredKeys.forEach((keyId) =>\n\t\t\t\t{\n\t\t\t\t\tconst input = document.getElementById(keyId);\n\t\t\t\t\tif (input)\n\t\t\t\t\t{\n\t\t\t\t\t\tinput.oninput = (event) => GUI._onKeyChange(self, event);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\t// Tackle browser demands on having user action initiate audio context\n\t\t\t\tTone.start();\n\n\t\t\t\tconst onOkClicked = () =>\n\t\t\t\t{\n\t\t\t\t\t// update dictionary:\n\t\t\t\t\tObject.keys(dictionary).forEach((key, keyIdx) =>\n\t\t\t\t\t{\n\t\t\t\t\t\tconst input = document.getElementById(\"form-input-\" + keyIdx);\n\t\t\t\t\t\tif (input)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdictionary[key] = input.value;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\t\tself._dialogComponent.button = \"OK\";\n\t\t\t\t\tjQuery(\"#expDialog\").dialog(\"close\");\n\n\t\t\t\t\t// switch to full screen if requested:\n\t\t\t\t\tself._psychoJS.window.adjustScreenSize();\n\n\t\t\t\t\t// Clear events (and keypresses) accumulated during the dialog\n\t\t\t\t\tself._psychoJS.eventManager.clearEvents();\n\t\t\t\t}\n\n\t\t\t\t// init and open the dialog box:\n\t\t\t\tself._dialogComponent.button = \"Cancel\";\n\t\t\t\tjQuery(\"#expDialog\").dialog({\n\t\t\t\t\twidth: \"500\",\n\n\t\t\t\t\tautoOpen: true,\n\t\t\t\t\tmodal: false,\n\t\t\t\t\tcloseOnEscape: false,\n\t\t\t\t\tresizable: false,\n\t\t\t\t\tdraggable: false,\n\n\t\t\t\t\tbuttons: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tid: \"buttonCancel\",\n\t\t\t\t\t\t\ttext: cancelText,\n\t\t\t\t\t\t\tclick: function()\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tself._dialogComponent.button = \"Cancel\";\n\t\t\t\t\t\t\t\tjQuery(\"#expDialog\").dialog(\"close\");\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tid: \"buttonOk\",\n\t\t\t\t\t\t\ttext: okText,\n\t\t\t\t\t\t\tclick: onOkClicked,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\n\t\t\t\t\t// close is called by both buttons and when the user clicks on the cross:\n\t\t\t\t\tclose: function()\n\t\t\t\t\t{\n\t\t\t\t\t\t// jQuery.unblockUI();\n\t\t\t\t\t\tjQuery(this).dialog(\"destroy\").remove();\n\t\t\t\t\t\tself._dialogComponent.status = PsychoJS.Status.FINISHED;\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\t\t// change colour of title bar\n\t\t\t\t\t.prev(\".ui-dialog-titlebar\").css(\"background\", \"green\");\n\n\t\t\t\t// update the OK button status:\n\t\t\t\tself._updateOkButtonStatus();\n\n\t\t\t\t// block UI until user has pressed dialog button:\n\t\t\t\t// note: block UI does not allow for text to be entered in the dialog form boxes, alas!\n\t\t\t\t// jQuery.blockUI({ message: \"\", baseZ: 1});\n\n\t\t\t\t// show dialog box:\n\t\t\t\tjQuery(\"#progressbar\").progressbar({ value: self._progressBarCurrentValue });\n\t\t\t\tjQuery(\"#progressbar\").progressbar(\"option\", \"max\", self._progressBarMax);\n\t\t\t}\n\n\t\t\tif (self._dialogComponent.status === PsychoJS.Status.FINISHED)\n\t\t\t{\n\t\t\t\treturn Scheduler.Event.NEXT;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn Scheduler.Event.FLIP_REPEAT;\n\t\t\t}\n\t\t};\n\t}\n\n\t_removeWelcomeDialogBox()\n\t{\n\t\tjQuery(\"#expDialog\").dialog(\"destroy\").remove();\n\t}\n\n\t/**\n\t * @callback GUI.onOK\n\t */\n\t/**\n\t * Show a message to the participant in a dialog box.\n\t *\n\t * <p>This function can be used to display both warning and error messages.</p>\n\t *\n\t * @name module:core.GUI#dialog\n\t * @function\n\t * @public\n\t * @param {Object} options\n\t * @param {string} options.message - the message to be displayed\n\t * @param {Object.<string, *>} options.error - an exception\n\t * @param {string} options.warning - a warning message\n\t * @param {boolean} [options.showOK=true] - specifies whether to show the OK button\n\t * @param {GUI.onOK} [options.onOK] - function called when the participant presses the OK button\n\t */\n\tdialog({\n\t\tmessage,\n\t\twarning,\n\t\terror,\n\t\tshowOK = true,\n\t\tonOK,\n\t\tokText,\n\t\taddErrorToPsychoJS = true,\n\t} = {})\n\t{\n\t\t// close the previously opened dialog box, if there is one:\n\t\tthis.closeDialog();\n\n\t\tlet htmlCode;\n\t\tlet titleColour;\n\t\t// Title bar direction — the participant's language is RTL in some\n\t\t// studies, and each part of the dialog states its own direction.\n\t\tlet titleDirection = \"ltr\";\n\t\tlet titleLanguage = \"en\";\n\t\tlet localizedOkText;\n\n\t\t// we are displaying an error:\n\t\tif (typeof error !== \"undefined\")\n\t\t{\n\t\t\tthis._psychoJS.logger.fatal(util.toString(error));\n\n\t\t\t// let extraMessageFromEasyEyes = \"\";\n\t\t\t// if (window.errorHandler)\n\t\t\t// {\n\t\t\t// \textraMessageFromEasyEyes = window.errorHandler(error);\n\t\t\t// }\n\n\t\t\tlet errorCode = null;\n\n\t\t\t// go through the error stack and look for errorCode if there is one:\n\t\t\tconst contextChain = [];\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\tif (typeof error === \"object\" && \"errorCode\" in error)\n\t\t\t\t{\n\t\t\t\t\terrorCode = error.errorCode;\n\t\t\t\t}\n\n\t\t\t\tif (typeof error === \"object\" && \"context\" in error)\n\t\t\t\t{\n\t\t\t\t\tcontextChain.push(error.context);\n\t\t\t\t\terror = error.error;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// limit the size of the error:\n\t\t\t\t\tif (error && error.length >= 1000)\n\t\t\t\t\t{\n\t\t\t\t\t\terror = error.substring(1, 1000);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// if we found an errorCode, we replace the stack-based message by a more user-friendly one:\n\t\t\tif (errorCode)\n\t\t\t{\n\t\t\t\tconst error = this._userFriendlyError(errorCode);\n\t\t\t\thtmlCode = error.htmlCode;\n\t\t\t\ttitleColour = error.titleColour;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tconst context = buildErrorContext(paramReader);\n\n\t\t\t\tif (addErrorToPsychoJS)\n\t\t\t\t{\n\t\t\t\t\ttry\n\t\t\t\t\t{\n\t\t\t\t\t\tpsychoJS.experiment.addData(\"error\", error + formatErrorContextAsText(context));\n\t\t\t\t\t}\n\t\t\t\t\tcatch (e)\n\t\t\t\t\t{\n\t\t\t\t\t\tconsole.error(\"Error when trying to record the error in the data: \" + e);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst runtimeError = buildRuntimeErrorMessage({\n\t\t\t\t\terrorDescription: error,\n\t\t\t\t\tcontextChain,\n\t\t\t\t\tcontext,\n\t\t\t\t});\n\t\t\t\ttitleDirection = runtimeError.titleDirection;\n\t\t\t\ttitleLanguage = runtimeError.titleLanguage;\n\t\t\t\tlocalizedOkText = runtimeError.okText;\n\n\t\t\t\thtmlCode = `<div id=\"msgDialog\" title=\"${runtimeError.title.replace(/\"/g, \""\")}\">`\n\t\t\t\t\t+ runtimeError.html\n\t\t\t\t\t+ \"</div>\";\n\n\t\t\t\ttitleColour = \"red\";\n\t\t\t}\n\t\t}\n\t\t// we are displaying a message:\n\t\telse if (typeof message !== \"undefined\")\n\t\t{\n\t\t\thtmlCode = '<div id=\"msgDialog\" title=\"EasyEyes\">'\n\t\t\t\t+ '<p class=\"validateTips\">' + message + \"</p>\"\n\t\t\t\t+ \"</div>\";\n\t\t\ttitleColour = \"green\";\n\t\t}\n\t\t// we are displaying a warning:\n\t\telse if (typeof warning !== \"undefined\")\n\t\t{\n\t\t\thtmlCode = '<div id=\"msgDialog\" title=\"Warning\">'\n\t\t\t\t+ '<p class=\"validateTips\">' + warning + \"</p>\"\n\t\t\t\t+ \"</div>\";\n\t\t\ttitleColour = \"orange\";\n\t\t}\n\n\t\t// replace root by the html code:\n\t\tconst dialogElement = document.getElementById(\"root\");\n\t\tdialogElement.innerHTML = htmlCode;\n\n\t\t// init and open the dialog box:\n\t\tconst self = this;\n\t\tjQuery(\"#msgDialog\").dialog({\n\t\t\t// dialogClass: \"no-close\", //uncomment to prevent the user from closing the dialog box\n\t\t\t// closeText:\"X\", // this is not working for some reason so we're manually changing the close button text a bit further down\n\t\t\t\n\t\t\twidth: \"500\",\n\n\t\t\tautoOpen: true,\n\t\t\tmodal: false,\n\t\t\tcloseOnEscape: false,\n\t\t\tresizable: false,\n\t\t\tdraggable: false,\n\n\t\t\tbuttons: (!showOK) ? [] : [{\n\t\t\t\tid: \"buttonOk\",\n\t\t\t\ttext: okText ?? localizedOkText ?? \"OK\",\n\t\t\t\tclick: function()\n\t\t\t\t{\n\t\t\t\t\tjQuery(this).dialog(\"destroy\").remove();\n\n\t\t\t\t\t// execute callback function:\n\t\t\t\t\tif (typeof onOK !== \"undefined\")\n\t\t\t\t\t{\n\t\t\t\t\t\tonOK();\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t}],\n\t\t})\n\t\t\t// change colour of title bar\n\t\t\t.prev(\".ui-dialog-titlebar\").css(\"background\", titleColour);\n\t\t\t// The title bar text follows the participant's language; the close\n\t\t\t// button keeps its own position, so only the title span is flipped.\n\t\t\tconst dialogTitleElement = document.getElementsByClassName(\"ui-dialog-title\")[0];\n\t\t\tif (dialogTitleElement)\n\t\t\t{\n\t\t\t\tdialogTitleElement.setAttribute(\"dir\", titleDirection);\n\t\t\t\tdialogTitleElement.setAttribute(\"lang\", titleLanguage);\n\t\t\t}\n\t\t\tconst dialogCloseButton = document.getElementsByClassName(\"ui-dialog-titlebar-close\")[0];\n\t\t\tif (dialogCloseButton){\n\t\t\t\tdialogCloseButton.innerHTML = \"X\";\n\t\t\t}\n\t\t\t\n\t}\n\n\t/**\n * Show a message to the participant directly in the main window.\n *\n * <p>This function can be used to display both warning and error messages.</p>\n *\n * @name module:core.GUI#displayMessage\n * @function\n * @public\n * @param {Object} options\n * @param {string} options.message - the message to be displayed\n * @param {Object.<string, *>} options.error - an exception\n * @param {string} options.warning - a warning message\n * @param {string} [options.okUrl] - the URL to redirect \n */\ndisplayMessage({\n message,\n warning,\n error,\n\tokUrl,\n\tisCompleted,\n\tokText\n} = {}) {\n let htmlCode;\n let titleColor;\n\n // Determine the type of message and set the HTML content and color accordingly\n if (error) {\n if (!error) {\n error = \"Unspecified JavaScript error\";\n }\n htmlCode = `<div id=\"msgDisplay\" class=\"error\"><p>${error}</p></div>`;\n titleColor = \"black\";\n } else if (message) {\n\t\tif (isCompleted && okUrl !== undefined){\n\t\t\thtmlCode = `<div id=\"msgDisplay\" class=\"message\">${message}</div>`;\n\t\t} else {\n\t\t\thtmlCode = `<div id=\"msgDisplay\" class=\"message\"><p>${message}</p></div>`;\n\t\t}\n \n titleColor = \"black\";\n } else if (warning) {\n htmlCode = `<div id=\"msgDisplay\" class=\"warning\"><p>${warning}</p></div>`;\n titleColor = \"black\";\n }\n\tlet displayElement; \n\tif (document.getElementById(\"exp-end-text\") == null){\n displayElement = document.createElement('div');} else {\n\tdisplayElement = document.getElementById(\"exp-end-text\");\n\t}\n displayElement.innerHTML = htmlCode;\n\n // Optionally, apply CSS styles to the message display\n displayElement.style.color = titleColor;\n displayElement.style.textAlign = 'center';\n\tdisplayElement.style.lineHeight = \"1.5\";\n\tdisplayElement.style.paddingTop = \"40vh\";\n\tdisplayElement.style.paddingBottom = \"30vh\";\n\tdisplayElement.style.display = \"flex\";\n\tdisplayElement.style.flexDirection = \"column\";\n\tdisplayElement.style.alignItems = \"center\";\n // displayElement.style.padding = '20px';\n\tdisplayElement.id = \"exp-end-text\";\n\tdisplayElement.style.visibility = \"visible\";\n\t//make font bigger\n\tdisplayElement.style.fontSize = \"24px\";\n\t//background color of body should be white\n\tdocument.body.style.backgroundColor = \"white\";\n\tdocument.body.appendChild(displayElement);\n\n\tif(isCompleted && okUrl !== undefined){\n\t// If an OK URL is provided, redirect the participant to that URL\n\tconst button = document.createElement('button');\n\tbutton.innerHTML = \"OK\";\n\tbutton.style.zIndex = \"100\";\n\tbutton.classList.add(\"form-input-btn\");\n\tbutton.addEventListener('click', () => {\n\t\t\twindow.location = okUrl;\t\n\t});\n\tdisplayElement.appendChild(button);\n\n}\n\n}\n\n// You might need to add CSS styles for classes `error`, `message`, and `warning` if not already defined\n\n\n\t/**\n\t * Close the previously opened dialog box, if there is one.\n\t *\n\t * @name module:core.GUI#closeDialog\n\t * @function\n\t * @public\n\t */\n\tcloseDialog()\n\t{\n\t\tconst expDialog = jQuery(\"#expDialog\");\n\t\tif (expDialog.length)\n\t\t{\n\t\t\texpDialog.dialog(\"destroy\").remove();\n\t\t}\n\t\tconst msgDialog = jQuery(\"#msgDialog\");\n\t\tif (msgDialog.length)\n\t\t{\n\t\t\tmsgDialog.dialog(\"destroy\").remove();\n\t\t}\n\t}\n\n\t/**\n\t * Listener for resource event from the [Server Manager]{@link ServerManager}.\n\t *\n\t * @name module:core.GUI#_onResourceEvents\n\t * @function\n\t * @private\n\t * @param {Object.<string, string|Symbol>} signal the signal\n\t */\n\t_onResourceEvents(signal)\n\t{\n\t\tthis._psychoJS.logger.debug(\"signal: \" + util.toString(signal));\n\n\t\t// the download of the specified resources has started:\n\t\tif (signal.message === ServerManager.Event.DOWNLOADING_RESOURCES)\n\t\t{\n\t\t\t// for each resource, we have a 'downloading resource' and a 'resource downloaded' message:\n\t\t\tthis._progressBarMax = signal.count * 2;\n\t\t\tjQuery(\"#progressbar\").progressbar(\"option\", \"max\", this._progressBarMax);\n\n\t\t\tthis._progressBarCurrentValue = 0;\n\t\t}\n\t\t// all the resources have been downloaded: show the ok button\n\t\telse if (signal.message === ServerManager.Event.DOWNLOAD_COMPLETED)\n\t\t{\n\t\t\tthis._allResourcesDownloaded = true;\n\t\t\tjQuery(\"#progressMsg\").text(\"All resources downloaded.\");\n\t\t\tthis._updateOkButtonStatus();\n\t\t}\n\t\t// update progress bar:\n\t\telse if (\n\t\t\tsignal.message === ServerManager.Event.DOWNLOADING_RESOURCE\n\t\t\t|| signal.message === ServerManager.Event.RESOURCE_DOWNLOADED\n\t\t)\n\t\t{\n\t\t\tif (typeof this._progressBarCurrentValue === \"undefined\")\n\t\t\t{\n\t\t\t\tthis._progressBarCurrentValue = 0;\n\t\t\t}\n\t\t\t++this._progressBarCurrentValue;\n\n\t\t\tif (signal.message === ServerManager.Event.RESOURCE_DOWNLOADED)\n\t\t\t{\n\t\t\t\tjQuery(\"#progressMsg\").text(\"Downloaded \" + (this._progressBarCurrentValue / 2) + \" / \" + (this._progressBarMax / 2));\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tjQuery(\"#progressMsg\").text(\"Downloading \" + (this._progressBarCurrentValue / 2) + \" / \" + (this._progressBarMax / 2));\n\t\t\t}\n\t\t\t// $(\"#progressMsg\").text(signal.resource + ': downloaded.');\n\t\t\tjQuery(\"#progressbar\").progressbar(\"option\", \"value\", this._progressBarCurrentValue);\n\t\t}\n\t\t// unknown message: we just display it\n\t\telse\n\t\t{\n\t\t\tjQuery(\"#progressMsg\").text(signal.message);\n\t\t}\n\t}\n\n\t/**\n\t * Update the status of the OK button.\n\t *\n\t * @name module:core.GUI#_updateOkButtonStatus\n\t * @param [changeFocus = false] - whether or not to change the focus to the OK button\n\t * @function\n\t * @private\n\t */\n\t_updateOkButtonStatus(changeFocus = true)\n\t{\n\t\tif (\n\t\t\t(this._psychoJS.getEnvironment() === ExperimentHandler.Environment.LOCAL)\n\t\t\t|| (this._allResourcesDownloaded && this._setRequiredKeys && this._setRequiredKeys.size >= this._requiredKeys.length)\n\t\t)\n\t\t{\n\t\t\tif (changeFocus)\n\t\t\t{\n\t\t\t\tjQuery(\"#buttonOk\").button(\"option\", \"disabled\", false).focus();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tjQuery(\"#buttonOk\").button(\"option\", \"disabled\", false);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tjQuery(\"#buttonOk\").button(\"option\", \"disabled\", true);\n\t\t}\n\n\t\t// strangely, changing the disabled option sometimes fails to update the ui,\n\t\t// so we need to hide it and show it again:\n\t\tjQuery(\"#buttonOk\").hide(0, () =>\n\t\t{\n\t\t\tjQuery(\"#buttonOk\").show();\n\t\t});\n\t}\n\n\t/**\n\t * Listener for change event for required keys.\n\t *\n\t * @name module:core.GUI#_onKeyChange\n\t * @function\n\t * @static\n\t * @private\n\t * @param {module:core.GUI} gui - this GUI\n\t * @param {Event} event - event\n\t */\n\tstatic _onKeyChange(gui, event)\n\t{\n\t\tconst element = event.target;\n\t\tconst value = element.value;\n\n\t\tif (typeof value !== \"undefined\" && value.length > 0)\n\t\t{\n\t\t\tgui._setRequiredKeys.set(event.target, true);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tgui._setRequiredKeys.delete(event.target);\n\t\t}\n\n\t\tgui._updateOkButtonStatus(false);\n\t}\n\n\t/**\n\t * Get a more user-friendly html message.\n\t *\n\t * @param {number} errorCode - the pavlovia.org server error code\n\t * @private\n\t * @return {{htmlCode: string, titleColour: string}} a user-friendly error message\n\t */\n\t_userFriendlyError(errorCode)\n\t{\n\t\tswitch (errorCode)\n\t\t{\n\t\t\t// INTERNAL_ERROR\n\t\t\tcase 1:\n\t\t\t\treturn {\n\t\t\t\t\thtmlCode:\n\t\t\t\t\t\t'<div id=\"msgDialog\" title=\"Error\"><p>Oops we encountered an internal server error.</p><p class=\"psychojs-alert-text\">Click the REPORT button to report the error to the EasyEyes team. We will try to fix it. Thank you for your help.</p></div>',\n\t\t\t\t\ttitleColour: \"red\",\n\t\t\t\t};\n\n\t\t\t// MONGODB_ERROR\n\n\t\t\tcase 2:\n\t\t\t\treturn {\n\t\t\t\t\thtmlCode:\n\t\t\t\t\t\t'<div id=\"msgDialog\" title=\"Error\"><p>Oops we encountered a database error.</p><p class=\"psychojs-alert-text\">Click the REPORT button to report the error to the EasyEyes team. We will try to fix it. Thank you for your help.</p></div>',\n\t\t\t\t\ttitleColour: \"red\",\n\t\t\t\t};\n\n\t\t\t// STATUS_NONE\n\n\t\t\tcase 20:\n\t\t\t\treturn {\n\t\t\t\t\thtmlCode:\n\t\t\t\t\t\t`<div id=\"msgDialog\" title=\"Warning\"><p><strong>${this._psychoJS.config.experiment.fullpath}</strong> does not have any status and cannot be run.</p><p>If you are the experiment designer, go to your <a href=\"https://pavlovia.org/${this._psychoJS.config.experiment.fullpath}\">experiment page</a> and change the experiment status to either PILOTING or RUNNING.</p><p>Otherwise please contact the experiment designer to let him or her know that the status must be changed to RUNNING for participants to be able to run it.</p></div>`,\n\t\t\t\t\ttitleColour: \"orange\",\n\t\t\t\t};\n\n\t\t\t// STATUS_INACTIVE\n\n\t\t\tcase 21:\n\t\t\t\treturn {\n\t\t\t\t\thtmlCode:\n\t\t\t\t\t\t`<div id=\"msgDialog\" title=\"Warning\"><p><strong>${this._psychoJS.config.experiment.fullpath}</strong> is currently inactive and cannot be run.</p><p>If you are the experiment designer, go to your <a href=\"https://pavlovia.org/${this._psychoJS.config.experiment.fullpath}\">experiment page</a> and change the experiment status to either PILOTING or RUNNING.</p><p>Otherwise please contact the experiment designer to let him or her know that the status must be changed to RUNNING for participants to be able to run it.</p></div>`,\n\t\t\t\t\ttitleColour: \"orange\",\n\t\t\t\t};\n\n\t\t\t// STATUS_DELETED\n\n\t\t\tcase 22:\n\t\t\t\treturn {\n\t\t\t\t\thtmlCode:\n\t\t\t\t\t\t`<div id=\"msgDialog\" title=\"Warning\"><p><strong>${this._psychoJS.config.experiment.fullpath}</strong> has been deleted and cannot be run.</p><p>If you are the experiment designer, either go to your <a href=\"https://pavlovia.org/${this._psychoJS.config.experiment.fullpath}\">experiment page</a> and change the experiment status to either PILOTING or RUNNING, or generate a new experiment.</p><p>Otherwise please contact the experiment designer to let him or her know that the experiment has been deleted and cannot be run any longer.</p></div>`,\n\t\t\t\t\ttitleColour: \"orange\",\n\t\t\t\t};\n\n\t\t\t// STATUS_ARCHIVED\n\n\t\t\tcase 23:\n\t\t\t\treturn {\n\t\t\t\t\thtmlCode:\n\t\t\t\t\t\t`<div id=\"msgDialog\" title=\"Warning\"><p><strong>${this._psychoJS.config.experiment.fullpath}</strong> has been archived and cannot be run.</p><p>If you are the experiment designer, go to your <a href=\"https://pavlovia.org/${this._psychoJS.config.experiment.fullpath}\">experiment page</a> and change the experiment status to either PILOTING or RUNNING.</p><p>Otherwise please contact the experiment designer to let him or her know that the experiment has been archived and cannot be run at the moment.</p></div>`,\n\t\t\t\t\ttitleColour: \"orange\",\n\t\t\t\t};\n\n\t\t\t// PILOTING_NO_TOKEN\n\n\t\t\tcase 30:\n\t\t\t\treturn {\n\t\t\t\t\thtmlCode:\n\t\t\t\t\t\t`<div id=\"msgDialog\" title=\"Warning\"><p><strong>${this._psychoJS.config.experiment.fullpath}</strong> is currently in PILOTING mode but the pilot token is missing from the URL.</p><p>If you are the experiment designer, you can pilot it by pressing the pilot button on your <a href=\"https://pavlovia.org/${this._psychoJS.config.experiment.fullpath}\">experiment page</a>.</p><p>Otherwise please contact the experiment designer to let him or her know that the experiment status must be changed to RUNNING for participants to be able to run it.</p></div>`,\n\t\t\t\t\ttitleColour: \"orange\",\n\t\t\t\t};\n\n\t\t\t// PILOTING_INVALID_TOKEN\n\n\t\t\tcase 31:\n\t\t\t\treturn {\n\t\t\t\t\thtmlCode:\n\t\t\t\t\t\t`<div id=\"msgDialog\" title=\"Warning\"><p><strong>${this._psychoJS.config.experiment.fullpath}</strong> cannot be run because the pilot token in the URL is invalid, possibly because it has expired.</p><p>If you are the experiment designer, you can generate a new token by pressing the pilot button on your <a href=\"https://pavlovia.org/${this._psychoJS.config.experiment.fullpath}\">experiment page</a>.</p><p>Otherwise please contact the experiment designer to let him or her know that the experiment status must be changed to RUNNING for participants to be able to run it.</p></div>`,\n\t\t\t\t\ttitleColour: \"orange\",\n\t\t\t\t};\n\n\t\t\t// LICENSE_EXPIRED\n\n\t\t\tcase 50:\n\t\t\t\treturn {\n\t\t\t\t\thtmlCode:\n\t\t\t\t\t\t`<div id=\"msgDialog\" title=\"Warning\"><p><strong>${this._psychoJS.config.experiment.fullpath}</strong> is covered by a license that has expired. </p><p>If you are the experiment designer, you can either contact the license manager to inquire about the expiration, or you can run your experiments using credits. You will find all relevant details about the license on your <a href=\"https://pavlovia.org/${this._psychoJS.config.experiment.fullpath}\">experiment page</a>, where you will also be able to change its running mode to CREDIT.</p><p>Otherwise please contact the experiment designer to let him or her know that there is an issue with the experiment's license having expired.</p></div>`,\n\t\t\t\t\ttitleColour: \"orange\",\n\t\t\t\t};\n\n\t\t\t// LICENSE_APPROVAL_NEEDED\n\n\t\t\tcase 51:\n\t\t\t\treturn {\n\t\t\t\t\thtmlCode:\n\t\t\t\t\t\t`<div id=\"msgDialog\" title=\"Warning\"><p><strong>${this._psychoJS.config.experiment.fullpath}</strong> is covered by a license that requires one or more documents to be approved before the experiment can be run. </p><p>If you are the experiment designer, please contact the license manager and ask him or her which documents must be approved. You will find all relevant details about the license on your <a href=\"https://pavlovia.org/${this._psychoJS.config.experiment.fullpath}\">experiment page</a>.</p><p>Otherwise please contact the experiment designer to let him or her know that there is an issue with the experiment's license requiring documents to be approved.</p></div>`,\n\t\t\t\t\ttitleColour: \"orange\",\n\t\t\t\t};\n\n\t\t\t// CREDIT_NOT_ENOUGH\n\n\t\t\tcase 60:\n\t\t\t\treturn {\n\t\t\t\t\thtmlCode:\n\t\t\t\t\t\t`<div id=\"msgDialog\" title=\"Warning\"><p><strong>${this._psychoJS.config.experiment.fullpath}</strong> does not have any assigned credit left and cannot be run.</p><p>If you are the experiment designer, you can assign more credits to it on your <a href=\"https://pavlovia.org/${this._psychoJS.config.experiment.fullpath}\">experiment page</a>.</p><p>Otherwise please contact the experiment designer to let him or her know that the experiment requires more assigned credits to run.</p></div>`,\n\t\t\t\t\ttitleColour: \"orange\",\n\t\t\t\t};\n\n\t\t\tdefault:\n\t\t\t\treturn {\n\t\t\t\t\thtmlCode:\n\t\t\t\t\t\t`<div id=\"msgDialog\" title=\"Error\"><p>Unfortunately we encountered an unspecified error (error code: ${errorCode}.</p><p class=\"psychojs-alert-text\">Click the REPORT button to report the error to the EasyEyes team. We will try to fix it. Thank you for your help.</p></div>`,\n\t\t\t\t\ttitleColour: \"red\",\n\t\t\t\t};\n\t\t}\n\t}\n}\n\n/**\n * Maximal dimensions of the dialog window.\n *\n * @name module:core.GUI#dialogMaxSize\n * @enum {Symbol}\n * @readonly\n * @public\n */\nGUI.dialogMaxSize = [500, 600];\n\n/**\n * Dialog window margins.\n *\n * @name module:core.GUI#dialogMargin\n * @enum {Symbol}\n * @readonly\n * @public\n */\nGUI.dialogMargin = [50, 50];\n\n\nfunction upperFirst(s)\n{\n\treturn s[0].toUpperCase() + s.slice(1);\n}\n\nfunction getItemName(item, participantText, sessionText) {\n\tif (item === 'participant')\n\t\treturn participantText\n\telse if (item === 'session')\n\t\treturn sessionText\n\telse return upperFirst(item)\n}\n","/**\n * Logger\n *\n * @author Alain Pitiot\n * @version 2021.2.0\n * @copyright (c) 2017-2020 Ilixa Ltd. (http://ilixa.com) (c) 2020-2021 Open Science Tools Ltd. (https://opensciencetools.org)\n * @license Distributed under the terms of the MIT License\n */\n\nimport log4javascript from \"log4javascript\";\nimport pako from \"pako\";\nimport { ExperimentHandler } from \"../data/ExperimentHandler.js\";\nimport { MonotonicClock } from \"../util/Clock.js\";\nimport * as util from \"../util/Util.js\";\n\n/**\n * <p>This class handles a variety of loggers, e.g. a browser console one (mostly for debugging),\n * a remote one, etc.</p>\n *\n * <p>Note: we use log4javascript for the console logger, and our own for the server logger.</p>\n *\n * @name module:core.Logger\n * @class\n * @param {*} threshold - the logging threshold, e.g. log4javascript.Level.ERROR\n */\nexport class Logger\n{\n\tconstructor(psychoJS, threshold)\n\t{\n\t\tthis._psychoJS = psychoJS;\n\n\t\t// browser console logger:\n\t\tthis.consoleLogger = log4javascript.getLogger(\"psychojs\");\n\n\t\tconst appender = new log4javascript.BrowserConsoleAppender();\n\t\tappender.setLayout(this._customConsoleLayout());\n\t\tappender.setThreshold(threshold);\n\n\t\tthis.consoleLogger.addAppender(appender);\n\t\tthis.consoleLogger.setLevel(threshold);\n\n\t\t// server logger:\n\t\tthis._serverLogs = [];\n\t\tthis._serverLevel = Logger.ServerLevel.WARNING;\n\t\tthis._serverLevelValue = this._getValue(this._serverLevel);\n\n\t\t// throttling of server logs\n\t\tthis._throttling = {\n\t\t\t// period of time (in seconds) over which we consider the number of logged messages:\n\t\t\twindow: 1,\n\t\t\t// threshold (i.e. number of messages over the throttling window) at which point\n\t\t\t// we start throttling:\n\t\t\tthreshold: 20,\n\t\t\t// throttling factor: 10 -> only 1 in 10 messages is logged\n\t\t\tfactor: 10,\n\t\t\t// minimum duration (in seconds) of throttling\n\t\t\tminimumDuration: 2,\n\t\t\t// time at which throttling started:\n\t\t\tstartOfThrottling: 0,\n\t\t\t// whether or not we are currently throttling:\n\t\t\tisThrottling: false,\n\t\t\t// throttling message index:\n\t\t\tindex: 0,\n\t\t\t// whether or not the designer has already been warned:\n\t\t\tdesignerWasWarned: false,\n\t\t};\n\t}\n\n\t/**\n\t * Change the logging level.\n\t *\n\t * @name module:core.Logger#setLevel\n\t * @public\n\t * @param {module:core.Logger.ServerLevel} serverLevel - the new logging level\n\t */\n\tsetLevel(serverLevel)\n\t{\n\t\tthis._serverLevel = serverLevel;\n\t\tthis._serverLevelValue = this._getValue(this._serverLevel);\n\t}\n\n\t/**\n\t * Log a server message at the EXP level.\n\t *\n\t * @name module:core.Logger#exp\n\t * @public\n\t * @param {string} msg - the message to be logged.\n\t * @param {number} [time] - the logging time\n\t * @param {object} [obj] - the associated object (e.g. a Trial)\n\t */\n\texp(msg, time, obj)\n\t{\n\t\tthis.log(msg, Logger.ServerLevel.EXP, time, obj);\n\t}\n\n\t/**\n\t * Log a server message at the DATA level.\n\t *\n\t * @name module:core.Logger#data\n\t * @public\n\t * @param {string} msg - the message to be logged.\n\t * @param {number} [time] - the logging time\n\t * @param {object} [obj] - the associated object (e.g. a Trial)\n\t */\n\tdata(msg, time, obj)\n\t{\n\t\tthis.log(msg, Logger.ServerLevel.DATA, time, obj);\n\t}\n\n\t/**\n\t * Log a server message.\n\t *\n\t * @name module:core.Logger#log\n\t * @public\n\t * @param {string} msg - the message to be logged.\n\t * @param {module:core.Logger.ServerLevel} level - logging level\n\t * @param {number} [time] - the logging time\n\t * @param {object} [obj] - the associated object (e.g. a Trial)\n\t */\n\tlog(msg, level, time, obj)\n\t{\n\t\t// only log if the level is higher or equal to the previously defined server level:\n\t\tconst levelValue = this._getValue(level);\n\t\tif (levelValue < this._serverLevelValue)\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tif (typeof time === \"undefined\")\n\t\t{\n\t\t\ttime = MonotonicClock.getReferenceTime();\n\t\t}\n\n\t\t/* [coming soon]\n\t\t// check whether we need to throttle:\n\t\tif (this._throttle(time))\n\t\t{\n\t\t\treturn;\n\t\t}\n\t */\n\n\t\tthis._serverLogs.push({\n\t\t\tmsg,\n\t\t\tlevel,\n\t\t\ttime,\n\t\t\tobj: util.toString(obj),\n\t\t});\n\t}\n\n\t/**\n\t * Check whether or not a log messages must be throttled.\n\t *\n\t * @name module:core.Logger#_throttle\n\t * @protected\n\t *\n\t * @param {number} time - the time of the latest log message\n\t * @return {boolean} whether or not to log the message\n\t */\n\t_throttle(time)\n\t{\n\t\t// if more messages than this._throttling.threshold have been logged between\n\t\t// time and the start of the throttling window, we need to throttle:\n\t\tif (this._serverLogs.length > this._throttling.threshold)\n\t\t{\n\t\t\tconst timeAtStartThrottlingWindow = this._serverLogs[this._serverLogs.length - 1 - this._throttling.threshold].time;\n\t\t\tif (time - timeAtStartThrottlingWindow < this._throttling.window)\n\t\t\t{\n\t\t\t\t// warn the designer if we are not already throttling:\n\t\t\t\tif (!this._throttling.isThrottling)\n\t\t\t\t{\n\t\t\t\t\tconst msg = `<p>[time= ${time.toFixed(3)}] More than ${this._throttling.threshold} messages were logged in the past ${this._throttling.window}s.</p>`\n\t\t\t\t\t\t+ `<p>We are now throttling: only 1 in ${this._throttling.factor} messages will be logged.</p>`\n\t\t\t\t\t\t+ `<p>You may want to change your experiment's logging level. Please see <a href=\"https://www.psychopy.org/api/logging.html\">psychopy.org/api/logging.html</a> for details.</p>`;\n\n\t\t\t\t\t// console warning:\n\t\t\t\t\tthis._psychoJS.logger.warn(msg);\n\n\t\t\t\t\t// in PILOTING mode and locally, we also warn the experimenter with a dialog box,\n\t\t\t\t\t// but only once:\n\t\t\t\t\tif (\n\t\t\t\t\t\t!this._throttling.designerWasWarned\n\t\t\t\t\t\t&& (this._psychoJS.getEnvironment() === ExperimentHandler.Environment.LOCAL\n\t\t\t\t\t\t\t|| this._psychoJS.config.experiment.status === \"PILOTING\")\n\t\t\t\t\t)\n\t\t\t\t\t{\n\t\t\t\t\t\tthis._throttling.designerWasWarned = true;\n\n\t\t\t\t\t\tthis._psychoJS.gui.dialog({\n\t\t\t\t\t\t\twarning: msg,\n\t\t\t\t\t\t\tshowOK: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._throttling.isThrottling = true;\n\t\t\t\t\tthis._throttling.startOfThrottling = time;\n\t\t\t\t\tthis._throttling.index = 0;\n\t\t\t\t}\n\n\t\t\t\t++this._throttling.index;\n\t\t\t\tif (this._throttling.index < this._throttling.factor)\n\t\t\t\t{\n\t\t\t\t\t// no logging\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tthis._throttling.index = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (\n\t\t\t\t\tthis._throttling.isThrottling\n\t\t\t\t\t&& (time - this._throttling.startOfThrottling) > this._throttling.minimumDuration\n\t\t\t\t)\n\t\t\t\t{\n\t\t\t\t\tthis._psychoJS.logger.info(`[time= ${time.toFixed(3)}] Log messages are not throttled any longer.`);\n\t\t\t\t\tthis._throttling.isThrottling = false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Flush all server logs to the server.\n\t *\n\t * <p>Note: the logs are compressed using Pako's zlib algorithm.\n\t * See https://github.com/nodeca/pako for details.</p>\n\t *\n\t * @name module:core.Logger#flush\n\t * @public\n\t */\n\tasync flush()\n\t{\n\t\tconst response = {\n\t\t\torigin: \"Logger.flush\",\n\t\t\tcontext: \"when flushing participant's logs for experiment: \" + this._psychoJS.config.experiment.fullpath,\n\t\t};\n\n\t\tthis._psychoJS.logger.info(\"[PsychoJS] Flush server logs.\");\n\n\t\t// prepare the formatted logs:\n\t\tlet formattedLogs = \"\";\n\t\tfor (const log of this._serverLogs)\n\t\t{\n\t\t\tlet formattedLog = util.toString(log.time)\n\t\t\t\t+ \"\\t\" + Symbol.keyFor(log.level)\n\t\t\t\t+ \"\\t\" + log.msg;\n\t\t\tif (log.obj !== \"undefined\")\n\t\t\t{\n\t\t\t\tformattedLog += \"\\t\" + log.obj;\n\t\t\t}\n\t\t\tformattedLog += \"\\n\";\n\n\t\t\tformattedLogs += formattedLog;\n\t\t}\n\n\t\t// send logs to the server or display them in the console:\n\t\tif (\n\t\t\tthis._psychoJS.getEnvironment() === ExperimentHandler.Environment.SERVER\n\t\t\t&& this._psychoJS.config.experiment.status === \"RUNNING\"\n\t\t\t&& !this._psychoJS._serverMsg.has(\"__pilotToken\")\n\t\t)\n\t\t{\n\t\t\t// if the pako compression library is present, we compress the logs:\n\t\t\tif (typeof pako !== \"undefined\")\n\t\t\t{\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tconst utf16DeflatedLogs = pako.deflate(formattedLogs, { to: \"string\" });\n\t\t\t\t\t// const utf16DeflatedLogs = pako.deflate(unescape(encodeURIComponent(formattedLogs)), {to: 'string'});\n\t\t\t\t\tconst base64DeflatedLogs = btoa(utf16DeflatedLogs);\n\n\t\t\t\t\treturn await this._psychoJS.serverManager.uploadLog(base64DeflatedLogs, true);\n\t\t\t\t}\n\t\t\t\tcatch (error)\n\t\t\t\t{\n\t\t\t\t\tconsole.error(\"log compression error:\", error);\n\t\t\t\t\tthrow Object.assign(response, { error: error });\n\t\t\t\t}\n\t\t\t}\n\t\t\t// the pako compression library is not present, we do not compress the logs:\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn await this._psychoJS.serverManager.uploadLog(formattedLogs, false);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthis._psychoJS.logger.debug(\"\\n\" + formattedLogs);\n\t\t}\n\t}\n\n\t/**\n\t * Create a custom console layout.\n\t *\n\t * @name module:core.Logger#_customConsoleLayout\n\t * @private\n\t * @return {*} the custom layout\n\t */\n\t_customConsoleLayout()\n\t{\n\t\tconst detectedBrowser = util.detectBrowser();\n\n\t\tconst customLayout = new log4javascript.PatternLayout(\"%p %d{HH:mm:ss.SSS} %f{1} | %m\");\n\t\tcustomLayout.setCustomField(\"location\", function(layout, loggingReference)\n\t\t{\n\t\t\t// we throw a fake exception to retrieve the stack trace\n\t\t\ttry\n\t\t\t{\n\t\t\t\t// (0)();\n\t\t\t\tthrow Error(\"fake exception\");\n\t\t\t}\n\t\t\tcatch (e)\n\t\t\t{\n\t\t\t\tconst stackEntries = e.stack.replace(/^.*?\\n/, \"\").replace(/(?:\\n@:0)?\\s+$/m, \"\").replace(/^\\(/gm, \"{anon}(\").split(\"\\n\");\n\n\t\t\t\tlet relevantEntry;\n\t\t\t\tif (detectedBrowser === \"Firefox\")\n\t\t\t\t{\n\t\t\t\t\t// look for entry immediately after those of log4javascript:\n\t\t\t\t\tfor (let entry of stackEntries)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (entry.indexOf(\"log4javascript.min.js\") <= 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\trelevantEntry = entry;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tconst buf = relevantEntry.split(\":\");\n\t\t\t\t\tconst line = buf[buf.length - 2];\n\t\t\t\t\tconst file = buf[buf.length - 3].split(\"/\").pop();\n\t\t\t\t\tconst method = relevantEntry.split(\"@\")[0];\n\n\t\t\t\t\treturn method + \" \" + file + \":\" + line;\n\t\t\t\t}\n\t\t\t\telse if (detectedBrowser === \"Safari\")\n\t\t\t\t{\n\t\t\t\t\treturn \"unknown\";\n\t\t\t\t}\n\t\t\t\telse if (detectedBrowser === \"Chrome\")\n\t\t\t\t{\n\t\t\t\t\trelevantEntry = stackEntries.pop();\n\n\t\t\t\t\tlet buf = relevantEntry.split(\" \");\n\t\t\t\t\tlet fileLine = buf.pop();\n\t\t\t\t\tconst method = buf.pop();\n\t\t\t\t\tbuf = fileLine.split(\":\");\n\t\t\t\t\tbuf.pop();\n\t\t\t\t\tconst line = buf.pop();\n\t\t\t\t\tconst file = buf.pop().split(\"/\").pop();\n\n\t\t\t\t\treturn method + \" \" + file + \":\" + line;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\treturn \"unknown\";\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\treturn customLayout;\n\t}\n\n\t/**\n\t * Get the integer value associated with a logging level.\n\t *\n\t * @name module:core.Logger#_getValue\n\t * @protected\n\t * @param {module:core.Logger.ServerLevel} level - the logging level\n\t * @return {number} - the value associated with the logging level, or 30 is the logging level is unknown.\n\t */\n\t_getValue(level)\n\t{\n\t\tconst levelAsString = Symbol.keyFor(level);\n\t\treturn (levelAsString in Logger._ServerLevelValue) ? Logger._ServerLevelValue[levelAsString] : 30;\n\t}\n}\n\n/**\n * Server logging level.\n *\n * @name module:core.Logger#ServerLevel\n * @enum {Symbol}\n * @readonly\n * @public\n *\n * @note These are similar to PsychoPy's logging levels, as defined in logging.py\n */\nLogger.ServerLevel = {\n\tCRITICAL: Symbol.for(\"CRITICAL\"),\n\tERROR: Symbol.for(\"ERROR\"),\n\tWARNING: Symbol.for(\"WARNING\"),\n\tDATA: Symbol.for(\"DATA\"),\n\tEXP: Symbol.for(\"EXP\"),\n\tINFO: Symbol.for(\"INFO\"),\n\tDEBUG: Symbol.for(\"DEBUG\"),\n\tNOTSET: Symbol.for(\"NOTSET\"),\n};\n\n/**\n * Server logging level values.\n *\n * <p>We use those values to determine whether a log is to be sent to the server or not.</p>\n *\n * @name module:core.Logger#_ServerLevelValue\n * @enum {number}\n * @readonly\n * @protected\n */\nLogger._ServerLevelValue = {\n\t\"CRITICAL\": 50,\n\t\"ERROR\": 40,\n\t\"WARNING\": 30,\n\t\"DATA\": 25,\n\t\"EXP\": 22,\n\t\"INFO\": 20,\n\t\"DEBUG\": 10,\n\t\"NOTSET\": 0,\n};\n","/*\nobject-assign\n(c) Sindre Sorhus\n@license MIT\n*/\n\n'use strict';\n/* eslint-disable no-unused-vars */\nvar getOwnPropertySymbols = Object.getOwnPropertySymbols;\nvar hasOwnProperty = Object.prototype.hasOwnProperty;\nvar propIsEnumerable = Object.prototype.propertyIsEnumerable;\n\nfunction toObject(val) {\n\tif (val === null || val === undefined) {\n\t\tthrow new TypeError('Object.assign cannot be called with null or undefined');\n\t}\n\n\treturn Object(val);\n}\n\nfunction shouldUseNative() {\n\ttry {\n\t\tif (!Object.assign) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Detect buggy property enumeration order in older V8 versions.\n\n\t\t// https://bugs.chromium.org/p/v8/issues/detail?id=4118\n\t\tvar test1 = new String('abc'); // eslint-disable-line no-new-wrappers\n\t\ttest1[5] = 'de';\n\t\tif (Object.getOwnPropertyNames(test1)[0] === '5') {\n\t\t\treturn false;\n\t\t}\n\n\t\t// https://bugs.chromium.org/p/v8/issues/detail?id=3056\n\t\tvar test2 = {};\n\t\tfor (var i = 0; i < 10; i++) {\n\t\t\ttest2['_' + String.fromCharCode(i)] = i;\n\t\t}\n\t\tvar order2 = Object.getOwnPropertyNames(test2).map(function (n) {\n\t\t\treturn test2[n];\n\t\t});\n\t\tif (order2.join('') !== '0123456789') {\n\t\t\treturn false;\n\t\t}\n\n\t\t// https://bugs.chromium.org/p/v8/issues/detail?id=3056\n\t\tvar test3 = {};\n\t\t'abcdefghijklmnopqrst'.split('').forEach(function (letter) {\n\t\t\ttest3[letter] = letter;\n\t\t});\n\t\tif (Object.keys(Object.assign({}, test3)).join('') !==\n\t\t\t\t'abcdefghijklmnopqrst') {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t} catch (err) {\n\t\t// We don't expect any of the above to throw, but better to be safe.\n\t\treturn false;\n\t}\n}\n\nmodule.exports = shouldUseNative() ? Object.assign : function (target, source) {\n\tvar from;\n\tvar to = toObject(target);\n\tvar symbols;\n\n\tfor (var s = 1; s < arguments.length; s++) {\n\t\tfrom = Object(arguments[s]);\n\n\t\tfor (var key in from) {\n\t\t\tif (hasOwnProperty.call(from, key)) {\n\t\t\t\tto[key] = from[key];\n\t\t\t}\n\t\t}\n\n\t\tif (getOwnPropertySymbols) {\n\t\t\tsymbols = getOwnPropertySymbols(from);\n\t\t\tfor (var i = 0; i < symbols.length; i++) {\n\t\t\t\tif (propIsEnumerable.call(from, symbols[i])) {\n\t\t\t\t\tto[symbols[i]] = from[symbols[i]];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn to;\n};\n","/*!\n * @pixi/polyfill - v6.5.8\n * Compiled Sun, 23 Oct 2022 23:01:45 UTC\n *\n * @pixi/polyfill is licensed under the MIT License.\n * http://www.opensource.org/licenses/mit-license\n */\nimport Polyfill from 'promise-polyfill';\nimport objectAssign from 'object-assign';\n\nif (typeof globalThis === 'undefined') {\n if (typeof self !== 'undefined') {\n // covers browsers\n // @ts-expect-error not-writable ts(2540) error only on node\n self.globalThis = self;\n }\n else if (typeof global !== 'undefined') {\n // covers versions of Node < 12\n // @ts-expect-error not-writable ts(2540) error only on node\n global.globalThis = global;\n }\n}\n\n// Support for IE 9 - 11 which does not include Promises\nif (!globalThis.Promise) {\n globalThis.Promise = Polyfill;\n}\n\n// References:\nif (!Object.assign) {\n Object.assign = objectAssign;\n}\n\n// References:\n// http://paulirish.com/2011/requestanimationframe-for-smart-animating/\n// https://gist.github.com/1579671\n// http://updates.html5rocks.com/2012/05/requestAnimationFrame-API-now-with-sub-millisecond-precision\n// https://gist.github.com/timhall/4078614\n// https://github.com/Financial-Times/polyfill-service/tree/master/polyfills/requestAnimationFrame\n// Expected to be used with Browserfiy\n// Browserify automatically detects the use of `global` and passes the\n// correct reference of `global`, `globalThis`, and finally `window`\nvar ONE_FRAME_TIME = 16;\n// Date.now\nif (!(Date.now && Date.prototype.getTime)) {\n Date.now = function now() {\n return new Date().getTime();\n };\n}\n// performance.now\nif (!(globalThis.performance && globalThis.performance.now)) {\n var startTime_1 = Date.now();\n if (!globalThis.performance) {\n globalThis.performance = {};\n }\n globalThis.performance.now = function () { return Date.now() - startTime_1; };\n}\n// requestAnimationFrame\nvar lastTime = Date.now();\nvar vendors = ['ms', 'moz', 'webkit', 'o'];\nfor (var x = 0; x < vendors.length && !globalThis.requestAnimationFrame; ++x) {\n var p = vendors[x];\n globalThis.requestAnimationFrame = globalThis[p + \"RequestAnimationFrame\"];\n globalThis.cancelAnimationFrame = globalThis[p + \"CancelAnimationFrame\"]\n || globalThis[p + \"CancelRequestAnimationFrame\"];\n}\nif (!globalThis.requestAnimationFrame) {\n globalThis.requestAnimationFrame = function (callback) {\n if (typeof callback !== 'function') {\n throw new TypeError(callback + \"is not a function\");\n }\n var currentTime = Date.now();\n var delay = ONE_FRAME_TIME + lastTime - currentTime;\n if (delay < 0) {\n delay = 0;\n }\n lastTime = currentTime;\n return globalThis.self.setTimeout(function () {\n lastTime = Date.now();\n callback(performance.now());\n }, delay);\n };\n}\nif (!globalThis.cancelAnimationFrame) {\n globalThis.cancelAnimationFrame = function (id) { return clearTimeout(id); };\n}\n\n// References:\n// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign\nif (!Math.sign) {\n Math.sign = function mathSign(x) {\n x = Number(x);\n if (x === 0 || isNaN(x)) {\n return x;\n }\n return x > 0 ? 1 : -1;\n };\n}\n\n// References:\n// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger\nif (!Number.isInteger) {\n Number.isInteger = function numberIsInteger(value) {\n return typeof value === 'number' && isFinite(value) && Math.floor(value) === value;\n };\n}\n\nif (!globalThis.ArrayBuffer) {\n globalThis.ArrayBuffer = Array;\n}\nif (!globalThis.Float32Array) {\n globalThis.Float32Array = Array;\n}\nif (!globalThis.Uint32Array) {\n globalThis.Uint32Array = Array;\n}\nif (!globalThis.Uint16Array) {\n globalThis.Uint16Array = Array;\n}\nif (!globalThis.Uint8Array) {\n globalThis.Uint8Array = Array;\n}\nif (!globalThis.Int32Array) {\n globalThis.Int32Array = Array;\n}\n//# sourceMappingURL=polyfill.mjs.map\n","/*!\n * @pixi/constants - v6.5.8\n * Compiled Sun, 23 Oct 2022 23:01:45 UTC\n *\n * @pixi/constants is licensed under the MIT License.\n * http://www.opensource.org/licenses/mit-license\n */\n/**\n * Different types of environments for WebGL.\n * @static\n * @memberof PIXI\n * @name ENV\n * @enum {number}\n * @property {number} WEBGL_LEGACY - Used for older v1 WebGL devices. PixiJS will aim to ensure compatibility\n * with older / less advanced devices. If you experience unexplained flickering prefer this environment.\n * @property {number} WEBGL - Version 1 of WebGL\n * @property {number} WEBGL2 - Version 2 of WebGL\n */\nvar ENV;\n(function (ENV) {\n ENV[ENV[\"WEBGL_LEGACY\"] = 0] = \"WEBGL_LEGACY\";\n ENV[ENV[\"WEBGL\"] = 1] = \"WEBGL\";\n ENV[ENV[\"WEBGL2\"] = 2] = \"WEBGL2\";\n})(ENV || (ENV = {}));\n/**\n * Constant to identify the Renderer Type.\n * @static\n * @memberof PIXI\n * @name RENDERER_TYPE\n * @enum {number}\n * @property {number} UNKNOWN - Unknown render type.\n * @property {number} WEBGL - WebGL render type.\n * @property {number} CANVAS - Canvas render type.\n */\nvar RENDERER_TYPE;\n(function (RENDERER_TYPE) {\n RENDERER_TYPE[RENDERER_TYPE[\"UNKNOWN\"] = 0] = \"UNKNOWN\";\n RENDERER_TYPE[RENDERER_TYPE[\"WEBGL\"] = 1] = \"WEBGL\";\n RENDERER_TYPE[RENDERER_TYPE[\"CANVAS\"] = 2] = \"CANVAS\";\n})(RENDERER_TYPE || (RENDERER_TYPE = {}));\n/**\n * Bitwise OR of masks that indicate the buffers to be cleared.\n * @static\n * @memberof PIXI\n * @name BUFFER_BITS\n * @enum {number}\n * @property {number} COLOR - Indicates the buffers currently enabled for color writing.\n * @property {number} DEPTH - Indicates the depth buffer.\n * @property {number} STENCIL - Indicates the stencil buffer.\n */\nvar BUFFER_BITS;\n(function (BUFFER_BITS) {\n BUFFER_BITS[BUFFER_BITS[\"COLOR\"] = 16384] = \"COLOR\";\n BUFFER_BITS[BUFFER_BITS[\"DEPTH\"] = 256] = \"DEPTH\";\n BUFFER_BITS[BUFFER_BITS[\"STENCIL\"] = 1024] = \"STENCIL\";\n})(BUFFER_BITS || (BUFFER_BITS = {}));\n/**\n * Various blend modes supported by PIXI.\n *\n * IMPORTANT - The WebGL renderer only supports the NORMAL, ADD, MULTIPLY and SCREEN blend modes.\n * Anything else will silently act like NORMAL.\n * @memberof PIXI\n * @name BLEND_MODES\n * @enum {number}\n * @property {number} NORMAL -\n * @property {number} ADD -\n * @property {number} MULTIPLY -\n * @property {number} SCREEN -\n * @property {number} OVERLAY -\n * @property {number} DARKEN -\n * @property {number} LIGHTEN -\n * @property {number} COLOR_DODGE -\n * @property {number} COLOR_BURN -\n * @property {number} HARD_LIGHT -\n * @property {number} SOFT_LIGHT -\n * @property {number} DIFFERENCE -\n * @property {number} EXCLUSION -\n * @property {number} HUE -\n * @property {number} SATURATION -\n * @property {number} COLOR -\n * @property {number} LUMINOSITY -\n * @property {number} NORMAL_NPM -\n * @property {number} ADD_NPM -\n * @property {number} SCREEN_NPM -\n * @property {number} NONE -\n * @property {number} SRC_IN -\n * @property {number} SRC_OUT -\n * @property {number} SRC_ATOP -\n * @property {number} DST_OVER -\n * @property {number} DST_IN -\n * @property {number} DST_OUT -\n * @property {number} DST_ATOP -\n * @property {number} SUBTRACT -\n * @property {number} SRC_OVER -\n * @property {number} ERASE -\n * @property {number} XOR -\n */\nvar BLEND_MODES;\n(function (BLEND_MODES) {\n BLEND_MODES[BLEND_MODES[\"NORMAL\"] = 0] = \"NORMAL\";\n BLEND_MODES[BLEND_MODES[\"ADD\"] = 1] = \"ADD\";\n BLEND_MODES[BLEND_MODES[\"MULTIPLY\"] = 2] = \"MULTIPLY\";\n BLEND_MODES[BLEND_MODES[\"SCREEN\"] = 3] = \"SCREEN\";\n BLEND_MODES[BLEND_MODES[\"OVERLAY\"] = 4] = \"OVERLAY\";\n BLEND_MODES[BLEND_MODES[\"DARKEN\"] = 5] = \"DARKEN\";\n BLEND_MODES[BLEND_MODES[\"LIGHTEN\"] = 6] = \"LIGHTEN\";\n BLEND_MODES[BLEND_MODES[\"COLOR_DODGE\"] = 7] = \"COLOR_DODGE\";\n BLEND_MODES[BLEND_MODES[\"COLOR_BURN\"] = 8] = \"COLOR_BURN\";\n BLEND_MODES[BLEND_MODES[\"HARD_LIGHT\"] = 9] = \"HARD_LIGHT\";\n BLEND_MODES[BLEND_MODES[\"SOFT_LIGHT\"] = 10] = \"SOFT_LIGHT\";\n BLEND_MODES[BLEND_MODES[\"DIFFERENCE\"] = 11] = \"DIFFERENCE\";\n BLEND_MODES[BLEND_MODES[\"EXCLUSION\"] = 12] = \"EXCLUSION\";\n BLEND_MODES[BLEND_MODES[\"HUE\"] = 13] = \"HUE\";\n BLEND_MODES[BLEND_MODES[\"SATURATION\"] = 14] = \"SATURATION\";\n BLEND_MODES[BLEND_MODES[\"COLOR\"] = 15] = \"COLOR\";\n BLEND_MODES[BLEND_MODES[\"LUMINOSITY\"] = 16] = \"LUMINOSITY\";\n BLEND_MODES[BLEND_MODES[\"NORMAL_NPM\"] = 17] = \"NORMAL_NPM\";\n BLEND_MODES[BLEND_MODES[\"ADD_NPM\"] = 18] = \"ADD_NPM\";\n BLEND_MODES[BLEND_MODES[\"SCREEN_NPM\"] = 19] = \"SCREEN_NPM\";\n BLEND_MODES[BLEND_MODES[\"NONE\"] = 20] = \"NONE\";\n BLEND_MODES[BLEND_MODES[\"SRC_OVER\"] = 0] = \"SRC_OVER\";\n BLEND_MODES[BLEND_MODES[\"SRC_IN\"] = 21] = \"SRC_IN\";\n BLEND_MODES[BLEND_MODES[\"SRC_OUT\"] = 22] = \"SRC_OUT\";\n BLEND_MODES[BLEND_MODES[\"SRC_ATOP\"] = 23] = \"SRC_ATOP\";\n BLEND_MODES[BLEND_MODES[\"DST_OVER\"] = 24] = \"DST_OVER\";\n BLEND_MODES[BLEND_MODES[\"DST_IN\"] = 25] = \"DST_IN\";\n BLEND_MODES[BLEND_MODES[\"DST_OUT\"] = 26] = \"DST_OUT\";\n BLEND_MODES[BLEND_MODES[\"DST_ATOP\"] = 27] = \"DST_ATOP\";\n BLEND_MODES[BLEND_MODES[\"ERASE\"] = 26] = \"ERASE\";\n BLEND_MODES[BLEND_MODES[\"SUBTRACT\"] = 28] = \"SUBTRACT\";\n BLEND_MODES[BLEND_MODES[\"XOR\"] = 29] = \"XOR\";\n})(BLEND_MODES || (BLEND_MODES = {}));\n/**\n * Various webgl draw modes. These can be used to specify which GL drawMode to use\n * under certain situations and renderers.\n * @memberof PIXI\n * @static\n * @name DRAW_MODES\n * @enum {number}\n * @property {number} POINTS -\n * @property {number} LINES -\n * @property {number} LINE_LOOP -\n * @property {number} LINE_STRIP -\n * @property {number} TRIANGLES -\n * @property {number} TRIANGLE_STRIP -\n * @property {number} TRIANGLE_FAN -\n */\nvar DRAW_MODES;\n(function (DRAW_MODES) {\n DRAW_MODES[DRAW_MODES[\"POINTS\"] = 0] = \"POINTS\";\n DRAW_MODES[DRAW_MODES[\"LINES\"] = 1] = \"LINES\";\n DRAW_MODES[DRAW_MODES[\"LINE_LOOP\"] = 2] = \"LINE_LOOP\";\n DRAW_MODES[DRAW_MODES[\"LINE_STRIP\"] = 3] = \"LINE_STRIP\";\n DRAW_MODES[DRAW_MODES[\"TRIANGLES\"] = 4] = \"TRIANGLES\";\n DRAW_MODES[DRAW_MODES[\"TRIANGLE_STRIP\"] = 5] = \"TRIANGLE_STRIP\";\n DRAW_MODES[DRAW_MODES[\"TRIANGLE_FAN\"] = 6] = \"TRIANGLE_FAN\";\n})(DRAW_MODES || (DRAW_MODES = {}));\n/**\n * Various GL texture/resources formats.\n * @memberof PIXI\n * @static\n * @name FORMATS\n * @enum {number}\n * @property {number} [RGBA=6408] -\n * @property {number} [RGB=6407] -\n * @property {number} [RG=33319] -\n * @property {number} [RED=6403] -\n * @property {number} [RGBA_INTEGER=36249] -\n * @property {number} [RGB_INTEGER=36248] -\n * @property {number} [RG_INTEGER=33320] -\n * @property {number} [RED_INTEGER=36244] -\n * @property {number} [ALPHA=6406] -\n * @property {number} [LUMINANCE=6409] -\n * @property {number} [LUMINANCE_ALPHA=6410] -\n * @property {number} [DEPTH_COMPONENT=6402] -\n * @property {number} [DEPTH_STENCIL=34041] -\n */\nvar FORMATS;\n(function (FORMATS) {\n FORMATS[FORMATS[\"RGBA\"] = 6408] = \"RGBA\";\n FORMATS[FORMATS[\"RGB\"] = 6407] = \"RGB\";\n FORMATS[FORMATS[\"RG\"] = 33319] = \"RG\";\n FORMATS[FORMATS[\"RED\"] = 6403] = \"RED\";\n FORMATS[FORMATS[\"RGBA_INTEGER\"] = 36249] = \"RGBA_INTEGER\";\n FORMATS[FORMATS[\"RGB_INTEGER\"] = 36248] = \"RGB_INTEGER\";\n FORMATS[FORMATS[\"RG_INTEGER\"] = 33320] = \"RG_INTEGER\";\n FORMATS[FORMATS[\"RED_INTEGER\"] = 36244] = \"RED_INTEGER\";\n FORMATS[FORMATS[\"ALPHA\"] = 6406] = \"ALPHA\";\n FORMATS[FORMATS[\"LUMINANCE\"] = 6409] = \"LUMINANCE\";\n FORMATS[FORMATS[\"LUMINANCE_ALPHA\"] = 6410] = \"LUMINANCE_ALPHA\";\n FORMATS[FORMATS[\"DEPTH_COMPONENT\"] = 6402] = \"DEPTH_COMPONENT\";\n FORMATS[FORMATS[\"DEPTH_STENCIL\"] = 34041] = \"DEPTH_STENCIL\";\n})(FORMATS || (FORMATS = {}));\n/**\n * Various GL target types.\n * @memberof PIXI\n * @static\n * @name TARGETS\n * @enum {number}\n * @property {number} [TEXTURE_2D=3553] -\n * @property {number} [TEXTURE_CUBE_MAP=34067] -\n * @property {number} [TEXTURE_2D_ARRAY=35866] -\n * @property {number} [TEXTURE_CUBE_MAP_POSITIVE_X=34069] -\n * @property {number} [TEXTURE_CUBE_MAP_NEGATIVE_X=34070] -\n * @property {number} [TEXTURE_CUBE_MAP_POSITIVE_Y=34071] -\n * @property {number} [TEXTURE_CUBE_MAP_NEGATIVE_Y=34072] -\n * @property {number} [TEXTURE_CUBE_MAP_POSITIVE_Z=34073] -\n * @property {number} [TEXTURE_CUBE_MAP_NEGATIVE_Z=34074] -\n */\nvar TARGETS;\n(function (TARGETS) {\n TARGETS[TARGETS[\"TEXTURE_2D\"] = 3553] = \"TEXTURE_2D\";\n TARGETS[TARGETS[\"TEXTURE_CUBE_MAP\"] = 34067] = \"TEXTURE_CUBE_MAP\";\n TARGETS[TARGETS[\"TEXTURE_2D_ARRAY\"] = 35866] = \"TEXTURE_2D_ARRAY\";\n TARGETS[TARGETS[\"TEXTURE_CUBE_MAP_POSITIVE_X\"] = 34069] = \"TEXTURE_CUBE_MAP_POSITIVE_X\";\n TARGETS[TARGETS[\"TEXTURE_CUBE_MAP_NEGATIVE_X\"] = 34070] = \"TEXTURE_CUBE_MAP_NEGATIVE_X\";\n TARGETS[TARGETS[\"TEXTURE_CUBE_MAP_POSITIVE_Y\"] = 34071] = \"TEXTURE_CUBE_MAP_POSITIVE_Y\";\n TARGETS[TARGETS[\"TEXTURE_CUBE_MAP_NEGATIVE_Y\"] = 34072] = \"TEXTURE_CUBE_MAP_NEGATIVE_Y\";\n TARGETS[TARGETS[\"TEXTURE_CUBE_MAP_POSITIVE_Z\"] = 34073] = \"TEXTURE_CUBE_MAP_POSITIVE_Z\";\n TARGETS[TARGETS[\"TEXTURE_CUBE_MAP_NEGATIVE_Z\"] = 34074] = \"TEXTURE_CUBE_MAP_NEGATIVE_Z\";\n})(TARGETS || (TARGETS = {}));\n/**\n * Various GL data format types.\n * @memberof PIXI\n * @static\n * @name TYPES\n * @enum {number}\n * @property {number} [UNSIGNED_BYTE=5121] -\n * @property {number} [UNSIGNED_SHORT=5123] -\n * @property {number} [UNSIGNED_SHORT_5_6_5=33635] -\n * @property {number} [UNSIGNED_SHORT_4_4_4_4=32819] -\n * @property {number} [UNSIGNED_SHORT_5_5_5_1=32820] -\n * @property {number} [UNSIGNED_INT=5125] -\n * @property {number} [UNSIGNED_INT_10F_11F_11F_REV=35899] -\n * @property {number} [UNSIGNED_INT_2_10_10_10_REV=33640] -\n * @property {number} [UNSIGNED_INT_24_8=34042] -\n * @property {number} [UNSIGNED_INT_5_9_9_9_REV=35902] -\n * @property {number} [BYTE=5120] -\n * @property {number} [SHORT=5122] -\n * @property {number} [INT=5124] -\n * @property {number} [FLOAT=5126] -\n * @property {number} [FLOAT_32_UNSIGNED_INT_24_8_REV=36269] -\n * @property {number} [HALF_FLOAT=36193] -\n */\nvar TYPES;\n(function (TYPES) {\n TYPES[TYPES[\"UNSIGNED_BYTE\"] = 5121] = \"UNSIGNED_BYTE\";\n TYPES[TYPES[\"UNSIGNED_SHORT\"] = 5123] = \"UNSIGNED_SHORT\";\n TYPES[TYPES[\"UNSIGNED_SHORT_5_6_5\"] = 33635] = \"UNSIGNED_SHORT_5_6_5\";\n TYPES[TYPES[\"UNSIGNED_SHORT_4_4_4_4\"] = 32819] = \"UNSIGNED_SHORT_4_4_4_4\";\n TYPES[TYPES[\"UNSIGNED_SHORT_5_5_5_1\"] = 32820] = \"UNSIGNED_SHORT_5_5_5_1\";\n TYPES[TYPES[\"UNSIGNED_INT\"] = 5125] = \"UNSIGNED_INT\";\n TYPES[TYPES[\"UNSIGNED_INT_10F_11F_11F_REV\"] = 35899] = \"UNSIGNED_INT_10F_11F_11F_REV\";\n TYPES[TYPES[\"UNSIGNED_INT_2_10_10_10_REV\"] = 33640] = \"UNSIGNED_INT_2_10_10_10_REV\";\n TYPES[TYPES[\"UNSIGNED_INT_24_8\"] = 34042] = \"UNSIGNED_INT_24_8\";\n TYPES[TYPES[\"UNSIGNED_INT_5_9_9_9_REV\"] = 35902] = \"UNSIGNED_INT_5_9_9_9_REV\";\n TYPES[TYPES[\"BYTE\"] = 5120] = \"BYTE\";\n TYPES[TYPES[\"SHORT\"] = 5122] = \"SHORT\";\n TYPES[TYPES[\"INT\"] = 5124] = \"INT\";\n TYPES[TYPES[\"FLOAT\"] = 5126] = \"FLOAT\";\n TYPES[TYPES[\"FLOAT_32_UNSIGNED_INT_24_8_REV\"] = 36269] = \"FLOAT_32_UNSIGNED_INT_24_8_REV\";\n TYPES[TYPES[\"HALF_FLOAT\"] = 36193] = \"HALF_FLOAT\";\n})(TYPES || (TYPES = {}));\n/**\n * Various sampler types. Correspond to `sampler`, `isampler`, `usampler` GLSL types respectively.\n * WebGL1 works only with FLOAT.\n * @memberof PIXI\n * @static\n * @name SAMPLER_TYPES\n * @enum {number}\n * @property {number} [FLOAT=0] -\n * @property {number} [INT=1] -\n * @property {number} [UINT=2] -\n */\nvar SAMPLER_TYPES;\n(function (SAMPLER_TYPES) {\n SAMPLER_TYPES[SAMPLER_TYPES[\"FLOAT\"] = 0] = \"FLOAT\";\n SAMPLER_TYPES[SAMPLER_TYPES[\"INT\"] = 1] = \"INT\";\n SAMPLER_TYPES[SAMPLER_TYPES[\"UINT\"] = 2] = \"UINT\";\n})(SAMPLER_TYPES || (SAMPLER_TYPES = {}));\n/**\n * The scale modes that are supported by pixi.\n *\n * The {@link PIXI.settings.SCALE_MODE} scale mode affects the default scaling mode of future operations.\n * It can be re-assigned to either LINEAR or NEAREST, depending upon suitability.\n * @memberof PIXI\n * @static\n * @name SCALE_MODES\n * @enum {number}\n * @property {number} LINEAR Smooth scaling\n * @property {number} NEAREST Pixelating scaling\n */\nvar SCALE_MODES;\n(function (SCALE_MODES) {\n SCALE_MODES[SCALE_MODES[\"NEAREST\"] = 0] = \"NEAREST\";\n SCALE_MODES[SCALE_MODES[\"LINEAR\"] = 1] = \"LINEAR\";\n})(SCALE_MODES || (SCALE_MODES = {}));\n/**\n * The wrap modes that are supported by pixi.\n *\n * The {@link PIXI.settings.WRAP_MODE} wrap mode affects the default wrapping mode of future operations.\n * It can be re-assigned to either CLAMP or REPEAT, depending upon suitability.\n * If the texture is non power of two then clamp will be used regardless as WebGL can\n * only use REPEAT if the texture is po2.\n *\n * This property only affects WebGL.\n * @name WRAP_MODES\n * @memberof PIXI\n * @static\n * @enum {number}\n * @property {number} CLAMP - The textures uvs are clamped\n * @property {number} REPEAT - The texture uvs tile and repeat\n * @property {number} MIRRORED_REPEAT - The texture uvs tile and repeat with mirroring\n */\nvar WRAP_MODES;\n(function (WRAP_MODES) {\n WRAP_MODES[WRAP_MODES[\"CLAMP\"] = 33071] = \"CLAMP\";\n WRAP_MODES[WRAP_MODES[\"REPEAT\"] = 10497] = \"REPEAT\";\n WRAP_MODES[WRAP_MODES[\"MIRRORED_REPEAT\"] = 33648] = \"MIRRORED_REPEAT\";\n})(WRAP_MODES || (WRAP_MODES = {}));\n/**\n * Mipmap filtering modes that are supported by pixi.\n *\n * The {@link PIXI.settings.MIPMAP_TEXTURES} affects default texture filtering.\n * Mipmaps are generated for a baseTexture if its `mipmap` field is `ON`,\n * or its `POW2` and texture dimensions are powers of 2.\n * Due to platform restriction, `ON` option will work like `POW2` for webgl-1.\n *\n * This property only affects WebGL.\n * @name MIPMAP_MODES\n * @memberof PIXI\n * @static\n * @enum {number}\n * @property {number} OFF - No mipmaps\n * @property {number} POW2 - Generate mipmaps if texture dimensions are pow2\n * @property {number} ON - Always generate mipmaps\n * @property {number} ON_MANUAL - Use mipmaps, but do not auto-generate them; this is used with a resource\n * that supports buffering each level-of-detail.\n */\nvar MIPMAP_MODES;\n(function (MIPMAP_MODES) {\n MIPMAP_MODES[MIPMAP_MODES[\"OFF\"] = 0] = \"OFF\";\n MIPMAP_MODES[MIPMAP_MODES[\"POW2\"] = 1] = \"POW2\";\n MIPMAP_MODES[MIPMAP_MODES[\"ON\"] = 2] = \"ON\";\n MIPMAP_MODES[MIPMAP_MODES[\"ON_MANUAL\"] = 3] = \"ON_MANUAL\";\n})(MIPMAP_MODES || (MIPMAP_MODES = {}));\n/**\n * How to treat textures with premultiplied alpha\n * @name ALPHA_MODES\n * @memberof PIXI\n * @static\n * @enum {number}\n * @property {number} NO_PREMULTIPLIED_ALPHA - Source is not premultiplied, leave it like that.\n * Option for compressed and data textures that are created from typed arrays.\n * @property {number} PREMULTIPLY_ON_UPLOAD - Source is not premultiplied, premultiply on upload.\n * Default option, used for all loaded images.\n * @property {number} PREMULTIPLIED_ALPHA - Source is already premultiplied\n * Example: spine atlases with `_pma` suffix.\n * @property {number} NPM - Alias for NO_PREMULTIPLIED_ALPHA.\n * @property {number} UNPACK - Default option, alias for PREMULTIPLY_ON_UPLOAD.\n * @property {number} PMA - Alias for PREMULTIPLIED_ALPHA.\n */\nvar ALPHA_MODES;\n(function (ALPHA_MODES) {\n ALPHA_MODES[ALPHA_MODES[\"NPM\"] = 0] = \"NPM\";\n ALPHA_MODES[ALPHA_MODES[\"UNPACK\"] = 1] = \"UNPACK\";\n ALPHA_MODES[ALPHA_MODES[\"PMA\"] = 2] = \"PMA\";\n ALPHA_MODES[ALPHA_MODES[\"NO_PREMULTIPLIED_ALPHA\"] = 0] = \"NO_PREMULTIPLIED_ALPHA\";\n ALPHA_MODES[ALPHA_MODES[\"PREMULTIPLY_ON_UPLOAD\"] = 1] = \"PREMULTIPLY_ON_UPLOAD\";\n ALPHA_MODES[ALPHA_MODES[\"PREMULTIPLY_ALPHA\"] = 2] = \"PREMULTIPLY_ALPHA\";\n ALPHA_MODES[ALPHA_MODES[\"PREMULTIPLIED_ALPHA\"] = 2] = \"PREMULTIPLIED_ALPHA\";\n})(ALPHA_MODES || (ALPHA_MODES = {}));\n/**\n * Configure whether filter textures are cleared after binding.\n *\n * Filter textures need not be cleared if the filter does not use pixel blending. {@link CLEAR_MODES.BLIT} will detect\n * this and skip clearing as an optimization.\n * @name CLEAR_MODES\n * @memberof PIXI\n * @static\n * @enum {number}\n * @property {number} BLEND - Do not clear the filter texture. The filter's output will blend on top of the output texture.\n * @property {number} CLEAR - Always clear the filter texture.\n * @property {number} BLIT - Clear only if {@link FilterSystem.forceClear} is set or if the filter uses pixel blending.\n * @property {number} NO - Alias for BLEND, same as `false` in earlier versions\n * @property {number} YES - Alias for CLEAR, same as `true` in earlier versions\n * @property {number} AUTO - Alias for BLIT\n */\nvar CLEAR_MODES;\n(function (CLEAR_MODES) {\n CLEAR_MODES[CLEAR_MODES[\"NO\"] = 0] = \"NO\";\n CLEAR_MODES[CLEAR_MODES[\"YES\"] = 1] = \"YES\";\n CLEAR_MODES[CLEAR_MODES[\"AUTO\"] = 2] = \"AUTO\";\n CLEAR_MODES[CLEAR_MODES[\"BLEND\"] = 0] = \"BLEND\";\n CLEAR_MODES[CLEAR_MODES[\"CLEAR\"] = 1] = \"CLEAR\";\n CLEAR_MODES[CLEAR_MODES[\"BLIT\"] = 2] = \"BLIT\";\n})(CLEAR_MODES || (CLEAR_MODES = {}));\n/**\n * The gc modes that are supported by pixi.\n *\n * The {@link PIXI.settings.GC_MODE} Garbage Collection mode for PixiJS textures is AUTO\n * If set to GC_MODE, the renderer will occasionally check textures usage. If they are not\n * used for a specified period of time they will be removed from the GPU. They will of course\n * be uploaded again when they are required. This is a silent behind the scenes process that\n * should ensure that the GPU does not get filled up.\n *\n * Handy for mobile devices!\n * This property only affects WebGL.\n * @name GC_MODES\n * @enum {number}\n * @static\n * @memberof PIXI\n * @property {number} AUTO - Garbage collection will happen periodically automatically\n * @property {number} MANUAL - Garbage collection will need to be called manually\n */\nvar GC_MODES;\n(function (GC_MODES) {\n GC_MODES[GC_MODES[\"AUTO\"] = 0] = \"AUTO\";\n GC_MODES[GC_MODES[\"MANUAL\"] = 1] = \"MANUAL\";\n})(GC_MODES || (GC_MODES = {}));\n/**\n * Constants that specify float precision in shaders.\n * @name PRECISION\n * @memberof PIXI\n * @constant\n * @static\n * @enum {string}\n * @property {string} [LOW='lowp'] -\n * @property {string} [MEDIUM='mediump'] -\n * @property {string} [HIGH='highp'] -\n */\nvar PRECISION;\n(function (PRECISION) {\n PRECISION[\"LOW\"] = \"lowp\";\n PRECISION[\"MEDIUM\"] = \"mediump\";\n PRECISION[\"HIGH\"] = \"highp\";\n})(PRECISION || (PRECISION = {}));\n/**\n * Constants for mask implementations.\n * We use `type` suffix because it leads to very different behaviours\n * @name MASK_TYPES\n * @memberof PIXI\n * @static\n * @enum {number}\n * @property {number} NONE - Mask is ignored\n * @property {number} SCISSOR - Scissor mask, rectangle on screen, cheap\n * @property {number} STENCIL - Stencil mask, 1-bit, medium, works only if renderer supports stencil\n * @property {number} SPRITE - Mask that uses SpriteMaskFilter, uses temporary RenderTexture\n * @property {number} COLOR - Color mask (RGBA)\n */\nvar MASK_TYPES;\n(function (MASK_TYPES) {\n MASK_TYPES[MASK_TYPES[\"NONE\"] = 0] = \"NONE\";\n MASK_TYPES[MASK_TYPES[\"SCISSOR\"] = 1] = \"SCISSOR\";\n MASK_TYPES[MASK_TYPES[\"STENCIL\"] = 2] = \"STENCIL\";\n MASK_TYPES[MASK_TYPES[\"SPRITE\"] = 3] = \"SPRITE\";\n MASK_TYPES[MASK_TYPES[\"COLOR\"] = 4] = \"COLOR\";\n})(MASK_TYPES || (MASK_TYPES = {}));\n/**\n * Bitwise OR of masks that indicate the color channels that are rendered to.\n * @static\n * @memberof PIXI\n * @name COLOR_MASK_BITS\n * @enum {number}\n * @property {number} RED - Red channel.\n * @property {number} GREEN - Green channel\n * @property {number} BLUE - Blue channel.\n * @property {number} ALPHA - Alpha channel.\n */\nvar COLOR_MASK_BITS;\n(function (COLOR_MASK_BITS) {\n COLOR_MASK_BITS[COLOR_MASK_BITS[\"RED\"] = 1] = \"RED\";\n COLOR_MASK_BITS[COLOR_MASK_BITS[\"GREEN\"] = 2] = \"GREEN\";\n COLOR_MASK_BITS[COLOR_MASK_BITS[\"BLUE\"] = 4] = \"BLUE\";\n COLOR_MASK_BITS[COLOR_MASK_BITS[\"ALPHA\"] = 8] = \"ALPHA\";\n})(COLOR_MASK_BITS || (COLOR_MASK_BITS = {}));\n/**\n * Constants for multi-sampling antialiasing.\n * @see PIXI.Framebuffer#multisample\n * @name MSAA_QUALITY\n * @memberof PIXI\n * @static\n * @enum {number}\n * @property {number} NONE - No multisampling for this renderTexture\n * @property {number} LOW - Try 2 samples\n * @property {number} MEDIUM - Try 4 samples\n * @property {number} HIGH - Try 8 samples\n */\nvar MSAA_QUALITY;\n(function (MSAA_QUALITY) {\n MSAA_QUALITY[MSAA_QUALITY[\"NONE\"] = 0] = \"NONE\";\n MSAA_QUALITY[MSAA_QUALITY[\"LOW\"] = 2] = \"LOW\";\n MSAA_QUALITY[MSAA_QUALITY[\"MEDIUM\"] = 4] = \"MEDIUM\";\n MSAA_QUALITY[MSAA_QUALITY[\"HIGH\"] = 8] = \"HIGH\";\n})(MSAA_QUALITY || (MSAA_QUALITY = {}));\n/**\n * Constants for various buffer types in Pixi\n * @see PIXI.BUFFER_TYPE\n * @name BUFFER_TYPE\n * @memberof PIXI\n * @static\n * @enum {number}\n * @property {number} ELEMENT_ARRAY_BUFFER - buffer type for using as an index buffer\n * @property {number} ARRAY_BUFFER - buffer type for using attribute data\n * @property {number} UNIFORM_BUFFER - the buffer type is for uniform buffer objects\n */\nvar BUFFER_TYPE;\n(function (BUFFER_TYPE) {\n BUFFER_TYPE[BUFFER_TYPE[\"ELEMENT_ARRAY_BUFFER\"] = 34963] = \"ELEMENT_ARRAY_BUFFER\";\n BUFFER_TYPE[BUFFER_TYPE[\"ARRAY_BUFFER\"] = 34962] = \"ARRAY_BUFFER\";\n // NOT YET SUPPORTED\n BUFFER_TYPE[BUFFER_TYPE[\"UNIFORM_BUFFER\"] = 35345] = \"UNIFORM_BUFFER\";\n})(BUFFER_TYPE || (BUFFER_TYPE = {}));\n\nexport { ALPHA_MODES, BLEND_MODES, BUFFER_BITS, BUFFER_TYPE, CLEAR_MODES, COLOR_MASK_BITS, DRAW_MODES, ENV, FORMATS, GC_MODES, MASK_TYPES, MIPMAP_MODES, MSAA_QUALITY, PRECISION, RENDERER_TYPE, SAMPLER_TYPES, SCALE_MODES, TARGETS, TYPES, WRAP_MODES };\n//# sourceMappingURL=constants.mjs.map\n","/*!\n * @pixi/settings - v6.5.8\n * Compiled Sun, 23 Oct 2022 23:01:45 UTC\n *\n * @pixi/settings is licensed under the MIT License.\n * http://www.opensource.org/licenses/mit-license\n */\nimport { MIPMAP_MODES, MSAA_QUALITY, GC_MODES, WRAP_MODES, SCALE_MODES, PRECISION } from '@pixi/constants';\n\nvar BrowserAdapter = {\n /**\n * Creates a canvas element of the given size.\n * This canvas is created using the browser's native canvas element.\n * @param width - width of the canvas\n * @param height - height of the canvas\n */\n createCanvas: function (width, height) {\n var canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n return canvas;\n },\n getWebGLRenderingContext: function () { return WebGLRenderingContext; },\n getNavigator: function () { return navigator; },\n getBaseUrl: function () { var _a; return ((_a = document.baseURI) !== null && _a !== void 0 ? _a : window.location.href); },\n fetch: function (url, options) { return fetch(url, options); },\n};\n\nvar appleIphone = /iPhone/i;\nvar appleIpod = /iPod/i;\nvar appleTablet = /iPad/i;\nvar appleUniversal = /\\biOS-universal(?:.+)Mac\\b/i;\nvar androidPhone = /\\bAndroid(?:.+)Mobile\\b/i;\nvar androidTablet = /Android/i;\nvar amazonPhone = /(?:SD4930UR|\\bSilk(?:.+)Mobile\\b)/i;\nvar amazonTablet = /Silk/i;\nvar windowsPhone = /Windows Phone/i;\nvar windowsTablet = /\\bWindows(?:.+)ARM\\b/i;\nvar otherBlackBerry = /BlackBerry/i;\nvar otherBlackBerry10 = /BB10/i;\nvar otherOpera = /Opera Mini/i;\nvar otherChrome = /\\b(CriOS|Chrome)(?:.+)Mobile/i;\nvar otherFirefox = /Mobile(?:.+)Firefox\\b/i;\nvar isAppleTabletOnIos13 = function (navigator) {\n return (typeof navigator !== 'undefined' &&\n navigator.platform === 'MacIntel' &&\n typeof navigator.maxTouchPoints === 'number' &&\n navigator.maxTouchPoints > 1 &&\n typeof MSStream === 'undefined');\n};\nfunction createMatch(userAgent) {\n return function (regex) { return regex.test(userAgent); };\n}\nfunction isMobile$1(param) {\n var nav = {\n userAgent: '',\n platform: '',\n maxTouchPoints: 0\n };\n if (!param && typeof navigator !== 'undefined') {\n nav = {\n userAgent: navigator.userAgent,\n platform: navigator.platform,\n maxTouchPoints: navigator.maxTouchPoints || 0\n };\n }\n else if (typeof param === 'string') {\n nav.userAgent = param;\n }\n else if (param && param.userAgent) {\n nav = {\n userAgent: param.userAgent,\n platform: param.platform,\n maxTouchPoints: param.maxTouchPoints || 0\n };\n }\n var userAgent = nav.userAgent;\n var tmp = userAgent.split('[FBAN');\n if (typeof tmp[1] !== 'undefined') {\n userAgent = tmp[0];\n }\n tmp = userAgent.split('Twitter');\n if (typeof tmp[1] !== 'undefined') {\n userAgent = tmp[0];\n }\n var match = createMatch(userAgent);\n var result = {\n apple: {\n phone: match(appleIphone) && !match(windowsPhone),\n ipod: match(appleIpod),\n tablet: !match(appleIphone) &&\n (match(appleTablet) || isAppleTabletOnIos13(nav)) &&\n !match(windowsPhone),\n universal: match(appleUniversal),\n device: (match(appleIphone) ||\n match(appleIpod) ||\n match(appleTablet) ||\n match(appleUniversal) ||\n isAppleTabletOnIos13(nav)) &&\n !match(windowsPhone)\n },\n amazon: {\n phone: match(amazonPhone),\n tablet: !match(amazonPhone) && match(amazonTablet),\n device: match(amazonPhone) || match(amazonTablet)\n },\n android: {\n phone: (!match(windowsPhone) && match(amazonPhone)) ||\n (!match(windowsPhone) && match(androidPhone)),\n tablet: !match(windowsPhone) &&\n !match(amazonPhone) &&\n !match(androidPhone) &&\n (match(amazonTablet) || match(androidTablet)),\n device: (!match(windowsPhone) &&\n (match(amazonPhone) ||\n match(amazonTablet) ||\n match(androidPhone) ||\n match(androidTablet))) ||\n match(/\\bokhttp\\b/i)\n },\n windows: {\n phone: match(windowsPhone),\n tablet: match(windowsTablet),\n device: match(windowsPhone) || match(windowsTablet)\n },\n other: {\n blackberry: match(otherBlackBerry),\n blackberry10: match(otherBlackBerry10),\n opera: match(otherOpera),\n firefox: match(otherFirefox),\n chrome: match(otherChrome),\n device: match(otherBlackBerry) ||\n match(otherBlackBerry10) ||\n match(otherOpera) ||\n match(otherFirefox) ||\n match(otherChrome)\n },\n any: false,\n phone: false,\n tablet: false\n };\n result.any =\n result.apple.device ||\n result.android.device ||\n result.windows.device ||\n result.other.device;\n result.phone =\n result.apple.phone || result.android.phone || result.windows.phone;\n result.tablet =\n result.apple.tablet || result.android.tablet || result.windows.tablet;\n return result;\n}\n\nvar isMobile = isMobile$1(globalThis.navigator);\n\n/**\n * Uploading the same buffer multiple times in a single frame can cause performance issues.\n * Apparent on iOS so only check for that at the moment\n * This check may become more complex if this issue pops up elsewhere.\n * @private\n * @returns {boolean} `true` if the same buffer may be uploaded more than once.\n */\nfunction canUploadSameBuffer() {\n return !isMobile.apple.device;\n}\n\n/**\n * The maximum recommended texture units to use.\n * In theory the bigger the better, and for desktop we'll use as many as we can.\n * But some mobile devices slow down if there is to many branches in the shader.\n * So in practice there seems to be a sweet spot size that varies depending on the device.\n *\n * In v4, all mobile devices were limited to 4 texture units because for this.\n * In v5, we allow all texture units to be used on modern Apple or Android devices.\n * @private\n * @param {number} max\n * @returns {number} The maximum recommended texture units to use.\n */\nfunction maxRecommendedTextures(max) {\n var allowMax = true;\n if (isMobile.tablet || isMobile.phone) {\n if (isMobile.apple.device) {\n var match = (navigator.userAgent).match(/OS (\\d+)_(\\d+)?/);\n if (match) {\n var majorVersion = parseInt(match[1], 10);\n // Limit texture units on devices below iOS 11, which will be older hardware\n if (majorVersion < 11) {\n allowMax = false;\n }\n }\n }\n if (isMobile.android.device) {\n var match = (navigator.userAgent).match(/Android\\s([0-9.]*)/);\n if (match) {\n var majorVersion = parseInt(match[1], 10);\n // Limit texture units on devices below Android 7 (Nougat), which will be older hardware\n if (majorVersion < 7) {\n allowMax = false;\n }\n }\n }\n }\n return allowMax ? max : 4;\n}\n\n/**\n * User's customizable globals for overriding the default PIXI settings, such\n * as a renderer's default resolution, framerate, float precision, etc.\n * @example\n * // Use the native window resolution as the default resolution\n * // will support high-density displays when rendering\n * PIXI.settings.RESOLUTION = window.devicePixelRatio;\n *\n * // Disable interpolation when scaling, will make texture be pixelated\n * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;\n * @namespace PIXI.settings\n */\nvar settings = {\n /**\n * This adapter is used to call methods that are platform dependent.\n * For example `document.createElement` only runs on the web but fails in node environments.\n * This allows us to support more platforms by abstracting away specific implementations per platform.\n *\n * By default the adapter is set to work in the browser. However you can create your own\n * by implementing the `IAdapter` interface. See `IAdapter` for more information.\n * @name ADAPTER\n * @memberof PIXI.settings\n * @type {PIXI.IAdapter}\n * @default PIXI.BrowserAdapter\n */\n ADAPTER: BrowserAdapter,\n /**\n * If set to true WebGL will attempt make textures mimpaped by default.\n * Mipmapping will only succeed if the base texture uploaded has power of two dimensions.\n * @static\n * @name MIPMAP_TEXTURES\n * @memberof PIXI.settings\n * @type {PIXI.MIPMAP_MODES}\n * @default PIXI.MIPMAP_MODES.POW2\n */\n MIPMAP_TEXTURES: MIPMAP_MODES.POW2,\n /**\n * Default anisotropic filtering level of textures.\n * Usually from 0 to 16\n * @static\n * @name ANISOTROPIC_LEVEL\n * @memberof PIXI.settings\n * @type {number}\n * @default 0\n */\n ANISOTROPIC_LEVEL: 0,\n /**\n * Default resolution / device pixel ratio of the renderer.\n * @static\n * @name RESOLUTION\n * @memberof PIXI.settings\n * @type {number}\n * @default 1\n */\n RESOLUTION: 1,\n /**\n * Default filter resolution.\n * @static\n * @name FILTER_RESOLUTION\n * @memberof PIXI.settings\n * @type {number}\n * @default 1\n */\n FILTER_RESOLUTION: 1,\n /**\n * Default filter samples.\n * @static\n * @name FILTER_MULTISAMPLE\n * @memberof PIXI.settings\n * @type {PIXI.MSAA_QUALITY}\n * @default PIXI.MSAA_QUALITY.NONE\n */\n FILTER_MULTISAMPLE: MSAA_QUALITY.NONE,\n /**\n * The maximum textures that this device supports.\n * @static\n * @name SPRITE_MAX_TEXTURES\n * @memberof PIXI.settings\n * @type {number}\n * @default 32\n */\n SPRITE_MAX_TEXTURES: maxRecommendedTextures(32),\n // TODO: maybe change to SPRITE.BATCH_SIZE: 2000\n // TODO: maybe add PARTICLE.BATCH_SIZE: 15000\n /**\n * The default sprite batch size.\n *\n * The default aims to balance desktop and mobile devices.\n * @static\n * @name SPRITE_BATCH_SIZE\n * @memberof PIXI.settings\n * @type {number}\n * @default 4096\n */\n SPRITE_BATCH_SIZE: 4096,\n /**\n * The default render options if none are supplied to {@link PIXI.Renderer}\n * or {@link PIXI.CanvasRenderer}.\n * @static\n * @name RENDER_OPTIONS\n * @memberof PIXI.settings\n * @type {object}\n * @property {HTMLCanvasElement} [view=null] -\n * @property {boolean} [antialias=false] -\n * @property {boolean} [autoDensity=false] -\n * @property {boolean} [useContextAlpha=true] -\n * @property {number} [backgroundColor=0x000000] -\n * @property {number} [backgroundAlpha=1] -\n * @property {boolean} [clearBeforeRender=true] -\n * @property {boolean} [preserveDrawingBuffer=false] -\n * @property {number} [width=800] -\n * @property {number} [height=600] -\n * @property {boolean} [legacy=false] -\n */\n RENDER_OPTIONS: {\n view: null,\n antialias: false,\n autoDensity: false,\n backgroundColor: 0x000000,\n backgroundAlpha: 1,\n useContextAlpha: true,\n clearBeforeRender: true,\n preserveDrawingBuffer: false,\n width: 800,\n height: 600,\n legacy: false,\n },\n /**\n * Default Garbage Collection mode.\n * @static\n * @name GC_MODE\n * @memberof PIXI.settings\n * @type {PIXI.GC_MODES}\n * @default PIXI.GC_MODES.AUTO\n */\n GC_MODE: GC_MODES.AUTO,\n /**\n * Default Garbage Collection max idle.\n * @static\n * @name GC_MAX_IDLE\n * @memberof PIXI.settings\n * @type {number}\n * @default 3600\n */\n GC_MAX_IDLE: 60 * 60,\n /**\n * Default Garbage Collection maximum check count.\n * @static\n * @name GC_MAX_CHECK_COUNT\n * @memberof PIXI.settings\n * @type {number}\n * @default 600\n */\n GC_MAX_CHECK_COUNT: 60 * 10,\n /**\n * Default wrap modes that are supported by pixi.\n * @static\n * @name WRAP_MODE\n * @memberof PIXI.settings\n * @type {PIXI.WRAP_MODES}\n * @default PIXI.WRAP_MODES.CLAMP\n */\n WRAP_MODE: WRAP_MODES.CLAMP,\n /**\n * Default scale mode for textures.\n * @static\n * @name SCALE_MODE\n * @memberof PIXI.settings\n * @type {PIXI.SCALE_MODES}\n * @default PIXI.SCALE_MODES.LINEAR\n */\n SCALE_MODE: SCALE_MODES.LINEAR,\n /**\n * Default specify float precision in vertex shader.\n * @static\n * @name PRECISION_VERTEX\n * @memberof PIXI.settings\n * @type {PIXI.PRECISION}\n * @default PIXI.PRECISION.HIGH\n */\n PRECISION_VERTEX: PRECISION.HIGH,\n /**\n * Default specify float precision in fragment shader.\n * iOS is best set at highp due to https://github.com/pixijs/pixi.js/issues/3742\n * @static\n * @name PRECISION_FRAGMENT\n * @memberof PIXI.settings\n * @type {PIXI.PRECISION}\n * @default PIXI.PRECISION.MEDIUM\n */\n PRECISION_FRAGMENT: isMobile.apple.device ? PRECISION.HIGH : PRECISION.MEDIUM,\n /**\n * Can we upload the same buffer in a single frame?\n * @static\n * @name CAN_UPLOAD_SAME_BUFFER\n * @memberof PIXI.settings\n * @type {boolean}\n */\n CAN_UPLOAD_SAME_BUFFER: canUploadSameBuffer(),\n /**\n * Enables bitmap creation before image load. This feature is experimental.\n * @static\n * @name CREATE_IMAGE_BITMAP\n * @memberof PIXI.settings\n * @type {boolean}\n * @default false\n */\n CREATE_IMAGE_BITMAP: false,\n /**\n * If true PixiJS will Math.floor() x/y values when rendering, stopping pixel interpolation.\n * Advantages can include sharper image quality (like text) and faster rendering on canvas.\n * The main disadvantage is movement of objects may appear less smooth.\n * @static\n * @constant\n * @memberof PIXI.settings\n * @type {boolean}\n * @default false\n */\n ROUND_PIXELS: false,\n};\n\nexport { BrowserAdapter, isMobile, settings };\n//# sourceMappingURL=settings.mjs.map\n","/*!\n * @pixi/utils - v6.5.8\n * Compiled Sun, 23 Oct 2022 23:01:45 UTC\n *\n * @pixi/utils is licensed under the MIT License.\n * http://www.opensource.org/licenses/mit-license\n */\nimport { settings } from '@pixi/settings';\nexport { isMobile } from '@pixi/settings';\nexport { default as EventEmitter } from 'eventemitter3';\nexport { default as earcut } from 'earcut';\nimport { parse, format, resolve } from 'url';\nimport { BLEND_MODES } from '@pixi/constants';\n\n/**\n * This file contains redeclared types for Node `url` and `querystring` modules. These modules\n * don't provide their own typings but instead are a part of the full Node typings. The purpose of\n * this file is to redeclare the required types to avoid having the whole Node types as a\n * dependency.\n */\nvar url = {\n parse: parse,\n format: format,\n resolve: resolve,\n};\n\nfunction assertPath(path) {\n if (typeof path !== 'string') {\n throw new TypeError(\"Path must be a string. Received \" + JSON.stringify(path));\n }\n}\nfunction removeUrlParams(url) {\n var re = url.split('?')[0];\n return re.split('#')[0];\n}\nfunction escapeRegExp(string) {\n return string.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'); // $& means the whole matched string\n}\nfunction replaceAll(str, find, replace) {\n return str.replace(new RegExp(escapeRegExp(find), 'g'), replace);\n}\n// Resolves . and .. elements in a path with directory names\nfunction normalizeStringPosix(path, allowAboveRoot) {\n var res = '';\n var lastSegmentLength = 0;\n var lastSlash = -1;\n var dots = 0;\n var code;\n for (var i = 0; i <= path.length; ++i) {\n if (i < path.length) {\n code = path.charCodeAt(i);\n }\n else if (code === 47) {\n break;\n }\n else {\n code = 47;\n }\n if (code === 47) {\n if (lastSlash === i - 1 || dots === 1) ;\n else if (lastSlash !== i - 1 && dots === 2) {\n if (res.length < 2\n || lastSegmentLength !== 2\n || res.charCodeAt(res.length - 1) !== 46\n || res.charCodeAt(res.length - 2) !== 46) {\n if (res.length > 2) {\n var lastSlashIndex = res.lastIndexOf('/');\n if (lastSlashIndex !== res.length - 1) {\n if (lastSlashIndex === -1) {\n res = '';\n lastSegmentLength = 0;\n }\n else {\n res = res.slice(0, lastSlashIndex);\n lastSegmentLength = res.length - 1 - res.lastIndexOf('/');\n }\n lastSlash = i;\n dots = 0;\n continue;\n }\n }\n else if (res.length === 2 || res.length === 1) {\n res = '';\n lastSegmentLength = 0;\n lastSlash = i;\n dots = 0;\n continue;\n }\n }\n if (allowAboveRoot) {\n if (res.length > 0) {\n res += '/..';\n }\n else {\n res = '..';\n }\n lastSegmentLength = 2;\n }\n }\n else {\n if (res.length > 0) {\n res += \"/\" + path.slice(lastSlash + 1, i);\n }\n else {\n res = path.slice(lastSlash + 1, i);\n }\n lastSegmentLength = i - lastSlash - 1;\n }\n lastSlash = i;\n dots = 0;\n }\n else if (code === 46 && dots !== -1) {\n ++dots;\n }\n else {\n dots = -1;\n }\n }\n return res;\n}\nvar path = {\n /**\n * Converts a path to posix format.\n * @param path - The path to convert to posix\n */\n toPosix: function (path) { return replaceAll(path, '\\\\', '/'); },\n /**\n * Checks if the path is a URL\n * @param path - The path to check\n */\n isUrl: function (path) { return (/^https?:/).test(this.toPosix(path)); },\n /**\n * Checks if the path is a data URL\n * @param path - The path to check\n */\n isDataUrl: function (path) {\n // eslint-disable-next-line max-len\n return (/^data:([a-z]+\\/[a-z0-9-+.]+(;[a-z0-9-.!#$%*+.{}|~`]+=[a-z0-9-.!#$%*+.{}()_|~`]+)*)?(;base64)?,([a-z0-9!$&',()*+;=\\-._~:@\\/?%\\s<>]*?)$/i)\n .test(path);\n },\n /**\n * Checks if the path has a protocol e.g. http://\n * This will return true for windows file paths\n * @param path - The path to check\n */\n hasProtocol: function (path) { return (/^[^/:]+:\\//).test(this.toPosix(path)); },\n /**\n * Returns the protocol of the path e.g. http://, C:/, file:///\n * @param path - The path to get the protocol from\n */\n getProtocol: function (path) {\n assertPath(path);\n path = this.toPosix(path);\n var protocol = '';\n var isFile = (/^file:\\/\\/\\//).exec(path);\n var isHttp = (/^[^/:]+:\\/\\//).exec(path);\n var isWindows = (/^[^/:]+:\\//).exec(path);\n if (isFile || isHttp || isWindows) {\n var arr = (isFile === null || isFile === void 0 ? void 0 : isFile[0]) || (isHttp === null || isHttp === void 0 ? void 0 : isHttp[0]) || (isWindows === null || isWindows === void 0 ? void 0 : isWindows[0]);\n protocol = arr;\n path = path.slice(arr.length);\n }\n return protocol;\n },\n /**\n * Converts URL to an absolute path.\n * When loading from a Web Worker, we must use absolute paths.\n * If the URL is already absolute we return it as is\n * If it's not, we convert it\n * @param url - The URL to test\n * @param customBaseUrl - The base URL to use\n * @param customRootUrl - The root URL to use\n */\n toAbsolute: function (url, customBaseUrl, customRootUrl) {\n if (this.isDataUrl(url))\n { return url; }\n var baseUrl = removeUrlParams(this.toPosix(customBaseUrl !== null && customBaseUrl !== void 0 ? customBaseUrl : settings.ADAPTER.getBaseUrl()));\n var rootUrl = removeUrlParams(this.toPosix(customRootUrl !== null && customRootUrl !== void 0 ? customRootUrl : this.rootname(baseUrl)));\n assertPath(url);\n url = this.toPosix(url);\n // root relative url\n if (url.startsWith('/')) {\n return path.join(rootUrl, url.slice(1));\n }\n var absolutePath = this.isAbsolute(url) ? url : this.join(baseUrl, url);\n return absolutePath;\n },\n /**\n * Normalizes the given path, resolving '..' and '.' segments\n * @param path - The path to normalize\n */\n normalize: function (path) {\n path = this.toPosix(path);\n assertPath(path);\n if (path.length === 0)\n { return '.'; }\n var protocol = '';\n var isAbsolute = path.startsWith('/');\n if (this.hasProtocol(path)) {\n protocol = this.rootname(path);\n path = path.slice(protocol.length);\n }\n var trailingSeparator = path.endsWith('/');\n // Normalize the path\n path = normalizeStringPosix(path, false);\n if (path.length > 0 && trailingSeparator)\n { path += '/'; }\n if (isAbsolute)\n { return \"/\" + path; }\n return protocol + path;\n },\n /**\n * Determines if path is an absolute path.\n * Absolute paths can be urls, data urls, or paths on disk\n * @param path - The path to test\n */\n isAbsolute: function (path) {\n assertPath(path);\n path = this.toPosix(path);\n if (this.hasProtocol(path))\n { return true; }\n return path.startsWith('/');\n },\n /**\n * Joins all given path segments together using the platform-specific separator as a delimiter,\n * then normalizes the resulting path\n * @param segments - The segments of the path to join\n */\n join: function () {\n var arguments$1 = arguments;\n\n var _a;\n var segments = [];\n for (var _i = 0; _i < arguments.length; _i++) {\n segments[_i] = arguments$1[_i];\n }\n if (segments.length === 0) {\n return '.';\n }\n var joined;\n for (var i = 0; i < segments.length; ++i) {\n var arg = segments[i];\n assertPath(arg);\n if (arg.length > 0) {\n if (joined === undefined)\n { joined = arg; }\n else {\n var prevArg = (_a = segments[i - 1]) !== null && _a !== void 0 ? _a : '';\n if (this.extname(prevArg)) {\n joined += \"/../\" + arg;\n }\n else {\n joined += \"/\" + arg;\n }\n }\n }\n }\n if (joined === undefined) {\n return '.';\n }\n return this.normalize(joined);\n },\n /**\n * Returns the directory name of a path\n * @param path - The path to parse\n */\n dirname: function (path) {\n assertPath(path);\n if (path.length === 0)\n { return '.'; }\n path = this.toPosix(path);\n var code = path.charCodeAt(0);\n var hasRoot = code === 47;\n var end = -1;\n var matchedSlash = true;\n var proto = this.getProtocol(path);\n var origpath = path;\n path = path.slice(proto.length);\n for (var i = path.length - 1; i >= 1; --i) {\n code = path.charCodeAt(i);\n if (code === 47) {\n if (!matchedSlash) {\n end = i;\n break;\n }\n }\n else {\n // We saw the first non-path separator\n matchedSlash = false;\n }\n }\n // if end is -1 and its a url then we need to add the path back\n // eslint-disable-next-line no-nested-ternary\n if (end === -1)\n { return hasRoot ? '/' : this.isUrl(origpath) ? proto + path : proto; }\n if (hasRoot && end === 1)\n { return '//'; }\n return proto + path.slice(0, end);\n },\n /**\n * Returns the root of the path e.g. /, C:/, file:///, http://domain.com/\n * @param path - The path to parse\n */\n rootname: function (path) {\n assertPath(path);\n path = this.toPosix(path);\n var root = '';\n if (path.startsWith('/'))\n { root = '/'; }\n else {\n root = this.getProtocol(path);\n }\n if (this.isUrl(path)) {\n // need to find the first path separator\n var index = path.indexOf('/', root.length);\n if (index !== -1) {\n root = path.slice(0, index);\n }\n else\n { root = path; }\n if (!root.endsWith('/'))\n { root += '/'; }\n }\n return root;\n },\n /**\n * Returns the last portion of a path\n * @param path - The path to test\n * @param ext - Optional extension to remove\n */\n basename: function (path, ext) {\n assertPath(path);\n if (ext)\n { assertPath(ext); }\n path = this.toPosix(path);\n var start = 0;\n var end = -1;\n var matchedSlash = true;\n var i;\n if (ext !== undefined && ext.length > 0 && ext.length <= path.length) {\n if (ext.length === path.length && ext === path)\n { return ''; }\n var extIdx = ext.length - 1;\n var firstNonSlashEnd = -1;\n for (i = path.length - 1; i >= 0; --i) {\n var code = path.charCodeAt(i);\n if (code === 47) {\n // If we reached a path separator that was not part of a set of path\n // separators at the end of the string, stop now\n if (!matchedSlash) {\n start = i + 1;\n break;\n }\n }\n else {\n if (firstNonSlashEnd === -1) {\n // We saw the first non-path separator, remember this index in case\n // we need it if the extension ends up not matching\n matchedSlash = false;\n firstNonSlashEnd = i + 1;\n }\n if (extIdx >= 0) {\n // Try to match the explicit extension\n if (code === ext.charCodeAt(extIdx)) {\n if (--extIdx === -1) {\n // We matched the extension, so mark this as the end of our path\n // component\n end = i;\n }\n }\n else {\n // Extension does not match, so our result is the entire path\n // component\n extIdx = -1;\n end = firstNonSlashEnd;\n }\n }\n }\n }\n if (start === end)\n { end = firstNonSlashEnd; }\n else if (end === -1)\n { end = path.length; }\n return path.slice(start, end);\n }\n for (i = path.length - 1; i >= 0; --i) {\n if (path.charCodeAt(i) === 47) {\n // If we reached a path separator that was not part of a set of path\n // separators at the end of the string, stop now\n if (!matchedSlash) {\n start = i + 1;\n break;\n }\n }\n else if (end === -1) {\n // We saw the first non-path separator, mark this as the end of our\n // path component\n matchedSlash = false;\n end = i + 1;\n }\n }\n if (end === -1)\n { return ''; }\n return path.slice(start, end);\n },\n /**\n * Returns the extension of the path, from the last occurrence of the . (period) character to end of string in the last\n * portion of the path. If there is no . in the last portion of the path, or if there are no . characters other than\n * the first character of the basename of path, an empty string is returned.\n * @param path - The path to parse\n */\n extname: function (path) {\n assertPath(path);\n path = this.toPosix(path);\n var startDot = -1;\n var startPart = 0;\n var end = -1;\n var matchedSlash = true;\n // Track the state of characters (if any) we see before our first dot and\n // after any path separator we find\n var preDotState = 0;\n for (var i = path.length - 1; i >= 0; --i) {\n var code = path.charCodeAt(i);\n if (code === 47) {\n // If we reached a path separator that was not part of a set of path\n // separators at the end of the string, stop now\n if (!matchedSlash) {\n startPart = i + 1;\n break;\n }\n continue;\n }\n if (end === -1) {\n // We saw the first non-path separator, mark this as the end of our\n // extension\n matchedSlash = false;\n end = i + 1;\n }\n if (code === 46) {\n // If this is our first dot, mark it as the start of our extension\n if (startDot === -1)\n { startDot = i; }\n else if (preDotState !== 1)\n { preDotState = 1; }\n }\n else if (startDot !== -1) {\n // We saw a non-dot and non-path separator before our dot, so we should\n // have a good chance at having a non-empty extension\n preDotState = -1;\n }\n }\n if (startDot === -1 || end === -1\n // We saw a non-dot character immediately before the dot\n || preDotState === 0\n // The (right-most) trimmed path component is exactly '..'\n // eslint-disable-next-line no-mixed-operators\n || preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) {\n return '';\n }\n return path.slice(startDot, end);\n },\n /**\n * Parses a path into an object containing the 'root', `dir`, `base`, `ext`, and `name` properties.\n * @param path - The path to parse\n */\n parse: function (path) {\n assertPath(path);\n var ret = { root: '', dir: '', base: '', ext: '', name: '' };\n if (path.length === 0)\n { return ret; }\n path = this.toPosix(path);\n var code = path.charCodeAt(0);\n var isAbsolute = this.isAbsolute(path);\n var start;\n ret.root = this.rootname(path);\n if (isAbsolute || this.hasProtocol(path)) {\n start = 1;\n }\n else {\n start = 0;\n }\n var startDot = -1;\n var startPart = 0;\n var end = -1;\n var matchedSlash = true;\n var i = path.length - 1;\n // Track the state of characters (if any) we see before our first dot and\n // after any path separator we find\n var preDotState = 0;\n // Get non-dir info\n for (; i >= start; --i) {\n code = path.charCodeAt(i);\n if (code === 47) {\n // If we reached a path separator that was not part of a set of path\n // separators at the end of the string, stop now\n if (!matchedSlash) {\n startPart = i + 1;\n break;\n }\n continue;\n }\n if (end === -1) {\n // We saw the first non-path separator, mark this as the end of our\n // extension\n matchedSlash = false;\n end = i + 1;\n }\n if (code === 46) {\n // If this is our first dot, mark it as the start of our extension\n if (startDot === -1)\n { startDot = i; }\n else if (preDotState !== 1)\n { preDotState = 1; }\n }\n else if (startDot !== -1) {\n // We saw a non-dot and non-path separator before our dot, so we should\n // have a good chance at having a non-empty extension\n preDotState = -1;\n }\n }\n if (startDot === -1 || end === -1\n // We saw a non-dot character immediately before the dot\n || preDotState === 0\n // The (right-most) trimmed path component is exactly '..'\n // eslint-disable-next-line no-mixed-operators\n || preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) {\n if (end !== -1) {\n if (startPart === 0 && isAbsolute)\n { ret.base = ret.name = path.slice(1, end); }\n else\n { ret.base = ret.name = path.slice(startPart, end); }\n }\n }\n else {\n if (startPart === 0 && isAbsolute) {\n ret.name = path.slice(1, startDot);\n ret.base = path.slice(1, end);\n }\n else {\n ret.name = path.slice(startPart, startDot);\n ret.base = path.slice(startPart, end);\n }\n ret.ext = path.slice(startDot, end);\n }\n ret.dir = this.dirname(path);\n return ret;\n },\n sep: '/',\n delimiter: ':'\n};\n\n/**\n * The prefix that denotes a URL is for a retina asset.\n * @static\n * @name RETINA_PREFIX\n * @memberof PIXI.settings\n * @type {RegExp}\n * @default /@([0-9\\.]+)x/\n * @example `@2x`\n */\nsettings.RETINA_PREFIX = /@([0-9\\.]+)x/;\n/**\n * Should the `failIfMajorPerformanceCaveat` flag be enabled as a context option used in the `isWebGLSupported` function.\n * If set to true, a WebGL renderer can fail to be created if the browser thinks there could be performance issues when\n * using WebGL.\n *\n * In PixiJS v6 this has changed from true to false by default, to allow WebGL to work in as many scenarios as possible.\n * However, some users may have a poor experience, for example, if a user has a gpu or driver version blacklisted by the\n * browser.\n *\n * If your application requires high performance rendering, you may wish to set this to false.\n * We recommend one of two options if you decide to set this flag to false:\n *\n * 1: Use the `pixi.js-legacy` package, which includes a Canvas renderer as a fallback in case high performance WebGL is\n * not supported.\n *\n * 2: Call `isWebGLSupported` (which if found in the PIXI.utils package) in your code before attempting to create a PixiJS\n * renderer, and show an error message to the user if the function returns false, explaining that their device & browser\n * combination does not support high performance WebGL.\n * This is a much better strategy than trying to create a PixiJS renderer and finding it then fails.\n * @static\n * @name FAIL_IF_MAJOR_PERFORMANCE_CAVEAT\n * @memberof PIXI.settings\n * @type {boolean}\n * @default false\n */\nsettings.FAIL_IF_MAJOR_PERFORMANCE_CAVEAT = false;\n\nvar saidHello = false;\nvar VERSION = '6.5.8';\n/**\n * Skips the hello message of renderers that are created after this is run.\n * @function skipHello\n * @memberof PIXI.utils\n */\nfunction skipHello() {\n saidHello = true;\n}\n/**\n * Logs out the version and renderer information for this running instance of PIXI.\n * If you don't want to see this message you can run `PIXI.utils.skipHello()` before\n * creating your renderer. Keep in mind that doing that will forever make you a jerk face.\n * @static\n * @function sayHello\n * @memberof PIXI.utils\n * @param {string} type - The string renderer type to log.\n */\nfunction sayHello(type) {\n var _a;\n if (saidHello) {\n return;\n }\n if (settings.ADAPTER.getNavigator().userAgent.toLowerCase().indexOf('chrome') > -1) {\n var args = [\n \"\\n %c %c %c PixiJS \" + VERSION + \" - \\u2730 \" + type + \" \\u2730 %c %c http://www.pixijs.com/ %c %c \\u2665%c\\u2665%c\\u2665 \\n\\n\",\n 'background: #ff66a5; padding:5px 0;',\n 'background: #ff66a5; padding:5px 0;',\n 'color: #ff66a5; background: #030307; padding:5px 0;',\n 'background: #ff66a5; padding:5px 0;',\n 'background: #ffc3dc; padding:5px 0;',\n 'background: #ff66a5; padding:5px 0;',\n 'color: #ff2424; background: #fff; padding:5px 0;',\n 'color: #ff2424; background: #fff; padding:5px 0;',\n 'color: #ff2424; background: #fff; padding:5px 0;' ];\n (_a = globalThis.console).log.apply(_a, args);\n }\n else if (globalThis.console) {\n globalThis.console.log(\"PixiJS \" + VERSION + \" - \" + type + \" - http://www.pixijs.com/\");\n }\n saidHello = true;\n}\n\nvar supported;\n/**\n * Helper for checking for WebGL support.\n * @memberof PIXI.utils\n * @function isWebGLSupported\n * @returns {boolean} Is WebGL supported.\n */\nfunction isWebGLSupported() {\n if (typeof supported === 'undefined') {\n supported = (function supported() {\n var contextOptions = {\n stencil: true,\n failIfMajorPerformanceCaveat: settings.FAIL_IF_MAJOR_PERFORMANCE_CAVEAT,\n };\n try {\n if (!settings.ADAPTER.getWebGLRenderingContext()) {\n return false;\n }\n var canvas = settings.ADAPTER.createCanvas();\n var gl = (canvas.getContext('webgl', contextOptions)\n || canvas.getContext('experimental-webgl', contextOptions));\n var success = !!(gl && gl.getContextAttributes().stencil);\n if (gl) {\n var loseContext = gl.getExtension('WEBGL_lose_context');\n if (loseContext) {\n loseContext.loseContext();\n }\n }\n gl = null;\n return success;\n }\n catch (e) {\n return false;\n }\n })();\n }\n return supported;\n}\n\nvar aliceblue = \"#f0f8ff\";\nvar antiquewhite = \"#faebd7\";\nvar aqua = \"#00ffff\";\nvar aquamarine = \"#7fffd4\";\nvar azure = \"#f0ffff\";\nvar beige = \"#f5f5dc\";\nvar bisque = \"#ffe4c4\";\nvar black = \"#000000\";\nvar blanchedalmond = \"#ffebcd\";\nvar blue = \"#0000ff\";\nvar blueviolet = \"#8a2be2\";\nvar brown = \"#a52a2a\";\nvar burlywood = \"#deb887\";\nvar cadetblue = \"#5f9ea0\";\nvar chartreuse = \"#7fff00\";\nvar chocolate = \"#d2691e\";\nvar coral = \"#ff7f50\";\nvar cornflowerblue = \"#6495ed\";\nvar cornsilk = \"#fff8dc\";\nvar crimson = \"#dc143c\";\nvar cyan = \"#00ffff\";\nvar darkblue = \"#00008b\";\nvar darkcyan = \"#008b8b\";\nvar darkgoldenrod = \"#b8860b\";\nvar darkgray = \"#a9a9a9\";\nvar darkgreen = \"#006400\";\nvar darkgrey = \"#a9a9a9\";\nvar darkkhaki = \"#bdb76b\";\nvar darkmagenta = \"#8b008b\";\nvar darkolivegreen = \"#556b2f\";\nvar darkorange = \"#ff8c00\";\nvar darkorchid = \"#9932cc\";\nvar darkred = \"#8b0000\";\nvar darksalmon = \"#e9967a\";\nvar darkseagreen = \"#8fbc8f\";\nvar darkslateblue = \"#483d8b\";\nvar darkslategray = \"#2f4f4f\";\nvar darkslategrey = \"#2f4f4f\";\nvar darkturquoise = \"#00ced1\";\nvar darkviolet = \"#9400d3\";\nvar deeppink = \"#ff1493\";\nvar deepskyblue = \"#00bfff\";\nvar dimgray = \"#696969\";\nvar dimgrey = \"#696969\";\nvar dodgerblue = \"#1e90ff\";\nvar firebrick = \"#b22222\";\nvar floralwhite = \"#fffaf0\";\nvar forestgreen = \"#228b22\";\nvar fuchsia = \"#ff00ff\";\nvar gainsboro = \"#dcdcdc\";\nvar ghostwhite = \"#f8f8ff\";\nvar goldenrod = \"#daa520\";\nvar gold = \"#ffd700\";\nvar gray = \"#808080\";\nvar green = \"#008000\";\nvar greenyellow = \"#adff2f\";\nvar grey = \"#808080\";\nvar honeydew = \"#f0fff0\";\nvar hotpink = \"#ff69b4\";\nvar indianred = \"#cd5c5c\";\nvar indigo = \"#4b0082\";\nvar ivory = \"#fffff0\";\nvar khaki = \"#f0e68c\";\nvar lavenderblush = \"#fff0f5\";\nvar lavender = \"#e6e6fa\";\nvar lawngreen = \"#7cfc00\";\nvar lemonchiffon = \"#fffacd\";\nvar lightblue = \"#add8e6\";\nvar lightcoral = \"#f08080\";\nvar lightcyan = \"#e0ffff\";\nvar lightgoldenrodyellow = \"#fafad2\";\nvar lightgray = \"#d3d3d3\";\nvar lightgreen = \"#90ee90\";\nvar lightgrey = \"#d3d3d3\";\nvar lightpink = \"#ffb6c1\";\nvar lightsalmon = \"#ffa07a\";\nvar lightseagreen = \"#20b2aa\";\nvar lightskyblue = \"#87cefa\";\nvar lightslategray = \"#778899\";\nvar lightslategrey = \"#778899\";\nvar lightsteelblue = \"#b0c4de\";\nvar lightyellow = \"#ffffe0\";\nvar lime = \"#00ff00\";\nvar limegreen = \"#32cd32\";\nvar linen = \"#faf0e6\";\nvar magenta = \"#ff00ff\";\nvar maroon = \"#800000\";\nvar mediumaquamarine = \"#66cdaa\";\nvar mediumblue = \"#0000cd\";\nvar mediumorchid = \"#ba55d3\";\nvar mediumpurple = \"#9370db\";\nvar mediumseagreen = \"#3cb371\";\nvar mediumslateblue = \"#7b68ee\";\nvar mediumspringgreen = \"#00fa9a\";\nvar mediumturquoise = \"#48d1cc\";\nvar mediumvioletred = \"#c71585\";\nvar midnightblue = \"#191970\";\nvar mintcream = \"#f5fffa\";\nvar mistyrose = \"#ffe4e1\";\nvar moccasin = \"#ffe4b5\";\nvar navajowhite = \"#ffdead\";\nvar navy = \"#000080\";\nvar oldlace = \"#fdf5e6\";\nvar olive = \"#808000\";\nvar olivedrab = \"#6b8e23\";\nvar orange = \"#ffa500\";\nvar orangered = \"#ff4500\";\nvar orchid = \"#da70d6\";\nvar palegoldenrod = \"#eee8aa\";\nvar palegreen = \"#98fb98\";\nvar paleturquoise = \"#afeeee\";\nvar palevioletred = \"#db7093\";\nvar papayawhip = \"#ffefd5\";\nvar peachpuff = \"#ffdab9\";\nvar peru = \"#cd853f\";\nvar pink = \"#ffc0cb\";\nvar plum = \"#dda0dd\";\nvar powderblue = \"#b0e0e6\";\nvar purple = \"#800080\";\nvar rebeccapurple = \"#663399\";\nvar red = \"#ff0000\";\nvar rosybrown = \"#bc8f8f\";\nvar royalblue = \"#4169e1\";\nvar saddlebrown = \"#8b4513\";\nvar salmon = \"#fa8072\";\nvar sandybrown = \"#f4a460\";\nvar seagreen = \"#2e8b57\";\nvar seashell = \"#fff5ee\";\nvar sienna = \"#a0522d\";\nvar silver = \"#c0c0c0\";\nvar skyblue = \"#87ceeb\";\nvar slateblue = \"#6a5acd\";\nvar slategray = \"#708090\";\nvar slategrey = \"#708090\";\nvar snow = \"#fffafa\";\nvar springgreen = \"#00ff7f\";\nvar steelblue = \"#4682b4\";\nvar tan = \"#d2b48c\";\nvar teal = \"#008080\";\nvar thistle = \"#d8bfd8\";\nvar tomato = \"#ff6347\";\nvar turquoise = \"#40e0d0\";\nvar violet = \"#ee82ee\";\nvar wheat = \"#f5deb3\";\nvar white = \"#ffffff\";\nvar whitesmoke = \"#f5f5f5\";\nvar yellow = \"#ffff00\";\nvar yellowgreen = \"#9acd32\";\nvar cssColorNames = {\n\taliceblue: aliceblue,\n\tantiquewhite: antiquewhite,\n\taqua: aqua,\n\taquamarine: aquamarine,\n\tazure: azure,\n\tbeige: beige,\n\tbisque: bisque,\n\tblack: black,\n\tblanchedalmond: blanchedalmond,\n\tblue: blue,\n\tblueviolet: blueviolet,\n\tbrown: brown,\n\tburlywood: burlywood,\n\tcadetblue: cadetblue,\n\tchartreuse: chartreuse,\n\tchocolate: chocolate,\n\tcoral: coral,\n\tcornflowerblue: cornflowerblue,\n\tcornsilk: cornsilk,\n\tcrimson: crimson,\n\tcyan: cyan,\n\tdarkblue: darkblue,\n\tdarkcyan: darkcyan,\n\tdarkgoldenrod: darkgoldenrod,\n\tdarkgray: darkgray,\n\tdarkgreen: darkgreen,\n\tdarkgrey: darkgrey,\n\tdarkkhaki: darkkhaki,\n\tdarkmagenta: darkmagenta,\n\tdarkolivegreen: darkolivegreen,\n\tdarkorange: darkorange,\n\tdarkorchid: darkorchid,\n\tdarkred: darkred,\n\tdarksalmon: darksalmon,\n\tdarkseagreen: darkseagreen,\n\tdarkslateblue: darkslateblue,\n\tdarkslategray: darkslategray,\n\tdarkslategrey: darkslategrey,\n\tdarkturquoise: darkturquoise,\n\tdarkviolet: darkviolet,\n\tdeeppink: deeppink,\n\tdeepskyblue: deepskyblue,\n\tdimgray: dimgray,\n\tdimgrey: dimgrey,\n\tdodgerblue: dodgerblue,\n\tfirebrick: firebrick,\n\tfloralwhite: floralwhite,\n\tforestgreen: forestgreen,\n\tfuchsia: fuchsia,\n\tgainsboro: gainsboro,\n\tghostwhite: ghostwhite,\n\tgoldenrod: goldenrod,\n\tgold: gold,\n\tgray: gray,\n\tgreen: green,\n\tgreenyellow: greenyellow,\n\tgrey: grey,\n\thoneydew: honeydew,\n\thotpink: hotpink,\n\tindianred: indianred,\n\tindigo: indigo,\n\tivory: ivory,\n\tkhaki: khaki,\n\tlavenderblush: lavenderblush,\n\tlavender: lavender,\n\tlawngreen: lawngreen,\n\tlemonchiffon: lemonchiffon,\n\tlightblue: lightblue,\n\tlightcoral: lightcoral,\n\tlightcyan: lightcyan,\n\tlightgoldenrodyellow: lightgoldenrodyellow,\n\tlightgray: lightgray,\n\tlightgreen: lightgreen,\n\tlightgrey: lightgrey,\n\tlightpink: lightpink,\n\tlightsalmon: lightsalmon,\n\tlightseagreen: lightseagreen,\n\tlightskyblue: lightskyblue,\n\tlightslategray: lightslategray,\n\tlightslategrey: lightslategrey,\n\tlightsteelblue: lightsteelblue,\n\tlightyellow: lightyellow,\n\tlime: lime,\n\tlimegreen: limegreen,\n\tlinen: linen,\n\tmagenta: magenta,\n\tmaroon: maroon,\n\tmediumaquamarine: mediumaquamarine,\n\tmediumblue: mediumblue,\n\tmediumorchid: mediumorchid,\n\tmediumpurple: mediumpurple,\n\tmediumseagreen: mediumseagreen,\n\tmediumslateblue: mediumslateblue,\n\tmediumspringgreen: mediumspringgreen,\n\tmediumturquoise: mediumturquoise,\n\tmediumvioletred: mediumvioletred,\n\tmidnightblue: midnightblue,\n\tmintcream: mintcream,\n\tmistyrose: mistyrose,\n\tmoccasin: moccasin,\n\tnavajowhite: navajowhite,\n\tnavy: navy,\n\toldlace: oldlace,\n\tolive: olive,\n\tolivedrab: olivedrab,\n\torange: orange,\n\torangered: orangered,\n\torchid: orchid,\n\tpalegoldenrod: palegoldenrod,\n\tpalegreen: palegreen,\n\tpaleturquoise: paleturquoise,\n\tpalevioletred: palevioletred,\n\tpapayawhip: papayawhip,\n\tpeachpuff: peachpuff,\n\tperu: peru,\n\tpink: pink,\n\tplum: plum,\n\tpowderblue: powderblue,\n\tpurple: purple,\n\trebeccapurple: rebeccapurple,\n\tred: red,\n\trosybrown: rosybrown,\n\troyalblue: royalblue,\n\tsaddlebrown: saddlebrown,\n\tsalmon: salmon,\n\tsandybrown: sandybrown,\n\tseagreen: seagreen,\n\tseashell: seashell,\n\tsienna: sienna,\n\tsilver: silver,\n\tskyblue: skyblue,\n\tslateblue: slateblue,\n\tslategray: slategray,\n\tslategrey: slategrey,\n\tsnow: snow,\n\tspringgreen: springgreen,\n\tsteelblue: steelblue,\n\ttan: tan,\n\tteal: teal,\n\tthistle: thistle,\n\ttomato: tomato,\n\tturquoise: turquoise,\n\tviolet: violet,\n\twheat: wheat,\n\twhite: white,\n\twhitesmoke: whitesmoke,\n\tyellow: yellow,\n\tyellowgreen: yellowgreen\n};\n\n/**\n * Converts a hexadecimal color number to an [R, G, B] array of normalized floats (numbers from 0.0 to 1.0).\n * @example\n * PIXI.utils.hex2rgb(0xffffff); // returns [1, 1, 1]\n * @memberof PIXI.utils\n * @function hex2rgb\n * @param {number} hex - The hexadecimal number to convert\n * @param {number[]} [out=[]] - If supplied, this array will be used rather than returning a new one\n * @returns {number[]} An array representing the [R, G, B] of the color where all values are floats.\n */\nfunction hex2rgb(hex, out) {\n if (out === void 0) { out = []; }\n out[0] = ((hex >> 16) & 0xFF) / 255;\n out[1] = ((hex >> 8) & 0xFF) / 255;\n out[2] = (hex & 0xFF) / 255;\n return out;\n}\n/**\n * Converts a hexadecimal color number to a string.\n * @example\n * PIXI.utils.hex2string(0xffffff); // returns \"#ffffff\"\n * @memberof PIXI.utils\n * @function hex2string\n * @param {number} hex - Number in hex (e.g., `0xffffff`)\n * @returns {string} The string color (e.g., `\"#ffffff\"`).\n */\nfunction hex2string(hex) {\n var hexString = hex.toString(16);\n hexString = '000000'.substring(0, 6 - hexString.length) + hexString;\n return \"#\" + hexString;\n}\n/**\n * Converts a string to a hexadecimal color number.\n * It can handle:\n * hex strings starting with #: \"#ffffff\"\n * hex strings starting with 0x: \"0xffffff\"\n * hex strings without prefix: \"ffffff\"\n * css colors: \"black\"\n * @example\n * PIXI.utils.string2hex(\"#ffffff\"); // returns 0xffffff, which is 16777215 as an integer\n * @memberof PIXI.utils\n * @function string2hex\n * @param {string} string - The string color (e.g., `\"#ffffff\"`)\n * @returns {number} Number in hexadecimal.\n */\nfunction string2hex(string) {\n if (typeof string === 'string') {\n string = cssColorNames[string.toLowerCase()] || string;\n if (string[0] === '#') {\n string = string.slice(1);\n }\n }\n return parseInt(string, 16);\n}\n/**\n * Converts a color as an [R, G, B] array of normalized floats to a hexadecimal number.\n * @example\n * PIXI.utils.rgb2hex([1, 1, 1]); // returns 0xffffff, which is 16777215 as an integer\n * @memberof PIXI.utils\n * @function rgb2hex\n * @param {number[]} rgb - Array of numbers where all values are normalized floats from 0.0 to 1.0.\n * @returns {number} Number in hexadecimal.\n */\nfunction rgb2hex(rgb) {\n return (((rgb[0] * 255) << 16) + ((rgb[1] * 255) << 8) + (rgb[2] * 255 | 0));\n}\n\n/**\n * Corrects PixiJS blend, takes premultiplied alpha into account\n * @memberof PIXI.utils\n * @function mapPremultipliedBlendModes\n * @private\n * @returns {Array<number[]>} Mapped modes.\n */\nfunction mapPremultipliedBlendModes() {\n var pm = [];\n var npm = [];\n for (var i = 0; i < 32; i++) {\n pm[i] = i;\n npm[i] = i;\n }\n pm[BLEND_MODES.NORMAL_NPM] = BLEND_MODES.NORMAL;\n pm[BLEND_MODES.ADD_NPM] = BLEND_MODES.ADD;\n pm[BLEND_MODES.SCREEN_NPM] = BLEND_MODES.SCREEN;\n npm[BLEND_MODES.NORMAL] = BLEND_MODES.NORMAL_NPM;\n npm[BLEND_MODES.ADD] = BLEND_MODES.ADD_NPM;\n npm[BLEND_MODES.SCREEN] = BLEND_MODES.SCREEN_NPM;\n var array = [];\n array.push(npm);\n array.push(pm);\n return array;\n}\n/**\n * maps premultiply flag and blendMode to adjusted blendMode\n * @memberof PIXI.utils\n * @constant premultiplyBlendMode\n * @type {Array<number[]>}\n */\nvar premultiplyBlendMode = mapPremultipliedBlendModes();\n/**\n * changes blendMode according to texture format\n * @memberof PIXI.utils\n * @function correctBlendMode\n * @param {number} blendMode - supposed blend mode\n * @param {boolean} premultiplied - whether source is premultiplied\n * @returns {number} true blend mode for this texture\n */\nfunction correctBlendMode(blendMode, premultiplied) {\n return premultiplyBlendMode[premultiplied ? 1 : 0][blendMode];\n}\n/**\n * combines rgb and alpha to out array\n * @memberof PIXI.utils\n * @function premultiplyRgba\n * @param {Float32Array|number[]} rgb - input rgb\n * @param {number} alpha - alpha param\n * @param {Float32Array} [out] - output\n * @param {boolean} [premultiply=true] - do premultiply it\n * @returns {Float32Array} vec4 rgba\n */\nfunction premultiplyRgba(rgb, alpha, out, premultiply) {\n out = out || new Float32Array(4);\n if (premultiply || premultiply === undefined) {\n out[0] = rgb[0] * alpha;\n out[1] = rgb[1] * alpha;\n out[2] = rgb[2] * alpha;\n }\n else {\n out[0] = rgb[0];\n out[1] = rgb[1];\n out[2] = rgb[2];\n }\n out[3] = alpha;\n return out;\n}\n/**\n * premultiplies tint\n * @memberof PIXI.utils\n * @function premultiplyTint\n * @param {number} tint - integer RGB\n * @param {number} alpha - floating point alpha (0.0-1.0)\n * @returns {number} tint multiplied by alpha\n */\nfunction premultiplyTint(tint, alpha) {\n if (alpha === 1.0) {\n return (alpha * 255 << 24) + tint;\n }\n if (alpha === 0.0) {\n return 0;\n }\n var R = ((tint >> 16) & 0xFF);\n var G = ((tint >> 8) & 0xFF);\n var B = (tint & 0xFF);\n R = ((R * alpha) + 0.5) | 0;\n G = ((G * alpha) + 0.5) | 0;\n B = ((B * alpha) + 0.5) | 0;\n return (alpha * 255 << 24) + (R << 16) + (G << 8) + B;\n}\n/**\n * converts integer tint and float alpha to vec4 form, premultiplies by default\n * @memberof PIXI.utils\n * @function premultiplyTintToRgba\n * @param {number} tint - input tint\n * @param {number} alpha - alpha param\n * @param {Float32Array} [out] - output\n * @param {boolean} [premultiply=true] - do premultiply it\n * @returns {Float32Array} vec4 rgba\n */\nfunction premultiplyTintToRgba(tint, alpha, out, premultiply) {\n out = out || new Float32Array(4);\n out[0] = ((tint >> 16) & 0xFF) / 255.0;\n out[1] = ((tint >> 8) & 0xFF) / 255.0;\n out[2] = (tint & 0xFF) / 255.0;\n if (premultiply || premultiply === undefined) {\n out[0] *= alpha;\n out[1] *= alpha;\n out[2] *= alpha;\n }\n out[3] = alpha;\n return out;\n}\n\n/**\n * Generic Mask Stack data structure\n * @memberof PIXI.utils\n * @function createIndicesForQuads\n * @param {number} size - Number of quads\n * @param {Uint16Array|Uint32Array} [outBuffer] - Buffer for output, length has to be `6 * size`\n * @returns {Uint16Array|Uint32Array} - Resulting index buffer\n */\nfunction createIndicesForQuads(size, outBuffer) {\n if (outBuffer === void 0) { outBuffer = null; }\n // the total number of indices in our array, there are 6 points per quad.\n var totalIndices = size * 6;\n outBuffer = outBuffer || new Uint16Array(totalIndices);\n if (outBuffer.length !== totalIndices) {\n throw new Error(\"Out buffer length is incorrect, got \" + outBuffer.length + \" and expected \" + totalIndices);\n }\n // fill the indices with the quads to draw\n for (var i = 0, j = 0; i < totalIndices; i += 6, j += 4) {\n outBuffer[i + 0] = j + 0;\n outBuffer[i + 1] = j + 1;\n outBuffer[i + 2] = j + 2;\n outBuffer[i + 3] = j + 0;\n outBuffer[i + 4] = j + 2;\n outBuffer[i + 5] = j + 3;\n }\n return outBuffer;\n}\n\nfunction getBufferType(array) {\n if (array.BYTES_PER_ELEMENT === 4) {\n if (array instanceof Float32Array) {\n return 'Float32Array';\n }\n else if (array instanceof Uint32Array) {\n return 'Uint32Array';\n }\n return 'Int32Array';\n }\n else if (array.BYTES_PER_ELEMENT === 2) {\n if (array instanceof Uint16Array) {\n return 'Uint16Array';\n }\n }\n else if (array.BYTES_PER_ELEMENT === 1) {\n if (array instanceof Uint8Array) {\n return 'Uint8Array';\n }\n }\n // TODO map out the rest of the array elements!\n return null;\n}\n\n/* eslint-disable object-shorthand */\nvar map = { Float32Array: Float32Array, Uint32Array: Uint32Array, Int32Array: Int32Array, Uint8Array: Uint8Array };\nfunction interleaveTypedArrays(arrays, sizes) {\n var outSize = 0;\n var stride = 0;\n var views = {};\n for (var i = 0; i < arrays.length; i++) {\n stride += sizes[i];\n outSize += arrays[i].length;\n }\n var buffer = new ArrayBuffer(outSize * 4);\n var out = null;\n var littleOffset = 0;\n for (var i = 0; i < arrays.length; i++) {\n var size = sizes[i];\n var array = arrays[i];\n /*\n @todo This is unsafe casting but consistent with how the code worked previously. Should it stay this way\n or should and `getBufferTypeUnsafe` function be exposed that throws an Error if unsupported type is passed?\n */\n var type = getBufferType(array);\n if (!views[type]) {\n views[type] = new map[type](buffer);\n }\n out = views[type];\n for (var j = 0; j < array.length; j++) {\n var indexStart = ((j / size | 0) * stride) + littleOffset;\n var index = j % size;\n out[indexStart + index] = array[j];\n }\n littleOffset += size;\n }\n return new Float32Array(buffer);\n}\n\n// Taken from the bit-twiddle package\n/**\n * Rounds to next power of two.\n * @function nextPow2\n * @memberof PIXI.utils\n * @param {number} v - input value\n * @returns {number} - next rounded power of two\n */\nfunction nextPow2(v) {\n v += v === 0 ? 1 : 0;\n --v;\n v |= v >>> 1;\n v |= v >>> 2;\n v |= v >>> 4;\n v |= v >>> 8;\n v |= v >>> 16;\n return v + 1;\n}\n/**\n * Checks if a number is a power of two.\n * @function isPow2\n * @memberof PIXI.utils\n * @param {number} v - input value\n * @returns {boolean} `true` if value is power of two\n */\nfunction isPow2(v) {\n return !(v & (v - 1)) && (!!v);\n}\n/**\n * Computes ceil of log base 2\n * @function log2\n * @memberof PIXI.utils\n * @param {number} v - input value\n * @returns {number} logarithm base 2\n */\nfunction log2(v) {\n var r = (v > 0xFFFF ? 1 : 0) << 4;\n v >>>= r;\n var shift = (v > 0xFF ? 1 : 0) << 3;\n v >>>= shift;\n r |= shift;\n shift = (v > 0xF ? 1 : 0) << 2;\n v >>>= shift;\n r |= shift;\n shift = (v > 0x3 ? 1 : 0) << 1;\n v >>>= shift;\n r |= shift;\n return r | (v >> 1);\n}\n\n/**\n * Remove items from a javascript array without generating garbage\n * @function removeItems\n * @memberof PIXI.utils\n * @param {Array<any>} arr - Array to remove elements from\n * @param {number} startIdx - starting index\n * @param {number} removeCount - how many to remove\n */\nfunction removeItems(arr, startIdx, removeCount) {\n var length = arr.length;\n var i;\n if (startIdx >= length || removeCount === 0) {\n return;\n }\n removeCount = (startIdx + removeCount > length ? length - startIdx : removeCount);\n var len = length - removeCount;\n for (i = startIdx; i < len; ++i) {\n arr[i] = arr[i + removeCount];\n }\n arr.length = len;\n}\n\n/**\n * Returns sign of number\n * @memberof PIXI.utils\n * @function sign\n * @param {number} n - the number to check the sign of\n * @returns {number} 0 if `n` is 0, -1 if `n` is negative, 1 if `n` is positive\n */\nfunction sign(n) {\n if (n === 0)\n { return 0; }\n return n < 0 ? -1 : 1;\n}\n\nvar nextUid = 0;\n/**\n * Gets the next unique identifier\n * @memberof PIXI.utils\n * @function uid\n * @returns {number} The next unique identifier to use.\n */\nfunction uid() {\n return ++nextUid;\n}\n\n// A map of warning messages already fired\nvar warnings = {};\n/**\n * Helper for warning developers about deprecated features & settings.\n * A stack track for warnings is given; useful for tracking-down where\n * deprecated methods/properties/classes are being used within the code.\n * @memberof PIXI.utils\n * @function deprecation\n * @param {string} version - The version where the feature became deprecated\n * @param {string} message - Message should include what is deprecated, where, and the new solution\n * @param {number} [ignoreDepth=3] - The number of steps to ignore at the top of the error stack\n * this is mostly to ignore internal deprecation calls.\n */\nfunction deprecation(version, message, ignoreDepth) {\n if (ignoreDepth === void 0) { ignoreDepth = 3; }\n // Ignore duplicat\n if (warnings[message]) {\n return;\n }\n /* eslint-disable no-console */\n var stack = new Error().stack;\n // Handle IE < 10 and Safari < 6\n if (typeof stack === 'undefined') {\n console.warn('PixiJS Deprecation Warning: ', message + \"\\nDeprecated since v\" + version);\n }\n else {\n // chop off the stack trace which includes PixiJS internal calls\n stack = stack.split('\\n').splice(ignoreDepth).join('\\n');\n if (console.groupCollapsed) {\n console.groupCollapsed('%cPixiJS Deprecation Warning: %c%s', 'color:#614108;background:#fffbe6', 'font-weight:normal;color:#614108;background:#fffbe6', message + \"\\nDeprecated since v\" + version);\n console.warn(stack);\n console.groupEnd();\n }\n else {\n console.warn('PixiJS Deprecation Warning: ', message + \"\\nDeprecated since v\" + version);\n console.warn(stack);\n }\n }\n /* eslint-enable no-console */\n warnings[message] = true;\n}\n\n/**\n * @todo Describe property usage\n * @static\n * @name ProgramCache\n * @memberof PIXI.utils\n * @type {object}\n */\nvar ProgramCache = {};\n/**\n * @todo Describe property usage\n * @static\n * @name TextureCache\n * @memberof PIXI.utils\n * @type {object}\n */\nvar TextureCache = Object.create(null);\n/**\n * @todo Describe property usage\n * @static\n * @name BaseTextureCache\n * @memberof PIXI.utils\n * @type {object}\n */\nvar BaseTextureCache = Object.create(null);\n/**\n * Destroys all texture in the cache\n * @memberof PIXI.utils\n * @function destroyTextureCache\n */\nfunction destroyTextureCache() {\n var key;\n for (key in TextureCache) {\n TextureCache[key].destroy();\n }\n for (key in BaseTextureCache) {\n BaseTextureCache[key].destroy();\n }\n}\n/**\n * Removes all textures from cache, but does not destroy them\n * @memberof PIXI.utils\n * @function clearTextureCache\n */\nfunction clearTextureCache() {\n var key;\n for (key in TextureCache) {\n delete TextureCache[key];\n }\n for (key in BaseTextureCache) {\n delete BaseTextureCache[key];\n }\n}\n\n/**\n * Creates a Canvas element of the given size to be used as a target for rendering to.\n * @class\n * @memberof PIXI.utils\n */\nvar CanvasRenderTarget = /** @class */ (function () {\n /**\n * @param width - the width for the newly created canvas\n * @param height - the height for the newly created canvas\n * @param {number} [resolution=PIXI.settings.RESOLUTION] - The resolution / device pixel ratio of the canvas\n */\n function CanvasRenderTarget(width, height, resolution) {\n this.canvas = settings.ADAPTER.createCanvas();\n this.context = this.canvas.getContext('2d');\n this.resolution = resolution || settings.RESOLUTION;\n this.resize(width, height);\n }\n /**\n * Clears the canvas that was created by the CanvasRenderTarget class.\n * @private\n */\n CanvasRenderTarget.prototype.clear = function () {\n this.context.setTransform(1, 0, 0, 1, 0, 0);\n this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);\n };\n /**\n * Resizes the canvas to the specified width and height.\n * @param desiredWidth - the desired width of the canvas\n * @param desiredHeight - the desired height of the canvas\n */\n CanvasRenderTarget.prototype.resize = function (desiredWidth, desiredHeight) {\n this.canvas.width = Math.round(desiredWidth * this.resolution);\n this.canvas.height = Math.round(desiredHeight * this.resolution);\n };\n /** Destroys this canvas. */\n CanvasRenderTarget.prototype.destroy = function () {\n this.context = null;\n this.canvas = null;\n };\n Object.defineProperty(CanvasRenderTarget.prototype, \"width\", {\n /**\n * The width of the canvas buffer in pixels.\n * @member {number}\n */\n get: function () {\n return this.canvas.width;\n },\n set: function (val) {\n this.canvas.width = Math.round(val);\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(CanvasRenderTarget.prototype, \"height\", {\n /**\n * The height of the canvas buffer in pixels.\n * @member {number}\n */\n get: function () {\n return this.canvas.height;\n },\n set: function (val) {\n this.canvas.height = Math.round(val);\n },\n enumerable: false,\n configurable: true\n });\n return CanvasRenderTarget;\n}());\n\n/**\n * Trim transparent borders from a canvas\n * @memberof PIXI.utils\n * @function trimCanvas\n * @param {HTMLCanvasElement} canvas - the canvas to trim\n * @returns {object} Trim data\n */\nfunction trimCanvas(canvas) {\n // https://gist.github.com/remy/784508\n var width = canvas.width;\n var height = canvas.height;\n var context = canvas.getContext('2d', {\n willReadFrequently: true,\n });\n var imageData = context.getImageData(0, 0, width, height);\n var pixels = imageData.data;\n var len = pixels.length;\n var bound = {\n top: null,\n left: null,\n right: null,\n bottom: null,\n };\n var data = null;\n var i;\n var x;\n var y;\n for (i = 0; i < len; i += 4) {\n if (pixels[i + 3] !== 0) {\n x = (i / 4) % width;\n y = ~~((i / 4) / width);\n if (bound.top === null) {\n bound.top = y;\n }\n if (bound.left === null) {\n bound.left = x;\n }\n else if (x < bound.left) {\n bound.left = x;\n }\n if (bound.right === null) {\n bound.right = x + 1;\n }\n else if (bound.right < x) {\n bound.right = x + 1;\n }\n if (bound.bottom === null) {\n bound.bottom = y;\n }\n else if (bound.bottom < y) {\n bound.bottom = y;\n }\n }\n }\n if (bound.top !== null) {\n width = bound.right - bound.left;\n height = bound.bottom - bound.top + 1;\n data = context.getImageData(bound.left, bound.top, width, height);\n }\n return {\n height: height,\n width: width,\n data: data,\n };\n}\n\n/**\n * Regexp for data URI.\n * Based on: {@link https://github.com/ragingwind/data-uri-regex}\n * @static\n * @constant {RegExp|string} DATA_URI\n * @memberof PIXI\n * @example data:image/png;base64\n */\nvar DATA_URI = /^\\s*data:(?:([\\w-]+)\\/([\\w+.-]+))?(?:;charset=([\\w-]+))?(?:;(base64))?,(.*)/i;\n\n/**\n * @memberof PIXI.utils\n * @interface DecomposedDataUri\n */\n/**\n * type, eg. `image`\n * @memberof PIXI.utils.DecomposedDataUri#\n * @member {string} mediaType\n */\n/**\n * Sub type, eg. `png`\n * @memberof PIXI.utils.DecomposedDataUri#\n * @member {string} subType\n */\n/**\n * @memberof PIXI.utils.DecomposedDataUri#\n * @member {string} charset\n */\n/**\n * Data encoding, eg. `base64`\n * @memberof PIXI.utils.DecomposedDataUri#\n * @member {string} encoding\n */\n/**\n * The actual data\n * @memberof PIXI.utils.DecomposedDataUri#\n * @member {string} data\n */\n/**\n * Split a data URI into components. Returns undefined if\n * parameter `dataUri` is not a valid data URI.\n * @memberof PIXI.utils\n * @function decomposeDataUri\n * @param {string} dataUri - the data URI to check\n * @returns {PIXI.utils.DecomposedDataUri|undefined} The decomposed data uri or undefined\n */\nfunction decomposeDataUri(dataUri) {\n var dataUriMatch = DATA_URI.exec(dataUri);\n if (dataUriMatch) {\n return {\n mediaType: dataUriMatch[1] ? dataUriMatch[1].toLowerCase() : undefined,\n subType: dataUriMatch[2] ? dataUriMatch[2].toLowerCase() : undefined,\n charset: dataUriMatch[3] ? dataUriMatch[3].toLowerCase() : undefined,\n encoding: dataUriMatch[4] ? dataUriMatch[4].toLowerCase() : undefined,\n data: dataUriMatch[5],\n };\n }\n return undefined;\n}\n\nvar tempAnchor;\n/**\n * Sets the `crossOrigin` property for this resource based on if the url\n * for this resource is cross-origin. If crossOrigin was manually set, this\n * function does nothing.\n * Nipped from the resource loader!\n * @ignore\n * @param {string} url - The url to test.\n * @param {object} [loc=window.location] - The location object to test against.\n * @returns {string} The crossOrigin value to use (or empty string for none).\n */\nfunction determineCrossOrigin(url$1, loc) {\n if (loc === void 0) { loc = globalThis.location; }\n // data: and javascript: urls are considered same-origin\n if (url$1.indexOf('data:') === 0) {\n return '';\n }\n // default is window.location\n loc = loc || globalThis.location;\n if (!tempAnchor) {\n tempAnchor = document.createElement('a');\n }\n // let the browser determine the full href for the url of this resource and then\n // parse with the node url lib, we can't use the properties of the anchor element\n // because they don't work in IE9 :(\n tempAnchor.href = url$1;\n var parsedUrl = url.parse(tempAnchor.href);\n var samePort = (!parsedUrl.port && loc.port === '') || (parsedUrl.port === loc.port);\n // if cross origin\n if (parsedUrl.hostname !== loc.hostname || !samePort || parsedUrl.protocol !== loc.protocol) {\n return 'anonymous';\n }\n return '';\n}\n\n/**\n * get the resolution / device pixel ratio of an asset by looking for the prefix\n * used by spritesheets and image urls\n * @memberof PIXI.utils\n * @function getResolutionOfUrl\n * @param {string} url - the image path\n * @param {number} [defaultValue=1] - the defaultValue if no filename prefix is set.\n * @returns {number} resolution / device pixel ratio of an asset\n */\nfunction getResolutionOfUrl(url, defaultValue) {\n var resolution = settings.RETINA_PREFIX.exec(url);\n if (resolution) {\n return parseFloat(resolution[1]);\n }\n return defaultValue !== undefined ? defaultValue : 1;\n}\n\nexport { BaseTextureCache, CanvasRenderTarget, DATA_URI, ProgramCache, TextureCache, clearTextureCache, correctBlendMode, createIndicesForQuads, decomposeDataUri, deprecation, destroyTextureCache, determineCrossOrigin, getBufferType, getResolutionOfUrl, hex2rgb, hex2string, interleaveTypedArrays, isPow2, isWebGLSupported, log2, nextPow2, path, premultiplyBlendMode, premultiplyRgba, premultiplyTint, premultiplyTintToRgba, removeItems, rgb2hex, sayHello, sign, skipHello, string2hex, trimCanvas, uid, url };\n//# sourceMappingURL=utils.mjs.map\n","/*!\n * @pixi/math - v6.5.8\n * Compiled Sun, 23 Oct 2022 23:01:45 UTC\n *\n * @pixi/math is licensed under the MIT License.\n * http://www.opensource.org/licenses/mit-license\n */\n/**\n * Two Pi.\n * @static\n * @member {number}\n * @memberof PIXI\n */\nvar PI_2 = Math.PI * 2;\n/**\n * Conversion factor for converting radians to degrees.\n * @static\n * @member {number} RAD_TO_DEG\n * @memberof PIXI\n */\nvar RAD_TO_DEG = 180 / Math.PI;\n/**\n * Conversion factor for converting degrees to radians.\n * @static\n * @member {number}\n * @memberof PIXI\n */\nvar DEG_TO_RAD = Math.PI / 180;\n/**\n * Constants that identify shapes, mainly to prevent `instanceof` calls.\n * @static\n * @memberof PIXI\n * @enum {number}\n * @property {number} POLY Polygon\n * @property {number} RECT Rectangle\n * @property {number} CIRC Circle\n * @property {number} ELIP Ellipse\n * @property {number} RREC Rounded Rectangle\n */\nvar SHAPES;\n(function (SHAPES) {\n SHAPES[SHAPES[\"POLY\"] = 0] = \"POLY\";\n SHAPES[SHAPES[\"RECT\"] = 1] = \"RECT\";\n SHAPES[SHAPES[\"CIRC\"] = 2] = \"CIRC\";\n SHAPES[SHAPES[\"ELIP\"] = 3] = \"ELIP\";\n SHAPES[SHAPES[\"RREC\"] = 4] = \"RREC\";\n})(SHAPES || (SHAPES = {}));\n\n/**\n * The Point object represents a location in a two-dimensional coordinate system, where `x` represents\n * the position on the horizontal axis and `y` represents the position on the vertical axis\n * @class\n * @memberof PIXI\n * @implements {IPoint}\n */\nvar Point = /** @class */ (function () {\n /**\n * Creates a new `Point`\n * @param {number} [x=0] - position of the point on the x axis\n * @param {number} [y=0] - position of the point on the y axis\n */\n function Point(x, y) {\n if (x === void 0) { x = 0; }\n if (y === void 0) { y = 0; }\n /** Position of the point on the x axis */\n this.x = 0;\n /** Position of the point on the y axis */\n this.y = 0;\n this.x = x;\n this.y = y;\n }\n /**\n * Creates a clone of this point\n * @returns A clone of this point\n */\n Point.prototype.clone = function () {\n return new Point(this.x, this.y);\n };\n /**\n * Copies `x` and `y` from the given point into this point\n * @param p - The point to copy from\n * @returns The point instance itself\n */\n Point.prototype.copyFrom = function (p) {\n this.set(p.x, p.y);\n return this;\n };\n /**\n * Copies this point's x and y into the given point (`p`).\n * @param p - The point to copy to. Can be any of type that is or extends `IPointData`\n * @returns The point (`p`) with values updated\n */\n Point.prototype.copyTo = function (p) {\n p.set(this.x, this.y);\n return p;\n };\n /**\n * Accepts another point (`p`) and returns `true` if the given point is equal to this point\n * @param p - The point to check\n * @returns Returns `true` if both `x` and `y` are equal\n */\n Point.prototype.equals = function (p) {\n return (p.x === this.x) && (p.y === this.y);\n };\n /**\n * Sets the point to a new `x` and `y` position.\n * If `y` is omitted, both `x` and `y` will be set to `x`.\n * @param {number} [x=0] - position of the point on the `x` axis\n * @param {number} [y=x] - position of the point on the `y` axis\n * @returns The point instance itself\n */\n Point.prototype.set = function (x, y) {\n if (x === void 0) { x = 0; }\n if (y === void 0) { y = x; }\n this.x = x;\n this.y = y;\n return this;\n };\n Point.prototype.toString = function () {\n return \"[@pixi/math:Point x=\" + this.x + \" y=\" + this.y + \"]\";\n };\n return Point;\n}());\n\nvar tempPoints = [new Point(), new Point(), new Point(), new Point()];\n/**\n * Size object, contains width and height\n * @memberof PIXI\n * @typedef {object} ISize\n * @property {number} width - Width component\n * @property {number} height - Height component\n */\n/**\n * Rectangle object is an area defined by its position, as indicated by its top-left corner\n * point (x, y) and by its width and its height.\n * @memberof PIXI\n */\nvar Rectangle = /** @class */ (function () {\n /**\n * @param x - The X coordinate of the upper-left corner of the rectangle\n * @param y - The Y coordinate of the upper-left corner of the rectangle\n * @param width - The overall width of the rectangle\n * @param height - The overall height of the rectangle\n */\n function Rectangle(x, y, width, height) {\n if (x === void 0) { x = 0; }\n if (y === void 0) { y = 0; }\n if (width === void 0) { width = 0; }\n if (height === void 0) { height = 0; }\n this.x = Number(x);\n this.y = Number(y);\n this.width = Number(width);\n this.height = Number(height);\n this.type = SHAPES.RECT;\n }\n Object.defineProperty(Rectangle.prototype, \"left\", {\n /** Returns the left edge of the rectangle. */\n get: function () {\n return this.x;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Rectangle.prototype, \"right\", {\n /** Returns the right edge of the rectangle. */\n get: function () {\n return this.x + this.width;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Rectangle.prototype, \"top\", {\n /** Returns the top edge of the rectangle. */\n get: function () {\n return this.y;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Rectangle.prototype, \"bottom\", {\n /** Returns the bottom edge of the rectangle. */\n get: function () {\n return this.y + this.height;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Rectangle, \"EMPTY\", {\n /** A constant empty rectangle. */\n get: function () {\n return new Rectangle(0, 0, 0, 0);\n },\n enumerable: false,\n configurable: true\n });\n /**\n * Creates a clone of this Rectangle\n * @returns a copy of the rectangle\n */\n Rectangle.prototype.clone = function () {\n return new Rectangle(this.x, this.y, this.width, this.height);\n };\n /**\n * Copies another rectangle to this one.\n * @param rectangle - The rectangle to copy from.\n * @returns Returns itself.\n */\n Rectangle.prototype.copyFrom = function (rectangle) {\n this.x = rectangle.x;\n this.y = rectangle.y;\n this.width = rectangle.width;\n this.height = rectangle.height;\n return this;\n };\n /**\n * Copies this rectangle to another one.\n * @param rectangle - The rectangle to copy to.\n * @returns Returns given parameter.\n */\n Rectangle.prototype.copyTo = function (rectangle) {\n rectangle.x = this.x;\n rectangle.y = this.y;\n rectangle.width = this.width;\n rectangle.height = this.height;\n return rectangle;\n };\n /**\n * Checks whether the x and y coordinates given are contained within this Rectangle\n * @param x - The X coordinate of the point to test\n * @param y - The Y coordinate of the point to test\n * @returns Whether the x/y coordinates are within this Rectangle\n */\n Rectangle.prototype.contains = function (x, y) {\n if (this.width <= 0 || this.height <= 0) {\n return false;\n }\n if (x >= this.x && x < this.x + this.width) {\n if (y >= this.y && y < this.y + this.height) {\n return true;\n }\n }\n return false;\n };\n /**\n * Determines whether the `other` Rectangle transformed by `transform` intersects with `this` Rectangle object.\n * Returns true only if the area of the intersection is >0, this means that Rectangles\n * sharing a side are not overlapping. Another side effect is that an arealess rectangle\n * (width or height equal to zero) can't intersect any other rectangle.\n * @param {Rectangle} other - The Rectangle to intersect with `this`.\n * @param {Matrix} transform - The transformation matrix of `other`.\n * @returns {boolean} A value of `true` if the transformed `other` Rectangle intersects with `this`; otherwise `false`.\n */\n Rectangle.prototype.intersects = function (other, transform) {\n if (!transform) {\n var x0_1 = this.x < other.x ? other.x : this.x;\n var x1_1 = this.right > other.right ? other.right : this.right;\n if (x1_1 <= x0_1) {\n return false;\n }\n var y0_1 = this.y < other.y ? other.y : this.y;\n var y1_1 = this.bottom > other.bottom ? other.bottom : this.bottom;\n return y1_1 > y0_1;\n }\n var x0 = this.left;\n var x1 = this.right;\n var y0 = this.top;\n var y1 = this.bottom;\n if (x1 <= x0 || y1 <= y0) {\n return false;\n }\n var lt = tempPoints[0].set(other.left, other.top);\n var lb = tempPoints[1].set(other.left, other.bottom);\n var rt = tempPoints[2].set(other.right, other.top);\n var rb = tempPoints[3].set(other.right, other.bottom);\n if (rt.x <= lt.x || lb.y <= lt.y) {\n return false;\n }\n var s = Math.sign((transform.a * transform.d) - (transform.b * transform.c));\n if (s === 0) {\n return false;\n }\n transform.apply(lt, lt);\n transform.apply(lb, lb);\n transform.apply(rt, rt);\n transform.apply(rb, rb);\n if (Math.max(lt.x, lb.x, rt.x, rb.x) <= x0\n || Math.min(lt.x, lb.x, rt.x, rb.x) >= x1\n || Math.max(lt.y, lb.y, rt.y, rb.y) <= y0\n || Math.min(lt.y, lb.y, rt.y, rb.y) >= y1) {\n return false;\n }\n var nx = s * (lb.y - lt.y);\n var ny = s * (lt.x - lb.x);\n var n00 = (nx * x0) + (ny * y0);\n var n10 = (nx * x1) + (ny * y0);\n var n01 = (nx * x0) + (ny * y1);\n var n11 = (nx * x1) + (ny * y1);\n if (Math.max(n00, n10, n01, n11) <= (nx * lt.x) + (ny * lt.y)\n || Math.min(n00, n10, n01, n11) >= (nx * rb.x) + (ny * rb.y)) {\n return false;\n }\n var mx = s * (lt.y - rt.y);\n var my = s * (rt.x - lt.x);\n var m00 = (mx * x0) + (my * y0);\n var m10 = (mx * x1) + (my * y0);\n var m01 = (mx * x0) + (my * y1);\n var m11 = (mx * x1) + (my * y1);\n if (Math.max(m00, m10, m01, m11) <= (mx * lt.x) + (my * lt.y)\n || Math.min(m00, m10, m01, m11) >= (mx * rb.x) + (my * rb.y)) {\n return false;\n }\n return true;\n };\n /**\n * Pads the rectangle making it grow in all directions.\n * If paddingY is omitted, both paddingX and paddingY will be set to paddingX.\n * @param paddingX - The horizontal padding amount.\n * @param paddingY - The vertical padding amount.\n * @returns Returns itself.\n */\n Rectangle.prototype.pad = function (paddingX, paddingY) {\n if (paddingX === void 0) { paddingX = 0; }\n if (paddingY === void 0) { paddingY = paddingX; }\n this.x -= paddingX;\n this.y -= paddingY;\n this.width += paddingX * 2;\n this.height += paddingY * 2;\n return this;\n };\n /**\n * Fits this rectangle around the passed one.\n * @param rectangle - The rectangle to fit.\n * @returns Returns itself.\n */\n Rectangle.prototype.fit = function (rectangle) {\n var x1 = Math.max(this.x, rectangle.x);\n var x2 = Math.min(this.x + this.width, rectangle.x + rectangle.width);\n var y1 = Math.max(this.y, rectangle.y);\n var y2 = Math.min(this.y + this.height, rectangle.y + rectangle.height);\n this.x = x1;\n this.width = Math.max(x2 - x1, 0);\n this.y = y1;\n this.height = Math.max(y2 - y1, 0);\n return this;\n };\n /**\n * Enlarges rectangle that way its corners lie on grid\n * @param resolution - resolution\n * @param eps - precision\n * @returns Returns itself.\n */\n Rectangle.prototype.ceil = function (resolution, eps) {\n if (resolution === void 0) { resolution = 1; }\n if (eps === void 0) { eps = 0.001; }\n var x2 = Math.ceil((this.x + this.width - eps) * resolution) / resolution;\n var y2 = Math.ceil((this.y + this.height - eps) * resolution) / resolution;\n this.x = Math.floor((this.x + eps) * resolution) / resolution;\n this.y = Math.floor((this.y + eps) * resolution) / resolution;\n this.width = x2 - this.x;\n this.height = y2 - this.y;\n return this;\n };\n /**\n * Enlarges this rectangle to include the passed rectangle.\n * @param rectangle - The rectangle to include.\n * @returns Returns itself.\n */\n Rectangle.prototype.enlarge = function (rectangle) {\n var x1 = Math.min(this.x, rectangle.x);\n var x2 = Math.max(this.x + this.width, rectangle.x + rectangle.width);\n var y1 = Math.min(this.y, rectangle.y);\n var y2 = Math.max(this.y + this.height, rectangle.y + rectangle.height);\n this.x = x1;\n this.width = x2 - x1;\n this.y = y1;\n this.height = y2 - y1;\n return this;\n };\n Rectangle.prototype.toString = function () {\n return \"[@pixi/math:Rectangle x=\" + this.x + \" y=\" + this.y + \" width=\" + this.width + \" height=\" + this.height + \"]\";\n };\n return Rectangle;\n}());\n\n/**\n * The Circle object is used to help draw graphics and can also be used to specify a hit area for displayObjects.\n * @memberof PIXI\n */\nvar Circle = /** @class */ (function () {\n /**\n * @param x - The X coordinate of the center of this circle\n * @param y - The Y coordinate of the center of this circle\n * @param radius - The radius of the circle\n */\n function Circle(x, y, radius) {\n if (x === void 0) { x = 0; }\n if (y === void 0) { y = 0; }\n if (radius === void 0) { radius = 0; }\n this.x = x;\n this.y = y;\n this.radius = radius;\n this.type = SHAPES.CIRC;\n }\n /**\n * Creates a clone of this Circle instance\n * @returns A copy of the Circle\n */\n Circle.prototype.clone = function () {\n return new Circle(this.x, this.y, this.radius);\n };\n /**\n * Checks whether the x and y coordinates given are contained within this circle\n * @param x - The X coordinate of the point to test\n * @param y - The Y coordinate of the point to test\n * @returns Whether the x/y coordinates are within this Circle\n */\n Circle.prototype.contains = function (x, y) {\n if (this.radius <= 0) {\n return false;\n }\n var r2 = this.radius * this.radius;\n var dx = (this.x - x);\n var dy = (this.y - y);\n dx *= dx;\n dy *= dy;\n return (dx + dy <= r2);\n };\n /**\n * Returns the framing rectangle of the circle as a Rectangle object\n * @returns The framing rectangle\n */\n Circle.prototype.getBounds = function () {\n return new Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2);\n };\n Circle.prototype.toString = function () {\n return \"[@pixi/math:Circle x=\" + this.x + \" y=\" + this.y + \" radius=\" + this.radius + \"]\";\n };\n return Circle;\n}());\n\n/**\n * The Ellipse object is used to help draw graphics and can also be used to specify a hit area for displayObjects.\n * @memberof PIXI\n */\nvar Ellipse = /** @class */ (function () {\n /**\n * @param x - The X coordinate of the center of this ellipse\n * @param y - The Y coordinate of the center of this ellipse\n * @param halfWidth - The half width of this ellipse\n * @param halfHeight - The half height of this ellipse\n */\n function Ellipse(x, y, halfWidth, halfHeight) {\n if (x === void 0) { x = 0; }\n if (y === void 0) { y = 0; }\n if (halfWidth === void 0) { halfWidth = 0; }\n if (halfHeight === void 0) { halfHeight = 0; }\n this.x = x;\n this.y = y;\n this.width = halfWidth;\n this.height = halfHeight;\n this.type = SHAPES.ELIP;\n }\n /**\n * Creates a clone of this Ellipse instance\n * @returns {PIXI.Ellipse} A copy of the ellipse\n */\n Ellipse.prototype.clone = function () {\n return new Ellipse(this.x, this.y, this.width, this.height);\n };\n /**\n * Checks whether the x and y coordinates given are contained within this ellipse\n * @param x - The X coordinate of the point to test\n * @param y - The Y coordinate of the point to test\n * @returns Whether the x/y coords are within this ellipse\n */\n Ellipse.prototype.contains = function (x, y) {\n if (this.width <= 0 || this.height <= 0) {\n return false;\n }\n // normalize the coords to an ellipse with center 0,0\n var normx = ((x - this.x) / this.width);\n var normy = ((y - this.y) / this.height);\n normx *= normx;\n normy *= normy;\n return (normx + normy <= 1);\n };\n /**\n * Returns the framing rectangle of the ellipse as a Rectangle object\n * @returns The framing rectangle\n */\n Ellipse.prototype.getBounds = function () {\n return new Rectangle(this.x - this.width, this.y - this.height, this.width, this.height);\n };\n Ellipse.prototype.toString = function () {\n return \"[@pixi/math:Ellipse x=\" + this.x + \" y=\" + this.y + \" width=\" + this.width + \" height=\" + this.height + \"]\";\n };\n return Ellipse;\n}());\n\n/**\n * A class to define a shape via user defined coordinates.\n * @memberof PIXI\n */\nvar Polygon = /** @class */ (function () {\n /**\n * @param {PIXI.IPointData[]|number[]} points - This can be an array of Points\n * that form the polygon, a flat array of numbers that will be interpreted as [x,y, x,y, ...], or\n * the arguments passed can be all the points of the polygon e.g.\n * `new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...)`, or the arguments passed can be flat\n * x,y values e.g. `new Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are Numbers.\n */\n function Polygon() {\n var arguments$1 = arguments;\n\n var points = [];\n for (var _i = 0; _i < arguments.length; _i++) {\n points[_i] = arguments$1[_i];\n }\n var flat = Array.isArray(points[0]) ? points[0] : points;\n // if this is an array of points, convert it to a flat array of numbers\n if (typeof flat[0] !== 'number') {\n var p = [];\n for (var i = 0, il = flat.length; i < il; i++) {\n p.push(flat[i].x, flat[i].y);\n }\n flat = p;\n }\n this.points = flat;\n this.type = SHAPES.POLY;\n this.closeStroke = true;\n }\n /**\n * Creates a clone of this polygon.\n * @returns - A copy of the polygon.\n */\n Polygon.prototype.clone = function () {\n var points = this.points.slice();\n var polygon = new Polygon(points);\n polygon.closeStroke = this.closeStroke;\n return polygon;\n };\n /**\n * Checks whether the x and y coordinates passed to this function are contained within this polygon.\n * @param x - The X coordinate of the point to test.\n * @param y - The Y coordinate of the point to test.\n * @returns - Whether the x/y coordinates are within this polygon.\n */\n Polygon.prototype.contains = function (x, y) {\n var inside = false;\n // use some raycasting to test hits\n // https://github.com/substack/point-in-polygon/blob/master/index.js\n var length = this.points.length / 2;\n for (var i = 0, j = length - 1; i < length; j = i++) {\n var xi = this.points[i * 2];\n var yi = this.points[(i * 2) + 1];\n var xj = this.points[j * 2];\n var yj = this.points[(j * 2) + 1];\n var intersect = ((yi > y) !== (yj > y)) && (x < ((xj - xi) * ((y - yi) / (yj - yi))) + xi);\n if (intersect) {\n inside = !inside;\n }\n }\n return inside;\n };\n Polygon.prototype.toString = function () {\n return \"[@pixi/math:Polygon\"\n + (\"closeStroke=\" + this.closeStroke)\n + (\"points=\" + this.points.reduce(function (pointsDesc, currentPoint) { return pointsDesc + \", \" + currentPoint; }, '') + \"]\");\n };\n return Polygon;\n}());\n\n/**\n * The Rounded Rectangle object is an area that has nice rounded corners, as indicated by its\n * top-left corner point (x, y) and by its width and its height and its radius.\n * @memberof PIXI\n */\nvar RoundedRectangle = /** @class */ (function () {\n /**\n * @param x - The X coordinate of the upper-left corner of the rounded rectangle\n * @param y - The Y coordinate of the upper-left corner of the rounded rectangle\n * @param width - The overall width of this rounded rectangle\n * @param height - The overall height of this rounded rectangle\n * @param radius - Controls the radius of the rounded corners\n */\n function RoundedRectangle(x, y, width, height, radius) {\n if (x === void 0) { x = 0; }\n if (y === void 0) { y = 0; }\n if (width === void 0) { width = 0; }\n if (height === void 0) { height = 0; }\n if (radius === void 0) { radius = 20; }\n this.x = x;\n this.y = y;\n this.width = width;\n this.height = height;\n this.radius = radius;\n this.type = SHAPES.RREC;\n }\n /**\n * Creates a clone of this Rounded Rectangle.\n * @returns - A copy of the rounded rectangle.\n */\n RoundedRectangle.prototype.clone = function () {\n return new RoundedRectangle(this.x, this.y, this.width, this.height, this.radius);\n };\n /**\n * Checks whether the x and y coordinates given are contained within this Rounded Rectangle\n * @param x - The X coordinate of the point to test.\n * @param y - The Y coordinate of the point to test.\n * @returns - Whether the x/y coordinates are within this Rounded Rectangle.\n */\n RoundedRectangle.prototype.contains = function (x, y) {\n if (this.width <= 0 || this.height <= 0) {\n return false;\n }\n if (x >= this.x && x <= this.x + this.width) {\n if (y >= this.y && y <= this.y + this.height) {\n var radius = Math.max(0, Math.min(this.radius, Math.min(this.width, this.height) / 2));\n if ((y >= this.y + radius && y <= this.y + this.height - radius)\n || (x >= this.x + radius && x <= this.x + this.width - radius)) {\n return true;\n }\n var dx = x - (this.x + radius);\n var dy = y - (this.y + radius);\n var radius2 = radius * radius;\n if ((dx * dx) + (dy * dy) <= radius2) {\n return true;\n }\n dx = x - (this.x + this.width - radius);\n if ((dx * dx) + (dy * dy) <= radius2) {\n return true;\n }\n dy = y - (this.y + this.height - radius);\n if ((dx * dx) + (dy * dy) <= radius2) {\n return true;\n }\n dx = x - (this.x + radius);\n if ((dx * dx) + (dy * dy) <= radius2) {\n return true;\n }\n }\n }\n return false;\n };\n RoundedRectangle.prototype.toString = function () {\n return \"[@pixi/math:RoundedRectangle x=\" + this.x + \" y=\" + this.y\n + (\"width=\" + this.width + \" height=\" + this.height + \" radius=\" + this.radius + \"]\");\n };\n return RoundedRectangle;\n}());\n\n/**\n * The ObservablePoint object represents a location in a two-dimensional coordinate system, where `x` represents\n * the position on the horizontal axis and `y` represents the position on the vertical axis.\n *\n * An `ObservablePoint` is a point that triggers a callback when the point's position is changed.\n * @memberof PIXI\n */\nvar ObservablePoint = /** @class */ (function () {\n /**\n * Creates a new `ObservablePoint`\n * @param cb - callback function triggered when `x` and/or `y` are changed\n * @param scope - owner of callback\n * @param {number} [x=0] - position of the point on the x axis\n * @param {number} [y=0] - position of the point on the y axis\n */\n function ObservablePoint(cb, scope, x, y) {\n if (x === void 0) { x = 0; }\n if (y === void 0) { y = 0; }\n this._x = x;\n this._y = y;\n this.cb = cb;\n this.scope = scope;\n }\n /**\n * Creates a clone of this point.\n * The callback and scope params can be overridden otherwise they will default\n * to the clone object's values.\n * @override\n * @param cb - The callback function triggered when `x` and/or `y` are changed\n * @param scope - The owner of the callback\n * @returns a copy of this observable point\n */\n ObservablePoint.prototype.clone = function (cb, scope) {\n if (cb === void 0) { cb = this.cb; }\n if (scope === void 0) { scope = this.scope; }\n return new ObservablePoint(cb, scope, this._x, this._y);\n };\n /**\n * Sets the point to a new `x` and `y` position.\n * If `y` is omitted, both `x` and `y` will be set to `x`.\n * @param {number} [x=0] - position of the point on the x axis\n * @param {number} [y=x] - position of the point on the y axis\n * @returns The observable point instance itself\n */\n ObservablePoint.prototype.set = function (x, y) {\n if (x === void 0) { x = 0; }\n if (y === void 0) { y = x; }\n if (this._x !== x || this._y !== y) {\n this._x = x;\n this._y = y;\n this.cb.call(this.scope);\n }\n return this;\n };\n /**\n * Copies x and y from the given point (`p`)\n * @param p - The point to copy from. Can be any of type that is or extends `IPointData`\n * @returns The observable point instance itself\n */\n ObservablePoint.prototype.copyFrom = function (p) {\n if (this._x !== p.x || this._y !== p.y) {\n this._x = p.x;\n this._y = p.y;\n this.cb.call(this.scope);\n }\n return this;\n };\n /**\n * Copies this point's x and y into that of the given point (`p`)\n * @param p - The point to copy to. Can be any of type that is or extends `IPointData`\n * @returns The point (`p`) with values updated\n */\n ObservablePoint.prototype.copyTo = function (p) {\n p.set(this._x, this._y);\n return p;\n };\n /**\n * Accepts another point (`p`) and returns `true` if the given point is equal to this point\n * @param p - The point to check\n * @returns Returns `true` if both `x` and `y` are equal\n */\n ObservablePoint.prototype.equals = function (p) {\n return (p.x === this._x) && (p.y === this._y);\n };\n ObservablePoint.prototype.toString = function () {\n return \"[@pixi/math:ObservablePoint x=\" + 0 + \" y=\" + 0 + \" scope=\" + this.scope + \"]\";\n };\n Object.defineProperty(ObservablePoint.prototype, \"x\", {\n /** Position of the observable point on the x axis. */\n get: function () {\n return this._x;\n },\n set: function (value) {\n if (this._x !== value) {\n this._x = value;\n this.cb.call(this.scope);\n }\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(ObservablePoint.prototype, \"y\", {\n /** Position of the observable point on the y axis. */\n get: function () {\n return this._y;\n },\n set: function (value) {\n if (this._y !== value) {\n this._y = value;\n this.cb.call(this.scope);\n }\n },\n enumerable: false,\n configurable: true\n });\n return ObservablePoint;\n}());\n\n/**\n * The PixiJS Matrix as a class makes it a lot faster.\n *\n * Here is a representation of it:\n * ```js\n * | a | c | tx|\n * | b | d | ty|\n * | 0 | 0 | 1 |\n * ```\n * @memberof PIXI\n */\nvar Matrix = /** @class */ (function () {\n /**\n * @param a - x scale\n * @param b - y skew\n * @param c - x skew\n * @param d - y scale\n * @param tx - x translation\n * @param ty - y translation\n */\n function Matrix(a, b, c, d, tx, ty) {\n if (a === void 0) { a = 1; }\n if (b === void 0) { b = 0; }\n if (c === void 0) { c = 0; }\n if (d === void 0) { d = 1; }\n if (tx === void 0) { tx = 0; }\n if (ty === void 0) { ty = 0; }\n this.array = null;\n this.a = a;\n this.b = b;\n this.c = c;\n this.d = d;\n this.tx = tx;\n this.ty = ty;\n }\n /**\n * Creates a Matrix object based on the given array. The Element to Matrix mapping order is as follows:\n *\n * a = array[0]\n * b = array[1]\n * c = array[3]\n * d = array[4]\n * tx = array[2]\n * ty = array[5]\n * @param array - The array that the matrix will be populated from.\n */\n Matrix.prototype.fromArray = function (array) {\n this.a = array[0];\n this.b = array[1];\n this.c = array[3];\n this.d = array[4];\n this.tx = array[2];\n this.ty = array[5];\n };\n /**\n * Sets the matrix properties.\n * @param a - Matrix component\n * @param b - Matrix component\n * @param c - Matrix component\n * @param d - Matrix component\n * @param tx - Matrix component\n * @param ty - Matrix component\n * @returns This matrix. Good for chaining method calls.\n */\n Matrix.prototype.set = function (a, b, c, d, tx, ty) {\n this.a = a;\n this.b = b;\n this.c = c;\n this.d = d;\n this.tx = tx;\n this.ty = ty;\n return this;\n };\n /**\n * Creates an array from the current Matrix object.\n * @param transpose - Whether we need to transpose the matrix or not\n * @param [out=new Float32Array(9)] - If provided the array will be assigned to out\n * @returns The newly created array which contains the matrix\n */\n Matrix.prototype.toArray = function (transpose, out) {\n if (!this.array) {\n this.array = new Float32Array(9);\n }\n var array = out || this.array;\n if (transpose) {\n array[0] = this.a;\n array[1] = this.b;\n array[2] = 0;\n array[3] = this.c;\n array[4] = this.d;\n array[5] = 0;\n array[6] = this.tx;\n array[7] = this.ty;\n array[8] = 1;\n }\n else {\n array[0] = this.a;\n array[1] = this.c;\n array[2] = this.tx;\n array[3] = this.b;\n array[4] = this.d;\n array[5] = this.ty;\n array[6] = 0;\n array[7] = 0;\n array[8] = 1;\n }\n return array;\n };\n /**\n * Get a new position with the current transformation applied.\n * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering)\n * @param pos - The origin\n * @param {PIXI.Point} [newPos] - The point that the new position is assigned to (allowed to be same as input)\n * @returns {PIXI.Point} The new point, transformed through this matrix\n */\n Matrix.prototype.apply = function (pos, newPos) {\n newPos = (newPos || new Point());\n var x = pos.x;\n var y = pos.y;\n newPos.x = (this.a * x) + (this.c * y) + this.tx;\n newPos.y = (this.b * x) + (this.d * y) + this.ty;\n return newPos;\n };\n /**\n * Get a new position with the inverse of the current transformation applied.\n * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input)\n * @param pos - The origin\n * @param {PIXI.Point} [newPos] - The point that the new position is assigned to (allowed to be same as input)\n * @returns {PIXI.Point} The new point, inverse-transformed through this matrix\n */\n Matrix.prototype.applyInverse = function (pos, newPos) {\n newPos = (newPos || new Point());\n var id = 1 / ((this.a * this.d) + (this.c * -this.b));\n var x = pos.x;\n var y = pos.y;\n newPos.x = (this.d * id * x) + (-this.c * id * y) + (((this.ty * this.c) - (this.tx * this.d)) * id);\n newPos.y = (this.a * id * y) + (-this.b * id * x) + (((-this.ty * this.a) + (this.tx * this.b)) * id);\n return newPos;\n };\n /**\n * Translates the matrix on the x and y.\n * @param x - How much to translate x by\n * @param y - How much to translate y by\n * @returns This matrix. Good for chaining method calls.\n */\n Matrix.prototype.translate = function (x, y) {\n this.tx += x;\n this.ty += y;\n return this;\n };\n /**\n * Applies a scale transformation to the matrix.\n * @param x - The amount to scale horizontally\n * @param y - The amount to scale vertically\n * @returns This matrix. Good for chaining method calls.\n */\n Matrix.prototype.scale = function (x, y) {\n this.a *= x;\n this.d *= y;\n this.c *= x;\n this.b *= y;\n this.tx *= x;\n this.ty *= y;\n return this;\n };\n /**\n * Applies a rotation transformation to the matrix.\n * @param angle - The angle in radians.\n * @returns This matrix. Good for chaining method calls.\n */\n Matrix.prototype.rotate = function (angle) {\n var cos = Math.cos(angle);\n var sin = Math.sin(angle);\n var a1 = this.a;\n var c1 = this.c;\n var tx1 = this.tx;\n this.a = (a1 * cos) - (this.b * sin);\n this.b = (a1 * sin) + (this.b * cos);\n this.c = (c1 * cos) - (this.d * sin);\n this.d = (c1 * sin) + (this.d * cos);\n this.tx = (tx1 * cos) - (this.ty * sin);\n this.ty = (tx1 * sin) + (this.ty * cos);\n return this;\n };\n /**\n * Appends the given Matrix to this Matrix.\n * @param matrix - The matrix to append.\n * @returns This matrix. Good for chaining method calls.\n */\n Matrix.prototype.append = function (matrix) {\n var a1 = this.a;\n var b1 = this.b;\n var c1 = this.c;\n var d1 = this.d;\n this.a = (matrix.a * a1) + (matrix.b * c1);\n this.b = (matrix.a * b1) + (matrix.b * d1);\n this.c = (matrix.c * a1) + (matrix.d * c1);\n this.d = (matrix.c * b1) + (matrix.d * d1);\n this.tx = (matrix.tx * a1) + (matrix.ty * c1) + this.tx;\n this.ty = (matrix.tx * b1) + (matrix.ty * d1) + this.ty;\n return this;\n };\n /**\n * Sets the matrix based on all the available properties\n * @param x - Position on the x axis\n * @param y - Position on the y axis\n * @param pivotX - Pivot on the x axis\n * @param pivotY - Pivot on the y axis\n * @param scaleX - Scale on the x axis\n * @param scaleY - Scale on the y axis\n * @param rotation - Rotation in radians\n * @param skewX - Skew on the x axis\n * @param skewY - Skew on the y axis\n * @returns This matrix. Good for chaining method calls.\n */\n Matrix.prototype.setTransform = function (x, y, pivotX, pivotY, scaleX, scaleY, rotation, skewX, skewY) {\n this.a = Math.cos(rotation + skewY) * scaleX;\n this.b = Math.sin(rotation + skewY) * scaleX;\n this.c = -Math.sin(rotation - skewX) * scaleY;\n this.d = Math.cos(rotation - skewX) * scaleY;\n this.tx = x - ((pivotX * this.a) + (pivotY * this.c));\n this.ty = y - ((pivotX * this.b) + (pivotY * this.d));\n return this;\n };\n /**\n * Prepends the given Matrix to this Matrix.\n * @param matrix - The matrix to prepend\n * @returns This matrix. Good for chaining method calls.\n */\n Matrix.prototype.prepend = function (matrix) {\n var tx1 = this.tx;\n if (matrix.a !== 1 || matrix.b !== 0 || matrix.c !== 0 || matrix.d !== 1) {\n var a1 = this.a;\n var c1 = this.c;\n this.a = (a1 * matrix.a) + (this.b * matrix.c);\n this.b = (a1 * matrix.b) + (this.b * matrix.d);\n this.c = (c1 * matrix.a) + (this.d * matrix.c);\n this.d = (c1 * matrix.b) + (this.d * matrix.d);\n }\n this.tx = (tx1 * matrix.a) + (this.ty * matrix.c) + matrix.tx;\n this.ty = (tx1 * matrix.b) + (this.ty * matrix.d) + matrix.ty;\n return this;\n };\n /**\n * Decomposes the matrix (x, y, scaleX, scaleY, and rotation) and sets the properties on to a transform.\n * @param transform - The transform to apply the properties to.\n * @returns The transform with the newly applied properties\n */\n Matrix.prototype.decompose = function (transform) {\n // sort out rotation / skew..\n var a = this.a;\n var b = this.b;\n var c = this.c;\n var d = this.d;\n var pivot = transform.pivot;\n var skewX = -Math.atan2(-c, d);\n var skewY = Math.atan2(b, a);\n var delta = Math.abs(skewX + skewY);\n if (delta < 0.00001 || Math.abs(PI_2 - delta) < 0.00001) {\n transform.rotation = skewY;\n transform.skew.x = transform.skew.y = 0;\n }\n else {\n transform.rotation = 0;\n transform.skew.x = skewX;\n transform.skew.y = skewY;\n }\n // next set scale\n transform.scale.x = Math.sqrt((a * a) + (b * b));\n transform.scale.y = Math.sqrt((c * c) + (d * d));\n // next set position\n transform.position.x = this.tx + ((pivot.x * a) + (pivot.y * c));\n transform.position.y = this.ty + ((pivot.x * b) + (pivot.y * d));\n return transform;\n };\n /**\n * Inverts this matrix\n * @returns This matrix. Good for chaining method calls.\n */\n Matrix.prototype.invert = function () {\n var a1 = this.a;\n var b1 = this.b;\n var c1 = this.c;\n var d1 = this.d;\n var tx1 = this.tx;\n var n = (a1 * d1) - (b1 * c1);\n this.a = d1 / n;\n this.b = -b1 / n;\n this.c = -c1 / n;\n this.d = a1 / n;\n this.tx = ((c1 * this.ty) - (d1 * tx1)) / n;\n this.ty = -((a1 * this.ty) - (b1 * tx1)) / n;\n return this;\n };\n /**\n * Resets this Matrix to an identity (default) matrix.\n * @returns This matrix. Good for chaining method calls.\n */\n Matrix.prototype.identity = function () {\n this.a = 1;\n this.b = 0;\n this.c = 0;\n this.d = 1;\n this.tx = 0;\n this.ty = 0;\n return this;\n };\n /**\n * Creates a new Matrix object with the same values as this one.\n * @returns A copy of this matrix. Good for chaining method calls.\n */\n Matrix.prototype.clone = function () {\n var matrix = new Matrix();\n matrix.a = this.a;\n matrix.b = this.b;\n matrix.c = this.c;\n matrix.d = this.d;\n matrix.tx = this.tx;\n matrix.ty = this.ty;\n return matrix;\n };\n /**\n * Changes the values of the given matrix to be the same as the ones in this matrix\n * @param matrix - The matrix to copy to.\n * @returns The matrix given in parameter with its values updated.\n */\n Matrix.prototype.copyTo = function (matrix) {\n matrix.a = this.a;\n matrix.b = this.b;\n matrix.c = this.c;\n matrix.d = this.d;\n matrix.tx = this.tx;\n matrix.ty = this.ty;\n return matrix;\n };\n /**\n * Changes the values of the matrix to be the same as the ones in given matrix\n * @param {PIXI.Matrix} matrix - The matrix to copy from.\n * @returns {PIXI.Matrix} this\n */\n Matrix.prototype.copyFrom = function (matrix) {\n this.a = matrix.a;\n this.b = matrix.b;\n this.c = matrix.c;\n this.d = matrix.d;\n this.tx = matrix.tx;\n this.ty = matrix.ty;\n return this;\n };\n Matrix.prototype.toString = function () {\n return \"[@pixi/math:Matrix a=\" + this.a + \" b=\" + this.b + \" c=\" + this.c + \" d=\" + this.d + \" tx=\" + this.tx + \" ty=\" + this.ty + \"]\";\n };\n Object.defineProperty(Matrix, \"IDENTITY\", {\n /**\n * A default (identity) matrix\n * @readonly\n */\n get: function () {\n return new Matrix();\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Matrix, \"TEMP_MATRIX\", {\n /**\n * A temp matrix\n * @readonly\n */\n get: function () {\n return new Matrix();\n },\n enumerable: false,\n configurable: true\n });\n return Matrix;\n}());\n\n// Your friendly neighbour https://en.wikipedia.org/wiki/Dihedral_group\n/*\n * Transform matrix for operation n is:\n * | ux | vx |\n * | uy | vy |\n */\nvar ux = [1, 1, 0, -1, -1, -1, 0, 1, 1, 1, 0, -1, -1, -1, 0, 1];\nvar uy = [0, 1, 1, 1, 0, -1, -1, -1, 0, 1, 1, 1, 0, -1, -1, -1];\nvar vx = [0, -1, -1, -1, 0, 1, 1, 1, 0, 1, 1, 1, 0, -1, -1, -1];\nvar vy = [1, 1, 0, -1, -1, -1, 0, 1, -1, -1, 0, 1, 1, 1, 0, -1];\n/**\n * [Cayley Table]{@link https://en.wikipedia.org/wiki/Cayley_table}\n * for the composition of each rotation in the dihederal group D8.\n * @type {number[][]}\n * @private\n */\nvar rotationCayley = [];\n/**\n * Matrices for each `GD8Symmetry` rotation.\n * @type {PIXI.Matrix[]}\n * @private\n */\nvar rotationMatrices = [];\n/*\n * Alias for {@code Math.sign}.\n */\nvar signum = Math.sign;\n/*\n * Initializes `rotationCayley` and `rotationMatrices`. It is called\n * only once below.\n */\nfunction init() {\n for (var i = 0; i < 16; i++) {\n var row = [];\n rotationCayley.push(row);\n for (var j = 0; j < 16; j++) {\n /* Multiplies rotation matrices i and j. */\n var _ux = signum((ux[i] * ux[j]) + (vx[i] * uy[j]));\n var _uy = signum((uy[i] * ux[j]) + (vy[i] * uy[j]));\n var _vx = signum((ux[i] * vx[j]) + (vx[i] * vy[j]));\n var _vy = signum((uy[i] * vx[j]) + (vy[i] * vy[j]));\n /* Finds rotation matrix matching the product and pushes it. */\n for (var k = 0; k < 16; k++) {\n if (ux[k] === _ux && uy[k] === _uy\n && vx[k] === _vx && vy[k] === _vy) {\n row.push(k);\n break;\n }\n }\n }\n }\n for (var i = 0; i < 16; i++) {\n var mat = new Matrix();\n mat.set(ux[i], uy[i], vx[i], vy[i], 0, 0);\n rotationMatrices.push(mat);\n }\n}\ninit();\n/**\n * @memberof PIXI\n * @typedef {number} GD8Symmetry\n * @see PIXI.groupD8\n */\n/**\n * Implements the dihedral group D8, which is similar to\n * [group D4]{@link http://mathworld.wolfram.com/DihedralGroupD4.html};\n * D8 is the same but with diagonals, and it is used for texture\n * rotations.\n *\n * The directions the U- and V- axes after rotation\n * of an angle of `a: GD8Constant` are the vectors `(uX(a), uY(a))`\n * and `(vX(a), vY(a))`. These aren't necessarily unit vectors.\n *\n * **Origin:**<br>\n * This is the small part of gameofbombs.com portal system. It works.\n * @see PIXI.groupD8.E\n * @see PIXI.groupD8.SE\n * @see PIXI.groupD8.S\n * @see PIXI.groupD8.SW\n * @see PIXI.groupD8.W\n * @see PIXI.groupD8.NW\n * @see PIXI.groupD8.N\n * @see PIXI.groupD8.NE\n * @author Ivan @ivanpopelyshev\n * @namespace PIXI.groupD8\n * @memberof PIXI\n */\nvar groupD8 = {\n /**\n * | Rotation | Direction |\n * |----------|-----------|\n * | 0° | East |\n * @memberof PIXI.groupD8\n * @constant {PIXI.GD8Symmetry}\n */\n E: 0,\n /**\n * | Rotation | Direction |\n * |----------|-----------|\n * | 45°↻ | Southeast |\n * @memberof PIXI.groupD8\n * @constant {PIXI.GD8Symmetry}\n */\n SE: 1,\n /**\n * | Rotation | Direction |\n * |----------|-----------|\n * | 90°↻ | South |\n * @memberof PIXI.groupD8\n * @constant {PIXI.GD8Symmetry}\n */\n S: 2,\n /**\n * | Rotation | Direction |\n * |----------|-----------|\n * | 135°↻ | Southwest |\n * @memberof PIXI.groupD8\n * @constant {PIXI.GD8Symmetry}\n */\n SW: 3,\n /**\n * | Rotation | Direction |\n * |----------|-----------|\n * | 180° | West |\n * @memberof PIXI.groupD8\n * @constant {PIXI.GD8Symmetry}\n */\n W: 4,\n /**\n * | Rotation | Direction |\n * |-------------|--------------|\n * | -135°/225°↻ | Northwest |\n * @memberof PIXI.groupD8\n * @constant {PIXI.GD8Symmetry}\n */\n NW: 5,\n /**\n * | Rotation | Direction |\n * |-------------|--------------|\n * | -90°/270°↻ | North |\n * @memberof PIXI.groupD8\n * @constant {PIXI.GD8Symmetry}\n */\n N: 6,\n /**\n * | Rotation | Direction |\n * |-------------|--------------|\n * | -45°/315°↻ | Northeast |\n * @memberof PIXI.groupD8\n * @constant {PIXI.GD8Symmetry}\n */\n NE: 7,\n /**\n * Reflection about Y-axis.\n * @memberof PIXI.groupD8\n * @constant {PIXI.GD8Symmetry}\n */\n MIRROR_VERTICAL: 8,\n /**\n * Reflection about the main diagonal.\n * @memberof PIXI.groupD8\n * @constant {PIXI.GD8Symmetry}\n */\n MAIN_DIAGONAL: 10,\n /**\n * Reflection about X-axis.\n * @memberof PIXI.groupD8\n * @constant {PIXI.GD8Symmetry}\n */\n MIRROR_HORIZONTAL: 12,\n /**\n * Reflection about reverse diagonal.\n * @memberof PIXI.groupD8\n * @constant {PIXI.GD8Symmetry}\n */\n REVERSE_DIAGONAL: 14,\n /**\n * @memberof PIXI.groupD8\n * @param {PIXI.GD8Symmetry} ind - sprite rotation angle.\n * @returns {PIXI.GD8Symmetry} The X-component of the U-axis\n * after rotating the axes.\n */\n uX: function (ind) { return ux[ind]; },\n /**\n * @memberof PIXI.groupD8\n * @param {PIXI.GD8Symmetry} ind - sprite rotation angle.\n * @returns {PIXI.GD8Symmetry} The Y-component of the U-axis\n * after rotating the axes.\n */\n uY: function (ind) { return uy[ind]; },\n /**\n * @memberof PIXI.groupD8\n * @param {PIXI.GD8Symmetry} ind - sprite rotation angle.\n * @returns {PIXI.GD8Symmetry} The X-component of the V-axis\n * after rotating the axes.\n */\n vX: function (ind) { return vx[ind]; },\n /**\n * @memberof PIXI.groupD8\n * @param {PIXI.GD8Symmetry} ind - sprite rotation angle.\n * @returns {PIXI.GD8Symmetry} The Y-component of the V-axis\n * after rotating the axes.\n */\n vY: function (ind) { return vy[ind]; },\n /**\n * @memberof PIXI.groupD8\n * @param {PIXI.GD8Symmetry} rotation - symmetry whose opposite\n * is needed. Only rotations have opposite symmetries while\n * reflections don't.\n * @returns {PIXI.GD8Symmetry} The opposite symmetry of `rotation`\n */\n inv: function (rotation) {\n if (rotation & 8) // true only if between 8 & 15 (reflections)\n {\n return rotation & 15; // or rotation % 16\n }\n return (-rotation) & 7; // or (8 - rotation) % 8\n },\n /**\n * Composes the two D8 operations.\n *\n * Taking `^` as reflection:\n *\n * | | E=0 | S=2 | W=4 | N=6 | E^=8 | S^=10 | W^=12 | N^=14 |\n * |-------|-----|-----|-----|-----|------|-------|-------|-------|\n * | E=0 | E | S | W | N | E^ | S^ | W^ | N^ |\n * | S=2 | S | W | N | E | S^ | W^ | N^ | E^ |\n * | W=4 | W | N | E | S | W^ | N^ | E^ | S^ |\n * | N=6 | N | E | S | W | N^ | E^ | S^ | W^ |\n * | E^=8 | E^ | N^ | W^ | S^ | E | N | W | S |\n * | S^=10 | S^ | E^ | N^ | W^ | S | E | N | W |\n * | W^=12 | W^ | S^ | E^ | N^ | W | S | E | N |\n * | N^=14 | N^ | W^ | S^ | E^ | N | W | S | E |\n *\n * [This is a Cayley table]{@link https://en.wikipedia.org/wiki/Cayley_table}\n * @memberof PIXI.groupD8\n * @param {PIXI.GD8Symmetry} rotationSecond - Second operation, which\n * is the row in the above cayley table.\n * @param {PIXI.GD8Symmetry} rotationFirst - First operation, which\n * is the column in the above cayley table.\n * @returns {PIXI.GD8Symmetry} Composed operation\n */\n add: function (rotationSecond, rotationFirst) { return (rotationCayley[rotationSecond][rotationFirst]); },\n /**\n * Reverse of `add`.\n * @memberof PIXI.groupD8\n * @param {PIXI.GD8Symmetry} rotationSecond - Second operation\n * @param {PIXI.GD8Symmetry} rotationFirst - First operation\n * @returns {PIXI.GD8Symmetry} Result\n */\n sub: function (rotationSecond, rotationFirst) { return (rotationCayley[rotationSecond][groupD8.inv(rotationFirst)]); },\n /**\n * Adds 180 degrees to rotation, which is a commutative\n * operation.\n * @memberof PIXI.groupD8\n * @param {number} rotation - The number to rotate.\n * @returns {number} Rotated number\n */\n rotate180: function (rotation) { return rotation ^ 4; },\n /**\n * Checks if the rotation angle is vertical, i.e. south\n * or north. It doesn't work for reflections.\n * @memberof PIXI.groupD8\n * @param {PIXI.GD8Symmetry} rotation - The number to check.\n * @returns {boolean} Whether or not the direction is vertical\n */\n isVertical: function (rotation) { return (rotation & 3) === 2; },\n /**\n * Approximates the vector `V(dx,dy)` into one of the\n * eight directions provided by `groupD8`.\n * @memberof PIXI.groupD8\n * @param {number} dx - X-component of the vector\n * @param {number} dy - Y-component of the vector\n * @returns {PIXI.GD8Symmetry} Approximation of the vector into\n * one of the eight symmetries.\n */\n byDirection: function (dx, dy) {\n if (Math.abs(dx) * 2 <= Math.abs(dy)) {\n if (dy >= 0) {\n return groupD8.S;\n }\n return groupD8.N;\n }\n else if (Math.abs(dy) * 2 <= Math.abs(dx)) {\n if (dx > 0) {\n return groupD8.E;\n }\n return groupD8.W;\n }\n else if (dy > 0) {\n if (dx > 0) {\n return groupD8.SE;\n }\n return groupD8.SW;\n }\n else if (dx > 0) {\n return groupD8.NE;\n }\n return groupD8.NW;\n },\n /**\n * Helps sprite to compensate texture packer rotation.\n * @memberof PIXI.groupD8\n * @param {PIXI.Matrix} matrix - sprite world matrix\n * @param {PIXI.GD8Symmetry} rotation - The rotation factor to use.\n * @param {number} tx - sprite anchoring\n * @param {number} ty - sprite anchoring\n */\n matrixAppendRotationInv: function (matrix, rotation, tx, ty) {\n if (tx === void 0) { tx = 0; }\n if (ty === void 0) { ty = 0; }\n // Packer used \"rotation\", we use \"inv(rotation)\"\n var mat = rotationMatrices[groupD8.inv(rotation)];\n mat.tx = tx;\n mat.ty = ty;\n matrix.append(mat);\n },\n};\n\n/**\n * Transform that takes care about its versions.\n * @memberof PIXI\n */\nvar Transform = /** @class */ (function () {\n function Transform() {\n this.worldTransform = new Matrix();\n this.localTransform = new Matrix();\n this.position = new ObservablePoint(this.onChange, this, 0, 0);\n this.scale = new ObservablePoint(this.onChange, this, 1, 1);\n this.pivot = new ObservablePoint(this.onChange, this, 0, 0);\n this.skew = new ObservablePoint(this.updateSkew, this, 0, 0);\n this._rotation = 0;\n this._cx = 1;\n this._sx = 0;\n this._cy = 0;\n this._sy = 1;\n this._localID = 0;\n this._currentLocalID = 0;\n this._worldID = 0;\n this._parentID = 0;\n }\n /** Called when a value changes. */\n Transform.prototype.onChange = function () {\n this._localID++;\n };\n /** Called when the skew or the rotation changes. */\n Transform.prototype.updateSkew = function () {\n this._cx = Math.cos(this._rotation + this.skew.y);\n this._sx = Math.sin(this._rotation + this.skew.y);\n this._cy = -Math.sin(this._rotation - this.skew.x); // cos, added PI/2\n this._sy = Math.cos(this._rotation - this.skew.x); // sin, added PI/2\n this._localID++;\n };\n Transform.prototype.toString = function () {\n return \"[@pixi/math:Transform \"\n + (\"position=(\" + this.position.x + \", \" + this.position.y + \") \")\n + (\"rotation=\" + this.rotation + \" \")\n + (\"scale=(\" + this.scale.x + \", \" + this.scale.y + \") \")\n + (\"skew=(\" + this.skew.x + \", \" + this.skew.y + \") \")\n + \"]\";\n };\n /** Updates the local transformation matrix. */\n Transform.prototype.updateLocalTransform = function () {\n var lt = this.localTransform;\n if (this._localID !== this._currentLocalID) {\n // get the matrix values of the displayobject based on its transform properties..\n lt.a = this._cx * this.scale.x;\n lt.b = this._sx * this.scale.x;\n lt.c = this._cy * this.scale.y;\n lt.d = this._sy * this.scale.y;\n lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c));\n lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d));\n this._currentLocalID = this._localID;\n // force an update..\n this._parentID = -1;\n }\n };\n /**\n * Updates the local and the world transformation matrices.\n * @param parentTransform - The parent transform\n */\n Transform.prototype.updateTransform = function (parentTransform) {\n var lt = this.localTransform;\n if (this._localID !== this._currentLocalID) {\n // get the matrix values of the displayobject based on its transform properties..\n lt.a = this._cx * this.scale.x;\n lt.b = this._sx * this.scale.x;\n lt.c = this._cy * this.scale.y;\n lt.d = this._sy * this.scale.y;\n lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c));\n lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d));\n this._currentLocalID = this._localID;\n // force an update..\n this._parentID = -1;\n }\n if (this._parentID !== parentTransform._worldID) {\n // concat the parent matrix with the objects transform.\n var pt = parentTransform.worldTransform;\n var wt = this.worldTransform;\n wt.a = (lt.a * pt.a) + (lt.b * pt.c);\n wt.b = (lt.a * pt.b) + (lt.b * pt.d);\n wt.c = (lt.c * pt.a) + (lt.d * pt.c);\n wt.d = (lt.c * pt.b) + (lt.d * pt.d);\n wt.tx = (lt.tx * pt.a) + (lt.ty * pt.c) + pt.tx;\n wt.ty = (lt.tx * pt.b) + (lt.ty * pt.d) + pt.ty;\n this._parentID = parentTransform._worldID;\n // update the id of the transform..\n this._worldID++;\n }\n };\n /**\n * Decomposes a matrix and sets the transforms properties based on it.\n * @param matrix - The matrix to decompose\n */\n Transform.prototype.setFromMatrix = function (matrix) {\n matrix.decompose(this);\n this._localID++;\n };\n Object.defineProperty(Transform.prototype, \"rotation\", {\n /** The rotation of the object in radians. */\n get: function () {\n return this._rotation;\n },\n set: function (value) {\n if (this._rotation !== value) {\n this._rotation = value;\n this.updateSkew();\n }\n },\n enumerable: false,\n configurable: true\n });\n /** A default (identity) transform. */\n Transform.IDENTITY = new Transform();\n return Transform;\n}());\n\nexport { Circle, DEG_TO_RAD, Ellipse, Matrix, ObservablePoint, PI_2, Point, Polygon, RAD_TO_DEG, Rectangle, RoundedRectangle, SHAPES, Transform, groupD8 };\n//# sourceMappingURL=math.mjs.map\n","/*!\n * @pixi/display - v6.5.8\n * Compiled Sun, 23 Oct 2022 23:01:45 UTC\n *\n * @pixi/display is licensed under the MIT License.\n * http://www.opensource.org/licenses/mit-license\n */\nimport { settings } from '@pixi/settings';\nimport { Rectangle, RAD_TO_DEG, DEG_TO_RAD, Transform } from '@pixi/math';\nimport { EventEmitter, removeItems } from '@pixi/utils';\nimport { MASK_TYPES } from '@pixi/constants';\n\n/**\n * Sets the default value for the container property 'sortableChildren'.\n * If set to true, the container will sort its children by zIndex value\n * when updateTransform() is called, or manually if sortChildren() is called.\n *\n * This actually changes the order of elements in the array, so should be treated\n * as a basic solution that is not performant compared to other solutions,\n * such as @link https://github.com/pixijs/pixi-display\n *\n * Also be aware of that this may not work nicely with the addChildAt() function,\n * as the zIndex sorting may cause the child to automatically sorted to another position.\n * @static\n * @constant\n * @name SORTABLE_CHILDREN\n * @memberof PIXI.settings\n * @type {boolean}\n * @default false\n */\nsettings.SORTABLE_CHILDREN = false;\n\n/**\n * 'Builder' pattern for bounds rectangles.\n *\n * This could be called an Axis-Aligned Bounding Box.\n * It is not an actual shape. It is a mutable thing; no 'EMPTY' or those kind of problems.\n * @memberof PIXI\n */\nvar Bounds = /** @class */ (function () {\n function Bounds() {\n this.minX = Infinity;\n this.minY = Infinity;\n this.maxX = -Infinity;\n this.maxY = -Infinity;\n this.rect = null;\n this.updateID = -1;\n }\n /**\n * Checks if bounds are empty.\n * @returns - True if empty.\n */\n Bounds.prototype.isEmpty = function () {\n return this.minX > this.maxX || this.minY > this.maxY;\n };\n /** Clears the bounds and resets. */\n Bounds.prototype.clear = function () {\n this.minX = Infinity;\n this.minY = Infinity;\n this.maxX = -Infinity;\n this.maxY = -Infinity;\n };\n /**\n * Can return Rectangle.EMPTY constant, either construct new rectangle, either use your rectangle\n * It is not guaranteed that it will return tempRect\n * @param rect - Temporary object will be used if AABB is not empty\n * @returns - A rectangle of the bounds\n */\n Bounds.prototype.getRectangle = function (rect) {\n if (this.minX > this.maxX || this.minY > this.maxY) {\n return Rectangle.EMPTY;\n }\n rect = rect || new Rectangle(0, 0, 1, 1);\n rect.x = this.minX;\n rect.y = this.minY;\n rect.width = this.maxX - this.minX;\n rect.height = this.maxY - this.minY;\n return rect;\n };\n /**\n * This function should be inlined when its possible.\n * @param point - The point to add.\n */\n Bounds.prototype.addPoint = function (point) {\n this.minX = Math.min(this.minX, point.x);\n this.maxX = Math.max(this.maxX, point.x);\n this.minY = Math.min(this.minY, point.y);\n this.maxY = Math.max(this.maxY, point.y);\n };\n /**\n * Adds a point, after transformed. This should be inlined when its possible.\n * @param matrix\n * @param point\n */\n Bounds.prototype.addPointMatrix = function (matrix, point) {\n var a = matrix.a, b = matrix.b, c = matrix.c, d = matrix.d, tx = matrix.tx, ty = matrix.ty;\n var x = (a * point.x) + (c * point.y) + tx;\n var y = (b * point.x) + (d * point.y) + ty;\n this.minX = Math.min(this.minX, x);\n this.maxX = Math.max(this.maxX, x);\n this.minY = Math.min(this.minY, y);\n this.maxY = Math.max(this.maxY, y);\n };\n /**\n * Adds a quad, not transformed\n * @param vertices - The verts to add.\n */\n Bounds.prototype.addQuad = function (vertices) {\n var minX = this.minX;\n var minY = this.minY;\n var maxX = this.maxX;\n var maxY = this.maxY;\n var x = vertices[0];\n var y = vertices[1];\n minX = x < minX ? x : minX;\n minY = y < minY ? y : minY;\n maxX = x > maxX ? x : maxX;\n maxY = y > maxY ? y : maxY;\n x = vertices[2];\n y = vertices[3];\n minX = x < minX ? x : minX;\n minY = y < minY ? y : minY;\n maxX = x > maxX ? x : maxX;\n maxY = y > maxY ? y : maxY;\n x = vertices[4];\n y = vertices[5];\n minX = x < minX ? x : minX;\n minY = y < minY ? y : minY;\n maxX = x > maxX ? x : maxX;\n maxY = y > maxY ? y : maxY;\n x = vertices[6];\n y = vertices[7];\n minX = x < minX ? x : minX;\n minY = y < minY ? y : minY;\n maxX = x > maxX ? x : maxX;\n maxY = y > maxY ? y : maxY;\n this.minX = minX;\n this.minY = minY;\n this.maxX = maxX;\n this.maxY = maxY;\n };\n /**\n * Adds sprite frame, transformed.\n * @param transform - transform to apply\n * @param x0 - left X of frame\n * @param y0 - top Y of frame\n * @param x1 - right X of frame\n * @param y1 - bottom Y of frame\n */\n Bounds.prototype.addFrame = function (transform, x0, y0, x1, y1) {\n this.addFrameMatrix(transform.worldTransform, x0, y0, x1, y1);\n };\n /**\n * Adds sprite frame, multiplied by matrix\n * @param matrix - matrix to apply\n * @param x0 - left X of frame\n * @param y0 - top Y of frame\n * @param x1 - right X of frame\n * @param y1 - bottom Y of frame\n */\n Bounds.prototype.addFrameMatrix = function (matrix, x0, y0, x1, y1) {\n var a = matrix.a;\n var b = matrix.b;\n var c = matrix.c;\n var d = matrix.d;\n var tx = matrix.tx;\n var ty = matrix.ty;\n var minX = this.minX;\n var minY = this.minY;\n var maxX = this.maxX;\n var maxY = this.maxY;\n var x = (a * x0) + (c * y0) + tx;\n var y = (b * x0) + (d * y0) + ty;\n minX = x < minX ? x : minX;\n minY = y < minY ? y : minY;\n maxX = x > maxX ? x : maxX;\n maxY = y > maxY ? y : maxY;\n x = (a * x1) + (c * y0) + tx;\n y = (b * x1) + (d * y0) + ty;\n minX = x < minX ? x : minX;\n minY = y < minY ? y : minY;\n maxX = x > maxX ? x : maxX;\n maxY = y > maxY ? y : maxY;\n x = (a * x0) + (c * y1) + tx;\n y = (b * x0) + (d * y1) + ty;\n minX = x < minX ? x : minX;\n minY = y < minY ? y : minY;\n maxX = x > maxX ? x : maxX;\n maxY = y > maxY ? y : maxY;\n x = (a * x1) + (c * y1) + tx;\n y = (b * x1) + (d * y1) + ty;\n minX = x < minX ? x : minX;\n minY = y < minY ? y : minY;\n maxX = x > maxX ? x : maxX;\n maxY = y > maxY ? y : maxY;\n this.minX = minX;\n this.minY = minY;\n this.maxX = maxX;\n this.maxY = maxY;\n };\n /**\n * Adds screen vertices from array\n * @param vertexData - calculated vertices\n * @param beginOffset - begin offset\n * @param endOffset - end offset, excluded\n */\n Bounds.prototype.addVertexData = function (vertexData, beginOffset, endOffset) {\n var minX = this.minX;\n var minY = this.minY;\n var maxX = this.maxX;\n var maxY = this.maxY;\n for (var i = beginOffset; i < endOffset; i += 2) {\n var x = vertexData[i];\n var y = vertexData[i + 1];\n minX = x < minX ? x : minX;\n minY = y < minY ? y : minY;\n maxX = x > maxX ? x : maxX;\n maxY = y > maxY ? y : maxY;\n }\n this.minX = minX;\n this.minY = minY;\n this.maxX = maxX;\n this.maxY = maxY;\n };\n /**\n * Add an array of mesh vertices\n * @param transform - mesh transform\n * @param vertices - mesh coordinates in array\n * @param beginOffset - begin offset\n * @param endOffset - end offset, excluded\n */\n Bounds.prototype.addVertices = function (transform, vertices, beginOffset, endOffset) {\n this.addVerticesMatrix(transform.worldTransform, vertices, beginOffset, endOffset);\n };\n /**\n * Add an array of mesh vertices.\n * @param matrix - mesh matrix\n * @param vertices - mesh coordinates in array\n * @param beginOffset - begin offset\n * @param endOffset - end offset, excluded\n * @param padX - x padding\n * @param padY - y padding\n */\n Bounds.prototype.addVerticesMatrix = function (matrix, vertices, beginOffset, endOffset, padX, padY) {\n if (padX === void 0) { padX = 0; }\n if (padY === void 0) { padY = padX; }\n var a = matrix.a;\n var b = matrix.b;\n var c = matrix.c;\n var d = matrix.d;\n var tx = matrix.tx;\n var ty = matrix.ty;\n var minX = this.minX;\n var minY = this.minY;\n var maxX = this.maxX;\n var maxY = this.maxY;\n for (var i = beginOffset; i < endOffset; i += 2) {\n var rawX = vertices[i];\n var rawY = vertices[i + 1];\n var x = (a * rawX) + (c * rawY) + tx;\n var y = (d * rawY) + (b * rawX) + ty;\n minX = Math.min(minX, x - padX);\n maxX = Math.max(maxX, x + padX);\n minY = Math.min(minY, y - padY);\n maxY = Math.max(maxY, y + padY);\n }\n this.minX = minX;\n this.minY = minY;\n this.maxX = maxX;\n this.maxY = maxY;\n };\n /**\n * Adds other {@link Bounds}.\n * @param bounds - The Bounds to be added\n */\n Bounds.prototype.addBounds = function (bounds) {\n var minX = this.minX;\n var minY = this.minY;\n var maxX = this.maxX;\n var maxY = this.maxY;\n this.minX = bounds.minX < minX ? bounds.minX : minX;\n this.minY = bounds.minY < minY ? bounds.minY : minY;\n this.maxX = bounds.maxX > maxX ? bounds.maxX : maxX;\n this.maxY = bounds.maxY > maxY ? bounds.maxY : maxY;\n };\n /**\n * Adds other Bounds, masked with Bounds.\n * @param bounds - The Bounds to be added.\n * @param mask - TODO\n */\n Bounds.prototype.addBoundsMask = function (bounds, mask) {\n var _minX = bounds.minX > mask.minX ? bounds.minX : mask.minX;\n var _minY = bounds.minY > mask.minY ? bounds.minY : mask.minY;\n var _maxX = bounds.maxX < mask.maxX ? bounds.maxX : mask.maxX;\n var _maxY = bounds.maxY < mask.maxY ? bounds.maxY : mask.maxY;\n if (_minX <= _maxX && _minY <= _maxY) {\n var minX = this.minX;\n var minY = this.minY;\n var maxX = this.maxX;\n var maxY = this.maxY;\n this.minX = _minX < minX ? _minX : minX;\n this.minY = _minY < minY ? _minY : minY;\n this.maxX = _maxX > maxX ? _maxX : maxX;\n this.maxY = _maxY > maxY ? _maxY : maxY;\n }\n };\n /**\n * Adds other Bounds, multiplied by matrix. Bounds shouldn't be empty.\n * @param bounds - other bounds\n * @param matrix - multiplicator\n */\n Bounds.prototype.addBoundsMatrix = function (bounds, matrix) {\n this.addFrameMatrix(matrix, bounds.minX, bounds.minY, bounds.maxX, bounds.maxY);\n };\n /**\n * Adds other Bounds, masked with Rectangle.\n * @param bounds - TODO\n * @param area - TODO\n */\n Bounds.prototype.addBoundsArea = function (bounds, area) {\n var _minX = bounds.minX > area.x ? bounds.minX : area.x;\n var _minY = bounds.minY > area.y ? bounds.minY : area.y;\n var _maxX = bounds.maxX < area.x + area.width ? bounds.maxX : (area.x + area.width);\n var _maxY = bounds.maxY < area.y + area.height ? bounds.maxY : (area.y + area.height);\n if (_minX <= _maxX && _minY <= _maxY) {\n var minX = this.minX;\n var minY = this.minY;\n var maxX = this.maxX;\n var maxY = this.maxY;\n this.minX = _minX < minX ? _minX : minX;\n this.minY = _minY < minY ? _minY : minY;\n this.maxX = _maxX > maxX ? _maxX : maxX;\n this.maxY = _maxY > maxY ? _maxY : maxY;\n }\n };\n /**\n * Pads bounds object, making it grow in all directions.\n * If paddingY is omitted, both paddingX and paddingY will be set to paddingX.\n * @param paddingX - The horizontal padding amount.\n * @param paddingY - The vertical padding amount.\n */\n Bounds.prototype.pad = function (paddingX, paddingY) {\n if (paddingX === void 0) { paddingX = 0; }\n if (paddingY === void 0) { paddingY = paddingX; }\n if (!this.isEmpty()) {\n this.minX -= paddingX;\n this.maxX += paddingX;\n this.minY -= paddingY;\n this.maxY += paddingY;\n }\n };\n /**\n * Adds padded frame. (x0, y0) should be strictly less than (x1, y1)\n * @param x0 - left X of frame\n * @param y0 - top Y of frame\n * @param x1 - right X of frame\n * @param y1 - bottom Y of frame\n * @param padX - padding X\n * @param padY - padding Y\n */\n Bounds.prototype.addFramePad = function (x0, y0, x1, y1, padX, padY) {\n x0 -= padX;\n y0 -= padY;\n x1 += padX;\n y1 += padY;\n this.minX = this.minX < x0 ? this.minX : x0;\n this.maxX = this.maxX > x1 ? this.maxX : x1;\n this.minY = this.minY < y0 ? this.minY : y0;\n this.maxY = this.maxY > y1 ? this.maxY : y1;\n };\n return Bounds;\n}());\n\n/*! *****************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n/* global Reflect, Promise */\r\n\r\nvar extendStatics = function(d, b) {\r\n extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) { if (b.hasOwnProperty(p)) { d[p] = b[p]; } } };\r\n return extendStatics(d, b);\r\n};\r\n\r\nfunction __extends(d, b) {\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n}\n\n/**\n * The base class for all objects that are rendered on the screen.\n *\n * This is an abstract class and can not be used on its own; rather it should be extended.\n *\n * ## Display objects implemented in PixiJS\n *\n * | Display Object | Description |\n * | ------------------------------- | --------------------------------------------------------------------- |\n * | {@link PIXI.Container} | Adds support for `children` to DisplayObject |\n * | {@link PIXI.Graphics} | Shape-drawing display object similar to the Canvas API |\n * | {@link PIXI.Sprite} | Draws textures (i.e. images) |\n * | {@link PIXI.Text} | Draws text using the Canvas API internally |\n * | {@link PIXI.BitmapText} | More scaleable solution for text rendering, reusing glyph textures |\n * | {@link PIXI.TilingSprite} | Draws textures/images in a tiled fashion |\n * | {@link PIXI.AnimatedSprite} | Draws an animation of multiple images |\n * | {@link PIXI.Mesh} | Provides a lower-level API for drawing meshes with custom data |\n * | {@link PIXI.NineSlicePlane} | Mesh-related |\n * | {@link PIXI.SimpleMesh} | v4-compatible mesh |\n * | {@link PIXI.SimplePlane} | Mesh-related |\n * | {@link PIXI.SimpleRope} | Mesh-related |\n *\n * ## Transforms\n *\n * The [transform]{@link DisplayObject#transform} of a display object describes the projection from its\n * local coordinate space to its parent's local coordinate space. The following properties are derived\n * from the transform:\n *\n * <table>\n * <thead>\n * <tr>\n * <th>Property</th>\n * <th>Description</th>\n * </tr>\n * </thead>\n * <tbody>\n * <tr>\n * <td>[pivot]{@link PIXI.DisplayObject#pivot}</td>\n * <td>\n * Invariant under rotation, scaling, and skewing. The projection of into the parent's space of the pivot\n * is equal to position, regardless of the other three transformations. In other words, It is the center of\n * rotation, scaling, and skewing.\n * </td>\n * </tr>\n * <tr>\n * <td>[position]{@link PIXI.DisplayObject#position}</td>\n * <td>\n * Translation. This is the position of the [pivot]{@link PIXI.DisplayObject#pivot} in the parent's local\n * space. The default value of the pivot is the origin (0,0). If the top-left corner of your display object\n * is (0,0) in its local space, then the position will be its top-left corner in the parent's local space.\n * </td>\n * </tr>\n * <tr>\n * <td>[scale]{@link PIXI.DisplayObject#scale}</td>\n * <td>\n * Scaling. This will stretch (or compress) the display object's projection. The scale factors are along the\n * local coordinate axes. In other words, the display object is scaled before rotated or skewed. The center\n * of scaling is the [pivot]{@link PIXI.DisplayObject#pivot}.\n * </td>\n * </tr>\n * <tr>\n * <td>[rotation]{@link PIXI.DisplayObject#rotation}</td>\n * <td>\n * Rotation. This will rotate the display object's projection by this angle (in radians).\n * </td>\n * </tr>\n * <tr>\n * <td>[skew]{@link PIXI.DisplayObject#skew}</td>\n * <td>\n * <p>Skewing. This can be used to deform a rectangular display object into a parallelogram.</p>\n * <p>\n * In PixiJS, skew has a slightly different behaviour than the conventional meaning. It can be\n * thought of the net rotation applied to the coordinate axes (separately). For example, if \"skew.x\" is\n * ⍺ and \"skew.y\" is β, then the line x = 0 will be rotated by ⍺ (y = -x*cot⍺) and the line y = 0 will be\n * rotated by β (y = x*tanβ). A line y = x*tanϴ (i.e. a line at angle ϴ to the x-axis in local-space) will\n * be rotated by an angle between ⍺ and β.\n * </p>\n * <p>\n * It can be observed that if skew is applied equally to both axes, then it will be equivalent to applying\n * a rotation. Indeed, if \"skew.x\" = -ϴ and \"skew.y\" = ϴ, it will produce an equivalent of \"rotation\" = ϴ.\n * </p>\n * <p>\n * Another quite interesting observation is that \"skew.x\", \"skew.y\", rotation are communtative operations. Indeed,\n * because rotation is essentially a careful combination of the two.\n * </p>\n * </td>\n * </tr>\n * <tr>\n * <td>angle</td>\n * <td>Rotation. This is an alias for [rotation]{@link PIXI.DisplayObject#rotation}, but in degrees.</td>\n * </tr>\n * <tr>\n * <td>x</td>\n * <td>Translation. This is an alias for position.x!</td>\n * </tr>\n * <tr>\n * <td>y</td>\n * <td>Translation. This is an alias for position.y!</td>\n * </tr>\n * <tr>\n * <td>width</td>\n * <td>\n * Implemented in [Container]{@link PIXI.Container}. Scaling. The width property calculates scale.x by dividing\n * the \"requested\" width by the local bounding box width. It is indirectly an abstraction over scale.x, and there\n * is no concept of user-defined width.\n * </td>\n * </tr>\n * <tr>\n * <td>height</td>\n * <td>\n * Implemented in [Container]{@link PIXI.Container}. Scaling. The height property calculates scale.y by dividing\n * the \"requested\" height by the local bounding box height. It is indirectly an abstraction over scale.y, and there\n * is no concept of user-defined height.\n * </td>\n * </tr>\n * </tbody>\n * </table>\n *\n * ## Bounds\n *\n * The bounds of a display object is defined by the minimum axis-aligned rectangle in world space that can fit\n * around it. The abstract `calculateBounds` method is responsible for providing it (and it should use the\n * `worldTransform` to calculate in world space).\n *\n * There are a few additional types of bounding boxes:\n *\n * | Bounds | Description |\n * | --------------------- | ---------------------------------------------------------------------------------------- |\n * | World Bounds | This is synonymous is the regular bounds described above. See `getBounds()`. |\n * | Local Bounds | This the axis-aligned bounding box in the parent's local space. See `getLocalBounds()`. |\n * | Render Bounds | The bounds, but including extra rendering effects like filter padding. |\n * | Projected Bounds | The bounds of the projected display object onto the screen. Usually equals world bounds. |\n * | Relative Bounds | The bounds of a display object when projected onto a ancestor's (or parent's) space. |\n * | Natural Bounds | The bounds of an object in its own local space (not parent's space, like in local bounds)|\n * | Content Bounds | The natural bounds when excluding all children of a `Container`. |\n *\n * ### calculateBounds\n *\n * [Container]{@link Container} already implements `calculateBounds` in a manner that includes children.\n *\n * But for a non-Container display object, the `calculateBounds` method must be overridden in order for `getBounds` and\n * `getLocalBounds` to work. This method must write the bounds into `this._bounds`.\n *\n * Generally, the following technique works for most simple cases: take the list of points\n * forming the \"hull\" of the object (i.e. outline of the object's shape), and then add them\n * using {@link PIXI.Bounds#addPointMatrix}.\n *\n * ```js\n * calculateBounds(): void\n * {\n * const points = [...];\n *\n * for (let i = 0, j = points.length; i < j; i++)\n * {\n * this._bounds.addPointMatrix(this.worldTransform, points[i]);\n * }\n * }\n * ```\n *\n * You can optimize this for a large number of points by using {@link PIXI.Bounds#addVerticesMatrix} to pass them\n * in one array together.\n *\n * ## Alpha\n *\n * This alpha sets a display object's **relative opacity** w.r.t its parent. For example, if the alpha of a display\n * object is 0.5 and its parent's alpha is 0.5, then it will be rendered with 25% opacity (assuming alpha is not\n * applied on any ancestor further up the chain).\n *\n * The alpha with which the display object will be rendered is called the [worldAlpha]{@link PIXI.DisplayObject#worldAlpha}.\n *\n * ## Renderable vs Visible\n *\n * The `renderable` and `visible` properties can be used to prevent a display object from being rendered to the\n * screen. However, there is a subtle difference between the two. When using `renderable`, the transforms of the display\n * object (and its children subtree) will continue to be calculated. When using `visible`, the transforms will not\n * be calculated.\n *\n * It is recommended that applications use the `renderable` property for culling. See\n * [@pixi-essentials/cull]{@link https://www.npmjs.com/package/@pixi-essentials/cull} or\n * [pixi-cull]{@link https://www.npmjs.com/package/pixi-cull} for more details.\n *\n * Otherwise, to prevent an object from rendering in the general-purpose sense - `visible` is the property to use. This\n * one is also better in terms of performance.\n * @memberof PIXI\n */\nvar DisplayObject = /** @class */ (function (_super) {\n __extends(DisplayObject, _super);\n function DisplayObject() {\n var _this = _super.call(this) || this;\n _this.tempDisplayObjectParent = null;\n // TODO: need to create Transform from factory\n _this.transform = new Transform();\n _this.alpha = 1;\n _this.visible = true;\n _this.renderable = true;\n _this.cullable = false;\n _this.cullArea = null;\n _this.parent = null;\n _this.worldAlpha = 1;\n _this._lastSortedIndex = 0;\n _this._zIndex = 0;\n _this.filterArea = null;\n _this.filters = null;\n _this._enabledFilters = null;\n _this._bounds = new Bounds();\n _this._localBounds = null;\n _this._boundsID = 0;\n _this._boundsRect = null;\n _this._localBoundsRect = null;\n _this._mask = null;\n _this._maskRefCount = 0;\n _this._destroyed = false;\n _this.isSprite = false;\n _this.isMask = false;\n return _this;\n }\n /**\n * Mixes all enumerable properties and methods from a source object to DisplayObject.\n * @param source - The source of properties and methods to mix in.\n */\n DisplayObject.mixin = function (source) {\n // in ES8/ES2017, this would be really easy:\n // Object.defineProperties(DisplayObject.prototype, Object.getOwnPropertyDescriptors(source));\n // get all the enumerable property keys\n var keys = Object.keys(source);\n // loop through properties\n for (var i = 0; i < keys.length; ++i) {\n var propertyName = keys[i];\n // Set the property using the property descriptor - this works for accessors and normal value properties\n Object.defineProperty(DisplayObject.prototype, propertyName, Object.getOwnPropertyDescriptor(source, propertyName));\n }\n };\n Object.defineProperty(DisplayObject.prototype, \"destroyed\", {\n /**\n * Fired when this DisplayObject is added to a Container.\n * @instance\n * @event added\n * @param {PIXI.Container} container - The container added to.\n */\n /**\n * Fired when this DisplayObject is removed from a Container.\n * @instance\n * @event removed\n * @param {PIXI.Container} container - The container removed from.\n */\n /**\n * Fired when this DisplayObject is destroyed. This event is emitted once\n * destroy is finished.\n * @instance\n * @event destroyed\n */\n /** Readonly flag for destroyed display objects. */\n get: function () {\n return this._destroyed;\n },\n enumerable: false,\n configurable: true\n });\n /** Recursively updates transform of all objects from the root to this one internal function for toLocal() */\n DisplayObject.prototype._recursivePostUpdateTransform = function () {\n if (this.parent) {\n this.parent._recursivePostUpdateTransform();\n this.transform.updateTransform(this.parent.transform);\n }\n else {\n this.transform.updateTransform(this._tempDisplayObjectParent.transform);\n }\n };\n /** Updates the object transform for rendering. TODO - Optimization pass! */\n DisplayObject.prototype.updateTransform = function () {\n this._boundsID++;\n this.transform.updateTransform(this.parent.transform);\n // multiply the alphas..\n this.worldAlpha = this.alpha * this.parent.worldAlpha;\n };\n /**\n * Calculates and returns the (world) bounds of the display object as a [Rectangle]{@link PIXI.Rectangle}.\n *\n * This method is expensive on containers with a large subtree (like the stage). This is because the bounds\n * of a container depend on its children's bounds, which recursively causes all bounds in the subtree to\n * be recalculated. The upside, however, is that calling `getBounds` once on a container will indeed update\n * the bounds of all children (the whole subtree, in fact). This side effect should be exploited by using\n * `displayObject._bounds.getRectangle()` when traversing through all the bounds in a scene graph. Otherwise,\n * calling `getBounds` on each object in a subtree will cause the total cost to increase quadratically as\n * its height increases.\n *\n * The transforms of all objects in a container's **subtree** and of all **ancestors** are updated.\n * The world bounds of all display objects in a container's **subtree** will also be recalculated.\n *\n * The `_bounds` object stores the last calculation of the bounds. You can use to entirely skip bounds\n * calculation if needed.\n *\n * ```js\n * const lastCalculatedBounds = displayObject._bounds.getRectangle(optionalRect);\n * ```\n *\n * Do know that usage of `getLocalBounds` can corrupt the `_bounds` of children (the whole subtree, actually). This\n * is a known issue that has not been solved. See [getLocalBounds]{@link PIXI.DisplayObject#getLocalBounds} for more\n * details.\n *\n * `getBounds` should be called with `skipUpdate` equal to `true` in a render() call. This is because the transforms\n * are guaranteed to be update-to-date. In fact, recalculating inside a render() call may cause corruption in certain\n * cases.\n * @param skipUpdate - Setting to `true` will stop the transforms of the scene graph from\n * being updated. This means the calculation returned MAY be out of date BUT will give you a\n * nice performance boost.\n * @param rect - Optional rectangle to store the result of the bounds calculation.\n * @returns - The minimum axis-aligned rectangle in world space that fits around this object.\n */\n DisplayObject.prototype.getBounds = function (skipUpdate, rect) {\n if (!skipUpdate) {\n if (!this.parent) {\n this.parent = this._tempDisplayObjectParent;\n this.updateTransform();\n this.parent = null;\n }\n else {\n this._recursivePostUpdateTransform();\n this.updateTransform();\n }\n }\n if (this._bounds.updateID !== this._boundsID) {\n this.calculateBounds();\n this._bounds.updateID = this._boundsID;\n }\n if (!rect) {\n if (!this._boundsRect) {\n this._boundsRect = new Rectangle();\n }\n rect = this._boundsRect;\n }\n return this._bounds.getRectangle(rect);\n };\n /**\n * Retrieves the local bounds of the displayObject as a rectangle object.\n * @param rect - Optional rectangle to store the result of the bounds calculation.\n * @returns - The rectangular bounding area.\n */\n DisplayObject.prototype.getLocalBounds = function (rect) {\n if (!rect) {\n if (!this._localBoundsRect) {\n this._localBoundsRect = new Rectangle();\n }\n rect = this._localBoundsRect;\n }\n if (!this._localBounds) {\n this._localBounds = new Bounds();\n }\n var transformRef = this.transform;\n var parentRef = this.parent;\n this.parent = null;\n this.transform = this._tempDisplayObjectParent.transform;\n var worldBounds = this._bounds;\n var worldBoundsID = this._boundsID;\n this._bounds = this._localBounds;\n var bounds = this.getBounds(false, rect);\n this.parent = parentRef;\n this.transform = transformRef;\n this._bounds = worldBounds;\n this._bounds.updateID += this._boundsID - worldBoundsID; // reflect side-effects\n return bounds;\n };\n /**\n * Calculates the global position of the display object.\n * @param position - The world origin to calculate from.\n * @param point - A Point object in which to store the value, optional\n * (otherwise will create a new Point).\n * @param skipUpdate - Should we skip the update transform.\n * @returns - A point object representing the position of this object.\n */\n DisplayObject.prototype.toGlobal = function (position, point, skipUpdate) {\n if (skipUpdate === void 0) { skipUpdate = false; }\n if (!skipUpdate) {\n this._recursivePostUpdateTransform();\n // this parent check is for just in case the item is a root object.\n // If it is we need to give it a temporary parent so that displayObjectUpdateTransform works correctly\n // this is mainly to avoid a parent check in the main loop. Every little helps for performance :)\n if (!this.parent) {\n this.parent = this._tempDisplayObjectParent;\n this.displayObjectUpdateTransform();\n this.parent = null;\n }\n else {\n this.displayObjectUpdateTransform();\n }\n }\n // don't need to update the lot\n return this.worldTransform.apply(position, point);\n };\n /**\n * Calculates the local position of the display object relative to another point.\n * @param position - The world origin to calculate from.\n * @param from - The DisplayObject to calculate the global position from.\n * @param point - A Point object in which to store the value, optional\n * (otherwise will create a new Point).\n * @param skipUpdate - Should we skip the update transform\n * @returns - A point object representing the position of this object\n */\n DisplayObject.prototype.toLocal = function (position, from, point, skipUpdate) {\n if (from) {\n position = from.toGlobal(position, point, skipUpdate);\n }\n if (!skipUpdate) {\n this._recursivePostUpdateTransform();\n // this parent check is for just in case the item is a root object.\n // If it is we need to give it a temporary parent so that displayObjectUpdateTransform works correctly\n // this is mainly to avoid a parent check in the main loop. Every little helps for performance :)\n if (!this.parent) {\n this.parent = this._tempDisplayObjectParent;\n this.displayObjectUpdateTransform();\n this.parent = null;\n }\n else {\n this.displayObjectUpdateTransform();\n }\n }\n // simply apply the matrix..\n return this.worldTransform.applyInverse(position, point);\n };\n /**\n * Set the parent Container of this DisplayObject.\n * @param container - The Container to add this DisplayObject to.\n * @returns - The Container that this DisplayObject was added to.\n */\n DisplayObject.prototype.setParent = function (container) {\n if (!container || !container.addChild) {\n throw new Error('setParent: Argument must be a Container');\n }\n container.addChild(this);\n return container;\n };\n /**\n * Convenience function to set the position, scale, skew and pivot at once.\n * @param x - The X position\n * @param y - The Y position\n * @param scaleX - The X scale value\n * @param scaleY - The Y scale value\n * @param rotation - The rotation\n * @param skewX - The X skew value\n * @param skewY - The Y skew value\n * @param pivotX - The X pivot value\n * @param pivotY - The Y pivot value\n * @returns - The DisplayObject instance\n */\n DisplayObject.prototype.setTransform = function (x, y, scaleX, scaleY, rotation, skewX, skewY, pivotX, pivotY) {\n if (x === void 0) { x = 0; }\n if (y === void 0) { y = 0; }\n if (scaleX === void 0) { scaleX = 1; }\n if (scaleY === void 0) { scaleY = 1; }\n if (rotation === void 0) { rotation = 0; }\n if (skewX === void 0) { skewX = 0; }\n if (skewY === void 0) { skewY = 0; }\n if (pivotX === void 0) { pivotX = 0; }\n if (pivotY === void 0) { pivotY = 0; }\n this.position.x = x;\n this.position.y = y;\n this.scale.x = !scaleX ? 1 : scaleX;\n this.scale.y = !scaleY ? 1 : scaleY;\n this.rotation = rotation;\n this.skew.x = skewX;\n this.skew.y = skewY;\n this.pivot.x = pivotX;\n this.pivot.y = pivotY;\n return this;\n };\n /**\n * Base destroy method for generic display objects. This will automatically\n * remove the display object from its parent Container as well as remove\n * all current event listeners and internal references. Do not use a DisplayObject\n * after calling `destroy()`.\n * @param _options\n */\n DisplayObject.prototype.destroy = function (_options) {\n if (this.parent) {\n this.parent.removeChild(this);\n }\n this._destroyed = true;\n this.transform = null;\n this.parent = null;\n this._bounds = null;\n this.mask = null;\n this.cullArea = null;\n this.filters = null;\n this.filterArea = null;\n this.hitArea = null;\n this.interactive = false;\n this.interactiveChildren = false;\n this.emit('destroyed');\n this.removeAllListeners();\n };\n Object.defineProperty(DisplayObject.prototype, \"_tempDisplayObjectParent\", {\n /**\n * @protected\n * @member {PIXI.Container}\n */\n get: function () {\n if (this.tempDisplayObjectParent === null) {\n // eslint-disable-next-line @typescript-eslint/no-use-before-define\n this.tempDisplayObjectParent = new TemporaryDisplayObject();\n }\n return this.tempDisplayObjectParent;\n },\n enumerable: false,\n configurable: true\n });\n /**\n * Used in Renderer, cacheAsBitmap and other places where you call an `updateTransform` on root\n *\n * ```\n * const cacheParent = elem.enableTempParent();\n * elem.updateTransform();\n * elem.disableTempParent(cacheParent);\n * ```\n * @returns - current parent\n */\n DisplayObject.prototype.enableTempParent = function () {\n var myParent = this.parent;\n this.parent = this._tempDisplayObjectParent;\n return myParent;\n };\n /**\n * Pair method for `enableTempParent`\n * @param cacheParent - Actual parent of element\n */\n DisplayObject.prototype.disableTempParent = function (cacheParent) {\n this.parent = cacheParent;\n };\n Object.defineProperty(DisplayObject.prototype, \"x\", {\n /**\n * The position of the displayObject on the x axis relative to the local coordinates of the parent.\n * An alias to position.x\n */\n get: function () {\n return this.position.x;\n },\n set: function (value) {\n this.transform.position.x = value;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(DisplayObject.prototype, \"y\", {\n /**\n * The position of the displayObject on the y axis relative to the local coordinates of the parent.\n * An alias to position.y\n */\n get: function () {\n return this.position.y;\n },\n set: function (value) {\n this.transform.position.y = value;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(DisplayObject.prototype, \"worldTransform\", {\n /**\n * Current transform of the object based on world (parent) factors.\n * @readonly\n */\n get: function () {\n return this.transform.worldTransform;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(DisplayObject.prototype, \"localTransform\", {\n /**\n * Current transform of the object based on local factors: position, scale, other stuff.\n * @readonly\n */\n get: function () {\n return this.transform.localTransform;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(DisplayObject.prototype, \"position\", {\n /**\n * The coordinate of the object relative to the local coordinates of the parent.\n * @since 4.0.0\n */\n get: function () {\n return this.transform.position;\n },\n set: function (value) {\n this.transform.position.copyFrom(value);\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(DisplayObject.prototype, \"scale\", {\n /**\n * The scale factors of this object along the local coordinate axes.\n *\n * The default scale is (1, 1).\n * @since 4.0.0\n */\n get: function () {\n return this.transform.scale;\n },\n set: function (value) {\n this.transform.scale.copyFrom(value);\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(DisplayObject.prototype, \"pivot\", {\n /**\n * The center of rotation, scaling, and skewing for this display object in its local space. The `position`\n * is the projection of `pivot` in the parent's local space.\n *\n * By default, the pivot is the origin (0, 0).\n * @since 4.0.0\n */\n get: function () {\n return this.transform.pivot;\n },\n set: function (value) {\n this.transform.pivot.copyFrom(value);\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(DisplayObject.prototype, \"skew\", {\n /**\n * The skew factor for the object in radians.\n * @since 4.0.0\n */\n get: function () {\n return this.transform.skew;\n },\n set: function (value) {\n this.transform.skew.copyFrom(value);\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(DisplayObject.prototype, \"rotation\", {\n /**\n * The rotation of the object in radians.\n * 'rotation' and 'angle' have the same effect on a display object; rotation is in radians, angle is in degrees.\n */\n get: function () {\n return this.transform.rotation;\n },\n set: function (value) {\n this.transform.rotation = value;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(DisplayObject.prototype, \"angle\", {\n /**\n * The angle of the object in degrees.\n * 'rotation' and 'angle' have the same effect on a display object; rotation is in radians, angle is in degrees.\n */\n get: function () {\n return this.transform.rotation * RAD_TO_DEG;\n },\n set: function (value) {\n this.transform.rotation = value * DEG_TO_RAD;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(DisplayObject.prototype, \"zIndex\", {\n /**\n * The zIndex of the displayObject.\n *\n * If a container has the sortableChildren property set to true, children will be automatically\n * sorted by zIndex value; a higher value will mean it will be moved towards the end of the array,\n * and thus rendered on top of other display objects within the same container.\n * @see PIXI.Container#sortableChildren\n */\n get: function () {\n return this._zIndex;\n },\n set: function (value) {\n this._zIndex = value;\n if (this.parent) {\n this.parent.sortDirty = true;\n }\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(DisplayObject.prototype, \"worldVisible\", {\n /**\n * Indicates if the object is globally visible.\n * @readonly\n */\n get: function () {\n var item = this;\n do {\n if (!item.visible) {\n return false;\n }\n item = item.parent;\n } while (item);\n return true;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(DisplayObject.prototype, \"mask\", {\n /**\n * Sets a mask for the displayObject. A mask is an object that limits the visibility of an\n * object to the shape of the mask applied to it. In PixiJS a regular mask must be a\n * {@link PIXI.Graphics} or a {@link PIXI.Sprite} object. This allows for much faster masking in canvas as it\n * utilities shape clipping. Furthermore, a mask of an object must be in the subtree of its parent.\n * Otherwise, `getLocalBounds` may calculate incorrect bounds, which makes the container's width and height wrong.\n * To remove a mask, set this property to `null`.\n *\n * For sprite mask both alpha and red channel are used. Black mask is the same as transparent mask.\n * @example\n * const graphics = new PIXI.Graphics();\n * graphics.beginFill(0xFF3300);\n * graphics.drawRect(50, 250, 100, 100);\n * graphics.endFill();\n *\n * const sprite = new PIXI.Sprite(texture);\n * sprite.mask = graphics;\n * @todo At the moment, PIXI.CanvasRenderer doesn't support PIXI.Sprite as mask.\n */\n get: function () {\n return this._mask;\n },\n set: function (value) {\n if (this._mask === value) {\n return;\n }\n if (this._mask) {\n var maskObject = (this._mask.isMaskData\n ? this._mask.maskObject : this._mask);\n if (maskObject) {\n maskObject._maskRefCount--;\n if (maskObject._maskRefCount === 0) {\n maskObject.renderable = true;\n maskObject.isMask = false;\n }\n }\n }\n this._mask = value;\n if (this._mask) {\n var maskObject = (this._mask.isMaskData\n ? this._mask.maskObject : this._mask);\n if (maskObject) {\n if (maskObject._maskRefCount === 0) {\n maskObject.renderable = false;\n maskObject.isMask = true;\n }\n maskObject._maskRefCount++;\n }\n }\n },\n enumerable: false,\n configurable: true\n });\n return DisplayObject;\n}(EventEmitter));\n/**\n * @private\n */\nvar TemporaryDisplayObject = /** @class */ (function (_super) {\n __extends(TemporaryDisplayObject, _super);\n function TemporaryDisplayObject() {\n var _this = _super !== null && _super.apply(this, arguments) || this;\n _this.sortDirty = null;\n return _this;\n }\n return TemporaryDisplayObject;\n}(DisplayObject));\n/**\n * DisplayObject default updateTransform, does not update children of container.\n * Will crash if there's no parent element.\n * @memberof PIXI.DisplayObject#\n * @method displayObjectUpdateTransform\n */\nDisplayObject.prototype.displayObjectUpdateTransform = DisplayObject.prototype.updateTransform;\n\nfunction sortChildren(a, b) {\n if (a.zIndex === b.zIndex) {\n return a._lastSortedIndex - b._lastSortedIndex;\n }\n return a.zIndex - b.zIndex;\n}\n/**\n * Container is a general-purpose display object that holds children. It also adds built-in support for advanced\n * rendering features like masking and filtering.\n *\n * It is the base class of all display objects that act as a container for other objects, including Graphics\n * and Sprite.\n *\n * ```js\n * import { BlurFilter } from '@pixi/filter-blur';\n * import { Container } from '@pixi/display';\n * import { Graphics } from '@pixi/graphics';\n * import { Sprite } from '@pixi/sprite';\n *\n * let container = new Container();\n * let sprite = Sprite.from(\"https://s3-us-west-2.amazonaws.com/s.cdpn.io/693612/IaUrttj.png\");\n *\n * sprite.width = 512;\n * sprite.height = 512;\n *\n * // Adds a sprite as a child to this container. As a result, the sprite will be rendered whenever the container\n * // is rendered.\n * container.addChild(sprite);\n *\n * // Blurs whatever is rendered by the container\n * container.filters = [new BlurFilter()];\n *\n * // Only the contents within a circle at the center should be rendered onto the screen.\n * container.mask = new Graphics()\n * .beginFill(0xffffff)\n * .drawCircle(sprite.width / 2, sprite.height / 2, Math.min(sprite.width, sprite.height) / 2)\n * .endFill();\n * ```\n * @memberof PIXI\n */\nvar Container = /** @class */ (function (_super) {\n __extends(Container, _super);\n function Container() {\n var _this = _super.call(this) || this;\n _this.children = [];\n _this.sortableChildren = settings.SORTABLE_CHILDREN;\n _this.sortDirty = false;\n return _this;\n /**\n * Fired when a DisplayObject is added to this Container.\n * @event PIXI.Container#childAdded\n * @param {PIXI.DisplayObject} child - The child added to the Container.\n * @param {PIXI.Container} container - The container that added the child.\n * @param {number} index - The children's index of the added child.\n */\n /**\n * Fired when a DisplayObject is removed from this Container.\n * @event PIXI.DisplayObject#childRemoved\n * @param {PIXI.DisplayObject} child - The child removed from the Container.\n * @param {PIXI.Container} container - The container that removed the child.\n * @param {number} index - The former children's index of the removed child\n */\n }\n /**\n * Overridable method that can be used by Container subclasses whenever the children array is modified.\n * @param _length\n */\n Container.prototype.onChildrenChange = function (_length) {\n /* empty */\n };\n /**\n * Adds one or more children to the container.\n *\n * Multiple items can be added like so: `myContainer.addChild(thingOne, thingTwo, thingThree)`\n * @param {...PIXI.DisplayObject} children - The DisplayObject(s) to add to the container\n * @returns {PIXI.DisplayObject} - The first child that was added.\n */\n Container.prototype.addChild = function () {\n var arguments$1 = arguments;\n\n var children = [];\n for (var _i = 0; _i < arguments.length; _i++) {\n children[_i] = arguments$1[_i];\n }\n // if there is only one argument we can bypass looping through the them\n if (children.length > 1) {\n // loop through the array and add all children\n for (var i = 0; i < children.length; i++) {\n // eslint-disable-next-line prefer-rest-params\n this.addChild(children[i]);\n }\n }\n else {\n var child = children[0];\n // if the child has a parent then lets remove it as PixiJS objects can only exist in one place\n if (child.parent) {\n child.parent.removeChild(child);\n }\n child.parent = this;\n this.sortDirty = true;\n // ensure child transform will be recalculated\n child.transform._parentID = -1;\n this.children.push(child);\n // ensure bounds will be recalculated\n this._boundsID++;\n // TODO - lets either do all callbacks or all events.. not both!\n this.onChildrenChange(this.children.length - 1);\n this.emit('childAdded', child, this, this.children.length - 1);\n child.emit('added', this);\n }\n return children[0];\n };\n /**\n * Adds a child to the container at a specified index. If the index is out of bounds an error will be thrown\n * @param {PIXI.DisplayObject} child - The child to add\n * @param {number} index - The index to place the child in\n * @returns {PIXI.DisplayObject} The child that was added.\n */\n Container.prototype.addChildAt = function (child, index) {\n if (index < 0 || index > this.children.length) {\n throw new Error(child + \"addChildAt: The index \" + index + \" supplied is out of bounds \" + this.children.length);\n }\n if (child.parent) {\n child.parent.removeChild(child);\n }\n child.parent = this;\n this.sortDirty = true;\n // ensure child transform will be recalculated\n child.transform._parentID = -1;\n this.children.splice(index, 0, child);\n // ensure bounds will be recalculated\n this._boundsID++;\n // TODO - lets either do all callbacks or all events.. not both!\n this.onChildrenChange(index);\n child.emit('added', this);\n this.emit('childAdded', child, this, index);\n return child;\n };\n /**\n * Swaps the position of 2 Display Objects within this container.\n * @param child - First display object to swap\n * @param child2 - Second display object to swap\n */\n Container.prototype.swapChildren = function (child, child2) {\n if (child === child2) {\n return;\n }\n var index1 = this.getChildIndex(child);\n var index2 = this.getChildIndex(child2);\n this.children[index1] = child2;\n this.children[index2] = child;\n this.onChildrenChange(index1 < index2 ? index1 : index2);\n };\n /**\n * Returns the index position of a child DisplayObject instance\n * @param child - The DisplayObject instance to identify\n * @returns - The index position of the child display object to identify\n */\n Container.prototype.getChildIndex = function (child) {\n var index = this.children.indexOf(child);\n if (index === -1) {\n throw new Error('The supplied DisplayObject must be a child of the caller');\n }\n return index;\n };\n /**\n * Changes the position of an existing child in the display object container\n * @param child - The child DisplayObject instance for which you want to change the index number\n * @param index - The resulting index number for the child display object\n */\n Container.prototype.setChildIndex = function (child, index) {\n if (index < 0 || index >= this.children.length) {\n throw new Error(\"The index \" + index + \" supplied is out of bounds \" + this.children.length);\n }\n var currentIndex = this.getChildIndex(child);\n removeItems(this.children, currentIndex, 1); // remove from old position\n this.children.splice(index, 0, child); // add at new position\n this.onChildrenChange(index);\n };\n /**\n * Returns the child at the specified index\n * @param index - The index to get the child at\n * @returns - The child at the given index, if any.\n */\n Container.prototype.getChildAt = function (index) {\n if (index < 0 || index >= this.children.length) {\n throw new Error(\"getChildAt: Index (\" + index + \") does not exist.\");\n }\n return this.children[index];\n };\n /**\n * Removes one or more children from the container.\n * @param {...PIXI.DisplayObject} children - The DisplayObject(s) to remove\n * @returns {PIXI.DisplayObject} The first child that was removed.\n */\n Container.prototype.removeChild = function () {\n var arguments$1 = arguments;\n\n var children = [];\n for (var _i = 0; _i < arguments.length; _i++) {\n children[_i] = arguments$1[_i];\n }\n // if there is only one argument we can bypass looping through the them\n if (children.length > 1) {\n // loop through the arguments property and remove all children\n for (var i = 0; i < children.length; i++) {\n this.removeChild(children[i]);\n }\n }\n else {\n var child = children[0];\n var index = this.children.indexOf(child);\n if (index === -1)\n { return null; }\n child.parent = null;\n // ensure child transform will be recalculated\n child.transform._parentID = -1;\n removeItems(this.children, index, 1);\n // ensure bounds will be recalculated\n this._boundsID++;\n // TODO - lets either do all callbacks or all events.. not both!\n this.onChildrenChange(index);\n child.emit('removed', this);\n this.emit('childRemoved', child, this, index);\n }\n return children[0];\n };\n /**\n * Removes a child from the specified index position.\n * @param index - The index to get the child from\n * @returns The child that was removed.\n */\n Container.prototype.removeChildAt = function (index) {\n var child = this.getChildAt(index);\n // ensure child transform will be recalculated..\n child.parent = null;\n child.transform._parentID = -1;\n removeItems(this.children, index, 1);\n // ensure bounds will be recalculated\n this._boundsID++;\n // TODO - lets either do all callbacks or all events.. not both!\n this.onChildrenChange(index);\n child.emit('removed', this);\n this.emit('childRemoved', child, this, index);\n return child;\n };\n /**\n * Removes all children from this container that are within the begin and end indexes.\n * @param beginIndex - The beginning position.\n * @param endIndex - The ending position. Default value is size of the container.\n * @returns - List of removed children\n */\n Container.prototype.removeChildren = function (beginIndex, endIndex) {\n if (beginIndex === void 0) { beginIndex = 0; }\n if (endIndex === void 0) { endIndex = this.children.length; }\n var begin = beginIndex;\n var end = endIndex;\n var range = end - begin;\n var removed;\n if (range > 0 && range <= end) {\n removed = this.children.splice(begin, range);\n for (var i = 0; i < removed.length; ++i) {\n removed[i].parent = null;\n if (removed[i].transform) {\n removed[i].transform._parentID = -1;\n }\n }\n this._boundsID++;\n this.onChildrenChange(beginIndex);\n for (var i = 0; i < removed.length; ++i) {\n removed[i].emit('removed', this);\n this.emit('childRemoved', removed[i], this, i);\n }\n return removed;\n }\n else if (range === 0 && this.children.length === 0) {\n return [];\n }\n throw new RangeError('removeChildren: numeric values are outside the acceptable range.');\n };\n /** Sorts children by zIndex. Previous order is maintained for 2 children with the same zIndex. */\n Container.prototype.sortChildren = function () {\n var sortRequired = false;\n for (var i = 0, j = this.children.length; i < j; ++i) {\n var child = this.children[i];\n child._lastSortedIndex = i;\n if (!sortRequired && child.zIndex !== 0) {\n sortRequired = true;\n }\n }\n if (sortRequired && this.children.length > 1) {\n this.children.sort(sortChildren);\n }\n this.sortDirty = false;\n };\n /** Updates the transform on all children of this container for rendering. */\n Container.prototype.updateTransform = function () {\n if (this.sortableChildren && this.sortDirty) {\n this.sortChildren();\n }\n this._boundsID++;\n this.transform.updateTransform(this.parent.transform);\n // TODO: check render flags, how to process stuff here\n this.worldAlpha = this.alpha * this.parent.worldAlpha;\n for (var i = 0, j = this.children.length; i < j; ++i) {\n var child = this.children[i];\n if (child.visible) {\n child.updateTransform();\n }\n }\n };\n /**\n * Recalculates the bounds of the container.\n *\n * This implementation will automatically fit the children's bounds into the calculation. Each child's bounds\n * is limited to its mask's bounds or filterArea, if any is applied.\n */\n Container.prototype.calculateBounds = function () {\n this._bounds.clear();\n this._calculateBounds();\n for (var i = 0; i < this.children.length; i++) {\n var child = this.children[i];\n if (!child.visible || !child.renderable) {\n continue;\n }\n child.calculateBounds();\n // TODO: filter+mask, need to mask both somehow\n if (child._mask) {\n var maskObject = (child._mask.isMaskData\n ? child._mask.maskObject : child._mask);\n if (maskObject) {\n maskObject.calculateBounds();\n this._bounds.addBoundsMask(child._bounds, maskObject._bounds);\n }\n else {\n this._bounds.addBounds(child._bounds);\n }\n }\n else if (child.filterArea) {\n this._bounds.addBoundsArea(child._bounds, child.filterArea);\n }\n else {\n this._bounds.addBounds(child._bounds);\n }\n }\n this._bounds.updateID = this._boundsID;\n };\n /**\n * Retrieves the local bounds of the displayObject as a rectangle object.\n *\n * Calling `getLocalBounds` may invalidate the `_bounds` of the whole subtree below. If using it inside a render()\n * call, it is advised to call `getBounds()` immediately after to recalculate the world bounds of the subtree.\n * @param rect - Optional rectangle to store the result of the bounds calculation.\n * @param skipChildrenUpdate - Setting to `true` will stop re-calculation of children transforms,\n * it was default behaviour of pixi 4.0-5.2 and caused many problems to users.\n * @returns - The rectangular bounding area.\n */\n Container.prototype.getLocalBounds = function (rect, skipChildrenUpdate) {\n if (skipChildrenUpdate === void 0) { skipChildrenUpdate = false; }\n var result = _super.prototype.getLocalBounds.call(this, rect);\n if (!skipChildrenUpdate) {\n for (var i = 0, j = this.children.length; i < j; ++i) {\n var child = this.children[i];\n if (child.visible) {\n child.updateTransform();\n }\n }\n }\n return result;\n };\n /**\n * Recalculates the content bounds of this object. This should be overriden to\n * calculate the bounds of this specific object (not including children).\n * @protected\n */\n Container.prototype._calculateBounds = function () {\n // FILL IN//\n };\n /**\n * Renders this object and its children with culling.\n * @protected\n * @param {PIXI.Renderer} renderer - The renderer\n */\n Container.prototype._renderWithCulling = function (renderer) {\n var sourceFrame = renderer.renderTexture.sourceFrame;\n // If the source frame is empty, stop rendering.\n if (!(sourceFrame.width > 0 && sourceFrame.height > 0)) {\n return;\n }\n // Render the content of the container only if its bounds intersect with the source frame.\n // All filters are on the stack at this point, and the filter source frame is bound:\n // therefore, even if the bounds to non intersect the filter frame, the filter\n // is still applied and any filter padding that is in the frame is rendered correctly.\n var bounds;\n var transform;\n // If cullArea is set, we use this rectangle instead of the bounds of the object. The cullArea\n // rectangle must completely contain the container and its children including filter padding.\n if (this.cullArea) {\n bounds = this.cullArea;\n transform = this.worldTransform;\n }\n // If the container doesn't override _render, we can skip the bounds calculation and intersection test.\n else if (this._render !== Container.prototype._render) {\n bounds = this.getBounds(true);\n }\n // Render the container if the source frame intersects the bounds.\n if (bounds && sourceFrame.intersects(bounds, transform)) {\n this._render(renderer);\n }\n // If the bounds are defined by cullArea and do not intersect with the source frame, stop rendering.\n else if (this.cullArea) {\n return;\n }\n // Unless cullArea is set, we cannot skip the children if the bounds of the container do not intersect\n // the source frame, because the children might have filters with nonzero padding, which may intersect\n // with the source frame while the bounds do not: filter padding is not included in the bounds.\n // If cullArea is not set, render the children with culling temporarily enabled so that they are not rendered\n // if they are out of frame; otherwise, render the children normally.\n for (var i = 0, j = this.children.length; i < j; ++i) {\n var child = this.children[i];\n var childCullable = child.cullable;\n child.cullable = childCullable || !this.cullArea;\n child.render(renderer);\n child.cullable = childCullable;\n }\n };\n /**\n * Renders the object using the WebGL renderer.\n *\n * The [_render]{@link PIXI.Container#_render} method is be overriden for rendering the contents of the\n * container itself. This `render` method will invoke it, and also invoke the `render` methods of all\n * children afterward.\n *\n * If `renderable` or `visible` is false or if `worldAlpha` is not positive or if `cullable` is true and\n * the bounds of this object are out of frame, this implementation will entirely skip rendering.\n * See {@link PIXI.DisplayObject} for choosing between `renderable` or `visible`. Generally,\n * setting alpha to zero is not recommended for purely skipping rendering.\n *\n * When your scene becomes large (especially when it is larger than can be viewed in a single screen), it is\n * advised to employ **culling** to automatically skip rendering objects outside of the current screen.\n * See [cullable]{@link PIXI.DisplayObject#cullable} and [cullArea]{@link PIXI.DisplayObject#cullArea}.\n * Other culling methods might be better suited for a large number static objects; see\n * [@pixi-essentials/cull]{@link https://www.npmjs.com/package/@pixi-essentials/cull} and\n * [pixi-cull]{@link https://www.npmjs.com/package/pixi-cull}.\n *\n * The [renderAdvanced]{@link PIXI.Container#renderAdvanced} method is internally used when when masking or\n * filtering is applied on a container. This does, however, break batching and can affect performance when\n * masking and filtering is applied extensively throughout the scene graph.\n * @param renderer - The renderer\n */\n Container.prototype.render = function (renderer) {\n // if the object is not visible or the alpha is 0 then no need to render this element\n if (!this.visible || this.worldAlpha <= 0 || !this.renderable) {\n return;\n }\n // do a quick check to see if this element has a mask or a filter.\n if (this._mask || (this.filters && this.filters.length)) {\n this.renderAdvanced(renderer);\n }\n else if (this.cullable) {\n this._renderWithCulling(renderer);\n }\n else {\n this._render(renderer);\n for (var i = 0, j = this.children.length; i < j; ++i) {\n this.children[i].render(renderer);\n }\n }\n };\n /**\n * Render the object using the WebGL renderer and advanced features.\n * @param renderer - The renderer\n */\n Container.prototype.renderAdvanced = function (renderer) {\n var filters = this.filters;\n var mask = this._mask;\n // push filter first as we need to ensure the stencil buffer is correct for any masking\n if (filters) {\n if (!this._enabledFilters) {\n this._enabledFilters = [];\n }\n this._enabledFilters.length = 0;\n for (var i = 0; i < filters.length; i++) {\n if (filters[i].enabled) {\n this._enabledFilters.push(filters[i]);\n }\n }\n }\n var flush = (filters && this._enabledFilters && this._enabledFilters.length)\n || (mask && (!mask.isMaskData\n || (mask.enabled && (mask.autoDetect || mask.type !== MASK_TYPES.NONE))));\n if (flush) {\n renderer.batch.flush();\n }\n if (filters && this._enabledFilters && this._enabledFilters.length) {\n renderer.filter.push(this, this._enabledFilters);\n }\n if (mask) {\n renderer.mask.push(this, this._mask);\n }\n if (this.cullable) {\n this._renderWithCulling(renderer);\n }\n else {\n this._render(renderer);\n for (var i = 0, j = this.children.length; i < j; ++i) {\n this.children[i].render(renderer);\n }\n }\n if (flush) {\n renderer.batch.flush();\n }\n if (mask) {\n renderer.mask.pop(this);\n }\n if (filters && this._enabledFilters && this._enabledFilters.length) {\n renderer.filter.pop();\n }\n };\n /**\n * To be overridden by the subclasses.\n * @param _renderer - The renderer\n */\n Container.prototype._render = function (_renderer) {\n // this is where content itself gets rendered...\n };\n /**\n * Removes all internal references and listeners as well as removes children from the display list.\n * Do not use a Container after calling `destroy`.\n * @param options - Options parameter. A boolean will act as if all options\n * have been set to that value\n * @param {boolean} [options.children=false] - if set to true, all the children will have their destroy\n * method called as well. 'options' will be passed on to those calls.\n * @param {boolean} [options.texture=false] - Only used for child Sprites if options.children is set to true\n * Should it destroy the texture of the child sprite\n * @param {boolean} [options.baseTexture=false] - Only used for child Sprites if options.children is set to true\n * Should it destroy the base texture of the child sprite\n */\n Container.prototype.destroy = function (options) {\n _super.prototype.destroy.call(this);\n this.sortDirty = false;\n var destroyChildren = typeof options === 'boolean' ? options : options && options.children;\n var oldChildren = this.removeChildren(0, this.children.length);\n if (destroyChildren) {\n for (var i = 0; i < oldChildren.length; ++i) {\n oldChildren[i].destroy(options);\n }\n }\n };\n Object.defineProperty(Container.prototype, \"width\", {\n /** The width of the Container, setting this will actually modify the scale to achieve the value set. */\n get: function () {\n return this.scale.x * this.getLocalBounds().width;\n },\n set: function (value) {\n var width = this.getLocalBounds().width;\n if (width !== 0) {\n this.scale.x = value / width;\n }\n else {\n this.scale.x = 1;\n }\n this._width = value;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Container.prototype, \"height\", {\n /** The height of the Container, setting this will actually modify the scale to achieve the value set. */\n get: function () {\n return this.scale.y * this.getLocalBounds().height;\n },\n set: function (value) {\n var height = this.getLocalBounds().height;\n if (height !== 0) {\n this.scale.y = value / height;\n }\n else {\n this.scale.y = 1;\n }\n this._height = value;\n },\n enumerable: false,\n configurable: true\n });\n return Container;\n}(DisplayObject));\n/**\n * Container default updateTransform, does update children of container.\n * Will crash if there's no parent element.\n * @memberof PIXI.Container#\n * @method containerUpdateTransform\n */\nContainer.prototype.containerUpdateTransform = Container.prototype.updateTransform;\n\nexport { Bounds, Container, DisplayObject, TemporaryDisplayObject };\n//# sourceMappingURL=display.mjs.map\n","/*!\n * @pixi/extensions - v6.5.8\n * Compiled Sun, 23 Oct 2022 23:01:45 UTC\n *\n * @pixi/extensions is licensed under the MIT License.\n * http://www.opensource.org/licenses/mit-license\n */\n/*! *****************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n\r\nvar __assign = function() {\r\n __assign = Object.assign || function __assign(t) {\n var arguments$1 = arguments;\n\r\n for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n s = arguments$1[i];\r\n for (var p in s) { if (Object.prototype.hasOwnProperty.call(s, p)) { t[p] = s[p]; } }\r\n }\r\n return t;\r\n };\r\n return __assign.apply(this, arguments);\r\n};\n\n/**\n * Collection of valid extension types.\n * @memberof PIXI\n * @property {string} Application - Application plugins\n * @property {string} RendererPlugin - Plugins for Renderer\n * @property {string} CanvasRendererPlugin - Plugins for CanvasRenderer\n * @property {string} Loader - Plugins to use with Loader\n * @property {string} LoadParser - Parsers for Assets loader.\n * @property {string} ResolveParser - Parsers for Assets resolvers.\n * @property {string} CacheParser - Parsers for Assets cache.\n */\nvar ExtensionType;\n(function (ExtensionType) {\n ExtensionType[\"Application\"] = \"application\";\n ExtensionType[\"RendererPlugin\"] = \"renderer-webgl-plugin\";\n ExtensionType[\"CanvasRendererPlugin\"] = \"renderer-canvas-plugin\";\n ExtensionType[\"Loader\"] = \"loader\";\n ExtensionType[\"LoadParser\"] = \"load-parser\";\n ExtensionType[\"ResolveParser\"] = \"resolve-parser\";\n ExtensionType[\"CacheParser\"] = \"cache-parser\";\n ExtensionType[\"DetectionParser\"] = \"detection-parser\";\n})(ExtensionType || (ExtensionType = {}));\n/**\n * Convert input into extension format data.\n * @ignore\n */\nvar normalizeExtension = function (ext) {\n // Class/Object submission, use extension object\n if (typeof ext === 'function' || (typeof ext === 'object' && ext.extension)) {\n if (!ext.extension) {\n throw new Error('Extension class must have an extension object');\n }\n var metadata = (typeof ext.extension !== 'object')\n ? { type: ext.extension }\n : ext.extension;\n ext = __assign(__assign({}, metadata), { ref: ext });\n }\n if (typeof ext === 'object') {\n ext = __assign({}, ext);\n }\n else {\n throw new Error('Invalid extension type');\n }\n if (typeof ext.type === 'string') {\n ext.type = [ext.type];\n }\n return ext;\n};\n/**\n * Global registration of all PixiJS extensions. One-stop-shop for extensibility.\n * @memberof PIXI\n * @namespace extensions\n */\nvar extensions = {\n /** @ignore */\n _addHandlers: null,\n /** @ignore */\n _removeHandlers: null,\n /** @ignore */\n _queue: {},\n /**\n * Remove extensions from PixiJS.\n * @param extensions - Extensions to be removed.\n * @returns {PIXI.extensions} For chaining.\n */\n remove: function () {\n var arguments$1 = arguments;\n\n var _this = this;\n var extensions = [];\n for (var _i = 0; _i < arguments.length; _i++) {\n extensions[_i] = arguments$1[_i];\n }\n extensions.map(normalizeExtension).forEach(function (ext) {\n ext.type.forEach(function (type) { var _a, _b; return (_b = (_a = _this._removeHandlers)[type]) === null || _b === void 0 ? void 0 : _b.call(_a, ext); });\n });\n return this;\n },\n /**\n * Register new extensions with PixiJS.\n * @param extensions - The spread of extensions to add to PixiJS.\n * @returns {PIXI.extensions} For chaining.\n */\n add: function () {\n var arguments$1 = arguments;\n\n var _this = this;\n var extensions = [];\n for (var _i = 0; _i < arguments.length; _i++) {\n extensions[_i] = arguments$1[_i];\n }\n // Handle any extensions either passed as class w/ data or as data\n extensions.map(normalizeExtension).forEach(function (ext) {\n ext.type.forEach(function (type) {\n var handlers = _this._addHandlers;\n var queue = _this._queue;\n if (!handlers[type]) {\n queue[type] = queue[type] || [];\n queue[type].push(ext);\n }\n else {\n handlers[type](ext);\n }\n });\n });\n return this;\n },\n /**\n * Internal method to handle extensions by name.\n * @param type - The extension type.\n * @param onAdd - Function for handling when extensions are added/registered passes {@link PIXI.ExtensionFormat}.\n * @param onRemove - Function for handling when extensions are removed/unregistered passes {@link PIXI.ExtensionFormat}.\n * @returns {PIXI.extensions} For chaining.\n */\n handle: function (type, onAdd, onRemove) {\n var addHandlers = this._addHandlers = this._addHandlers || {};\n var removeHandlers = this._removeHandlers = this._removeHandlers || {};\n if (addHandlers[type] || removeHandlers[type]) {\n throw new Error(\"Extension type \" + type + \" already has a handler\");\n }\n addHandlers[type] = onAdd;\n removeHandlers[type] = onRemove;\n // Process the queue\n var queue = this._queue;\n // Process any plugins that have been registered before the handler\n if (queue[type]) {\n queue[type].forEach(function (ext) { return onAdd(ext); });\n delete queue[type];\n }\n return this;\n },\n /**\n * Handle a type, but using a map by `name` property.\n * @param type - Type of extension to handle.\n * @param map - The object map of named extensions.\n * @returns {PIXI.extensions} For chaining.\n */\n handleByMap: function (type, map) {\n return this.handle(type, function (extension) {\n map[extension.name] = extension.ref;\n }, function (extension) {\n delete map[extension.name];\n });\n },\n /**\n * Handle a type, but using a list of extensions.\n * @param type - Type of extension to handle.\n * @param list - The list of extensions.\n * @returns {PIXI.extensions} For chaining.\n */\n handleByList: function (type, list) {\n return this.handle(type, function (extension) {\n var _a, _b;\n list.push(extension.ref);\n // TODO: remove me later, only added for @pixi/loaders\n if (type === ExtensionType.Loader) {\n (_b = (_a = extension.ref).add) === null || _b === void 0 ? void 0 : _b.call(_a);\n }\n }, function (extension) {\n var index = list.indexOf(extension.ref);\n if (index !== -1) {\n list.splice(index, 1);\n }\n });\n },\n};\n\nexport { ExtensionType, extensions };\n//# sourceMappingURL=extensions.mjs.map\n","/*!\n * @pixi/ticker - v6.5.8\n * Compiled Sun, 23 Oct 2022 23:01:45 UTC\n *\n * @pixi/ticker is licensed under the MIT License.\n * http://www.opensource.org/licenses/mit-license\n */\nimport { settings } from '@pixi/settings';\nimport { ExtensionType } from '@pixi/extensions';\n\n/**\n * Target frames per millisecond.\n * @static\n * @name TARGET_FPMS\n * @memberof PIXI.settings\n * @type {number}\n * @default 0.06\n */\nsettings.TARGET_FPMS = 0.06;\n\n/**\n * Represents the update priorities used by internal PIXI classes when registered with\n * the {@link PIXI.Ticker} object. Higher priority items are updated first and lower\n * priority items, such as render, should go later.\n * @static\n * @constant\n * @name UPDATE_PRIORITY\n * @memberof PIXI\n * @enum {number}\n * @property {number} [INTERACTION=50] Highest priority, used for {@link PIXI.InteractionManager}\n * @property {number} [HIGH=25] High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.AnimatedSprite}\n * @property {number} [NORMAL=0] Default priority for ticker events, see {@link PIXI.Ticker#add}.\n * @property {number} [LOW=-25] Low priority used for {@link PIXI.Application} rendering.\n * @property {number} [UTILITY=-50] Lowest priority used for {@link PIXI.BasePrepare} utility.\n */\nvar UPDATE_PRIORITY;\n(function (UPDATE_PRIORITY) {\n UPDATE_PRIORITY[UPDATE_PRIORITY[\"INTERACTION\"] = 50] = \"INTERACTION\";\n UPDATE_PRIORITY[UPDATE_PRIORITY[\"HIGH\"] = 25] = \"HIGH\";\n UPDATE_PRIORITY[UPDATE_PRIORITY[\"NORMAL\"] = 0] = \"NORMAL\";\n UPDATE_PRIORITY[UPDATE_PRIORITY[\"LOW\"] = -25] = \"LOW\";\n UPDATE_PRIORITY[UPDATE_PRIORITY[\"UTILITY\"] = -50] = \"UTILITY\";\n})(UPDATE_PRIORITY || (UPDATE_PRIORITY = {}));\n\n/**\n * Internal class for handling the priority sorting of ticker handlers.\n * @private\n * @class\n * @memberof PIXI\n */\nvar TickerListener = /** @class */ (function () {\n /**\n * Constructor\n * @private\n * @param fn - The listener function to be added for one update\n * @param context - The listener context\n * @param priority - The priority for emitting\n * @param once - If the handler should fire once\n */\n function TickerListener(fn, context, priority, once) {\n if (context === void 0) { context = null; }\n if (priority === void 0) { priority = 0; }\n if (once === void 0) { once = false; }\n /** The next item in chain. */\n this.next = null;\n /** The previous item in chain. */\n this.previous = null;\n /** `true` if this listener has been destroyed already. */\n this._destroyed = false;\n this.fn = fn;\n this.context = context;\n this.priority = priority;\n this.once = once;\n }\n /**\n * Simple compare function to figure out if a function and context match.\n * @private\n * @param fn - The listener function to be added for one update\n * @param context - The listener context\n * @returns `true` if the listener match the arguments\n */\n TickerListener.prototype.match = function (fn, context) {\n if (context === void 0) { context = null; }\n return this.fn === fn && this.context === context;\n };\n /**\n * Emit by calling the current function.\n * @private\n * @param deltaTime - time since the last emit.\n * @returns Next ticker\n */\n TickerListener.prototype.emit = function (deltaTime) {\n if (this.fn) {\n if (this.context) {\n this.fn.call(this.context, deltaTime);\n }\n else {\n this.fn(deltaTime);\n }\n }\n var redirect = this.next;\n if (this.once) {\n this.destroy(true);\n }\n // Soft-destroying should remove\n // the next reference\n if (this._destroyed) {\n this.next = null;\n }\n return redirect;\n };\n /**\n * Connect to the list.\n * @private\n * @param previous - Input node, previous listener\n */\n TickerListener.prototype.connect = function (previous) {\n this.previous = previous;\n if (previous.next) {\n previous.next.previous = this;\n }\n this.next = previous.next;\n previous.next = this;\n };\n /**\n * Destroy and don't use after this.\n * @private\n * @param hard - `true` to remove the `next` reference, this\n * is considered a hard destroy. Soft destroy maintains the next reference.\n * @returns The listener to redirect while emitting or removing.\n */\n TickerListener.prototype.destroy = function (hard) {\n if (hard === void 0) { hard = false; }\n this._destroyed = true;\n this.fn = null;\n this.context = null;\n // Disconnect, hook up next and previous\n if (this.previous) {\n this.previous.next = this.next;\n }\n if (this.next) {\n this.next.previous = this.previous;\n }\n // Redirect to the next item\n var redirect = this.next;\n // Remove references\n this.next = hard ? null : redirect;\n this.previous = null;\n return redirect;\n };\n return TickerListener;\n}());\n\n/**\n * A Ticker class that runs an update loop that other objects listen to.\n *\n * This class is composed around listeners meant for execution on the next requested animation frame.\n * Animation frames are requested only when necessary, e.g. When the ticker is started and the emitter has listeners.\n * @class\n * @memberof PIXI\n */\nvar Ticker = /** @class */ (function () {\n function Ticker() {\n var _this = this;\n /**\n * Whether or not this ticker should invoke the method\n * {@link PIXI.Ticker#start} automatically\n * when a listener is added.\n */\n this.autoStart = false;\n /**\n * Scalar time value from last frame to this frame.\n * This value is capped by setting {@link PIXI.Ticker#minFPS}\n * and is scaled with {@link PIXI.Ticker#speed}.\n * **Note:** The cap may be exceeded by scaling.\n */\n this.deltaTime = 1;\n /**\n * The last time {@link PIXI.Ticker#update} was invoked.\n * This value is also reset internally outside of invoking\n * update, but only when a new animation frame is requested.\n * If the platform supports DOMHighResTimeStamp,\n * this value will have a precision of 1 µs.\n */\n this.lastTime = -1;\n /**\n * Factor of current {@link PIXI.Ticker#deltaTime}.\n * @example\n * // Scales ticker.deltaTime to what would be\n * // the equivalent of approximately 120 FPS\n * ticker.speed = 2;\n */\n this.speed = 1;\n /**\n * Whether or not this ticker has been started.\n * `true` if {@link PIXI.Ticker#start} has been called.\n * `false` if {@link PIXI.Ticker#stop} has been called.\n * While `false`, this value may change to `true` in the\n * event of {@link PIXI.Ticker#autoStart} being `true`\n * and a listener is added.\n */\n this.started = false;\n /** Internal current frame request ID */\n this._requestId = null;\n /**\n * Internal value managed by minFPS property setter and getter.\n * This is the maximum allowed milliseconds between updates.\n */\n this._maxElapsedMS = 100;\n /**\n * Internal value managed by minFPS property setter and getter.\n * This is the minimum allowed milliseconds between updates.\n */\n this._minElapsedMS = 0;\n /** If enabled, deleting is disabled.*/\n this._protected = false;\n /** The last time keyframe was executed. Maintains a relatively fixed interval with the previous value. */\n this._lastFrame = -1;\n this._head = new TickerListener(null, null, Infinity);\n this.deltaMS = 1 / settings.TARGET_FPMS;\n this.elapsedMS = 1 / settings.TARGET_FPMS;\n this._tick = function (time) {\n _this._requestId = null;\n if (_this.started) {\n // Invoke listeners now\n _this.update(time);\n // Listener side effects may have modified ticker state.\n if (_this.started && _this._requestId === null && _this._head.next) {\n _this._requestId = requestAnimationFrame(_this._tick);\n }\n }\n };\n }\n /**\n * Conditionally requests a new animation frame.\n * If a frame has not already been requested, and if the internal\n * emitter has listeners, a new frame is requested.\n * @private\n */\n Ticker.prototype._requestIfNeeded = function () {\n if (this._requestId === null && this._head.next) {\n // ensure callbacks get correct delta\n this.lastTime = performance.now();\n this._lastFrame = this.lastTime;\n this._requestId = requestAnimationFrame(this._tick);\n }\n };\n /**\n * Conditionally cancels a pending animation frame.\n * @private\n */\n Ticker.prototype._cancelIfNeeded = function () {\n if (this._requestId !== null) {\n cancelAnimationFrame(this._requestId);\n this._requestId = null;\n }\n };\n /**\n * Conditionally requests a new animation frame.\n * If the ticker has been started it checks if a frame has not already\n * been requested, and if the internal emitter has listeners. If these\n * conditions are met, a new frame is requested. If the ticker has not\n * been started, but autoStart is `true`, then the ticker starts now,\n * and continues with the previous conditions to request a new frame.\n * @private\n */\n Ticker.prototype._startIfPossible = function () {\n if (this.started) {\n this._requestIfNeeded();\n }\n else if (this.autoStart) {\n this.start();\n }\n };\n /**\n * Register a handler for tick events. Calls continuously unless\n * it is removed or the ticker is stopped.\n * @param fn - The listener function to be added for updates\n * @param context - The listener context\n * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting\n * @returns This instance of a ticker\n */\n Ticker.prototype.add = function (fn, context, priority) {\n if (priority === void 0) { priority = UPDATE_PRIORITY.NORMAL; }\n return this._addListener(new TickerListener(fn, context, priority));\n };\n /**\n * Add a handler for the tick event which is only execute once.\n * @param fn - The listener function to be added for one update\n * @param context - The listener context\n * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting\n * @returns This instance of a ticker\n */\n Ticker.prototype.addOnce = function (fn, context, priority) {\n if (priority === void 0) { priority = UPDATE_PRIORITY.NORMAL; }\n return this._addListener(new TickerListener(fn, context, priority, true));\n };\n /**\n * Internally adds the event handler so that it can be sorted by priority.\n * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run\n * before the rendering.\n * @private\n * @param listener - Current listener being added.\n * @returns This instance of a ticker\n */\n Ticker.prototype._addListener = function (listener) {\n // For attaching to head\n var current = this._head.next;\n var previous = this._head;\n // Add the first item\n if (!current) {\n listener.connect(previous);\n }\n else {\n // Go from highest to lowest priority\n while (current) {\n if (listener.priority > current.priority) {\n listener.connect(previous);\n break;\n }\n previous = current;\n current = current.next;\n }\n // Not yet connected\n if (!listener.previous) {\n listener.connect(previous);\n }\n }\n this._startIfPossible();\n return this;\n };\n /**\n * Removes any handlers matching the function and context parameters.\n * If no handlers are left after removing, then it cancels the animation frame.\n * @param fn - The listener function to be removed\n * @param context - The listener context to be removed\n * @returns This instance of a ticker\n */\n Ticker.prototype.remove = function (fn, context) {\n var listener = this._head.next;\n while (listener) {\n // We found a match, lets remove it\n // no break to delete all possible matches\n // incase a listener was added 2+ times\n if (listener.match(fn, context)) {\n listener = listener.destroy();\n }\n else {\n listener = listener.next;\n }\n }\n if (!this._head.next) {\n this._cancelIfNeeded();\n }\n return this;\n };\n Object.defineProperty(Ticker.prototype, \"count\", {\n /**\n * The number of listeners on this ticker, calculated by walking through linked list\n * @readonly\n * @member {number}\n */\n get: function () {\n if (!this._head) {\n return 0;\n }\n var count = 0;\n var current = this._head;\n while ((current = current.next)) {\n count++;\n }\n return count;\n },\n enumerable: false,\n configurable: true\n });\n /** Starts the ticker. If the ticker has listeners a new animation frame is requested at this point. */\n Ticker.prototype.start = function () {\n if (!this.started) {\n this.started = true;\n this._requestIfNeeded();\n }\n };\n /** Stops the ticker. If the ticker has requested an animation frame it is canceled at this point. */\n Ticker.prototype.stop = function () {\n if (this.started) {\n this.started = false;\n this._cancelIfNeeded();\n }\n };\n /** Destroy the ticker and don't use after this. Calling this method removes all references to internal events. */\n Ticker.prototype.destroy = function () {\n if (!this._protected) {\n this.stop();\n var listener = this._head.next;\n while (listener) {\n listener = listener.destroy(true);\n }\n this._head.destroy();\n this._head = null;\n }\n };\n /**\n * Triggers an update. An update entails setting the\n * current {@link PIXI.Ticker#elapsedMS},\n * the current {@link PIXI.Ticker#deltaTime},\n * invoking all listeners with current deltaTime,\n * and then finally setting {@link PIXI.Ticker#lastTime}\n * with the value of currentTime that was provided.\n * This method will be called automatically by animation\n * frame callbacks if the ticker instance has been started\n * and listeners are added.\n * @param {number} [currentTime=performance.now()] - the current time of execution\n */\n Ticker.prototype.update = function (currentTime) {\n if (currentTime === void 0) { currentTime = performance.now(); }\n var elapsedMS;\n // If the difference in time is zero or negative, we ignore most of the work done here.\n // If there is no valid difference, then should be no reason to let anyone know about it.\n // A zero delta, is exactly that, nothing should update.\n //\n // The difference in time can be negative, and no this does not mean time traveling.\n // This can be the result of a race condition between when an animation frame is requested\n // on the current JavaScript engine event loop, and when the ticker's start method is invoked\n // (which invokes the internal _requestIfNeeded method). If a frame is requested before\n // _requestIfNeeded is invoked, then the callback for the animation frame the ticker requests,\n // can receive a time argument that can be less than the lastTime value that was set within\n // _requestIfNeeded. This difference is in microseconds, but this is enough to cause problems.\n //\n // This check covers this browser engine timing issue, as well as if consumers pass an invalid\n // currentTime value. This may happen if consumers opt-out of the autoStart, and update themselves.\n if (currentTime > this.lastTime) {\n // Save uncapped elapsedMS for measurement\n elapsedMS = this.elapsedMS = currentTime - this.lastTime;\n // cap the milliseconds elapsed used for deltaTime\n if (elapsedMS > this._maxElapsedMS) {\n elapsedMS = this._maxElapsedMS;\n }\n elapsedMS *= this.speed;\n // If not enough time has passed, exit the function.\n // Get ready for next frame by setting _lastFrame, but based on _minElapsedMS\n // adjustment to ensure a relatively stable interval.\n if (this._minElapsedMS) {\n var delta = currentTime - this._lastFrame | 0;\n if (delta < this._minElapsedMS) {\n return;\n }\n this._lastFrame = currentTime - (delta % this._minElapsedMS);\n }\n this.deltaMS = elapsedMS;\n this.deltaTime = this.deltaMS * settings.TARGET_FPMS;\n // Cache a local reference, in-case ticker is destroyed\n // during the emit, we can still check for head.next\n var head = this._head;\n // Invoke listeners added to internal emitter\n var listener = head.next;\n while (listener) {\n listener = listener.emit(this.deltaTime);\n }\n if (!head.next) {\n this._cancelIfNeeded();\n }\n }\n else {\n this.deltaTime = this.deltaMS = this.elapsedMS = 0;\n }\n this.lastTime = currentTime;\n };\n Object.defineProperty(Ticker.prototype, \"FPS\", {\n /**\n * The frames per second at which this ticker is running.\n * The default is approximately 60 in most modern browsers.\n * **Note:** This does not factor in the value of\n * {@link PIXI.Ticker#speed}, which is specific\n * to scaling {@link PIXI.Ticker#deltaTime}.\n * @member {number}\n * @readonly\n */\n get: function () {\n return 1000 / this.elapsedMS;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Ticker.prototype, \"minFPS\", {\n /**\n * Manages the maximum amount of milliseconds allowed to\n * elapse between invoking {@link PIXI.Ticker#update}.\n * This value is used to cap {@link PIXI.Ticker#deltaTime},\n * but does not effect the measured value of {@link PIXI.Ticker#FPS}.\n * When setting this property it is clamped to a value between\n * `0` and `PIXI.settings.TARGET_FPMS * 1000`.\n * @member {number}\n * @default 10\n */\n get: function () {\n return 1000 / this._maxElapsedMS;\n },\n set: function (fps) {\n // Minimum must be below the maxFPS\n var minFPS = Math.min(this.maxFPS, fps);\n // Must be at least 0, but below 1 / settings.TARGET_FPMS\n var minFPMS = Math.min(Math.max(0, minFPS) / 1000, settings.TARGET_FPMS);\n this._maxElapsedMS = 1 / minFPMS;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Ticker.prototype, \"maxFPS\", {\n /**\n * Manages the minimum amount of milliseconds required to\n * elapse between invoking {@link PIXI.Ticker#update}.\n * This will effect the measured value of {@link PIXI.Ticker#FPS}.\n * If it is set to `0`, then there is no limit; PixiJS will render as many frames as it can.\n * Otherwise it will be at least `minFPS`\n * @member {number}\n * @default 0\n */\n get: function () {\n if (this._minElapsedMS) {\n return Math.round(1000 / this._minElapsedMS);\n }\n return 0;\n },\n set: function (fps) {\n if (fps === 0) {\n this._minElapsedMS = 0;\n }\n else {\n // Max must be at least the minFPS\n var maxFPS = Math.max(this.minFPS, fps);\n this._minElapsedMS = 1 / (maxFPS / 1000);\n }\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Ticker, \"shared\", {\n /**\n * The shared ticker instance used by {@link PIXI.AnimatedSprite} and by\n * {@link PIXI.VideoResource} to update animation frames / video textures.\n *\n * It may also be used by {@link PIXI.Application} if created with the `sharedTicker` option property set to true.\n *\n * The property {@link PIXI.Ticker#autoStart} is set to `true` for this instance.\n * Please follow the examples for usage, including how to opt-out of auto-starting the shared ticker.\n * @example\n * let ticker = PIXI.Ticker.shared;\n * // Set this to prevent starting this ticker when listeners are added.\n * // By default this is true only for the PIXI.Ticker.shared instance.\n * ticker.autoStart = false;\n * // FYI, call this to ensure the ticker is stopped. It should be stopped\n * // if you have not attempted to render anything yet.\n * ticker.stop();\n * // Call this when you are ready for a running shared ticker.\n * ticker.start();\n * @example\n * // You may use the shared ticker to render...\n * let renderer = PIXI.autoDetectRenderer();\n * let stage = new PIXI.Container();\n * document.body.appendChild(renderer.view);\n * ticker.add(function (time) {\n * renderer.render(stage);\n * });\n * @example\n * // Or you can just update it manually.\n * ticker.autoStart = false;\n * ticker.stop();\n * function animate(time) {\n * ticker.update(time);\n * renderer.render(stage);\n * requestAnimationFrame(animate);\n * }\n * animate(performance.now());\n * @member {PIXI.Ticker}\n * @static\n */\n get: function () {\n if (!Ticker._shared) {\n var shared = Ticker._shared = new Ticker();\n shared.autoStart = true;\n shared._protected = true;\n }\n return Ticker._shared;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Ticker, \"system\", {\n /**\n * The system ticker instance used by {@link PIXI.InteractionManager} and by\n * {@link PIXI.BasePrepare} for core timing functionality that shouldn't usually need to be paused,\n * unlike the `shared` ticker which drives visual animations and rendering which may want to be paused.\n *\n * The property {@link PIXI.Ticker#autoStart} is set to `true` for this instance.\n * @member {PIXI.Ticker}\n * @static\n */\n get: function () {\n if (!Ticker._system) {\n var system = Ticker._system = new Ticker();\n system.autoStart = true;\n system._protected = true;\n }\n return Ticker._system;\n },\n enumerable: false,\n configurable: true\n });\n return Ticker;\n}());\n\n/**\n * Middleware for for Application Ticker.\n * @example\n * import {TickerPlugin} from '@pixi/ticker';\n * import {Application} from '@pixi/app';\n * import {extensions} from '@pixi/extensions';\n * extensions.add(TickerPlugin);\n * @class\n * @memberof PIXI\n */\nvar TickerPlugin = /** @class */ (function () {\n function TickerPlugin() {\n }\n /**\n * Initialize the plugin with scope of application instance\n * @static\n * @private\n * @param {object} [options] - See application options\n */\n TickerPlugin.init = function (options) {\n var _this = this;\n // Set default\n options = Object.assign({\n autoStart: true,\n sharedTicker: false,\n }, options);\n // Create ticker setter\n Object.defineProperty(this, 'ticker', {\n set: function (ticker) {\n if (this._ticker) {\n this._ticker.remove(this.render, this);\n }\n this._ticker = ticker;\n if (ticker) {\n ticker.add(this.render, this, UPDATE_PRIORITY.LOW);\n }\n },\n get: function () {\n return this._ticker;\n },\n });\n /**\n * Convenience method for stopping the render.\n * @method\n * @memberof PIXI.Application\n * @instance\n */\n this.stop = function () {\n _this._ticker.stop();\n };\n /**\n * Convenience method for starting the render.\n * @method\n * @memberof PIXI.Application\n * @instance\n */\n this.start = function () {\n _this._ticker.start();\n };\n /**\n * Internal reference to the ticker.\n * @type {PIXI.Ticker}\n * @name _ticker\n * @memberof PIXI.Application#\n * @private\n */\n this._ticker = null;\n /**\n * Ticker for doing render updates.\n * @type {PIXI.Ticker}\n * @name ticker\n * @memberof PIXI.Application#\n * @default PIXI.Ticker.shared\n */\n this.ticker = options.sharedTicker ? Ticker.shared : new Ticker();\n // Start the rendering\n if (options.autoStart) {\n this.start();\n }\n };\n /**\n * Clean up the ticker, scoped to application.\n * @static\n * @private\n */\n TickerPlugin.destroy = function () {\n if (this._ticker) {\n var oldTicker = this._ticker;\n this.ticker = null;\n oldTicker.destroy();\n }\n };\n /** @ignore */\n TickerPlugin.extension = ExtensionType.Application;\n return TickerPlugin;\n}());\n\nexport { Ticker, TickerPlugin, UPDATE_PRIORITY };\n//# sourceMappingURL=ticker.mjs.map\n","/*!\n * @pixi/core - v6.5.8\n * Compiled Sun, 23 Oct 2022 23:01:45 UTC\n *\n * @pixi/core is licensed under the MIT License.\n * http://www.opensource.org/licenses/mit-license\n */\nimport { settings } from '@pixi/settings';\nimport { ENV, ALPHA_MODES, SCALE_MODES, FORMATS, TYPES, TARGETS, MIPMAP_MODES, MSAA_QUALITY, BUFFER_TYPE, CLEAR_MODES, DRAW_MODES, BUFFER_BITS, MASK_TYPES, PRECISION, BLEND_MODES, GC_MODES, SAMPLER_TYPES, WRAP_MODES, RENDERER_TYPE } from '@pixi/constants';\nimport { isMobile, isPow2, BaseTextureCache, TextureCache, uid, EventEmitter, determineCrossOrigin, getResolutionOfUrl, deprecation, nextPow2, getBufferType, ProgramCache, removeItems, hex2string, hex2rgb, sayHello, isWebGLSupported, premultiplyBlendMode, log2, premultiplyTint } from '@pixi/utils';\nimport { extensions as extensions$1, ExtensionType } from '@pixi/extensions';\nexport * from '@pixi/extensions';\nimport { Runner } from '@pixi/runner';\nimport { Ticker } from '@pixi/ticker';\nimport { groupD8, Rectangle, Point, Matrix } from '@pixi/math';\n\n/**\n * The maximum support for using WebGL. If a device does not\n * support WebGL version, for instance WebGL 2, it will still\n * attempt to fallback support to WebGL 1. If you want to\n * explicitly remove feature support to target a more stable\n * baseline, prefer a lower environment.\n *\n * Due to {@link https://bugs.chromium.org/p/chromium/issues/detail?id=934823|bug in chromium}\n * we disable webgl2 by default for all non-apple mobile devices.\n * @static\n * @name PREFER_ENV\n * @memberof PIXI.settings\n * @type {number}\n * @default PIXI.ENV.WEBGL2\n */\nsettings.PREFER_ENV = isMobile.any ? ENV.WEBGL : ENV.WEBGL2;\n/**\n * If set to `true`, *only* Textures and BaseTexture objects stored\n * in the caches ({@link PIXI.utils.TextureCache TextureCache} and\n * {@link PIXI.utils.BaseTextureCache BaseTextureCache}) can be\n * used when calling {@link PIXI.Texture.from Texture.from} or\n * {@link PIXI.BaseTexture.from BaseTexture.from}.\n * Otherwise, these `from` calls throw an exception. Using this property\n * can be useful if you want to enforce preloading all assets with\n * {@link PIXI.Loader Loader}.\n * @static\n * @name STRICT_TEXTURE_CACHE\n * @memberof PIXI.settings\n * @type {boolean}\n * @default false\n */\nsettings.STRICT_TEXTURE_CACHE = false;\n\n/**\n * Collection of installed resource types, class must extend {@link PIXI.Resource}.\n * @example\n * class CustomResource extends PIXI.Resource {\n * // MUST have source, options constructor signature\n * // for auto-detected resources to be created.\n * constructor(source, options) {\n * super();\n * }\n * upload(renderer, baseTexture, glTexture) {\n * // upload with GL\n * return true;\n * }\n * // used to auto-detect resource\n * static test(source, extension) {\n * return extension === 'xyz'|| source instanceof SomeClass;\n * }\n * }\n * // Install the new resource type\n * PIXI.INSTALLED.push(CustomResource);\n * @memberof PIXI\n * @type {Array<PIXI.IResourcePlugin>}\n * @static\n * @readonly\n */\nvar INSTALLED = [];\n/**\n * Create a resource element from a single source element. This\n * auto-detects which type of resource to create. All resources that\n * are auto-detectable must have a static `test` method and a constructor\n * with the arguments `(source, options?)`. Currently, the supported\n * resources for auto-detection include:\n * - {@link PIXI.ImageResource}\n * - {@link PIXI.CanvasResource}\n * - {@link PIXI.VideoResource}\n * - {@link PIXI.SVGResource}\n * - {@link PIXI.BufferResource}\n * @static\n * @memberof PIXI\n * @function autoDetectResource\n * @param {string|*} source - Resource source, this can be the URL to the resource,\n * a typed-array (for BufferResource), HTMLVideoElement, SVG data-uri\n * or any other resource that can be auto-detected. If not resource is\n * detected, it's assumed to be an ImageResource.\n * @param {object} [options] - Pass-through options to use for Resource\n * @param {number} [options.width] - Width of BufferResource or SVG rasterization\n * @param {number} [options.height] - Height of BufferResource or SVG rasterization\n * @param {boolean} [options.autoLoad=true] - Image, SVG and Video flag to start loading\n * @param {number} [options.scale=1] - SVG source scale. Overridden by width, height\n * @param {boolean} [options.createBitmap=PIXI.settings.CREATE_IMAGE_BITMAP] - Image option to create Bitmap object\n * @param {boolean} [options.crossorigin=true] - Image and Video option to set crossOrigin\n * @param {boolean} [options.autoPlay=true] - Video option to start playing video immediately\n * @param {number} [options.updateFPS=0] - Video option to update how many times a second the\n * texture should be updated from the video. Leave at 0 to update at every render\n * @returns {PIXI.Resource} The created resource.\n */\nfunction autoDetectResource(source, options) {\n if (!source) {\n return null;\n }\n var extension = '';\n if (typeof source === 'string') {\n // search for file extension: period, 3-4 chars, then ?, # or EOL\n var result = (/\\.(\\w{3,4})(?:$|\\?|#)/i).exec(source);\n if (result) {\n extension = result[1].toLowerCase();\n }\n }\n for (var i = INSTALLED.length - 1; i >= 0; --i) {\n var ResourcePlugin = INSTALLED[i];\n if (ResourcePlugin.test && ResourcePlugin.test(source, extension)) {\n return new ResourcePlugin(source, options);\n }\n }\n throw new Error('Unrecognized source type to auto-detect Resource');\n}\n\n/*! *****************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n/* global Reflect, Promise */\r\n\r\nvar extendStatics = function(d, b) {\r\n extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) { if (b.hasOwnProperty(p)) { d[p] = b[p]; } } };\r\n return extendStatics(d, b);\r\n};\r\n\r\nfunction __extends(d, b) {\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n}\r\n\r\nvar __assign = function() {\r\n __assign = Object.assign || function __assign(t) {\n var arguments$1 = arguments;\n\r\n for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n s = arguments$1[i];\r\n for (var p in s) { if (Object.prototype.hasOwnProperty.call(s, p)) { t[p] = s[p]; } }\r\n }\r\n return t;\r\n };\r\n return __assign.apply(this, arguments);\r\n};\r\n\r\nfunction __rest(s, e) {\r\n var t = {};\r\n for (var p in s) { if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\r\n { t[p] = s[p]; } }\r\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\r\n { for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\r\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\r\n { t[p[i]] = s[p[i]]; }\r\n } }\r\n return t;\r\n}\n\n/**\n * Base resource class for textures that manages validation and uploading, depending on its type.\n *\n * Uploading of a base texture to the GPU is required.\n * @memberof PIXI\n */\nvar Resource = /** @class */ (function () {\n /**\n * @param width - Width of the resource\n * @param height - Height of the resource\n */\n function Resource(width, height) {\n if (width === void 0) { width = 0; }\n if (height === void 0) { height = 0; }\n this._width = width;\n this._height = height;\n this.destroyed = false;\n this.internal = false;\n this.onResize = new Runner('setRealSize');\n this.onUpdate = new Runner('update');\n this.onError = new Runner('onError');\n }\n /**\n * Bind to a parent BaseTexture\n * @param baseTexture - Parent texture\n */\n Resource.prototype.bind = function (baseTexture) {\n this.onResize.add(baseTexture);\n this.onUpdate.add(baseTexture);\n this.onError.add(baseTexture);\n // Call a resize immediate if we already\n // have the width and height of the resource\n if (this._width || this._height) {\n this.onResize.emit(this._width, this._height);\n }\n };\n /**\n * Unbind to a parent BaseTexture\n * @param baseTexture - Parent texture\n */\n Resource.prototype.unbind = function (baseTexture) {\n this.onResize.remove(baseTexture);\n this.onUpdate.remove(baseTexture);\n this.onError.remove(baseTexture);\n };\n /**\n * Trigger a resize event\n * @param width - X dimension\n * @param height - Y dimension\n */\n Resource.prototype.resize = function (width, height) {\n if (width !== this._width || height !== this._height) {\n this._width = width;\n this._height = height;\n this.onResize.emit(width, height);\n }\n };\n Object.defineProperty(Resource.prototype, \"valid\", {\n /**\n * Has been validated\n * @readonly\n */\n get: function () {\n return !!this._width && !!this._height;\n },\n enumerable: false,\n configurable: true\n });\n /** Has been updated trigger event. */\n Resource.prototype.update = function () {\n if (!this.destroyed) {\n this.onUpdate.emit();\n }\n };\n /**\n * This can be overridden to start preloading a resource\n * or do any other prepare step.\n * @protected\n * @returns Handle the validate event\n */\n Resource.prototype.load = function () {\n return Promise.resolve(this);\n };\n Object.defineProperty(Resource.prototype, \"width\", {\n /**\n * The width of the resource.\n * @readonly\n */\n get: function () {\n return this._width;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Resource.prototype, \"height\", {\n /**\n * The height of the resource.\n * @readonly\n */\n get: function () {\n return this._height;\n },\n enumerable: false,\n configurable: true\n });\n /**\n * Set the style, optional to override\n * @param _renderer - yeah, renderer!\n * @param _baseTexture - the texture\n * @param _glTexture - texture instance for this webgl context\n * @returns - `true` is success\n */\n Resource.prototype.style = function (_renderer, _baseTexture, _glTexture) {\n return false;\n };\n /** Clean up anything, this happens when destroying is ready. */\n Resource.prototype.dispose = function () {\n // override\n };\n /**\n * Call when destroying resource, unbind any BaseTexture object\n * before calling this method, as reference counts are maintained\n * internally.\n */\n Resource.prototype.destroy = function () {\n if (!this.destroyed) {\n this.destroyed = true;\n this.dispose();\n this.onError.removeAll();\n this.onError = null;\n this.onResize.removeAll();\n this.onResize = null;\n this.onUpdate.removeAll();\n this.onUpdate = null;\n }\n };\n /**\n * Abstract, used to auto-detect resource type.\n * @param {*} _source - The source object\n * @param {string} _extension - The extension of source, if set\n */\n Resource.test = function (_source, _extension) {\n return false;\n };\n return Resource;\n}());\n\n/**\n * @interface SharedArrayBuffer\n */\n/**\n * Buffer resource with data of typed array.\n * @memberof PIXI\n */\nvar BufferResource = /** @class */ (function (_super) {\n __extends(BufferResource, _super);\n /**\n * @param source - Source buffer\n * @param options - Options\n * @param {number} options.width - Width of the texture\n * @param {number} options.height - Height of the texture\n */\n function BufferResource(source, options) {\n var _this = this;\n var _a = options || {}, width = _a.width, height = _a.height;\n if (!width || !height) {\n throw new Error('BufferResource width or height invalid');\n }\n _this = _super.call(this, width, height) || this;\n _this.data = source;\n return _this;\n }\n /**\n * Upload the texture to the GPU.\n * @param renderer - Upload to the renderer\n * @param baseTexture - Reference to parent texture\n * @param glTexture - glTexture\n * @returns - true is success\n */\n BufferResource.prototype.upload = function (renderer, baseTexture, glTexture) {\n var gl = renderer.gl;\n gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, baseTexture.alphaMode === ALPHA_MODES.UNPACK);\n var width = baseTexture.realWidth;\n var height = baseTexture.realHeight;\n if (glTexture.width === width && glTexture.height === height) {\n gl.texSubImage2D(baseTexture.target, 0, 0, 0, width, height, baseTexture.format, glTexture.type, this.data);\n }\n else {\n glTexture.width = width;\n glTexture.height = height;\n gl.texImage2D(baseTexture.target, 0, glTexture.internalFormat, width, height, 0, baseTexture.format, glTexture.type, this.data);\n }\n return true;\n };\n /** Destroy and don't use after this. */\n BufferResource.prototype.dispose = function () {\n this.data = null;\n };\n /**\n * Used to auto-detect the type of resource.\n * @param {*} source - The source object\n * @returns {boolean} `true` if <canvas>\n */\n BufferResource.test = function (source) {\n return source instanceof Float32Array\n || source instanceof Uint8Array\n || source instanceof Uint32Array;\n };\n return BufferResource;\n}(Resource));\n\nvar defaultBufferOptions = {\n scaleMode: SCALE_MODES.NEAREST,\n format: FORMATS.RGBA,\n alphaMode: ALPHA_MODES.NPM,\n};\n/**\n * A Texture stores the information that represents an image.\n * All textures have a base texture, which contains information about the source.\n * Therefore you can have many textures all using a single BaseTexture\n * @memberof PIXI\n * @typeParam R - The BaseTexture's Resource type.\n * @typeParam RO - The options for constructing resource.\n */\nvar BaseTexture = /** @class */ (function (_super) {\n __extends(BaseTexture, _super);\n /**\n * @param {PIXI.Resource|string|HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} [resource=null] -\n * The current resource to use, for things that aren't Resource objects, will be converted\n * into a Resource.\n * @param options - Collection of options\n * @param {PIXI.MIPMAP_MODES} [options.mipmap=PIXI.settings.MIPMAP_TEXTURES] - If mipmapping is enabled for texture\n * @param {number} [options.anisotropicLevel=PIXI.settings.ANISOTROPIC_LEVEL] - Anisotropic filtering level of texture\n * @param {PIXI.WRAP_MODES} [options.wrapMode=PIXI.settings.WRAP_MODE] - Wrap mode for textures\n * @param {PIXI.SCALE_MODES} [options.scaleMode=PIXI.settings.SCALE_MODE] - Default scale mode, linear, nearest\n * @param {PIXI.FORMATS} [options.format=PIXI.FORMATS.RGBA] - GL format type\n * @param {PIXI.TYPES} [options.type=PIXI.TYPES.UNSIGNED_BYTE] - GL data type\n * @param {PIXI.TARGETS} [options.target=PIXI.TARGETS.TEXTURE_2D] - GL texture target\n * @param {PIXI.ALPHA_MODES} [options.alphaMode=PIXI.ALPHA_MODES.UNPACK] - Pre multiply the image alpha\n * @param {number} [options.width=0] - Width of the texture\n * @param {number} [options.height=0] - Height of the texture\n * @param {number} [options.resolution=PIXI.settings.RESOLUTION] - Resolution of the base texture\n * @param {object} [options.resourceOptions] - Optional resource options,\n * see {@link PIXI.autoDetectResource autoDetectResource}\n */\n function BaseTexture(resource, options) {\n if (resource === void 0) { resource = null; }\n if (options === void 0) { options = null; }\n var _this = _super.call(this) || this;\n options = options || {};\n var alphaMode = options.alphaMode, mipmap = options.mipmap, anisotropicLevel = options.anisotropicLevel, scaleMode = options.scaleMode, width = options.width, height = options.height, wrapMode = options.wrapMode, format = options.format, type = options.type, target = options.target, resolution = options.resolution, resourceOptions = options.resourceOptions;\n // Convert the resource to a Resource object\n if (resource && !(resource instanceof Resource)) {\n resource = autoDetectResource(resource, resourceOptions);\n resource.internal = true;\n }\n _this.resolution = resolution || settings.RESOLUTION;\n _this.width = Math.round((width || 0) * _this.resolution) / _this.resolution;\n _this.height = Math.round((height || 0) * _this.resolution) / _this.resolution;\n _this._mipmap = mipmap !== undefined ? mipmap : settings.MIPMAP_TEXTURES;\n _this.anisotropicLevel = anisotropicLevel !== undefined ? anisotropicLevel : settings.ANISOTROPIC_LEVEL;\n _this._wrapMode = wrapMode || settings.WRAP_MODE;\n _this._scaleMode = scaleMode !== undefined ? scaleMode : settings.SCALE_MODE;\n _this.format = format || FORMATS.RGBA;\n _this.type = type || TYPES.UNSIGNED_BYTE;\n _this.target = target || TARGETS.TEXTURE_2D;\n _this.alphaMode = alphaMode !== undefined ? alphaMode : ALPHA_MODES.UNPACK;\n _this.uid = uid();\n _this.touched = 0;\n _this.isPowerOfTwo = false;\n _this._refreshPOT();\n _this._glTextures = {};\n _this.dirtyId = 0;\n _this.dirtyStyleId = 0;\n _this.cacheId = null;\n _this.valid = width > 0 && height > 0;\n _this.textureCacheIds = [];\n _this.destroyed = false;\n _this.resource = null;\n _this._batchEnabled = 0;\n _this._batchLocation = 0;\n _this.parentTextureArray = null;\n /**\n * Fired when a not-immediately-available source finishes loading.\n * @protected\n * @event PIXI.BaseTexture#loaded\n * @param {PIXI.BaseTexture} baseTexture - Resource loaded.\n */\n /**\n * Fired when a not-immediately-available source fails to load.\n * @protected\n * @event PIXI.BaseTexture#error\n * @param {PIXI.BaseTexture} baseTexture - Resource errored.\n * @param {ErrorEvent} event - Load error event.\n */\n /**\n * Fired when BaseTexture is updated.\n * @protected\n * @event PIXI.BaseTexture#loaded\n * @param {PIXI.BaseTexture} baseTexture - Resource loaded.\n */\n /**\n * Fired when BaseTexture is updated.\n * @protected\n * @event PIXI.BaseTexture#update\n * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.\n */\n /**\n * Fired when BaseTexture is destroyed.\n * @protected\n * @event PIXI.BaseTexture#dispose\n * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.\n */\n // Set the resource\n _this.setResource(resource);\n return _this;\n }\n Object.defineProperty(BaseTexture.prototype, \"realWidth\", {\n /**\n * Pixel width of the source of this texture\n * @readonly\n */\n get: function () {\n return Math.round(this.width * this.resolution);\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(BaseTexture.prototype, \"realHeight\", {\n /**\n * Pixel height of the source of this texture\n * @readonly\n */\n get: function () {\n return Math.round(this.height * this.resolution);\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(BaseTexture.prototype, \"mipmap\", {\n /**\n * Mipmap mode of the texture, affects downscaled images\n * @default PIXI.settings.MIPMAP_TEXTURES\n */\n get: function () {\n return this._mipmap;\n },\n set: function (value) {\n if (this._mipmap !== value) {\n this._mipmap = value;\n this.dirtyStyleId++;\n }\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(BaseTexture.prototype, \"scaleMode\", {\n /**\n * The scale mode to apply when scaling this texture\n * @default PIXI.settings.SCALE_MODE\n */\n get: function () {\n return this._scaleMode;\n },\n set: function (value) {\n if (this._scaleMode !== value) {\n this._scaleMode = value;\n this.dirtyStyleId++;\n }\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(BaseTexture.prototype, \"wrapMode\", {\n /**\n * How the texture wraps\n * @default PIXI.settings.WRAP_MODE\n */\n get: function () {\n return this._wrapMode;\n },\n set: function (value) {\n if (this._wrapMode !== value) {\n this._wrapMode = value;\n this.dirtyStyleId++;\n }\n },\n enumerable: false,\n configurable: true\n });\n /**\n * Changes style options of BaseTexture\n * @param scaleMode - Pixi scalemode\n * @param mipmap - enable mipmaps\n * @returns - this\n */\n BaseTexture.prototype.setStyle = function (scaleMode, mipmap) {\n var dirty;\n if (scaleMode !== undefined && scaleMode !== this.scaleMode) {\n this.scaleMode = scaleMode;\n dirty = true;\n }\n if (mipmap !== undefined && mipmap !== this.mipmap) {\n this.mipmap = mipmap;\n dirty = true;\n }\n if (dirty) {\n this.dirtyStyleId++;\n }\n return this;\n };\n /**\n * Changes w/h/resolution. Texture becomes valid if width and height are greater than zero.\n * @param desiredWidth - Desired visual width\n * @param desiredHeight - Desired visual height\n * @param resolution - Optionally set resolution\n * @returns - this\n */\n BaseTexture.prototype.setSize = function (desiredWidth, desiredHeight, resolution) {\n resolution = resolution || this.resolution;\n return this.setRealSize(desiredWidth * resolution, desiredHeight * resolution, resolution);\n };\n /**\n * Sets real size of baseTexture, preserves current resolution.\n * @param realWidth - Full rendered width\n * @param realHeight - Full rendered height\n * @param resolution - Optionally set resolution\n * @returns - this\n */\n BaseTexture.prototype.setRealSize = function (realWidth, realHeight, resolution) {\n this.resolution = resolution || this.resolution;\n this.width = Math.round(realWidth) / this.resolution;\n this.height = Math.round(realHeight) / this.resolution;\n this._refreshPOT();\n this.update();\n return this;\n };\n /**\n * Refresh check for isPowerOfTwo texture based on size\n * @private\n */\n BaseTexture.prototype._refreshPOT = function () {\n this.isPowerOfTwo = isPow2(this.realWidth) && isPow2(this.realHeight);\n };\n /**\n * Changes resolution\n * @param resolution - res\n * @returns - this\n */\n BaseTexture.prototype.setResolution = function (resolution) {\n var oldResolution = this.resolution;\n if (oldResolution === resolution) {\n return this;\n }\n this.resolution = resolution;\n if (this.valid) {\n this.width = Math.round(this.width * oldResolution) / resolution;\n this.height = Math.round(this.height * oldResolution) / resolution;\n this.emit('update', this);\n }\n this._refreshPOT();\n return this;\n };\n /**\n * Sets the resource if it wasn't set. Throws error if resource already present\n * @param resource - that is managing this BaseTexture\n * @returns - this\n */\n BaseTexture.prototype.setResource = function (resource) {\n if (this.resource === resource) {\n return this;\n }\n if (this.resource) {\n throw new Error('Resource can be set only once');\n }\n resource.bind(this);\n this.resource = resource;\n return this;\n };\n /** Invalidates the object. Texture becomes valid if width and height are greater than zero. */\n BaseTexture.prototype.update = function () {\n if (!this.valid) {\n if (this.width > 0 && this.height > 0) {\n this.valid = true;\n this.emit('loaded', this);\n this.emit('update', this);\n }\n }\n else {\n this.dirtyId++;\n this.dirtyStyleId++;\n this.emit('update', this);\n }\n };\n /**\n * Handle errors with resources.\n * @private\n * @param event - Error event emitted.\n */\n BaseTexture.prototype.onError = function (event) {\n this.emit('error', this, event);\n };\n /**\n * Destroys this base texture.\n * The method stops if resource doesn't want this texture to be destroyed.\n * Removes texture from all caches.\n */\n BaseTexture.prototype.destroy = function () {\n // remove and destroy the resource\n if (this.resource) {\n this.resource.unbind(this);\n // only destroy resourced created internally\n if (this.resource.internal) {\n this.resource.destroy();\n }\n this.resource = null;\n }\n if (this.cacheId) {\n delete BaseTextureCache[this.cacheId];\n delete TextureCache[this.cacheId];\n this.cacheId = null;\n }\n // finally let the WebGL renderer know..\n this.dispose();\n BaseTexture.removeFromCache(this);\n this.textureCacheIds = null;\n this.destroyed = true;\n };\n /**\n * Frees the texture from WebGL memory without destroying this texture object.\n * This means you can still use the texture later which will upload it to GPU\n * memory again.\n * @fires PIXI.BaseTexture#dispose\n */\n BaseTexture.prototype.dispose = function () {\n this.emit('dispose', this);\n };\n /** Utility function for BaseTexture|Texture cast. */\n BaseTexture.prototype.castToBaseTexture = function () {\n return this;\n };\n /**\n * Helper function that creates a base texture based on the source you provide.\n * The source can be - image url, image element, canvas element. If the\n * source is an image url or an image element and not in the base texture\n * cache, it will be created and loaded.\n * @static\n * @param {string|string[]|HTMLImageElement|HTMLCanvasElement|SVGElement|HTMLVideoElement} source - The\n * source to create base texture from.\n * @param options - See {@link PIXI.BaseTexture}'s constructor for options.\n * @param {string} [options.pixiIdPrefix=pixiid] - If a source has no id, this is the prefix of the generated id\n * @param {boolean} [strict] - Enforce strict-mode, see {@link PIXI.settings.STRICT_TEXTURE_CACHE}.\n * @returns {PIXI.BaseTexture} The new base texture.\n */\n BaseTexture.from = function (source, options, strict) {\n if (strict === void 0) { strict = settings.STRICT_TEXTURE_CACHE; }\n var isFrame = typeof source === 'string';\n var cacheId = null;\n if (isFrame) {\n cacheId = source;\n }\n else {\n if (!source._pixiId) {\n var prefix = (options && options.pixiIdPrefix) || 'pixiid';\n source._pixiId = prefix + \"_\" + uid();\n }\n cacheId = source._pixiId;\n }\n var baseTexture = BaseTextureCache[cacheId];\n // Strict-mode rejects invalid cacheIds\n if (isFrame && strict && !baseTexture) {\n throw new Error(\"The cacheId \\\"\" + cacheId + \"\\\" does not exist in BaseTextureCache.\");\n }\n if (!baseTexture) {\n baseTexture = new BaseTexture(source, options);\n baseTexture.cacheId = cacheId;\n BaseTexture.addToCache(baseTexture, cacheId);\n }\n return baseTexture;\n };\n /**\n * Create a new BaseTexture with a BufferResource from a Float32Array.\n * RGBA values are floats from 0 to 1.\n * @param {Float32Array|Uint8Array} buffer - The optional array to use, if no data\n * is provided, a new Float32Array is created.\n * @param width - Width of the resource\n * @param height - Height of the resource\n * @param options - See {@link PIXI.BaseTexture}'s constructor for options.\n * Default properties are different from the constructor's defaults.\n * @param {PIXI.FORMATS} [options.format=PIXI.FORMATS.RGBA] - GL format type\n * @param {PIXI.ALPHA_MODES} [options.alphaMode=PIXI.ALPHA_MODES.NPM] - Image alpha, not premultiplied by default\n * @param {PIXI.SCALE_MODES} [options.scaleMode=PIXI.SCALE_MODES.NEAREST] - Scale mode, pixelating by default\n * @returns - The resulting new BaseTexture\n */\n BaseTexture.fromBuffer = function (buffer, width, height, options) {\n buffer = buffer || new Float32Array(width * height * 4);\n var resource = new BufferResource(buffer, { width: width, height: height });\n var type = buffer instanceof Float32Array ? TYPES.FLOAT : TYPES.UNSIGNED_BYTE;\n return new BaseTexture(resource, Object.assign({}, defaultBufferOptions, options || { width: width, height: height, type: type }));\n };\n /**\n * Adds a BaseTexture to the global BaseTextureCache. This cache is shared across the whole PIXI object.\n * @param {PIXI.BaseTexture} baseTexture - The BaseTexture to add to the cache.\n * @param {string} id - The id that the BaseTexture will be stored against.\n */\n BaseTexture.addToCache = function (baseTexture, id) {\n if (id) {\n if (baseTexture.textureCacheIds.indexOf(id) === -1) {\n baseTexture.textureCacheIds.push(id);\n }\n if (BaseTextureCache[id]) {\n // eslint-disable-next-line no-console\n console.warn(\"BaseTexture added to the cache with an id [\" + id + \"] that already had an entry\");\n }\n BaseTextureCache[id] = baseTexture;\n }\n };\n /**\n * Remove a BaseTexture from the global BaseTextureCache.\n * @param {string|PIXI.BaseTexture} baseTexture - id of a BaseTexture to be removed, or a BaseTexture instance itself.\n * @returns {PIXI.BaseTexture|null} The BaseTexture that was removed.\n */\n BaseTexture.removeFromCache = function (baseTexture) {\n if (typeof baseTexture === 'string') {\n var baseTextureFromCache = BaseTextureCache[baseTexture];\n if (baseTextureFromCache) {\n var index = baseTextureFromCache.textureCacheIds.indexOf(baseTexture);\n if (index > -1) {\n baseTextureFromCache.textureCacheIds.splice(index, 1);\n }\n delete BaseTextureCache[baseTexture];\n return baseTextureFromCache;\n }\n }\n else if (baseTexture && baseTexture.textureCacheIds) {\n for (var i = 0; i < baseTexture.textureCacheIds.length; ++i) {\n delete BaseTextureCache[baseTexture.textureCacheIds[i]];\n }\n baseTexture.textureCacheIds.length = 0;\n return baseTexture;\n }\n return null;\n };\n /** Global number of the texture batch, used by multi-texture renderers. */\n BaseTexture._globalBatch = 0;\n return BaseTexture;\n}(EventEmitter));\n\n/**\n * Resource that can manage several resource (items) inside.\n * All resources need to have the same pixel size.\n * Parent class for CubeResource and ArrayResource\n * @memberof PIXI\n */\nvar AbstractMultiResource = /** @class */ (function (_super) {\n __extends(AbstractMultiResource, _super);\n /**\n * @param length\n * @param options - Options to for Resource constructor\n * @param {number} [options.width] - Width of the resource\n * @param {number} [options.height] - Height of the resource\n */\n function AbstractMultiResource(length, options) {\n var _this = this;\n var _a = options || {}, width = _a.width, height = _a.height;\n _this = _super.call(this, width, height) || this;\n _this.items = [];\n _this.itemDirtyIds = [];\n for (var i = 0; i < length; i++) {\n var partTexture = new BaseTexture();\n _this.items.push(partTexture);\n // -2 - first run of texture array upload\n // -1 - texture item was allocated\n // >=0 - texture item uploaded , in sync with items[i].dirtyId\n _this.itemDirtyIds.push(-2);\n }\n _this.length = length;\n _this._load = null;\n _this.baseTexture = null;\n return _this;\n }\n /**\n * Used from ArrayResource and CubeResource constructors.\n * @param resources - Can be resources, image elements, canvas, etc. ,\n * length should be same as constructor length\n * @param options - Detect options for resources\n */\n AbstractMultiResource.prototype.initFromArray = function (resources, options) {\n for (var i = 0; i < this.length; i++) {\n if (!resources[i]) {\n continue;\n }\n if (resources[i].castToBaseTexture) {\n this.addBaseTextureAt(resources[i].castToBaseTexture(), i);\n }\n else if (resources[i] instanceof Resource) {\n this.addResourceAt(resources[i], i);\n }\n else {\n this.addResourceAt(autoDetectResource(resources[i], options), i);\n }\n }\n };\n /** Destroy this BaseImageResource. */\n AbstractMultiResource.prototype.dispose = function () {\n for (var i = 0, len = this.length; i < len; i++) {\n this.items[i].destroy();\n }\n this.items = null;\n this.itemDirtyIds = null;\n this._load = null;\n };\n /**\n * Set a resource by ID\n * @param resource\n * @param index - Zero-based index of resource to set\n * @returns - Instance for chaining\n */\n AbstractMultiResource.prototype.addResourceAt = function (resource, index) {\n if (!this.items[index]) {\n throw new Error(\"Index \" + index + \" is out of bounds\");\n }\n // Inherit the first resource dimensions\n if (resource.valid && !this.valid) {\n this.resize(resource.width, resource.height);\n }\n this.items[index].setResource(resource);\n return this;\n };\n /**\n * Set the parent base texture.\n * @param baseTexture\n */\n AbstractMultiResource.prototype.bind = function (baseTexture) {\n if (this.baseTexture !== null) {\n throw new Error('Only one base texture per TextureArray is allowed');\n }\n _super.prototype.bind.call(this, baseTexture);\n for (var i = 0; i < this.length; i++) {\n this.items[i].parentTextureArray = baseTexture;\n this.items[i].on('update', baseTexture.update, baseTexture);\n }\n };\n /**\n * Unset the parent base texture.\n * @param baseTexture\n */\n AbstractMultiResource.prototype.unbind = function (baseTexture) {\n _super.prototype.unbind.call(this, baseTexture);\n for (var i = 0; i < this.length; i++) {\n this.items[i].parentTextureArray = null;\n this.items[i].off('update', baseTexture.update, baseTexture);\n }\n };\n /**\n * Load all the resources simultaneously\n * @returns - When load is resolved\n */\n AbstractMultiResource.prototype.load = function () {\n var _this = this;\n if (this._load) {\n return this._load;\n }\n var resources = this.items.map(function (item) { return item.resource; }).filter(function (item) { return item; });\n // TODO: also implement load part-by-part strategy\n var promises = resources.map(function (item) { return item.load(); });\n this._load = Promise.all(promises)\n .then(function () {\n var _a = _this.items[0], realWidth = _a.realWidth, realHeight = _a.realHeight;\n _this.resize(realWidth, realHeight);\n return Promise.resolve(_this);\n });\n return this._load;\n };\n return AbstractMultiResource;\n}(Resource));\n\n/**\n * A resource that contains a number of sources.\n * @memberof PIXI\n */\nvar ArrayResource = /** @class */ (function (_super) {\n __extends(ArrayResource, _super);\n /**\n * @param source - Number of items in array or the collection\n * of image URLs to use. Can also be resources, image elements, canvas, etc.\n * @param options - Options to apply to {@link PIXI.autoDetectResource}\n * @param {number} [options.width] - Width of the resource\n * @param {number} [options.height] - Height of the resource\n */\n function ArrayResource(source, options) {\n var _this = this;\n var _a = options || {}, width = _a.width, height = _a.height;\n var urls;\n var length;\n if (Array.isArray(source)) {\n urls = source;\n length = source.length;\n }\n else {\n length = source;\n }\n _this = _super.call(this, length, { width: width, height: height }) || this;\n if (urls) {\n _this.initFromArray(urls, options);\n }\n return _this;\n }\n /**\n * Set a baseTexture by ID,\n * ArrayResource just takes resource from it, nothing more\n * @param baseTexture\n * @param index - Zero-based index of resource to set\n * @returns - Instance for chaining\n */\n ArrayResource.prototype.addBaseTextureAt = function (baseTexture, index) {\n if (baseTexture.resource) {\n this.addResourceAt(baseTexture.resource, index);\n }\n else {\n throw new Error('ArrayResource does not support RenderTexture');\n }\n return this;\n };\n /**\n * Add binding\n * @param baseTexture\n */\n ArrayResource.prototype.bind = function (baseTexture) {\n _super.prototype.bind.call(this, baseTexture);\n baseTexture.target = TARGETS.TEXTURE_2D_ARRAY;\n };\n /**\n * Upload the resources to the GPU.\n * @param renderer\n * @param texture\n * @param glTexture\n * @returns - whether texture was uploaded\n */\n ArrayResource.prototype.upload = function (renderer, texture, glTexture) {\n var _a = this, length = _a.length, itemDirtyIds = _a.itemDirtyIds, items = _a.items;\n var gl = renderer.gl;\n if (glTexture.dirtyId < 0) {\n gl.texImage3D(gl.TEXTURE_2D_ARRAY, 0, glTexture.internalFormat, this._width, this._height, length, 0, texture.format, glTexture.type, null);\n }\n for (var i = 0; i < length; i++) {\n var item = items[i];\n if (itemDirtyIds[i] < item.dirtyId) {\n itemDirtyIds[i] = item.dirtyId;\n if (item.valid) {\n gl.texSubImage3D(gl.TEXTURE_2D_ARRAY, 0, 0, // xoffset\n 0, // yoffset\n i, // zoffset\n item.resource.width, item.resource.height, 1, texture.format, glTexture.type, item.resource.source);\n }\n }\n }\n return true;\n };\n return ArrayResource;\n}(AbstractMultiResource));\n\n/**\n * Base for all the image/canvas resources.\n * @memberof PIXI\n */\nvar BaseImageResource = /** @class */ (function (_super) {\n __extends(BaseImageResource, _super);\n /**\n * @param {HTMLImageElement|HTMLCanvasElement|HTMLVideoElement|SVGElement} source\n */\n function BaseImageResource(source) {\n var _this = this;\n var sourceAny = source;\n var width = sourceAny.naturalWidth || sourceAny.videoWidth || sourceAny.width;\n var height = sourceAny.naturalHeight || sourceAny.videoHeight || sourceAny.height;\n _this = _super.call(this, width, height) || this;\n _this.source = source;\n _this.noSubImage = false;\n return _this;\n }\n /**\n * Set cross origin based detecting the url and the crossorigin\n * @param element - Element to apply crossOrigin\n * @param url - URL to check\n * @param crossorigin - Cross origin value to use\n */\n BaseImageResource.crossOrigin = function (element, url, crossorigin) {\n if (crossorigin === undefined && url.indexOf('data:') !== 0) {\n element.crossOrigin = determineCrossOrigin(url);\n }\n else if (crossorigin !== false) {\n element.crossOrigin = typeof crossorigin === 'string' ? crossorigin : 'anonymous';\n }\n };\n /**\n * Upload the texture to the GPU.\n * @param renderer - Upload to the renderer\n * @param baseTexture - Reference to parent texture\n * @param glTexture\n * @param {HTMLImageElement|HTMLCanvasElement|HTMLVideoElement|SVGElement} [source] - (optional)\n * @returns - true is success\n */\n BaseImageResource.prototype.upload = function (renderer, baseTexture, glTexture, source) {\n var gl = renderer.gl;\n var width = baseTexture.realWidth;\n var height = baseTexture.realHeight;\n source = source || this.source;\n if (source instanceof HTMLImageElement) {\n if (!source.complete || source.naturalWidth === 0) {\n return false;\n }\n }\n else if (source instanceof HTMLVideoElement) {\n if (source.readyState <= 1) {\n return false;\n }\n }\n gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, baseTexture.alphaMode === ALPHA_MODES.UNPACK);\n if (!this.noSubImage\n && baseTexture.target === gl.TEXTURE_2D\n && glTexture.width === width\n && glTexture.height === height) {\n gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, baseTexture.format, glTexture.type, source);\n }\n else {\n glTexture.width = width;\n glTexture.height = height;\n gl.texImage2D(baseTexture.target, 0, glTexture.internalFormat, baseTexture.format, glTexture.type, source);\n }\n return true;\n };\n /**\n * Checks if source width/height was changed, resize can cause extra baseTexture update.\n * Triggers one update in any case.\n */\n BaseImageResource.prototype.update = function () {\n if (this.destroyed) {\n return;\n }\n var source = this.source;\n var width = source.naturalWidth || source.videoWidth || source.width;\n var height = source.naturalHeight || source.videoHeight || source.height;\n this.resize(width, height);\n _super.prototype.update.call(this);\n };\n /** Destroy this {@link BaseImageResource} */\n BaseImageResource.prototype.dispose = function () {\n this.source = null;\n };\n return BaseImageResource;\n}(Resource));\n\n/**\n * @interface OffscreenCanvas\n */\n/**\n * Resource type for HTMLCanvasElement.\n * @memberof PIXI\n */\nvar CanvasResource = /** @class */ (function (_super) {\n __extends(CanvasResource, _super);\n /**\n * @param source - Canvas element to use\n */\n // eslint-disable-next-line @typescript-eslint/no-useless-constructor\n function CanvasResource(source) {\n return _super.call(this, source) || this;\n }\n /**\n * Used to auto-detect the type of resource.\n * @param {*} source - The source object\n * @returns {boolean} `true` if source is HTMLCanvasElement or OffscreenCanvas\n */\n CanvasResource.test = function (source) {\n var OffscreenCanvas = globalThis.OffscreenCanvas;\n // Check for browsers that don't yet support OffscreenCanvas\n if (OffscreenCanvas && source instanceof OffscreenCanvas) {\n return true;\n }\n return globalThis.HTMLCanvasElement && source instanceof HTMLCanvasElement;\n };\n return CanvasResource;\n}(BaseImageResource));\n\n/**\n * Resource for a CubeTexture which contains six resources.\n * @memberof PIXI\n */\nvar CubeResource = /** @class */ (function (_super) {\n __extends(CubeResource, _super);\n /**\n * @param {Array<string|PIXI.Resource>} [source] - Collection of URLs or resources\n * to use as the sides of the cube.\n * @param options - ImageResource options\n * @param {number} [options.width] - Width of resource\n * @param {number} [options.height] - Height of resource\n * @param {number} [options.autoLoad=true] - Whether to auto-load resources\n * @param {number} [options.linkBaseTexture=true] - In case BaseTextures are supplied,\n * whether to copy them or use\n */\n function CubeResource(source, options) {\n var _this = this;\n var _a = options || {}, width = _a.width, height = _a.height, autoLoad = _a.autoLoad, linkBaseTexture = _a.linkBaseTexture;\n if (source && source.length !== CubeResource.SIDES) {\n throw new Error(\"Invalid length. Got \" + source.length + \", expected 6\");\n }\n _this = _super.call(this, 6, { width: width, height: height }) || this;\n for (var i = 0; i < CubeResource.SIDES; i++) {\n _this.items[i].target = TARGETS.TEXTURE_CUBE_MAP_POSITIVE_X + i;\n }\n _this.linkBaseTexture = linkBaseTexture !== false;\n if (source) {\n _this.initFromArray(source, options);\n }\n if (autoLoad !== false) {\n _this.load();\n }\n return _this;\n }\n /**\n * Add binding.\n * @param baseTexture - parent base texture\n */\n CubeResource.prototype.bind = function (baseTexture) {\n _super.prototype.bind.call(this, baseTexture);\n baseTexture.target = TARGETS.TEXTURE_CUBE_MAP;\n };\n CubeResource.prototype.addBaseTextureAt = function (baseTexture, index, linkBaseTexture) {\n if (!this.items[index]) {\n throw new Error(\"Index \" + index + \" is out of bounds\");\n }\n if (!this.linkBaseTexture\n || baseTexture.parentTextureArray\n || Object.keys(baseTexture._glTextures).length > 0) {\n // copy mode\n if (baseTexture.resource) {\n this.addResourceAt(baseTexture.resource, index);\n }\n else {\n throw new Error(\"CubeResource does not support copying of renderTexture.\");\n }\n }\n else {\n // link mode, the difficult one!\n baseTexture.target = TARGETS.TEXTURE_CUBE_MAP_POSITIVE_X + index;\n baseTexture.parentTextureArray = this.baseTexture;\n this.items[index] = baseTexture;\n }\n if (baseTexture.valid && !this.valid) {\n this.resize(baseTexture.realWidth, baseTexture.realHeight);\n }\n this.items[index] = baseTexture;\n return this;\n };\n /**\n * Upload the resource\n * @param renderer\n * @param _baseTexture\n * @param glTexture\n * @returns {boolean} true is success\n */\n CubeResource.prototype.upload = function (renderer, _baseTexture, glTexture) {\n var dirty = this.itemDirtyIds;\n for (var i = 0; i < CubeResource.SIDES; i++) {\n var side = this.items[i];\n if (dirty[i] < side.dirtyId || glTexture.dirtyId < _baseTexture.dirtyId) {\n if (side.valid && side.resource) {\n side.resource.upload(renderer, side, glTexture);\n dirty[i] = side.dirtyId;\n }\n else if (dirty[i] < -1) {\n // either item is not valid yet, either its a renderTexture\n // allocate the memory\n renderer.gl.texImage2D(side.target, 0, glTexture.internalFormat, _baseTexture.realWidth, _baseTexture.realHeight, 0, _baseTexture.format, glTexture.type, null);\n dirty[i] = -1;\n }\n }\n }\n return true;\n };\n /**\n * Used to auto-detect the type of resource.\n * @param {*} source - The source object\n * @returns {boolean} `true` if source is an array of 6 elements\n */\n CubeResource.test = function (source) {\n return Array.isArray(source) && source.length === CubeResource.SIDES;\n };\n /** Number of texture sides to store for CubeResources. */\n CubeResource.SIDES = 6;\n return CubeResource;\n}(AbstractMultiResource));\n\n/**\n * Resource type for HTMLImageElement.\n * @memberof PIXI\n */\nvar ImageResource = /** @class */ (function (_super) {\n __extends(ImageResource, _super);\n /**\n * @param source - image source or URL\n * @param options\n * @param {boolean} [options.autoLoad=true] - start loading process\n * @param {boolean} [options.createBitmap=PIXI.settings.CREATE_IMAGE_BITMAP] - whether its required to create\n * a bitmap before upload\n * @param {boolean} [options.crossorigin=true] - Load image using cross origin\n * @param {PIXI.ALPHA_MODES} [options.alphaMode=PIXI.ALPHA_MODES.UNPACK] - Premultiply image alpha in bitmap\n */\n function ImageResource(source, options) {\n var _this = this;\n options = options || {};\n if (!(source instanceof HTMLImageElement)) {\n var imageElement = new Image();\n BaseImageResource.crossOrigin(imageElement, source, options.crossorigin);\n imageElement.src = source;\n source = imageElement;\n }\n _this = _super.call(this, source) || this;\n // FireFox 68, and possibly other versions, seems like setting the HTMLImageElement#width and #height\n // to non-zero values before its loading completes if images are in a cache.\n // Because of this, need to set the `_width` and the `_height` to zero to avoid uploading incomplete images.\n // Please refer to the issue #5968 (https://github.com/pixijs/pixi.js/issues/5968).\n if (!source.complete && !!_this._width && !!_this._height) {\n _this._width = 0;\n _this._height = 0;\n }\n _this.url = source.src;\n _this._process = null;\n _this.preserveBitmap = false;\n _this.createBitmap = (options.createBitmap !== undefined\n ? options.createBitmap : settings.CREATE_IMAGE_BITMAP) && !!globalThis.createImageBitmap;\n _this.alphaMode = typeof options.alphaMode === 'number' ? options.alphaMode : null;\n _this.bitmap = null;\n _this._load = null;\n if (options.autoLoad !== false) {\n _this.load();\n }\n return _this;\n }\n /**\n * Returns a promise when image will be loaded and processed.\n * @param createBitmap - whether process image into bitmap\n */\n ImageResource.prototype.load = function (createBitmap) {\n var _this = this;\n if (this._load) {\n return this._load;\n }\n if (createBitmap !== undefined) {\n this.createBitmap = createBitmap;\n }\n this._load = new Promise(function (resolve, reject) {\n var source = _this.source;\n _this.url = source.src;\n var completed = function () {\n if (_this.destroyed) {\n return;\n }\n source.onload = null;\n source.onerror = null;\n _this.resize(source.width, source.height);\n _this._load = null;\n if (_this.createBitmap) {\n resolve(_this.process());\n }\n else {\n resolve(_this);\n }\n };\n if (source.complete && source.src) {\n completed();\n }\n else {\n source.onload = completed;\n source.onerror = function (event) {\n // Avoids Promise freezing when resource broken\n reject(event);\n _this.onError.emit(event);\n };\n }\n });\n return this._load;\n };\n /**\n * Called when we need to convert image into BitmapImage.\n * Can be called multiple times, real promise is cached inside.\n * @returns - Cached promise to fill that bitmap\n */\n ImageResource.prototype.process = function () {\n var _this = this;\n var source = this.source;\n if (this._process !== null) {\n return this._process;\n }\n if (this.bitmap !== null || !globalThis.createImageBitmap) {\n return Promise.resolve(this);\n }\n var createImageBitmap = globalThis.createImageBitmap;\n var cors = !source.crossOrigin || source.crossOrigin === 'anonymous';\n this._process = fetch(source.src, {\n mode: cors ? 'cors' : 'no-cors'\n })\n .then(function (r) { return r.blob(); })\n .then(function (blob) { return createImageBitmap(blob, 0, 0, source.width, source.height, {\n premultiplyAlpha: _this.alphaMode === null || _this.alphaMode === ALPHA_MODES.UNPACK\n ? 'premultiply' : 'none',\n }); })\n .then(function (bitmap) {\n if (_this.destroyed) {\n return Promise.reject();\n }\n _this.bitmap = bitmap;\n _this.update();\n _this._process = null;\n return Promise.resolve(_this);\n });\n return this._process;\n };\n /**\n * Upload the image resource to GPU.\n * @param renderer - Renderer to upload to\n * @param baseTexture - BaseTexture for this resource\n * @param glTexture - GLTexture to use\n * @returns {boolean} true is success\n */\n ImageResource.prototype.upload = function (renderer, baseTexture, glTexture) {\n if (typeof this.alphaMode === 'number') {\n // bitmap stores unpack premultiply flag, we dont have to notify texImage2D about it\n baseTexture.alphaMode = this.alphaMode;\n }\n if (!this.createBitmap) {\n return _super.prototype.upload.call(this, renderer, baseTexture, glTexture);\n }\n if (!this.bitmap) {\n // yeah, ignore the output\n this.process();\n if (!this.bitmap) {\n return false;\n }\n }\n _super.prototype.upload.call(this, renderer, baseTexture, glTexture, this.bitmap);\n if (!this.preserveBitmap) {\n // checks if there are other renderers that possibly need this bitmap\n var flag = true;\n var glTextures = baseTexture._glTextures;\n for (var key in glTextures) {\n var otherTex = glTextures[key];\n if (otherTex !== glTexture && otherTex.dirtyId !== baseTexture.dirtyId) {\n flag = false;\n break;\n }\n }\n if (flag) {\n if (this.bitmap.close) {\n this.bitmap.close();\n }\n this.bitmap = null;\n }\n }\n return true;\n };\n /** Destroys this resource. */\n ImageResource.prototype.dispose = function () {\n this.source.onload = null;\n this.source.onerror = null;\n _super.prototype.dispose.call(this);\n if (this.bitmap) {\n this.bitmap.close();\n this.bitmap = null;\n }\n this._process = null;\n this._load = null;\n };\n /**\n * Used to auto-detect the type of resource.\n * @param {*} source - The source object\n * @returns {boolean} `true` if source is string or HTMLImageElement\n */\n ImageResource.test = function (source) {\n return typeof source === 'string' || source instanceof HTMLImageElement;\n };\n return ImageResource;\n}(BaseImageResource));\n\n/**\n * Resource type for SVG elements and graphics.\n * @memberof PIXI\n */\nvar SVGResource = /** @class */ (function (_super) {\n __extends(SVGResource, _super);\n /**\n * @param sourceBase64 - Base64 encoded SVG element or URL for SVG file.\n * @param {object} [options] - Options to use\n * @param {number} [options.scale=1] - Scale to apply to SVG. Overridden by...\n * @param {number} [options.width] - Rasterize SVG this wide. Aspect ratio preserved if height not specified.\n * @param {number} [options.height] - Rasterize SVG this high. Aspect ratio preserved if width not specified.\n * @param {boolean} [options.autoLoad=true] - Start loading right away.\n */\n function SVGResource(sourceBase64, options) {\n var _this = this;\n options = options || {};\n _this = _super.call(this, settings.ADAPTER.createCanvas()) || this;\n _this._width = 0;\n _this._height = 0;\n _this.svg = sourceBase64;\n _this.scale = options.scale || 1;\n _this._overrideWidth = options.width;\n _this._overrideHeight = options.height;\n _this._resolve = null;\n _this._crossorigin = options.crossorigin;\n _this._load = null;\n if (options.autoLoad !== false) {\n _this.load();\n }\n return _this;\n }\n SVGResource.prototype.load = function () {\n var _this = this;\n if (this._load) {\n return this._load;\n }\n this._load = new Promise(function (resolve) {\n // Save this until after load is finished\n _this._resolve = function () {\n _this.resize(_this.source.width, _this.source.height);\n resolve(_this);\n };\n // Convert SVG inline string to data-uri\n if (SVGResource.SVG_XML.test(_this.svg.trim())) {\n if (!btoa) {\n throw new Error('Your browser doesn\\'t support base64 conversions.');\n }\n _this.svg = \"data:image/svg+xml;base64,\" + btoa(unescape(encodeURIComponent(_this.svg)));\n }\n _this._loadSvg();\n });\n return this._load;\n };\n /** Loads an SVG image from `imageUrl` or `data URL`. */\n SVGResource.prototype._loadSvg = function () {\n var _this = this;\n var tempImage = new Image();\n BaseImageResource.crossOrigin(tempImage, this.svg, this._crossorigin);\n tempImage.src = this.svg;\n tempImage.onerror = function (event) {\n if (!_this._resolve) {\n return;\n }\n tempImage.onerror = null;\n _this.onError.emit(event);\n };\n tempImage.onload = function () {\n if (!_this._resolve) {\n return;\n }\n var svgWidth = tempImage.width;\n var svgHeight = tempImage.height;\n if (!svgWidth || !svgHeight) {\n throw new Error('The SVG image must have width and height defined (in pixels), canvas API needs them.');\n }\n // Set render size\n var width = svgWidth * _this.scale;\n var height = svgHeight * _this.scale;\n if (_this._overrideWidth || _this._overrideHeight) {\n width = _this._overrideWidth || _this._overrideHeight / svgHeight * svgWidth;\n height = _this._overrideHeight || _this._overrideWidth / svgWidth * svgHeight;\n }\n width = Math.round(width);\n height = Math.round(height);\n // Create a canvas element\n var canvas = _this.source;\n canvas.width = width;\n canvas.height = height;\n canvas._pixiId = \"canvas_\" + uid();\n // Draw the Svg to the canvas\n canvas\n .getContext('2d')\n .drawImage(tempImage, 0, 0, svgWidth, svgHeight, 0, 0, width, height);\n _this._resolve();\n _this._resolve = null;\n };\n };\n /**\n * Get size from an svg string using a regular expression.\n * @param svgString - a serialized svg element\n * @returns - image extension\n */\n SVGResource.getSize = function (svgString) {\n var sizeMatch = SVGResource.SVG_SIZE.exec(svgString);\n var size = {};\n if (sizeMatch) {\n size[sizeMatch[1]] = Math.round(parseFloat(sizeMatch[3]));\n size[sizeMatch[5]] = Math.round(parseFloat(sizeMatch[7]));\n }\n return size;\n };\n /** Destroys this texture. */\n SVGResource.prototype.dispose = function () {\n _super.prototype.dispose.call(this);\n this._resolve = null;\n this._crossorigin = null;\n };\n /**\n * Used to auto-detect the type of resource.\n * @param {*} source - The source object\n * @param {string} extension - The extension of source, if set\n * @returns {boolean} - If the source is a SVG source or data file\n */\n SVGResource.test = function (source, extension) {\n // url file extension is SVG\n return extension === 'svg'\n // source is SVG data-uri\n || (typeof source === 'string' && source.startsWith('data:image/svg+xml'))\n // source is SVG inline\n || (typeof source === 'string' && SVGResource.SVG_XML.test(source));\n };\n /**\n * Regular expression for SVG XML document.\n * @example <?xml version=\"1.0\" encoding=\"utf-8\" ?><!-- image/svg --><svg\n * @readonly\n */\n SVGResource.SVG_XML = /^(<\\?xml[^?]+\\?>)?\\s*(<!--[^(-->)]*-->)?\\s*\\<svg/m;\n /**\n * Regular expression for SVG size.\n * @example <svg width=\"100\" height=\"100\"></svg>\n * @readonly\n */\n SVGResource.SVG_SIZE = /<svg[^>]*(?:\\s(width|height)=('|\")(\\d*(?:\\.\\d+)?)(?:px)?('|\"))[^>]*(?:\\s(width|height)=('|\")(\\d*(?:\\.\\d+)?)(?:px)?('|\"))[^>]*>/i; // eslint-disable-line max-len\n return SVGResource;\n}(BaseImageResource));\n\n/**\n * Resource type for {@code HTMLVideoElement}.\n * @memberof PIXI\n */\nvar VideoResource = /** @class */ (function (_super) {\n __extends(VideoResource, _super);\n /**\n * @param {HTMLVideoElement|object|string|Array<string|object>} source - Video element to use.\n * @param {object} [options] - Options to use\n * @param {boolean} [options.autoLoad=true] - Start loading the video immediately\n * @param {boolean} [options.autoPlay=true] - Start playing video immediately\n * @param {number} [options.updateFPS=0] - How many times a second to update the texture from the video.\n * Leave at 0 to update at every render.\n * @param {boolean} [options.crossorigin=true] - Load image using cross origin\n */\n function VideoResource(source, options) {\n var _this = this;\n options = options || {};\n if (!(source instanceof HTMLVideoElement)) {\n var videoElement = document.createElement('video');\n // workaround for https://github.com/pixijs/pixi.js/issues/5996\n videoElement.setAttribute('preload', 'auto');\n videoElement.setAttribute('webkit-playsinline', '');\n videoElement.setAttribute('playsinline', '');\n if (typeof source === 'string') {\n source = [source];\n }\n var firstSrc = source[0].src || source[0];\n BaseImageResource.crossOrigin(videoElement, firstSrc, options.crossorigin);\n // array of objects or strings\n for (var i = 0; i < source.length; ++i) {\n var sourceElement = document.createElement('source');\n var _a = source[i], src = _a.src, mime = _a.mime;\n src = src || source[i];\n var baseSrc = src.split('?').shift().toLowerCase();\n var ext = baseSrc.slice(baseSrc.lastIndexOf('.') + 1);\n mime = mime || VideoResource.MIME_TYPES[ext] || \"video/\" + ext;\n sourceElement.src = src;\n sourceElement.type = mime;\n videoElement.appendChild(sourceElement);\n }\n // Override the source\n source = videoElement;\n }\n _this = _super.call(this, source) || this;\n _this.noSubImage = true;\n _this._autoUpdate = true;\n _this._isConnectedToTicker = false;\n _this._updateFPS = options.updateFPS || 0;\n _this._msToNextUpdate = 0;\n _this.autoPlay = options.autoPlay !== false;\n _this._load = null;\n _this._resolve = null;\n // Bind for listeners\n _this._onCanPlay = _this._onCanPlay.bind(_this);\n _this._onError = _this._onError.bind(_this);\n if (options.autoLoad !== false) {\n _this.load();\n }\n return _this;\n }\n /**\n * Trigger updating of the texture.\n * @param _deltaTime - time delta since last tick\n */\n VideoResource.prototype.update = function (_deltaTime) {\n if (!this.destroyed) {\n // account for if video has had its playbackRate changed\n var elapsedMS = Ticker.shared.elapsedMS * this.source.playbackRate;\n this._msToNextUpdate = Math.floor(this._msToNextUpdate - elapsedMS);\n if (!this._updateFPS || this._msToNextUpdate <= 0) {\n _super.prototype.update.call(this);\n this._msToNextUpdate = this._updateFPS ? Math.floor(1000 / this._updateFPS) : 0;\n }\n }\n };\n /**\n * Start preloading the video resource.\n * @returns {Promise<void>} Handle the validate event\n */\n VideoResource.prototype.load = function () {\n var _this = this;\n if (this._load) {\n return this._load;\n }\n var source = this.source;\n if ((source.readyState === source.HAVE_ENOUGH_DATA || source.readyState === source.HAVE_FUTURE_DATA)\n && source.width && source.height) {\n source.complete = true;\n }\n source.addEventListener('play', this._onPlayStart.bind(this));\n source.addEventListener('pause', this._onPlayStop.bind(this));\n if (!this._isSourceReady()) {\n source.addEventListener('canplay', this._onCanPlay);\n source.addEventListener('canplaythrough', this._onCanPlay);\n source.addEventListener('error', this._onError, true);\n }\n else {\n this._onCanPlay();\n }\n this._load = new Promise(function (resolve) {\n if (_this.valid) {\n resolve(_this);\n }\n else {\n _this._resolve = resolve;\n source.load();\n }\n });\n return this._load;\n };\n /**\n * Handle video error events.\n * @param event\n */\n VideoResource.prototype._onError = function (event) {\n this.source.removeEventListener('error', this._onError, true);\n this.onError.emit(event);\n };\n /**\n * Returns true if the underlying source is playing.\n * @returns - True if playing.\n */\n VideoResource.prototype._isSourcePlaying = function () {\n var source = this.source;\n return (!source.paused && !source.ended && this._isSourceReady());\n };\n /**\n * Returns true if the underlying source is ready for playing.\n * @returns - True if ready.\n */\n VideoResource.prototype._isSourceReady = function () {\n var source = this.source;\n return source.readyState > 2;\n };\n /** Runs the update loop when the video is ready to play. */\n VideoResource.prototype._onPlayStart = function () {\n // Just in case the video has not received its can play even yet..\n if (!this.valid) {\n this._onCanPlay();\n }\n if (this.autoUpdate && !this._isConnectedToTicker) {\n Ticker.shared.add(this.update, this);\n this._isConnectedToTicker = true;\n }\n };\n /** Fired when a pause event is triggered, stops the update loop. */\n VideoResource.prototype._onPlayStop = function () {\n if (this._isConnectedToTicker) {\n Ticker.shared.remove(this.update, this);\n this._isConnectedToTicker = false;\n }\n };\n /** Fired when the video is loaded and ready to play. */\n VideoResource.prototype._onCanPlay = function () {\n var source = this.source;\n source.removeEventListener('canplay', this._onCanPlay);\n source.removeEventListener('canplaythrough', this._onCanPlay);\n var valid = this.valid;\n this.resize(source.videoWidth, source.videoHeight);\n // prevent multiple loaded dispatches..\n if (!valid && this._resolve) {\n this._resolve(this);\n this._resolve = null;\n }\n if (this._isSourcePlaying()) {\n this._onPlayStart();\n }\n else if (this.autoPlay) {\n source.play();\n }\n };\n /** Destroys this texture. */\n VideoResource.prototype.dispose = function () {\n if (this._isConnectedToTicker) {\n Ticker.shared.remove(this.update, this);\n this._isConnectedToTicker = false;\n }\n var source = this.source;\n if (source) {\n source.removeEventListener('error', this._onError, true);\n source.pause();\n source.src = '';\n source.load();\n }\n _super.prototype.dispose.call(this);\n };\n Object.defineProperty(VideoResource.prototype, \"autoUpdate\", {\n /** Should the base texture automatically update itself, set to true by default. */\n get: function () {\n return this._autoUpdate;\n },\n set: function (value) {\n if (value !== this._autoUpdate) {\n this._autoUpdate = value;\n if (!this._autoUpdate && this._isConnectedToTicker) {\n Ticker.shared.remove(this.update, this);\n this._isConnectedToTicker = false;\n }\n else if (this._autoUpdate && !this._isConnectedToTicker && this._isSourcePlaying()) {\n Ticker.shared.add(this.update, this);\n this._isConnectedToTicker = true;\n }\n }\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(VideoResource.prototype, \"updateFPS\", {\n /**\n * How many times a second to update the texture from the video. Leave at 0 to update at every render.\n * A lower fps can help performance, as updating the texture at 60fps on a 30ps video may not be efficient.\n */\n get: function () {\n return this._updateFPS;\n },\n set: function (value) {\n if (value !== this._updateFPS) {\n this._updateFPS = value;\n }\n },\n enumerable: false,\n configurable: true\n });\n /**\n * Used to auto-detect the type of resource.\n * @param {*} source - The source object\n * @param {string} extension - The extension of source, if set\n * @returns {boolean} `true` if video source\n */\n VideoResource.test = function (source, extension) {\n return (globalThis.HTMLVideoElement && source instanceof HTMLVideoElement)\n || VideoResource.TYPES.indexOf(extension) > -1;\n };\n /**\n * List of common video file extensions supported by VideoResource.\n * @readonly\n */\n VideoResource.TYPES = ['mp4', 'm4v', 'webm', 'ogg', 'ogv', 'h264', 'avi', 'mov'];\n /**\n * Map of video MIME types that can't be directly derived from file extensions.\n * @readonly\n */\n VideoResource.MIME_TYPES = {\n ogv: 'video/ogg',\n mov: 'video/quicktime',\n m4v: 'video/mp4',\n };\n return VideoResource;\n}(BaseImageResource));\n\n/**\n * Resource type for ImageBitmap.\n * @memberof PIXI\n */\nvar ImageBitmapResource = /** @class */ (function (_super) {\n __extends(ImageBitmapResource, _super);\n /**\n * @param source - Image element to use\n */\n // eslint-disable-next-line @typescript-eslint/no-useless-constructor\n function ImageBitmapResource(source) {\n return _super.call(this, source) || this;\n }\n /**\n * Used to auto-detect the type of resource.\n * @param {*} source - The source object\n * @returns {boolean} `true` if source is an ImageBitmap\n */\n ImageBitmapResource.test = function (source) {\n return !!globalThis.createImageBitmap && typeof ImageBitmap !== 'undefined' && source instanceof ImageBitmap;\n };\n return ImageBitmapResource;\n}(BaseImageResource));\n\nINSTALLED.push(ImageResource, ImageBitmapResource, CanvasResource, VideoResource, SVGResource, BufferResource, CubeResource, ArrayResource);\n\nvar _resources = {\n __proto__: null,\n Resource: Resource,\n BaseImageResource: BaseImageResource,\n INSTALLED: INSTALLED,\n autoDetectResource: autoDetectResource,\n AbstractMultiResource: AbstractMultiResource,\n ArrayResource: ArrayResource,\n BufferResource: BufferResource,\n CanvasResource: CanvasResource,\n CubeResource: CubeResource,\n ImageResource: ImageResource,\n SVGResource: SVGResource,\n VideoResource: VideoResource,\n ImageBitmapResource: ImageBitmapResource\n};\n\n/**\n * Resource type for DepthTexture.\n * @memberof PIXI\n */\nvar DepthResource = /** @class */ (function (_super) {\n __extends(DepthResource, _super);\n function DepthResource() {\n return _super !== null && _super.apply(this, arguments) || this;\n }\n /**\n * Upload the texture to the GPU.\n * @param renderer - Upload to the renderer\n * @param baseTexture - Reference to parent texture\n * @param glTexture - glTexture\n * @returns - true is success\n */\n DepthResource.prototype.upload = function (renderer, baseTexture, glTexture) {\n var gl = renderer.gl;\n gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, baseTexture.alphaMode === ALPHA_MODES.UNPACK);\n var width = baseTexture.realWidth;\n var height = baseTexture.realHeight;\n if (glTexture.width === width && glTexture.height === height) {\n gl.texSubImage2D(baseTexture.target, 0, 0, 0, width, height, baseTexture.format, glTexture.type, this.data);\n }\n else {\n glTexture.width = width;\n glTexture.height = height;\n gl.texImage2D(baseTexture.target, 0, glTexture.internalFormat, width, height, 0, baseTexture.format, glTexture.type, this.data);\n }\n return true;\n };\n return DepthResource;\n}(BufferResource));\n\n/**\n * A framebuffer can be used to render contents off of the screen. {@link PIXI.BaseRenderTexture} uses\n * one internally to render into itself. You can attach a depth or stencil buffer to a framebuffer.\n *\n * On WebGL 2 machines, shaders can output to multiple textures simultaneously with GLSL 300 ES.\n * @memberof PIXI\n */\nvar Framebuffer = /** @class */ (function () {\n /**\n * @param width - Width of the frame buffer\n * @param height - Height of the frame buffer\n */\n function Framebuffer(width, height) {\n this.width = Math.round(width || 100);\n this.height = Math.round(height || 100);\n this.stencil = false;\n this.depth = false;\n this.dirtyId = 0;\n this.dirtyFormat = 0;\n this.dirtySize = 0;\n this.depthTexture = null;\n this.colorTextures = [];\n this.glFramebuffers = {};\n this.disposeRunner = new Runner('disposeFramebuffer');\n this.multisample = MSAA_QUALITY.NONE;\n }\n Object.defineProperty(Framebuffer.prototype, \"colorTexture\", {\n /**\n * Reference to the colorTexture.\n * @readonly\n */\n get: function () {\n return this.colorTextures[0];\n },\n enumerable: false,\n configurable: true\n });\n /**\n * Add texture to the colorTexture array.\n * @param index - Index of the array to add the texture to\n * @param texture - Texture to add to the array\n */\n Framebuffer.prototype.addColorTexture = function (index, texture) {\n if (index === void 0) { index = 0; }\n // TODO add some validation to the texture - same width / height etc?\n this.colorTextures[index] = texture || new BaseTexture(null, {\n scaleMode: SCALE_MODES.NEAREST,\n resolution: 1,\n mipmap: MIPMAP_MODES.OFF,\n width: this.width,\n height: this.height,\n });\n this.dirtyId++;\n this.dirtyFormat++;\n return this;\n };\n /**\n * Add a depth texture to the frame buffer.\n * @param texture - Texture to add.\n */\n Framebuffer.prototype.addDepthTexture = function (texture) {\n /* eslint-disable max-len */\n this.depthTexture = texture || new BaseTexture(new DepthResource(null, { width: this.width, height: this.height }), {\n scaleMode: SCALE_MODES.NEAREST,\n resolution: 1,\n width: this.width,\n height: this.height,\n mipmap: MIPMAP_MODES.OFF,\n format: FORMATS.DEPTH_COMPONENT,\n type: TYPES.UNSIGNED_SHORT,\n });\n this.dirtyId++;\n this.dirtyFormat++;\n return this;\n };\n /** Enable depth on the frame buffer. */\n Framebuffer.prototype.enableDepth = function () {\n this.depth = true;\n this.dirtyId++;\n this.dirtyFormat++;\n return this;\n };\n /** Enable stencil on the frame buffer. */\n Framebuffer.prototype.enableStencil = function () {\n this.stencil = true;\n this.dirtyId++;\n this.dirtyFormat++;\n return this;\n };\n /**\n * Resize the frame buffer\n * @param width - Width of the frame buffer to resize to\n * @param height - Height of the frame buffer to resize to\n */\n Framebuffer.prototype.resize = function (width, height) {\n width = Math.round(width);\n height = Math.round(height);\n if (width === this.width && height === this.height)\n { return; }\n this.width = width;\n this.height = height;\n this.dirtyId++;\n this.dirtySize++;\n for (var i = 0; i < this.colorTextures.length; i++) {\n var texture = this.colorTextures[i];\n var resolution = texture.resolution;\n // take into account the fact the texture may have a different resolution..\n texture.setSize(width / resolution, height / resolution);\n }\n if (this.depthTexture) {\n var resolution = this.depthTexture.resolution;\n this.depthTexture.setSize(width / resolution, height / resolution);\n }\n };\n /** Disposes WebGL resources that are connected to this geometry. */\n Framebuffer.prototype.dispose = function () {\n this.disposeRunner.emit(this, false);\n };\n /** Destroys and removes the depth texture added to this framebuffer. */\n Framebuffer.prototype.destroyDepthTexture = function () {\n if (this.depthTexture) {\n this.depthTexture.destroy();\n this.depthTexture = null;\n ++this.dirtyId;\n ++this.dirtyFormat;\n }\n };\n return Framebuffer;\n}());\n\n/**\n * A BaseRenderTexture is a special texture that allows any PixiJS display object to be rendered to it.\n *\n * __Hint__: All DisplayObjects (i.e. Sprites) that render to a BaseRenderTexture should be preloaded\n * otherwise black rectangles will be drawn instead.\n *\n * A BaseRenderTexture takes a snapshot of any Display Object given to its render method. The position\n * and rotation of the given Display Objects is ignored. For example:\n *\n * ```js\n * let renderer = PIXI.autoDetectRenderer();\n * let baseRenderTexture = new PIXI.BaseRenderTexture({ width: 800, height: 600 });\n * let renderTexture = new PIXI.RenderTexture(baseRenderTexture);\n * let sprite = PIXI.Sprite.from(\"spinObj_01.png\");\n *\n * sprite.position.x = 800/2;\n * sprite.position.y = 600/2;\n * sprite.anchor.x = 0.5;\n * sprite.anchor.y = 0.5;\n *\n * renderer.render(sprite, {renderTexture});\n * ```\n *\n * The Sprite in this case will be rendered using its local transform. To render this sprite at 0,0\n * you can clear the transform\n *\n * ```js\n *\n * sprite.setTransform()\n *\n * let baseRenderTexture = new PIXI.BaseRenderTexture({ width: 100, height: 100 });\n * let renderTexture = new PIXI.RenderTexture(baseRenderTexture);\n *\n * renderer.render(sprite, {renderTexture}); // Renders to center of RenderTexture\n * ```\n * @memberof PIXI\n */\nvar BaseRenderTexture = /** @class */ (function (_super) {\n __extends(BaseRenderTexture, _super);\n /**\n * @param options\n * @param {number} [options.width=100] - The width of the base render texture.\n * @param {number} [options.height=100] - The height of the base render texture.\n * @param {PIXI.SCALE_MODES} [options.scaleMode=PIXI.settings.SCALE_MODE] - See {@link PIXI.SCALE_MODES}\n * for possible values.\n * @param {number} [options.resolution=PIXI.settings.RESOLUTION] - The resolution / device pixel ratio\n * of the texture being generated.\n * @param {PIXI.MSAA_QUALITY} [options.multisample=PIXI.MSAA_QUALITY.NONE] - The number of samples of the frame buffer.\n */\n function BaseRenderTexture(options) {\n if (options === void 0) { options = {}; }\n var _this = this;\n if (typeof options === 'number') {\n /* eslint-disable prefer-rest-params */\n // Backward compatibility of signature\n var width = arguments[0];\n var height = arguments[1];\n var scaleMode = arguments[2];\n var resolution = arguments[3];\n options = { width: width, height: height, scaleMode: scaleMode, resolution: resolution };\n /* eslint-enable prefer-rest-params */\n }\n options.width = options.width || 100;\n options.height = options.height || 100;\n options.multisample = options.multisample !== undefined ? options.multisample : MSAA_QUALITY.NONE;\n _this = _super.call(this, null, options) || this;\n // Set defaults\n _this.mipmap = MIPMAP_MODES.OFF;\n _this.valid = true;\n _this.clearColor = [0, 0, 0, 0];\n _this.framebuffer = new Framebuffer(_this.realWidth, _this.realHeight)\n .addColorTexture(0, _this);\n _this.framebuffer.multisample = options.multisample;\n // TODO - could this be added the systems?\n _this.maskStack = [];\n _this.filterStack = [{}];\n return _this;\n }\n /**\n * Resizes the BaseRenderTexture.\n * @param desiredWidth - The desired width to resize to.\n * @param desiredHeight - The desired height to resize to.\n */\n BaseRenderTexture.prototype.resize = function (desiredWidth, desiredHeight) {\n this.framebuffer.resize(desiredWidth * this.resolution, desiredHeight * this.resolution);\n this.setRealSize(this.framebuffer.width, this.framebuffer.height);\n };\n /**\n * Frees the texture and framebuffer from WebGL memory without destroying this texture object.\n * This means you can still use the texture later which will upload it to GPU\n * memory again.\n * @fires PIXI.BaseTexture#dispose\n */\n BaseRenderTexture.prototype.dispose = function () {\n this.framebuffer.dispose();\n _super.prototype.dispose.call(this);\n };\n /** Destroys this texture. */\n BaseRenderTexture.prototype.destroy = function () {\n _super.prototype.destroy.call(this);\n this.framebuffer.destroyDepthTexture();\n this.framebuffer = null;\n };\n return BaseRenderTexture;\n}(BaseTexture));\n\n/**\n * Stores a texture's frame in UV coordinates, in\n * which everything lies in the rectangle `[(0,0), (1,0),\n * (1,1), (0,1)]`.\n *\n * | Corner | Coordinates |\n * |--------------|-------------|\n * | Top-Left | `(x0,y0)` |\n * | Top-Right | `(x1,y1)` |\n * | Bottom-Right | `(x2,y2)` |\n * | Bottom-Left | `(x3,y3)` |\n * @protected\n * @memberof PIXI\n */\nvar TextureUvs = /** @class */ (function () {\n function TextureUvs() {\n this.x0 = 0;\n this.y0 = 0;\n this.x1 = 1;\n this.y1 = 0;\n this.x2 = 1;\n this.y2 = 1;\n this.x3 = 0;\n this.y3 = 1;\n this.uvsFloat32 = new Float32Array(8);\n }\n /**\n * Sets the texture Uvs based on the given frame information.\n * @protected\n * @param frame - The frame of the texture\n * @param baseFrame - The base frame of the texture\n * @param rotate - Rotation of frame, see {@link PIXI.groupD8}\n */\n TextureUvs.prototype.set = function (frame, baseFrame, rotate) {\n var tw = baseFrame.width;\n var th = baseFrame.height;\n if (rotate) {\n // width and height div 2 div baseFrame size\n var w2 = frame.width / 2 / tw;\n var h2 = frame.height / 2 / th;\n // coordinates of center\n var cX = (frame.x / tw) + w2;\n var cY = (frame.y / th) + h2;\n rotate = groupD8.add(rotate, groupD8.NW); // NW is top-left corner\n this.x0 = cX + (w2 * groupD8.uX(rotate));\n this.y0 = cY + (h2 * groupD8.uY(rotate));\n rotate = groupD8.add(rotate, 2); // rotate 90 degrees clockwise\n this.x1 = cX + (w2 * groupD8.uX(rotate));\n this.y1 = cY + (h2 * groupD8.uY(rotate));\n rotate = groupD8.add(rotate, 2);\n this.x2 = cX + (w2 * groupD8.uX(rotate));\n this.y2 = cY + (h2 * groupD8.uY(rotate));\n rotate = groupD8.add(rotate, 2);\n this.x3 = cX + (w2 * groupD8.uX(rotate));\n this.y3 = cY + (h2 * groupD8.uY(rotate));\n }\n else {\n this.x0 = frame.x / tw;\n this.y0 = frame.y / th;\n this.x1 = (frame.x + frame.width) / tw;\n this.y1 = frame.y / th;\n this.x2 = (frame.x + frame.width) / tw;\n this.y2 = (frame.y + frame.height) / th;\n this.x3 = frame.x / tw;\n this.y3 = (frame.y + frame.height) / th;\n }\n this.uvsFloat32[0] = this.x0;\n this.uvsFloat32[1] = this.y0;\n this.uvsFloat32[2] = this.x1;\n this.uvsFloat32[3] = this.y1;\n this.uvsFloat32[4] = this.x2;\n this.uvsFloat32[5] = this.y2;\n this.uvsFloat32[6] = this.x3;\n this.uvsFloat32[7] = this.y3;\n };\n TextureUvs.prototype.toString = function () {\n return \"[@pixi/core:TextureUvs \"\n + (\"x0=\" + this.x0 + \" y0=\" + this.y0 + \" \")\n + (\"x1=\" + this.x1 + \" y1=\" + this.y1 + \" x2=\" + this.x2 + \" \")\n + (\"y2=\" + this.y2 + \" x3=\" + this.x3 + \" y3=\" + this.y3)\n + \"]\";\n };\n return TextureUvs;\n}());\n\nvar DEFAULT_UVS = new TextureUvs();\n/**\n * Used to remove listeners from WHITE and EMPTY Textures\n * @ignore\n */\nfunction removeAllHandlers(tex) {\n tex.destroy = function _emptyDestroy() { };\n tex.on = function _emptyOn() { };\n tex.once = function _emptyOnce() { };\n tex.emit = function _emptyEmit() { };\n}\n/**\n * A texture stores the information that represents an image or part of an image.\n *\n * It cannot be added to the display list directly; instead use it as the texture for a Sprite.\n * If no frame is provided for a texture, then the whole image is used.\n *\n * You can directly create a texture from an image and then reuse it multiple times like this :\n *\n * ```js\n * let texture = PIXI.Texture.from('assets/image.png');\n * let sprite1 = new PIXI.Sprite(texture);\n * let sprite2 = new PIXI.Sprite(texture);\n * ```\n *\n * If you didnt pass the texture frame to constructor, it enables `noFrame` mode:\n * it subscribes on baseTexture events, it automatically resizes at the same time as baseTexture.\n *\n * Textures made from SVGs, loaded or not, cannot be used before the file finishes processing.\n * You can check for this by checking the sprite's _textureID property.\n * ```js\n * var texture = PIXI.Texture.from('assets/image.svg');\n * var sprite1 = new PIXI.Sprite(texture);\n * //sprite1._textureID should not be undefined if the texture has finished processing the SVG file\n * ```\n * You can use a ticker or rAF to ensure your sprites load the finished textures after processing. See issue #3068.\n * @memberof PIXI\n * @typeParam R - The BaseTexture's Resource type.\n */\nvar Texture = /** @class */ (function (_super) {\n __extends(Texture, _super);\n /**\n * @param baseTexture - The base texture source to create the texture from\n * @param frame - The rectangle frame of the texture to show\n * @param orig - The area of original texture\n * @param trim - Trimmed rectangle of original texture\n * @param rotate - indicates how the texture was rotated by texture packer. See {@link PIXI.groupD8}\n * @param anchor - Default anchor point used for sprite placement / rotation\n */\n function Texture(baseTexture, frame, orig, trim, rotate, anchor) {\n var _this = _super.call(this) || this;\n _this.noFrame = false;\n if (!frame) {\n _this.noFrame = true;\n frame = new Rectangle(0, 0, 1, 1);\n }\n if (baseTexture instanceof Texture) {\n baseTexture = baseTexture.baseTexture;\n }\n _this.baseTexture = baseTexture;\n _this._frame = frame;\n _this.trim = trim;\n _this.valid = false;\n _this._uvs = DEFAULT_UVS;\n _this.uvMatrix = null;\n _this.orig = orig || frame; // new Rectangle(0, 0, 1, 1);\n _this._rotate = Number(rotate || 0);\n if (rotate === true) {\n // this is old texturepacker legacy, some games/libraries are passing \"true\" for rotated textures\n _this._rotate = 2;\n }\n else if (_this._rotate % 2 !== 0) {\n throw new Error('attempt to use diamond-shaped UVs. If you are sure, set rotation manually');\n }\n _this.defaultAnchor = anchor ? new Point(anchor.x, anchor.y) : new Point(0, 0);\n _this._updateID = 0;\n _this.textureCacheIds = [];\n if (!baseTexture.valid) {\n baseTexture.once('loaded', _this.onBaseTextureUpdated, _this);\n }\n else if (_this.noFrame) {\n // if there is no frame we should monitor for any base texture changes..\n if (baseTexture.valid) {\n _this.onBaseTextureUpdated(baseTexture);\n }\n }\n else {\n _this.frame = frame;\n }\n if (_this.noFrame) {\n baseTexture.on('update', _this.onBaseTextureUpdated, _this);\n }\n return _this;\n }\n /**\n * Updates this texture on the gpu.\n *\n * Calls the TextureResource update.\n *\n * If you adjusted `frame` manually, please call `updateUvs()` instead.\n */\n Texture.prototype.update = function () {\n if (this.baseTexture.resource) {\n this.baseTexture.resource.update();\n }\n };\n /**\n * Called when the base texture is updated\n * @protected\n * @param baseTexture - The base texture.\n */\n Texture.prototype.onBaseTextureUpdated = function (baseTexture) {\n if (this.noFrame) {\n if (!this.baseTexture.valid) {\n return;\n }\n this._frame.width = baseTexture.width;\n this._frame.height = baseTexture.height;\n this.valid = true;\n this.updateUvs();\n }\n else {\n // TODO this code looks confusing.. boo to abusing getters and setters!\n // if user gave us frame that has bigger size than resized texture it can be a problem\n this.frame = this._frame;\n }\n this.emit('update', this);\n };\n /**\n * Destroys this texture\n * @param [destroyBase=false] - Whether to destroy the base texture as well\n */\n Texture.prototype.destroy = function (destroyBase) {\n if (this.baseTexture) {\n if (destroyBase) {\n var resource = this.baseTexture.resource;\n // delete the texture if it exists in the texture cache..\n // this only needs to be removed if the base texture is actually destroyed too..\n if (resource && resource.url && TextureCache[resource.url]) {\n Texture.removeFromCache(resource.url);\n }\n this.baseTexture.destroy();\n }\n this.baseTexture.off('loaded', this.onBaseTextureUpdated, this);\n this.baseTexture.off('update', this.onBaseTextureUpdated, this);\n this.baseTexture = null;\n }\n this._frame = null;\n this._uvs = null;\n this.trim = null;\n this.orig = null;\n this.valid = false;\n Texture.removeFromCache(this);\n this.textureCacheIds = null;\n };\n /**\n * Creates a new texture object that acts the same as this one.\n * @returns - The new texture\n */\n Texture.prototype.clone = function () {\n var clonedFrame = this._frame.clone();\n var clonedOrig = this._frame === this.orig ? clonedFrame : this.orig.clone();\n var clonedTexture = new Texture(this.baseTexture, !this.noFrame && clonedFrame, clonedOrig, this.trim && this.trim.clone(), this.rotate, this.defaultAnchor);\n if (this.noFrame) {\n clonedTexture._frame = clonedFrame;\n }\n return clonedTexture;\n };\n /**\n * Updates the internal WebGL UV cache. Use it after you change `frame` or `trim` of the texture.\n * Call it after changing the frame\n */\n Texture.prototype.updateUvs = function () {\n if (this._uvs === DEFAULT_UVS) {\n this._uvs = new TextureUvs();\n }\n this._uvs.set(this._frame, this.baseTexture, this.rotate);\n this._updateID++;\n };\n /**\n * Helper function that creates a new Texture based on the source you provide.\n * The source can be - frame id, image url, video url, canvas element, video element, base texture\n * @param {string|HTMLImageElement|HTMLCanvasElement|HTMLVideoElement|PIXI.BaseTexture} source -\n * Source or array of sources to create texture from\n * @param options - See {@link PIXI.BaseTexture}'s constructor for options.\n * @param {string} [options.pixiIdPrefix=pixiid] - If a source has no id, this is the prefix of the generated id\n * @param {boolean} [strict] - Enforce strict-mode, see {@link PIXI.settings.STRICT_TEXTURE_CACHE}.\n * @returns {PIXI.Texture} The newly created texture\n */\n Texture.from = function (source, options, strict) {\n if (options === void 0) { options = {}; }\n if (strict === void 0) { strict = settings.STRICT_TEXTURE_CACHE; }\n var isFrame = typeof source === 'string';\n var cacheId = null;\n if (isFrame) {\n cacheId = source;\n }\n else if (source instanceof BaseTexture) {\n if (!source.cacheId) {\n var prefix = (options && options.pixiIdPrefix) || 'pixiid';\n source.cacheId = prefix + \"-\" + uid();\n BaseTexture.addToCache(source, source.cacheId);\n }\n cacheId = source.cacheId;\n }\n else {\n if (!source._pixiId) {\n var prefix = (options && options.pixiIdPrefix) || 'pixiid';\n source._pixiId = prefix + \"_\" + uid();\n }\n cacheId = source._pixiId;\n }\n var texture = TextureCache[cacheId];\n // Strict-mode rejects invalid cacheIds\n if (isFrame && strict && !texture) {\n throw new Error(\"The cacheId \\\"\" + cacheId + \"\\\" does not exist in TextureCache.\");\n }\n if (!texture && !(source instanceof BaseTexture)) {\n if (!options.resolution) {\n options.resolution = getResolutionOfUrl(source);\n }\n texture = new Texture(new BaseTexture(source, options));\n texture.baseTexture.cacheId = cacheId;\n BaseTexture.addToCache(texture.baseTexture, cacheId);\n Texture.addToCache(texture, cacheId);\n }\n else if (!texture && (source instanceof BaseTexture)) {\n texture = new Texture(source);\n Texture.addToCache(texture, cacheId);\n }\n // lets assume its a base texture!\n return texture;\n };\n /**\n * Useful for loading textures via URLs. Use instead of `Texture.from` because\n * it does a better job of handling failed URLs more effectively. This also ignores\n * `PIXI.settings.STRICT_TEXTURE_CACHE`. Works for Videos, SVGs, Images.\n * @param url - The remote URL or array of URLs to load.\n * @param options - Optional options to include\n * @returns - A Promise that resolves to a Texture.\n */\n Texture.fromURL = function (url, options) {\n var resourceOptions = Object.assign({ autoLoad: false }, options === null || options === void 0 ? void 0 : options.resourceOptions);\n var texture = Texture.from(url, Object.assign({ resourceOptions: resourceOptions }, options), false);\n var resource = texture.baseTexture.resource;\n // The texture was already loaded\n if (texture.baseTexture.valid) {\n return Promise.resolve(texture);\n }\n // Manually load the texture, this should allow users to handle load errors\n return resource.load().then(function () { return Promise.resolve(texture); });\n };\n /**\n * Create a new Texture with a BufferResource from a Float32Array.\n * RGBA values are floats from 0 to 1.\n * @param {Float32Array|Uint8Array} buffer - The optional array to use, if no data\n * is provided, a new Float32Array is created.\n * @param width - Width of the resource\n * @param height - Height of the resource\n * @param options - See {@link PIXI.BaseTexture}'s constructor for options.\n * @returns - The resulting new BaseTexture\n */\n Texture.fromBuffer = function (buffer, width, height, options) {\n return new Texture(BaseTexture.fromBuffer(buffer, width, height, options));\n };\n /**\n * Create a texture from a source and add to the cache.\n * @param {HTMLImageElement|HTMLCanvasElement|string} source - The input source.\n * @param imageUrl - File name of texture, for cache and resolving resolution.\n * @param name - Human readable name for the texture cache. If no name is\n * specified, only `imageUrl` will be used as the cache ID.\n * @param options\n * @returns - Output texture\n */\n Texture.fromLoader = function (source, imageUrl, name, options) {\n var baseTexture = new BaseTexture(source, Object.assign({\n scaleMode: settings.SCALE_MODE,\n resolution: getResolutionOfUrl(imageUrl),\n }, options));\n var resource = baseTexture.resource;\n if (resource instanceof ImageResource) {\n resource.url = imageUrl;\n }\n var texture = new Texture(baseTexture);\n // No name, use imageUrl instead\n if (!name) {\n name = imageUrl;\n }\n // lets also add the frame to pixi's global cache for 'fromLoader' function\n BaseTexture.addToCache(texture.baseTexture, name);\n Texture.addToCache(texture, name);\n // also add references by url if they are different.\n if (name !== imageUrl) {\n BaseTexture.addToCache(texture.baseTexture, imageUrl);\n Texture.addToCache(texture, imageUrl);\n }\n // Generally images are valid right away\n if (texture.baseTexture.valid) {\n return Promise.resolve(texture);\n }\n // SVG assets need to be parsed async, let's wait\n return new Promise(function (resolve) {\n texture.baseTexture.once('loaded', function () { return resolve(texture); });\n });\n };\n /**\n * Adds a Texture to the global TextureCache. This cache is shared across the whole PIXI object.\n * @param texture - The Texture to add to the cache.\n * @param id - The id that the Texture will be stored against.\n */\n Texture.addToCache = function (texture, id) {\n if (id) {\n if (texture.textureCacheIds.indexOf(id) === -1) {\n texture.textureCacheIds.push(id);\n }\n if (TextureCache[id]) {\n // eslint-disable-next-line no-console\n console.warn(\"Texture added to the cache with an id [\" + id + \"] that already had an entry\");\n }\n TextureCache[id] = texture;\n }\n };\n /**\n * Remove a Texture from the global TextureCache.\n * @param texture - id of a Texture to be removed, or a Texture instance itself\n * @returns - The Texture that was removed\n */\n Texture.removeFromCache = function (texture) {\n if (typeof texture === 'string') {\n var textureFromCache = TextureCache[texture];\n if (textureFromCache) {\n var index = textureFromCache.textureCacheIds.indexOf(texture);\n if (index > -1) {\n textureFromCache.textureCacheIds.splice(index, 1);\n }\n delete TextureCache[texture];\n return textureFromCache;\n }\n }\n else if (texture && texture.textureCacheIds) {\n for (var i = 0; i < texture.textureCacheIds.length; ++i) {\n // Check that texture matches the one being passed in before deleting it from the cache.\n if (TextureCache[texture.textureCacheIds[i]] === texture) {\n delete TextureCache[texture.textureCacheIds[i]];\n }\n }\n texture.textureCacheIds.length = 0;\n return texture;\n }\n return null;\n };\n Object.defineProperty(Texture.prototype, \"resolution\", {\n /**\n * Returns resolution of baseTexture\n * @readonly\n */\n get: function () {\n return this.baseTexture.resolution;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Texture.prototype, \"frame\", {\n /**\n * The frame specifies the region of the base texture that this texture uses.\n * Please call `updateUvs()` after you change coordinates of `frame` manually.\n */\n get: function () {\n return this._frame;\n },\n set: function (frame) {\n this._frame = frame;\n this.noFrame = false;\n var x = frame.x, y = frame.y, width = frame.width, height = frame.height;\n var xNotFit = x + width > this.baseTexture.width;\n var yNotFit = y + height > this.baseTexture.height;\n if (xNotFit || yNotFit) {\n var relationship = xNotFit && yNotFit ? 'and' : 'or';\n var errorX = \"X: \" + x + \" + \" + width + \" = \" + (x + width) + \" > \" + this.baseTexture.width;\n var errorY = \"Y: \" + y + \" + \" + height + \" = \" + (y + height) + \" > \" + this.baseTexture.height;\n throw new Error('Texture Error: frame does not fit inside the base Texture dimensions: '\n + (errorX + \" \" + relationship + \" \" + errorY));\n }\n this.valid = width && height && this.baseTexture.valid;\n if (!this.trim && !this.rotate) {\n this.orig = frame;\n }\n if (this.valid) {\n this.updateUvs();\n }\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Texture.prototype, \"rotate\", {\n /**\n * Indicates whether the texture is rotated inside the atlas\n * set to 2 to compensate for texture packer rotation\n * set to 6 to compensate for spine packer rotation\n * can be used to rotate or mirror sprites\n * See {@link PIXI.groupD8} for explanation\n */\n get: function () {\n return this._rotate;\n },\n set: function (rotate) {\n this._rotate = rotate;\n if (this.valid) {\n this.updateUvs();\n }\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Texture.prototype, \"width\", {\n /** The width of the Texture in pixels. */\n get: function () {\n return this.orig.width;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Texture.prototype, \"height\", {\n /** The height of the Texture in pixels. */\n get: function () {\n return this.orig.height;\n },\n enumerable: false,\n configurable: true\n });\n /** Utility function for BaseTexture|Texture cast. */\n Texture.prototype.castToBaseTexture = function () {\n return this.baseTexture;\n };\n Object.defineProperty(Texture, \"EMPTY\", {\n /** An empty texture, used often to not have to create multiple empty textures. Can not be destroyed. */\n get: function () {\n if (!Texture._EMPTY) {\n Texture._EMPTY = new Texture(new BaseTexture());\n removeAllHandlers(Texture._EMPTY);\n removeAllHandlers(Texture._EMPTY.baseTexture);\n }\n return Texture._EMPTY;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Texture, \"WHITE\", {\n /** A white texture of 16x16 size, used for graphics and other things Can not be destroyed. */\n get: function () {\n if (!Texture._WHITE) {\n var canvas = settings.ADAPTER.createCanvas(16, 16);\n var context = canvas.getContext('2d');\n canvas.width = 16;\n canvas.height = 16;\n context.fillStyle = 'white';\n context.fillRect(0, 0, 16, 16);\n Texture._WHITE = new Texture(BaseTexture.from(canvas));\n removeAllHandlers(Texture._WHITE);\n removeAllHandlers(Texture._WHITE.baseTexture);\n }\n return Texture._WHITE;\n },\n enumerable: false,\n configurable: true\n });\n return Texture;\n}(EventEmitter));\n\n/**\n * A RenderTexture is a special texture that allows any PixiJS display object to be rendered to it.\n *\n * __Hint__: All DisplayObjects (i.e. Sprites) that render to a RenderTexture should be preloaded\n * otherwise black rectangles will be drawn instead.\n *\n * __Hint-2__: The actual memory allocation will happen on first render.\n * You shouldn't create renderTextures each frame just to delete them after, try to reuse them.\n *\n * A RenderTexture takes a snapshot of any Display Object given to its render method. For example:\n *\n * ```js\n * let renderer = PIXI.autoDetectRenderer();\n * let renderTexture = PIXI.RenderTexture.create({ width: 800, height: 600 });\n * let sprite = PIXI.Sprite.from(\"spinObj_01.png\");\n *\n * sprite.position.x = 800/2;\n * sprite.position.y = 600/2;\n * sprite.anchor.x = 0.5;\n * sprite.anchor.y = 0.5;\n *\n * renderer.render(sprite, {renderTexture});\n * ```\n * Note that you should not create a new renderer, but reuse the same one as the rest of the application.\n *\n * The Sprite in this case will be rendered using its local transform. To render this sprite at 0,0\n * you can clear the transform\n *\n * ```js\n *\n * sprite.setTransform()\n *\n * let renderTexture = new PIXI.RenderTexture.create({ width: 100, height: 100 });\n *\n * renderer.render(sprite, {renderTexture}); // Renders to center of RenderTexture\n * ```\n * @memberof PIXI\n */\nvar RenderTexture = /** @class */ (function (_super) {\n __extends(RenderTexture, _super);\n /**\n * @param baseRenderTexture - The base texture object that this texture uses.\n * @param frame - The rectangle frame of the texture to show.\n */\n function RenderTexture(baseRenderTexture, frame) {\n var _this = _super.call(this, baseRenderTexture, frame) || this;\n _this.valid = true;\n _this.filterFrame = null;\n _this.filterPoolKey = null;\n _this.updateUvs();\n return _this;\n }\n Object.defineProperty(RenderTexture.prototype, \"framebuffer\", {\n /**\n * Shortcut to `this.baseTexture.framebuffer`, saves baseTexture cast.\n * @readonly\n */\n get: function () {\n return this.baseTexture.framebuffer;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(RenderTexture.prototype, \"multisample\", {\n /**\n * Shortcut to `this.framebuffer.multisample`.\n * @default PIXI.MSAA_QUALITY.NONE\n */\n get: function () {\n return this.framebuffer.multisample;\n },\n set: function (value) {\n this.framebuffer.multisample = value;\n },\n enumerable: false,\n configurable: true\n });\n /**\n * Resizes the RenderTexture.\n * @param desiredWidth - The desired width to resize to.\n * @param desiredHeight - The desired height to resize to.\n * @param resizeBaseTexture - Should the baseTexture.width and height values be resized as well?\n */\n RenderTexture.prototype.resize = function (desiredWidth, desiredHeight, resizeBaseTexture) {\n if (resizeBaseTexture === void 0) { resizeBaseTexture = true; }\n var resolution = this.baseTexture.resolution;\n var width = Math.round(desiredWidth * resolution) / resolution;\n var height = Math.round(desiredHeight * resolution) / resolution;\n // TODO - could be not required..\n this.valid = (width > 0 && height > 0);\n this._frame.width = this.orig.width = width;\n this._frame.height = this.orig.height = height;\n if (resizeBaseTexture) {\n this.baseTexture.resize(width, height);\n }\n this.updateUvs();\n };\n /**\n * Changes the resolution of baseTexture, but does not change framebuffer size.\n * @param resolution - The new resolution to apply to RenderTexture\n */\n RenderTexture.prototype.setResolution = function (resolution) {\n var baseTexture = this.baseTexture;\n if (baseTexture.resolution === resolution) {\n return;\n }\n baseTexture.setResolution(resolution);\n this.resize(baseTexture.width, baseTexture.height, false);\n };\n RenderTexture.create = function (options) {\n var arguments$1 = arguments;\n\n var rest = [];\n for (var _i = 1; _i < arguments.length; _i++) {\n rest[_i - 1] = arguments$1[_i];\n }\n // @deprecated fallback, old-style: create(width, height, scaleMode, resolution)\n if (typeof options === 'number') {\n deprecation('6.0.0', 'Arguments (width, height, scaleMode, resolution) have been deprecated.');\n /* eslint-disable prefer-rest-params */\n options = {\n width: options,\n height: rest[0],\n scaleMode: rest[1],\n resolution: rest[2],\n };\n /* eslint-enable prefer-rest-params */\n }\n return new RenderTexture(new BaseRenderTexture(options));\n };\n return RenderTexture;\n}(Texture));\n\n/**\n * Texture pool, used by FilterSystem and plugins.\n *\n * Stores collection of temporary pow2 or screen-sized renderTextures\n *\n * If you use custom RenderTexturePool for your filters, you can use methods\n * `getFilterTexture` and `returnFilterTexture` same as in\n * @memberof PIXI\n */\nvar RenderTexturePool = /** @class */ (function () {\n /**\n * @param textureOptions - options that will be passed to BaseRenderTexture constructor\n * @param {PIXI.SCALE_MODES} [textureOptions.scaleMode] - See {@link PIXI.SCALE_MODES} for possible values.\n */\n function RenderTexturePool(textureOptions) {\n this.texturePool = {};\n this.textureOptions = textureOptions || {};\n this.enableFullScreen = false;\n this._pixelsWidth = 0;\n this._pixelsHeight = 0;\n }\n /**\n * Creates texture with params that were specified in pool constructor.\n * @param realWidth - Width of texture in pixels.\n * @param realHeight - Height of texture in pixels.\n * @param multisample - Number of samples of the framebuffer.\n */\n RenderTexturePool.prototype.createTexture = function (realWidth, realHeight, multisample) {\n if (multisample === void 0) { multisample = MSAA_QUALITY.NONE; }\n var baseRenderTexture = new BaseRenderTexture(Object.assign({\n width: realWidth,\n height: realHeight,\n resolution: 1,\n multisample: multisample,\n }, this.textureOptions));\n return new RenderTexture(baseRenderTexture);\n };\n /**\n * Gets a Power-of-Two render texture or fullScreen texture\n * @param minWidth - The minimum width of the render texture.\n * @param minHeight - The minimum height of the render texture.\n * @param resolution - The resolution of the render texture.\n * @param multisample - Number of samples of the render texture.\n * @returns The new render texture.\n */\n RenderTexturePool.prototype.getOptimalTexture = function (minWidth, minHeight, resolution, multisample) {\n if (resolution === void 0) { resolution = 1; }\n if (multisample === void 0) { multisample = MSAA_QUALITY.NONE; }\n var key;\n minWidth = Math.ceil((minWidth * resolution) - 1e-6);\n minHeight = Math.ceil((minHeight * resolution) - 1e-6);\n if (!this.enableFullScreen || minWidth !== this._pixelsWidth || minHeight !== this._pixelsHeight) {\n minWidth = nextPow2(minWidth);\n minHeight = nextPow2(minHeight);\n key = (((minWidth & 0xFFFF) << 16) | (minHeight & 0xFFFF)) >>> 0;\n if (multisample > 1) {\n key += multisample * 0x100000000;\n }\n }\n else {\n key = multisample > 1 ? -multisample : -1;\n }\n if (!this.texturePool[key]) {\n this.texturePool[key] = [];\n }\n var renderTexture = this.texturePool[key].pop();\n if (!renderTexture) {\n renderTexture = this.createTexture(minWidth, minHeight, multisample);\n }\n renderTexture.filterPoolKey = key;\n renderTexture.setResolution(resolution);\n return renderTexture;\n };\n /**\n * Gets extra texture of the same size as input renderTexture\n *\n * `getFilterTexture(input, 0.5)` or `getFilterTexture(0.5, input)`\n * @param input - renderTexture from which size and resolution will be copied\n * @param resolution - override resolution of the renderTexture\n * It overrides, it does not multiply\n * @param multisample - number of samples of the renderTexture\n */\n RenderTexturePool.prototype.getFilterTexture = function (input, resolution, multisample) {\n var filterTexture = this.getOptimalTexture(input.width, input.height, resolution || input.resolution, multisample || MSAA_QUALITY.NONE);\n filterTexture.filterFrame = input.filterFrame;\n return filterTexture;\n };\n /**\n * Place a render texture back into the pool.\n * @param renderTexture - The renderTexture to free\n */\n RenderTexturePool.prototype.returnTexture = function (renderTexture) {\n var key = renderTexture.filterPoolKey;\n renderTexture.filterFrame = null;\n this.texturePool[key].push(renderTexture);\n };\n /**\n * Alias for returnTexture, to be compliant with FilterSystem interface.\n * @param renderTexture - The renderTexture to free\n */\n RenderTexturePool.prototype.returnFilterTexture = function (renderTexture) {\n this.returnTexture(renderTexture);\n };\n /**\n * Clears the pool.\n * @param destroyTextures - Destroy all stored textures.\n */\n RenderTexturePool.prototype.clear = function (destroyTextures) {\n destroyTextures = destroyTextures !== false;\n if (destroyTextures) {\n for (var i in this.texturePool) {\n var textures = this.texturePool[i];\n if (textures) {\n for (var j = 0; j < textures.length; j++) {\n textures[j].destroy(true);\n }\n }\n }\n }\n this.texturePool = {};\n };\n /**\n * If screen size was changed, drops all screen-sized textures,\n * sets new screen size, sets `enableFullScreen` to true\n *\n * Size is measured in pixels, `renderer.view` can be passed here, not `renderer.screen`\n * @param size - Initial size of screen.\n */\n RenderTexturePool.prototype.setScreenSize = function (size) {\n if (size.width === this._pixelsWidth\n && size.height === this._pixelsHeight) {\n return;\n }\n this.enableFullScreen = size.width > 0 && size.height > 0;\n for (var i in this.texturePool) {\n if (!(Number(i) < 0)) {\n continue;\n }\n var textures = this.texturePool[i];\n if (textures) {\n for (var j = 0; j < textures.length; j++) {\n textures[j].destroy(true);\n }\n }\n this.texturePool[i] = [];\n }\n this._pixelsWidth = size.width;\n this._pixelsHeight = size.height;\n };\n /**\n * Key that is used to store fullscreen renderTextures in a pool\n * @constant\n */\n RenderTexturePool.SCREEN_KEY = -1;\n return RenderTexturePool;\n}());\n\n/* eslint-disable max-len */\n/**\n * Holds the information for a single attribute structure required to render geometry.\n *\n * This does not contain the actual data, but instead has a buffer id that maps to a {@link PIXI.Buffer}\n * This can include anything from positions, uvs, normals, colors etc.\n * @memberof PIXI\n */\nvar Attribute = /** @class */ (function () {\n /**\n * @param buffer - the id of the buffer that this attribute will look for\n * @param size - the size of the attribute. If you have 2 floats per vertex (eg position x and y) this would be 2.\n * @param normalized - should the data be normalized.\n * @param {PIXI.TYPES} [type=PIXI.TYPES.FLOAT] - what type of number is the attribute. Check {@link PIXI.TYPES} to see the ones available\n * @param [stride=0] - How far apart, in bytes, the start of each value is. (used for interleaving data)\n * @param [start=0] - How far into the array to start reading values (used for interleaving data)\n * @param [instance=false] - Whether the geometry is instanced.\n */\n function Attribute(buffer, size, normalized, type, stride, start, instance) {\n if (size === void 0) { size = 0; }\n if (normalized === void 0) { normalized = false; }\n if (type === void 0) { type = TYPES.FLOAT; }\n this.buffer = buffer;\n this.size = size;\n this.normalized = normalized;\n this.type = type;\n this.stride = stride;\n this.start = start;\n this.instance = instance;\n }\n /** Destroys the Attribute. */\n Attribute.prototype.destroy = function () {\n this.buffer = null;\n };\n /**\n * Helper function that creates an Attribute based on the information provided\n * @param buffer - the id of the buffer that this attribute will look for\n * @param [size=0] - the size of the attribute. If you have 2 floats per vertex (eg position x and y) this would be 2\n * @param [normalized=false] - should the data be normalized.\n * @param [type=PIXI.TYPES.FLOAT] - what type of number is the attribute. Check {@link PIXI.TYPES} to see the ones available\n * @param [stride=0] - How far apart, in bytes, the start of each value is. (used for interleaving data)\n * @returns - A new {@link PIXI.Attribute} based on the information provided\n */\n Attribute.from = function (buffer, size, normalized, type, stride) {\n return new Attribute(buffer, size, normalized, type, stride);\n };\n return Attribute;\n}());\n\nvar UID$4 = 0;\n/**\n * A wrapper for data so that it can be used and uploaded by WebGL\n * @memberof PIXI\n */\nvar Buffer = /** @class */ (function () {\n /**\n * @param {PIXI.IArrayBuffer} data - the data to store in the buffer.\n * @param _static - `true` for static buffer\n * @param index - `true` for index buffer\n */\n function Buffer(data, _static, index) {\n if (_static === void 0) { _static = true; }\n if (index === void 0) { index = false; }\n this.data = (data || new Float32Array(1));\n this._glBuffers = {};\n this._updateID = 0;\n this.index = index;\n this.static = _static;\n this.id = UID$4++;\n this.disposeRunner = new Runner('disposeBuffer');\n }\n // TODO could explore flagging only a partial upload?\n /**\n * Flags this buffer as requiring an upload to the GPU.\n * @param {PIXI.IArrayBuffer|number[]} [data] - the data to update in the buffer.\n */\n Buffer.prototype.update = function (data) {\n if (data instanceof Array) {\n data = new Float32Array(data);\n }\n this.data = data || this.data;\n this._updateID++;\n };\n /** Disposes WebGL resources that are connected to this geometry. */\n Buffer.prototype.dispose = function () {\n this.disposeRunner.emit(this, false);\n };\n /** Destroys the buffer. */\n Buffer.prototype.destroy = function () {\n this.dispose();\n this.data = null;\n };\n Object.defineProperty(Buffer.prototype, \"index\", {\n get: function () {\n return this.type === BUFFER_TYPE.ELEMENT_ARRAY_BUFFER;\n },\n /**\n * Flags whether this is an index buffer.\n *\n * Index buffers are of type `ELEMENT_ARRAY_BUFFER`. Note that setting this property to false will make\n * the buffer of type `ARRAY_BUFFER`.\n *\n * For backwards compatibility.\n */\n set: function (value) {\n this.type = value ? BUFFER_TYPE.ELEMENT_ARRAY_BUFFER : BUFFER_TYPE.ARRAY_BUFFER;\n },\n enumerable: false,\n configurable: true\n });\n /**\n * Helper function that creates a buffer based on an array or TypedArray\n * @param {ArrayBufferView | number[]} data - the TypedArray that the buffer will store. If this is a regular Array it will be converted to a Float32Array.\n * @returns - A new Buffer based on the data provided.\n */\n Buffer.from = function (data) {\n if (data instanceof Array) {\n data = new Float32Array(data);\n }\n return new Buffer(data);\n };\n return Buffer;\n}());\n\n/* eslint-disable object-shorthand */\nvar map$1 = {\n Float32Array: Float32Array,\n Uint32Array: Uint32Array,\n Int32Array: Int32Array,\n Uint8Array: Uint8Array,\n};\nfunction interleaveTypedArrays(arrays, sizes) {\n var outSize = 0;\n var stride = 0;\n var views = {};\n for (var i = 0; i < arrays.length; i++) {\n stride += sizes[i];\n outSize += arrays[i].length;\n }\n var buffer = new ArrayBuffer(outSize * 4);\n var out = null;\n var littleOffset = 0;\n for (var i = 0; i < arrays.length; i++) {\n var size = sizes[i];\n var array = arrays[i];\n var type = getBufferType(array);\n if (!views[type]) {\n views[type] = new map$1[type](buffer);\n }\n out = views[type];\n for (var j = 0; j < array.length; j++) {\n var indexStart = ((j / size | 0) * stride) + littleOffset;\n var index = j % size;\n out[indexStart + index] = array[j];\n }\n littleOffset += size;\n }\n return new Float32Array(buffer);\n}\n\nvar byteSizeMap$1 = { 5126: 4, 5123: 2, 5121: 1 };\nvar UID$3 = 0;\n/* eslint-disable object-shorthand */\nvar map = {\n Float32Array: Float32Array,\n Uint32Array: Uint32Array,\n Int32Array: Int32Array,\n Uint8Array: Uint8Array,\n Uint16Array: Uint16Array,\n};\n/* eslint-disable max-len */\n/**\n * The Geometry represents a model. It consists of two components:\n * - GeometryStyle - The structure of the model such as the attributes layout\n * - GeometryData - the data of the model - this consists of buffers.\n * This can include anything from positions, uvs, normals, colors etc.\n *\n * Geometry can be defined without passing in a style or data if required (thats how I prefer!)\n *\n * ```js\n * let geometry = new PIXI.Geometry();\n *\n * geometry.addAttribute('positions', [0, 0, 100, 0, 100, 100, 0, 100], 2);\n * geometry.addAttribute('uvs', [0,0,1,0,1,1,0,1],2)\n * geometry.addIndex([0,1,2,1,3,2])\n * ```\n * @memberof PIXI\n */\nvar Geometry = /** @class */ (function () {\n /**\n * @param buffers - An array of buffers. optional.\n * @param attributes - Of the geometry, optional structure of the attributes layout\n */\n function Geometry(buffers, attributes) {\n if (buffers === void 0) { buffers = []; }\n if (attributes === void 0) { attributes = {}; }\n this.buffers = buffers;\n this.indexBuffer = null;\n this.attributes = attributes;\n this.glVertexArrayObjects = {};\n this.id = UID$3++;\n this.instanced = false;\n this.instanceCount = 1;\n this.disposeRunner = new Runner('disposeGeometry');\n this.refCount = 0;\n }\n /**\n *\n * Adds an attribute to the geometry\n * Note: `stride` and `start` should be `undefined` if you dont know them, not 0!\n * @param id - the name of the attribute (matching up to a shader)\n * @param {PIXI.Buffer|number[]} buffer - the buffer that holds the data of the attribute . You can also provide an Array and a buffer will be created from it.\n * @param size - the size of the attribute. If you have 2 floats per vertex (eg position x and y) this would be 2\n * @param normalized - should the data be normalized.\n * @param [type=PIXI.TYPES.FLOAT] - what type of number is the attribute. Check {PIXI.TYPES} to see the ones available\n * @param [stride=0] - How far apart, in bytes, the start of each value is. (used for interleaving data)\n * @param [start=0] - How far into the array to start reading values (used for interleaving data)\n * @param instance - Instancing flag\n * @returns - Returns self, useful for chaining.\n */\n Geometry.prototype.addAttribute = function (id, buffer, size, normalized, type, stride, start, instance) {\n if (size === void 0) { size = 0; }\n if (normalized === void 0) { normalized = false; }\n if (instance === void 0) { instance = false; }\n if (!buffer) {\n throw new Error('You must pass a buffer when creating an attribute');\n }\n // check if this is a buffer!\n if (!(buffer instanceof Buffer)) {\n // its an array!\n if (buffer instanceof Array) {\n buffer = new Float32Array(buffer);\n }\n buffer = new Buffer(buffer);\n }\n var ids = id.split('|');\n if (ids.length > 1) {\n for (var i = 0; i < ids.length; i++) {\n this.addAttribute(ids[i], buffer, size, normalized, type);\n }\n return this;\n }\n var bufferIndex = this.buffers.indexOf(buffer);\n if (bufferIndex === -1) {\n this.buffers.push(buffer);\n bufferIndex = this.buffers.length - 1;\n }\n this.attributes[id] = new Attribute(bufferIndex, size, normalized, type, stride, start, instance);\n // assuming that if there is instanced data then this will be drawn with instancing!\n this.instanced = this.instanced || instance;\n return this;\n };\n /**\n * Returns the requested attribute.\n * @param id - The name of the attribute required\n * @returns - The attribute requested.\n */\n Geometry.prototype.getAttribute = function (id) {\n return this.attributes[id];\n };\n /**\n * Returns the requested buffer.\n * @param id - The name of the buffer required.\n * @returns - The buffer requested.\n */\n Geometry.prototype.getBuffer = function (id) {\n return this.buffers[this.getAttribute(id).buffer];\n };\n /**\n *\n * Adds an index buffer to the geometry\n * The index buffer contains integers, three for each triangle in the geometry, which reference the various attribute buffers (position, colour, UV coordinates, other UV coordinates, normal, …). There is only ONE index buffer.\n * @param {PIXI.Buffer|number[]} [buffer] - The buffer that holds the data of the index buffer. You can also provide an Array and a buffer will be created from it.\n * @returns - Returns self, useful for chaining.\n */\n Geometry.prototype.addIndex = function (buffer) {\n if (!(buffer instanceof Buffer)) {\n // its an array!\n if (buffer instanceof Array) {\n buffer = new Uint16Array(buffer);\n }\n buffer = new Buffer(buffer);\n }\n buffer.type = BUFFER_TYPE.ELEMENT_ARRAY_BUFFER;\n this.indexBuffer = buffer;\n if (this.buffers.indexOf(buffer) === -1) {\n this.buffers.push(buffer);\n }\n return this;\n };\n /**\n * Returns the index buffer\n * @returns - The index buffer.\n */\n Geometry.prototype.getIndex = function () {\n return this.indexBuffer;\n };\n /**\n * This function modifies the structure so that all current attributes become interleaved into a single buffer\n * This can be useful if your model remains static as it offers a little performance boost\n * @returns - Returns self, useful for chaining.\n */\n Geometry.prototype.interleave = function () {\n // a simple check to see if buffers are already interleaved..\n if (this.buffers.length === 1 || (this.buffers.length === 2 && this.indexBuffer))\n { return this; }\n // assume already that no buffers are interleaved\n var arrays = [];\n var sizes = [];\n var interleavedBuffer = new Buffer();\n var i;\n for (i in this.attributes) {\n var attribute = this.attributes[i];\n var buffer = this.buffers[attribute.buffer];\n arrays.push(buffer.data);\n sizes.push((attribute.size * byteSizeMap$1[attribute.type]) / 4);\n attribute.buffer = 0;\n }\n interleavedBuffer.data = interleaveTypedArrays(arrays, sizes);\n for (i = 0; i < this.buffers.length; i++) {\n if (this.buffers[i] !== this.indexBuffer) {\n this.buffers[i].destroy();\n }\n }\n this.buffers = [interleavedBuffer];\n if (this.indexBuffer) {\n this.buffers.push(this.indexBuffer);\n }\n return this;\n };\n /** Get the size of the geometries, in vertices. */\n Geometry.prototype.getSize = function () {\n for (var i in this.attributes) {\n var attribute = this.attributes[i];\n var buffer = this.buffers[attribute.buffer];\n return buffer.data.length / ((attribute.stride / 4) || attribute.size);\n }\n return 0;\n };\n /** Disposes WebGL resources that are connected to this geometry. */\n Geometry.prototype.dispose = function () {\n this.disposeRunner.emit(this, false);\n };\n /** Destroys the geometry. */\n Geometry.prototype.destroy = function () {\n this.dispose();\n this.buffers = null;\n this.indexBuffer = null;\n this.attributes = null;\n };\n /**\n * Returns a clone of the geometry.\n * @returns - A new clone of this geometry.\n */\n Geometry.prototype.clone = function () {\n var geometry = new Geometry();\n for (var i = 0; i < this.buffers.length; i++) {\n geometry.buffers[i] = new Buffer(this.buffers[i].data.slice(0));\n }\n for (var i in this.attributes) {\n var attrib = this.attributes[i];\n geometry.attributes[i] = new Attribute(attrib.buffer, attrib.size, attrib.normalized, attrib.type, attrib.stride, attrib.start, attrib.instance);\n }\n if (this.indexBuffer) {\n geometry.indexBuffer = geometry.buffers[this.buffers.indexOf(this.indexBuffer)];\n geometry.indexBuffer.type = BUFFER_TYPE.ELEMENT_ARRAY_BUFFER;\n }\n return geometry;\n };\n /**\n * Merges an array of geometries into a new single one.\n *\n * Geometry attribute styles must match for this operation to work.\n * @param geometries - array of geometries to merge\n * @returns - Shiny new geometry!\n */\n Geometry.merge = function (geometries) {\n // todo add a geometry check!\n // also a size check.. cant be too big!]\n var geometryOut = new Geometry();\n var arrays = [];\n var sizes = [];\n var offsets = [];\n var geometry;\n // pass one.. get sizes..\n for (var i = 0; i < geometries.length; i++) {\n geometry = geometries[i];\n for (var j = 0; j < geometry.buffers.length; j++) {\n sizes[j] = sizes[j] || 0;\n sizes[j] += geometry.buffers[j].data.length;\n offsets[j] = 0;\n }\n }\n // build the correct size arrays..\n for (var i = 0; i < geometry.buffers.length; i++) {\n // TODO types!\n arrays[i] = new map[getBufferType(geometry.buffers[i].data)](sizes[i]);\n geometryOut.buffers[i] = new Buffer(arrays[i]);\n }\n // pass to set data..\n for (var i = 0; i < geometries.length; i++) {\n geometry = geometries[i];\n for (var j = 0; j < geometry.buffers.length; j++) {\n arrays[j].set(geometry.buffers[j].data, offsets[j]);\n offsets[j] += geometry.buffers[j].data.length;\n }\n }\n geometryOut.attributes = geometry.attributes;\n if (geometry.indexBuffer) {\n geometryOut.indexBuffer = geometryOut.buffers[geometry.buffers.indexOf(geometry.indexBuffer)];\n geometryOut.indexBuffer.type = BUFFER_TYPE.ELEMENT_ARRAY_BUFFER;\n var offset = 0;\n var stride = 0;\n var offset2 = 0;\n var bufferIndexToCount = 0;\n // get a buffer\n for (var i = 0; i < geometry.buffers.length; i++) {\n if (geometry.buffers[i] !== geometry.indexBuffer) {\n bufferIndexToCount = i;\n break;\n }\n }\n // figure out the stride of one buffer..\n for (var i in geometry.attributes) {\n var attribute = geometry.attributes[i];\n if ((attribute.buffer | 0) === bufferIndexToCount) {\n stride += ((attribute.size * byteSizeMap$1[attribute.type]) / 4);\n }\n }\n // time to off set all indexes..\n for (var i = 0; i < geometries.length; i++) {\n var indexBufferData = geometries[i].indexBuffer.data;\n for (var j = 0; j < indexBufferData.length; j++) {\n geometryOut.indexBuffer.data[j + offset2] += offset;\n }\n offset += geometries[i].buffers[bufferIndexToCount].data.length / (stride);\n offset2 += indexBufferData.length;\n }\n }\n return geometryOut;\n };\n return Geometry;\n}());\n\n/**\n * Helper class to create a quad\n * @memberof PIXI\n */\nvar Quad = /** @class */ (function (_super) {\n __extends(Quad, _super);\n function Quad() {\n var _this = _super.call(this) || this;\n _this.addAttribute('aVertexPosition', new Float32Array([\n 0, 0,\n 1, 0,\n 1, 1,\n 0, 1 ]))\n .addIndex([0, 1, 3, 2]);\n return _this;\n }\n return Quad;\n}(Geometry));\n\n/**\n * Helper class to create a quad with uvs like in v4\n * @memberof PIXI\n */\nvar QuadUv = /** @class */ (function (_super) {\n __extends(QuadUv, _super);\n function QuadUv() {\n var _this = _super.call(this) || this;\n _this.vertices = new Float32Array([\n -1, -1,\n 1, -1,\n 1, 1,\n -1, 1 ]);\n _this.uvs = new Float32Array([\n 0, 0,\n 1, 0,\n 1, 1,\n 0, 1 ]);\n _this.vertexBuffer = new Buffer(_this.vertices);\n _this.uvBuffer = new Buffer(_this.uvs);\n _this.addAttribute('aVertexPosition', _this.vertexBuffer)\n .addAttribute('aTextureCoord', _this.uvBuffer)\n .addIndex([0, 1, 2, 0, 2, 3]);\n return _this;\n }\n /**\n * Maps two Rectangle to the quad.\n * @param targetTextureFrame - The first rectangle\n * @param destinationFrame - The second rectangle\n * @returns - Returns itself.\n */\n QuadUv.prototype.map = function (targetTextureFrame, destinationFrame) {\n var x = 0; // destinationFrame.x / targetTextureFrame.width;\n var y = 0; // destinationFrame.y / targetTextureFrame.height;\n this.uvs[0] = x;\n this.uvs[1] = y;\n this.uvs[2] = x + (destinationFrame.width / targetTextureFrame.width);\n this.uvs[3] = y;\n this.uvs[4] = x + (destinationFrame.width / targetTextureFrame.width);\n this.uvs[5] = y + (destinationFrame.height / targetTextureFrame.height);\n this.uvs[6] = x;\n this.uvs[7] = y + (destinationFrame.height / targetTextureFrame.height);\n x = destinationFrame.x;\n y = destinationFrame.y;\n this.vertices[0] = x;\n this.vertices[1] = y;\n this.vertices[2] = x + destinationFrame.width;\n this.vertices[3] = y;\n this.vertices[4] = x + destinationFrame.width;\n this.vertices[5] = y + destinationFrame.height;\n this.vertices[6] = x;\n this.vertices[7] = y + destinationFrame.height;\n this.invalidate();\n return this;\n };\n /**\n * Legacy upload method, just marks buffers dirty.\n * @returns - Returns itself.\n */\n QuadUv.prototype.invalidate = function () {\n this.vertexBuffer._updateID++;\n this.uvBuffer._updateID++;\n return this;\n };\n return QuadUv;\n}(Geometry));\n\nvar UID$2 = 0;\n/**\n * Uniform group holds uniform map and some ID's for work\n *\n * `UniformGroup` has two modes:\n *\n * 1: Normal mode\n * Normal mode will upload the uniforms with individual function calls as required\n *\n * 2: Uniform buffer mode\n * This mode will treat the uniforms as a uniform buffer. You can pass in either a buffer that you manually handle, or\n * or a generic object that PixiJS will automatically map to a buffer for you.\n * For maximum benefits, make Ubo UniformGroups static, and only update them each frame.\n *\n * Rules of UBOs:\n * - UBOs only work with WebGL2, so make sure you have a fallback!\n * - Only floats are supported (including vec[2,3,4], mat[2,3,4])\n * - Samplers cannot be used in ubo's (a GPU limitation)\n * - You must ensure that the object you pass in exactly matches in the shader ubo structure.\n * Otherwise, weirdness will ensue!\n * - The name of the ubo object added to the group must match exactly the name of the ubo in the shader.\n *\n * ```\n * // ubo in shader:\n * uniform myCoolData { // declaring a ubo..\n * mat4 uCoolMatrix;\n * float uFloatyMcFloatFace\n *\n *\n * // a new uniform buffer object..\n * const myCoolData = new UniformBufferGroup({\n * uCoolMatrix: new Matrix(),\n * uFloatyMcFloatFace: 23,\n * }}\n *\n * // build a shader...\n * const shader = Shader.from(srcVert, srcFrag, {\n * myCoolData // name matches the ubo name in the shader. will be processed accordingly.\n * })\n *\n * ```\n * @memberof PIXI\n */\nvar UniformGroup = /** @class */ (function () {\n /**\n * @param {object | Buffer} [uniforms] - Custom uniforms to use to augment the built-in ones. Or a pixi buffer.\n * @param isStatic - Uniforms wont be changed after creation.\n * @param isUbo - If true, will treat this uniform group as a uniform buffer object.\n */\n function UniformGroup(uniforms, isStatic, isUbo) {\n this.group = true;\n // lets generate this when the shader ?\n this.syncUniforms = {};\n this.dirtyId = 0;\n this.id = UID$2++;\n this.static = !!isStatic;\n this.ubo = !!isUbo;\n if (uniforms instanceof Buffer) {\n this.buffer = uniforms;\n this.buffer.type = BUFFER_TYPE.UNIFORM_BUFFER;\n this.autoManage = false;\n this.ubo = true;\n }\n else {\n this.uniforms = uniforms;\n if (this.ubo) {\n this.buffer = new Buffer(new Float32Array(1));\n this.buffer.type = BUFFER_TYPE.UNIFORM_BUFFER;\n this.autoManage = true;\n }\n }\n }\n UniformGroup.prototype.update = function () {\n this.dirtyId++;\n if (!this.autoManage && this.buffer) {\n this.buffer.update();\n }\n };\n UniformGroup.prototype.add = function (name, uniforms, _static) {\n if (!this.ubo) {\n this.uniforms[name] = new UniformGroup(uniforms, _static);\n }\n else {\n // eslint-disable-next-line max-len\n throw new Error('[UniformGroup] uniform groups in ubo mode cannot be modified, or have uniform groups nested in them');\n }\n };\n UniformGroup.from = function (uniforms, _static, _ubo) {\n return new UniformGroup(uniforms, _static, _ubo);\n };\n /**\n * A short hand function for creating a static UBO UniformGroup.\n * @param uniforms - the ubo item\n * @param _static - should this be updated each time it is used? defaults to true here!\n */\n UniformGroup.uboFrom = function (uniforms, _static) {\n return new UniformGroup(uniforms, _static !== null && _static !== void 0 ? _static : true, true);\n };\n return UniformGroup;\n}());\n\n/**\n * System plugin to the renderer to manage filter states.\n * @ignore\n */\nvar FilterState = /** @class */ (function () {\n function FilterState() {\n this.renderTexture = null;\n this.target = null;\n this.legacy = false;\n this.resolution = 1;\n this.multisample = MSAA_QUALITY.NONE;\n // next three fields are created only for root\n // re-assigned for everything else\n this.sourceFrame = new Rectangle();\n this.destinationFrame = new Rectangle();\n this.bindingSourceFrame = new Rectangle();\n this.bindingDestinationFrame = new Rectangle();\n this.filters = [];\n this.transform = null;\n }\n /** Clears the state */\n FilterState.prototype.clear = function () {\n this.target = null;\n this.filters = null;\n this.renderTexture = null;\n };\n return FilterState;\n}());\n\nvar tempPoints = [new Point(), new Point(), new Point(), new Point()];\nvar tempMatrix$2 = new Matrix();\n/**\n * System plugin to the renderer to manage filters.\n *\n * ## Pipeline\n *\n * The FilterSystem executes the filtering pipeline by rendering the display-object into a texture, applying its\n * [filters]{@link PIXI.Filter} in series, and the last filter outputs into the final render-target.\n *\n * The filter-frame is the rectangle in world space being filtered, and those contents are mapped into\n * `(0, 0, filterFrame.width, filterFrame.height)` into the filter render-texture. The filter-frame is also called\n * the source-frame, as it is used to bind the filter render-textures. The last filter outputs to the `filterFrame`\n * in the final render-target.\n *\n * ## Usage\n *\n * {@link PIXI.Container#renderAdvanced} is an example of how to use the filter system. It is a 3 step process:\n *\n * **push**: Use {@link PIXI.FilterSystem#push} to push the set of filters to be applied on a filter-target.\n * **render**: Render the contents to be filtered using the renderer. The filter-system will only capture the contents\n * inside the bounds of the filter-target. NOTE: Using {@link PIXI.Renderer#render} is\n * illegal during an existing render cycle, and it may reset the filter system.\n * **pop**: Use {@link PIXI.FilterSystem#pop} to pop & execute the filters you initially pushed. It will apply them\n * serially and output to the bounds of the filter-target.\n * @memberof PIXI\n */\nvar FilterSystem = /** @class */ (function () {\n /**\n * @param renderer - The renderer this System works for.\n */\n function FilterSystem(renderer) {\n this.renderer = renderer;\n this.defaultFilterStack = [{}];\n this.texturePool = new RenderTexturePool();\n this.texturePool.setScreenSize(renderer.view);\n this.statePool = [];\n this.quad = new Quad();\n this.quadUv = new QuadUv();\n this.tempRect = new Rectangle();\n this.activeState = {};\n this.globalUniforms = new UniformGroup({\n outputFrame: new Rectangle(),\n inputSize: new Float32Array(4),\n inputPixel: new Float32Array(4),\n inputClamp: new Float32Array(4),\n resolution: 1,\n // legacy variables\n filterArea: new Float32Array(4),\n filterClamp: new Float32Array(4),\n }, true);\n this.forceClear = false;\n this.useMaxPadding = false;\n }\n /**\n * Pushes a set of filters to be applied later to the system. This will redirect further rendering into an\n * input render-texture for the rest of the filtering pipeline.\n * @param {PIXI.DisplayObject} target - The target of the filter to render.\n * @param filters - The filters to apply.\n */\n FilterSystem.prototype.push = function (target, filters) {\n var _a, _b;\n var renderer = this.renderer;\n var filterStack = this.defaultFilterStack;\n var state = this.statePool.pop() || new FilterState();\n var renderTextureSystem = this.renderer.renderTexture;\n var resolution = filters[0].resolution;\n var multisample = filters[0].multisample;\n var padding = filters[0].padding;\n var autoFit = filters[0].autoFit;\n // We don't know whether it's a legacy filter until it was bound for the first time,\n // therefore we have to assume that it is if legacy is undefined.\n var legacy = (_a = filters[0].legacy) !== null && _a !== void 0 ? _a : true;\n for (var i = 1; i < filters.length; i++) {\n var filter = filters[i];\n // let's use the lowest resolution\n resolution = Math.min(resolution, filter.resolution);\n // let's use the lowest number of samples\n multisample = Math.min(multisample, filter.multisample);\n // figure out the padding required for filters\n padding = this.useMaxPadding\n // old behavior: use largest amount of padding!\n ? Math.max(padding, filter.padding)\n // new behavior: sum the padding\n : padding + filter.padding;\n // only auto fit if all filters are autofit\n autoFit = autoFit && filter.autoFit;\n legacy = legacy || ((_b = filter.legacy) !== null && _b !== void 0 ? _b : true);\n }\n if (filterStack.length === 1) {\n this.defaultFilterStack[0].renderTexture = renderTextureSystem.current;\n }\n filterStack.push(state);\n state.resolution = resolution;\n state.multisample = multisample;\n state.legacy = legacy;\n state.target = target;\n state.sourceFrame.copyFrom(target.filterArea || target.getBounds(true));\n state.sourceFrame.pad(padding);\n var sourceFrameProjected = this.tempRect.copyFrom(renderTextureSystem.sourceFrame);\n // Project source frame into world space (if projection is applied)\n if (renderer.projection.transform) {\n this.transformAABB(tempMatrix$2.copyFrom(renderer.projection.transform).invert(), sourceFrameProjected);\n }\n if (autoFit) {\n state.sourceFrame.fit(sourceFrameProjected);\n if (state.sourceFrame.width <= 0 || state.sourceFrame.height <= 0) {\n state.sourceFrame.width = 0;\n state.sourceFrame.height = 0;\n }\n }\n else if (!state.sourceFrame.intersects(sourceFrameProjected)) {\n state.sourceFrame.width = 0;\n state.sourceFrame.height = 0;\n }\n // Round sourceFrame in screen space based on render-texture.\n this.roundFrame(state.sourceFrame, renderTextureSystem.current ? renderTextureSystem.current.resolution : renderer.resolution, renderTextureSystem.sourceFrame, renderTextureSystem.destinationFrame, renderer.projection.transform);\n state.renderTexture = this.getOptimalFilterTexture(state.sourceFrame.width, state.sourceFrame.height, resolution, multisample);\n state.filters = filters;\n state.destinationFrame.width = state.renderTexture.width;\n state.destinationFrame.height = state.renderTexture.height;\n var destinationFrame = this.tempRect;\n destinationFrame.x = 0;\n destinationFrame.y = 0;\n destinationFrame.width = state.sourceFrame.width;\n destinationFrame.height = state.sourceFrame.height;\n state.renderTexture.filterFrame = state.sourceFrame;\n state.bindingSourceFrame.copyFrom(renderTextureSystem.sourceFrame);\n state.bindingDestinationFrame.copyFrom(renderTextureSystem.destinationFrame);\n state.transform = renderer.projection.transform;\n renderer.projection.transform = null;\n renderTextureSystem.bind(state.renderTexture, state.sourceFrame, destinationFrame);\n renderer.framebuffer.clear(0, 0, 0, 0);\n };\n /** Pops off the filter and applies it. */\n FilterSystem.prototype.pop = function () {\n var filterStack = this.defaultFilterStack;\n var state = filterStack.pop();\n var filters = state.filters;\n this.activeState = state;\n var globalUniforms = this.globalUniforms.uniforms;\n globalUniforms.outputFrame = state.sourceFrame;\n globalUniforms.resolution = state.resolution;\n var inputSize = globalUniforms.inputSize;\n var inputPixel = globalUniforms.inputPixel;\n var inputClamp = globalUniforms.inputClamp;\n inputSize[0] = state.destinationFrame.width;\n inputSize[1] = state.destinationFrame.height;\n inputSize[2] = 1.0 / inputSize[0];\n inputSize[3] = 1.0 / inputSize[1];\n inputPixel[0] = Math.round(inputSize[0] * state.resolution);\n inputPixel[1] = Math.round(inputSize[1] * state.resolution);\n inputPixel[2] = 1.0 / inputPixel[0];\n inputPixel[3] = 1.0 / inputPixel[1];\n inputClamp[0] = 0.5 * inputPixel[2];\n inputClamp[1] = 0.5 * inputPixel[3];\n inputClamp[2] = (state.sourceFrame.width * inputSize[2]) - (0.5 * inputPixel[2]);\n inputClamp[3] = (state.sourceFrame.height * inputSize[3]) - (0.5 * inputPixel[3]);\n // only update the rect if its legacy..\n if (state.legacy) {\n var filterArea = globalUniforms.filterArea;\n filterArea[0] = state.destinationFrame.width;\n filterArea[1] = state.destinationFrame.height;\n filterArea[2] = state.sourceFrame.x;\n filterArea[3] = state.sourceFrame.y;\n globalUniforms.filterClamp = globalUniforms.inputClamp;\n }\n this.globalUniforms.update();\n var lastState = filterStack[filterStack.length - 1];\n this.renderer.framebuffer.blit();\n if (filters.length === 1) {\n filters[0].apply(this, state.renderTexture, lastState.renderTexture, CLEAR_MODES.BLEND, state);\n this.returnFilterTexture(state.renderTexture);\n }\n else {\n var flip = state.renderTexture;\n var flop = this.getOptimalFilterTexture(flip.width, flip.height, state.resolution);\n flop.filterFrame = flip.filterFrame;\n var i = 0;\n for (i = 0; i < filters.length - 1; ++i) {\n if (i === 1 && state.multisample > 1) {\n flop = this.getOptimalFilterTexture(flip.width, flip.height, state.resolution);\n flop.filterFrame = flip.filterFrame;\n }\n filters[i].apply(this, flip, flop, CLEAR_MODES.CLEAR, state);\n var t = flip;\n flip = flop;\n flop = t;\n }\n filters[i].apply(this, flip, lastState.renderTexture, CLEAR_MODES.BLEND, state);\n if (i > 1 && state.multisample > 1) {\n this.returnFilterTexture(state.renderTexture);\n }\n this.returnFilterTexture(flip);\n this.returnFilterTexture(flop);\n }\n // lastState.renderTexture is blitted when lastState is popped\n state.clear();\n this.statePool.push(state);\n };\n /**\n * Binds a renderTexture with corresponding `filterFrame`, clears it if mode corresponds.\n * @param filterTexture - renderTexture to bind, should belong to filter pool or filter stack\n * @param clearMode - clearMode, by default its CLEAR/YES. See {@link PIXI.CLEAR_MODES}\n */\n FilterSystem.prototype.bindAndClear = function (filterTexture, clearMode) {\n if (clearMode === void 0) { clearMode = CLEAR_MODES.CLEAR; }\n var _a = this.renderer, renderTextureSystem = _a.renderTexture, stateSystem = _a.state;\n if (filterTexture === this.defaultFilterStack[this.defaultFilterStack.length - 1].renderTexture) {\n // Restore projection transform if rendering into the output render-target.\n this.renderer.projection.transform = this.activeState.transform;\n }\n else {\n // Prevent projection within filtering pipeline.\n this.renderer.projection.transform = null;\n }\n if (filterTexture && filterTexture.filterFrame) {\n var destinationFrame = this.tempRect;\n destinationFrame.x = 0;\n destinationFrame.y = 0;\n destinationFrame.width = filterTexture.filterFrame.width;\n destinationFrame.height = filterTexture.filterFrame.height;\n renderTextureSystem.bind(filterTexture, filterTexture.filterFrame, destinationFrame);\n }\n else if (filterTexture !== this.defaultFilterStack[this.defaultFilterStack.length - 1].renderTexture) {\n renderTextureSystem.bind(filterTexture);\n }\n else {\n // Restore binding for output render-target.\n this.renderer.renderTexture.bind(filterTexture, this.activeState.bindingSourceFrame, this.activeState.bindingDestinationFrame);\n }\n // Clear the texture in BLIT mode if blending is disabled or the forceClear flag is set. The blending\n // is stored in the 0th bit of the state.\n var autoClear = (stateSystem.stateId & 1) || this.forceClear;\n if (clearMode === CLEAR_MODES.CLEAR\n || (clearMode === CLEAR_MODES.BLIT && autoClear)) {\n // Use framebuffer.clear because we want to clear the whole filter texture, not just the filtering\n // area over which the shaders are run. This is because filters may sampling outside of it (e.g. blur)\n // instead of clamping their arithmetic.\n this.renderer.framebuffer.clear(0, 0, 0, 0);\n }\n };\n /**\n * Draws a filter using the default rendering process.\n *\n * This should be called only by {@link Filter#apply}.\n * @param filter - The filter to draw.\n * @param input - The input render target.\n * @param output - The target to output to.\n * @param clearMode - Should the output be cleared before rendering to it\n */\n FilterSystem.prototype.applyFilter = function (filter, input, output, clearMode) {\n var renderer = this.renderer;\n // Set state before binding, so bindAndClear gets the blend mode.\n renderer.state.set(filter.state);\n this.bindAndClear(output, clearMode);\n // set the uniforms..\n filter.uniforms.uSampler = input;\n filter.uniforms.filterGlobals = this.globalUniforms;\n // TODO make it so that the order of this does not matter..\n // because it does at the moment cos of global uniforms.\n // they need to get resynced\n renderer.shader.bind(filter);\n // check to see if the filter is a legacy one..\n filter.legacy = !!filter.program.attributeData.aTextureCoord;\n if (filter.legacy) {\n this.quadUv.map(input._frame, input.filterFrame);\n renderer.geometry.bind(this.quadUv);\n renderer.geometry.draw(DRAW_MODES.TRIANGLES);\n }\n else {\n renderer.geometry.bind(this.quad);\n renderer.geometry.draw(DRAW_MODES.TRIANGLE_STRIP);\n }\n };\n /**\n * Multiply _input normalized coordinates_ to this matrix to get _sprite texture normalized coordinates_.\n *\n * Use `outputMatrix * vTextureCoord` in the shader.\n * @param outputMatrix - The matrix to output to.\n * @param {PIXI.Sprite} sprite - The sprite to map to.\n * @returns The mapped matrix.\n */\n FilterSystem.prototype.calculateSpriteMatrix = function (outputMatrix, sprite) {\n var _a = this.activeState, sourceFrame = _a.sourceFrame, destinationFrame = _a.destinationFrame;\n var orig = sprite._texture.orig;\n var mappedMatrix = outputMatrix.set(destinationFrame.width, 0, 0, destinationFrame.height, sourceFrame.x, sourceFrame.y);\n var worldTransform = sprite.worldTransform.copyTo(Matrix.TEMP_MATRIX);\n worldTransform.invert();\n mappedMatrix.prepend(worldTransform);\n mappedMatrix.scale(1.0 / orig.width, 1.0 / orig.height);\n mappedMatrix.translate(sprite.anchor.x, sprite.anchor.y);\n return mappedMatrix;\n };\n /** Destroys this Filter System. */\n FilterSystem.prototype.destroy = function () {\n this.renderer = null;\n // Those textures has to be destroyed by RenderTextureSystem or FramebufferSystem\n this.texturePool.clear(false);\n };\n /**\n * Gets a Power-of-Two render texture or fullScreen texture\n * @param minWidth - The minimum width of the render texture in real pixels.\n * @param minHeight - The minimum height of the render texture in real pixels.\n * @param resolution - The resolution of the render texture.\n * @param multisample - Number of samples of the render texture.\n * @returns - The new render texture.\n */\n FilterSystem.prototype.getOptimalFilterTexture = function (minWidth, minHeight, resolution, multisample) {\n if (resolution === void 0) { resolution = 1; }\n if (multisample === void 0) { multisample = MSAA_QUALITY.NONE; }\n return this.texturePool.getOptimalTexture(minWidth, minHeight, resolution, multisample);\n };\n /**\n * Gets extra render texture to use inside current filter\n * To be compliant with older filters, you can use params in any order\n * @param input - renderTexture from which size and resolution will be copied\n * @param resolution - override resolution of the renderTexture\n * @param multisample - number of samples of the renderTexture\n */\n FilterSystem.prototype.getFilterTexture = function (input, resolution, multisample) {\n if (typeof input === 'number') {\n var swap = input;\n input = resolution;\n resolution = swap;\n }\n input = input || this.activeState.renderTexture;\n var filterTexture = this.texturePool.getOptimalTexture(input.width, input.height, resolution || input.resolution, multisample || MSAA_QUALITY.NONE);\n filterTexture.filterFrame = input.filterFrame;\n return filterTexture;\n };\n /**\n * Frees a render texture back into the pool.\n * @param renderTexture - The renderTarget to free\n */\n FilterSystem.prototype.returnFilterTexture = function (renderTexture) {\n this.texturePool.returnTexture(renderTexture);\n };\n /** Empties the texture pool. */\n FilterSystem.prototype.emptyPool = function () {\n this.texturePool.clear(true);\n };\n /** Calls `texturePool.resize()`, affects fullScreen renderTextures. */\n FilterSystem.prototype.resize = function () {\n this.texturePool.setScreenSize(this.renderer.view);\n };\n /**\n * @param matrix - first param\n * @param rect - second param\n */\n FilterSystem.prototype.transformAABB = function (matrix, rect) {\n var lt = tempPoints[0];\n var lb = tempPoints[1];\n var rt = tempPoints[2];\n var rb = tempPoints[3];\n lt.set(rect.left, rect.top);\n lb.set(rect.left, rect.bottom);\n rt.set(rect.right, rect.top);\n rb.set(rect.right, rect.bottom);\n matrix.apply(lt, lt);\n matrix.apply(lb, lb);\n matrix.apply(rt, rt);\n matrix.apply(rb, rb);\n var x0 = Math.min(lt.x, lb.x, rt.x, rb.x);\n var y0 = Math.min(lt.y, lb.y, rt.y, rb.y);\n var x1 = Math.max(lt.x, lb.x, rt.x, rb.x);\n var y1 = Math.max(lt.y, lb.y, rt.y, rb.y);\n rect.x = x0;\n rect.y = y0;\n rect.width = x1 - x0;\n rect.height = y1 - y0;\n };\n FilterSystem.prototype.roundFrame = function (frame, resolution, bindingSourceFrame, bindingDestinationFrame, transform) {\n if (frame.width <= 0 || frame.height <= 0 || bindingSourceFrame.width <= 0 || bindingSourceFrame.height <= 0) {\n return;\n }\n if (transform) {\n var a = transform.a, b = transform.b, c = transform.c, d = transform.d;\n // Skip if skew/rotation present in matrix, except for multiple of 90° rotation. If rotation\n // is a multiple of 90°, then either pair of (b,c) or (a,d) will be (0,0).\n if ((Math.abs(b) > 1e-4 || Math.abs(c) > 1e-4)\n && (Math.abs(a) > 1e-4 || Math.abs(d) > 1e-4)) {\n return;\n }\n }\n transform = transform ? tempMatrix$2.copyFrom(transform) : tempMatrix$2.identity();\n // Get forward transform from world space to screen space\n transform\n .translate(-bindingSourceFrame.x, -bindingSourceFrame.y)\n .scale(bindingDestinationFrame.width / bindingSourceFrame.width, bindingDestinationFrame.height / bindingSourceFrame.height)\n .translate(bindingDestinationFrame.x, bindingDestinationFrame.y);\n // Convert frame to screen space\n this.transformAABB(transform, frame);\n // Round frame in screen space\n frame.ceil(resolution);\n // Project back into world space.\n this.transformAABB(transform.invert(), frame);\n };\n return FilterSystem;\n}());\n\n/**\n * Base for a common object renderer that can be used as a\n * system renderer plugin.\n * @memberof PIXI\n */\nvar ObjectRenderer = /** @class */ (function () {\n /**\n * @param renderer - The renderer this manager works for.\n */\n function ObjectRenderer(renderer) {\n this.renderer = renderer;\n }\n /** Stub method that should be used to empty the current batch by rendering objects now. */\n ObjectRenderer.prototype.flush = function () {\n // flush!\n };\n /** Generic destruction method that frees all resources. This should be called by subclasses. */\n ObjectRenderer.prototype.destroy = function () {\n this.renderer = null;\n };\n /**\n * Stub method that initializes any state required before\n * rendering starts. It is different from the `prerender`\n * signal, which occurs every frame, in that it is called\n * whenever an object requests _this_ renderer specifically.\n */\n ObjectRenderer.prototype.start = function () {\n // set the shader..\n };\n /** Stops the renderer. It should free up any state and become dormant. */\n ObjectRenderer.prototype.stop = function () {\n this.flush();\n };\n /**\n * Keeps the object to render. It doesn't have to be\n * rendered immediately.\n * @param {PIXI.DisplayObject} _object - The object to render.\n */\n ObjectRenderer.prototype.render = function (_object) {\n // render the object\n };\n return ObjectRenderer;\n}());\n\n/**\n * System plugin to the renderer to manage batching.\n * @memberof PIXI\n */\nvar BatchSystem = /** @class */ (function () {\n /**\n * @param renderer - The renderer this System works for.\n */\n function BatchSystem(renderer) {\n this.renderer = renderer;\n this.emptyRenderer = new ObjectRenderer(renderer);\n this.currentRenderer = this.emptyRenderer;\n }\n /**\n * Changes the current renderer to the one given in parameter\n * @param objectRenderer - The object renderer to use.\n */\n BatchSystem.prototype.setObjectRenderer = function (objectRenderer) {\n if (this.currentRenderer === objectRenderer) {\n return;\n }\n this.currentRenderer.stop();\n this.currentRenderer = objectRenderer;\n this.currentRenderer.start();\n };\n /**\n * This should be called if you wish to do some custom rendering\n * It will basically render anything that may be batched up such as sprites\n */\n BatchSystem.prototype.flush = function () {\n this.setObjectRenderer(this.emptyRenderer);\n };\n /** Reset the system to an empty renderer */\n BatchSystem.prototype.reset = function () {\n this.setObjectRenderer(this.emptyRenderer);\n };\n /**\n * Handy function for batch renderers: copies bound textures in first maxTextures locations to array\n * sets actual _batchLocation for them\n * @param arr - arr copy destination\n * @param maxTextures - number of copied elements\n */\n BatchSystem.prototype.copyBoundTextures = function (arr, maxTextures) {\n var boundTextures = this.renderer.texture.boundTextures;\n for (var i = maxTextures - 1; i >= 0; --i) {\n arr[i] = boundTextures[i] || null;\n if (arr[i]) {\n arr[i]._batchLocation = i;\n }\n }\n };\n /**\n * Assigns batch locations to textures in array based on boundTextures state.\n * All textures in texArray should have `_batchEnabled = _batchId`,\n * and their count should be less than `maxTextures`.\n * @param texArray - textures to bound\n * @param boundTextures - current state of bound textures\n * @param batchId - marker for _batchEnabled param of textures in texArray\n * @param maxTextures - number of texture locations to manipulate\n */\n BatchSystem.prototype.boundArray = function (texArray, boundTextures, batchId, maxTextures) {\n var elements = texArray.elements, ids = texArray.ids, count = texArray.count;\n var j = 0;\n for (var i = 0; i < count; i++) {\n var tex = elements[i];\n var loc = tex._batchLocation;\n if (loc >= 0 && loc < maxTextures\n && boundTextures[loc] === tex) {\n ids[i] = loc;\n continue;\n }\n while (j < maxTextures) {\n var bound = boundTextures[j];\n if (bound && bound._batchEnabled === batchId\n && bound._batchLocation === j) {\n j++;\n continue;\n }\n ids[i] = j;\n tex._batchLocation = j;\n boundTextures[j] = tex;\n break;\n }\n }\n };\n /**\n * @ignore\n */\n BatchSystem.prototype.destroy = function () {\n this.renderer = null;\n };\n return BatchSystem;\n}());\n\nvar CONTEXT_UID_COUNTER = 0;\n/**\n * System plugin to the renderer to manage the context.\n * @memberof PIXI\n */\nvar ContextSystem = /** @class */ (function () {\n /** @param renderer - The renderer this System works for. */\n function ContextSystem(renderer) {\n this.renderer = renderer;\n this.webGLVersion = 1;\n this.extensions = {};\n this.supports = {\n uint32Indices: false,\n };\n // Bind functions\n this.handleContextLost = this.handleContextLost.bind(this);\n this.handleContextRestored = this.handleContextRestored.bind(this);\n renderer.view.addEventListener('webglcontextlost', this.handleContextLost, false);\n renderer.view.addEventListener('webglcontextrestored', this.handleContextRestored, false);\n }\n Object.defineProperty(ContextSystem.prototype, \"isLost\", {\n /**\n * `true` if the context is lost\n * @readonly\n */\n get: function () {\n return (!this.gl || this.gl.isContextLost());\n },\n enumerable: false,\n configurable: true\n });\n /**\n * Handles the context change event.\n * @param {WebGLRenderingContext} gl - New WebGL context.\n */\n ContextSystem.prototype.contextChange = function (gl) {\n this.gl = gl;\n this.renderer.gl = gl;\n this.renderer.CONTEXT_UID = CONTEXT_UID_COUNTER++;\n // restore a context if it was previously lost\n if (gl.isContextLost() && gl.getExtension('WEBGL_lose_context')) {\n gl.getExtension('WEBGL_lose_context').restoreContext();\n }\n };\n /**\n * Initializes the context.\n * @protected\n * @param {WebGLRenderingContext} gl - WebGL context\n */\n ContextSystem.prototype.initFromContext = function (gl) {\n this.gl = gl;\n this.validateContext(gl);\n this.renderer.gl = gl;\n this.renderer.CONTEXT_UID = CONTEXT_UID_COUNTER++;\n this.renderer.runners.contextChange.emit(gl);\n };\n /**\n * Initialize from context options\n * @protected\n * @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/getContext\n * @param {object} options - context attributes\n */\n ContextSystem.prototype.initFromOptions = function (options) {\n var gl = this.createContext(this.renderer.view, options);\n this.initFromContext(gl);\n };\n /**\n * Helper class to create a WebGL Context\n * @param canvas - the canvas element that we will get the context from\n * @param options - An options object that gets passed in to the canvas element containing the\n * context attributes\n * @see https://developer.mozilla.org/en/docs/Web/API/HTMLCanvasElement/getContext\n * @returns {WebGLRenderingContext} the WebGL context\n */\n ContextSystem.prototype.createContext = function (canvas, options) {\n var gl;\n if (settings.PREFER_ENV >= ENV.WEBGL2) {\n gl = canvas.getContext('webgl2', options);\n }\n if (gl) {\n this.webGLVersion = 2;\n }\n else {\n this.webGLVersion = 1;\n gl = canvas.getContext('webgl', options) || canvas.getContext('experimental-webgl', options);\n if (!gl) {\n // fail, not able to get a context\n throw new Error('This browser does not support WebGL. Try using the canvas renderer');\n }\n }\n this.gl = gl;\n this.getExtensions();\n return this.gl;\n };\n /** Auto-populate the {@link PIXI.ContextSystem.extensions extensions}. */\n ContextSystem.prototype.getExtensions = function () {\n // time to set up default extensions that Pixi uses.\n var gl = this.gl;\n var common = {\n anisotropicFiltering: gl.getExtension('EXT_texture_filter_anisotropic'),\n floatTextureLinear: gl.getExtension('OES_texture_float_linear'),\n s3tc: gl.getExtension('WEBGL_compressed_texture_s3tc'),\n s3tc_sRGB: gl.getExtension('WEBGL_compressed_texture_s3tc_srgb'),\n etc: gl.getExtension('WEBGL_compressed_texture_etc'),\n etc1: gl.getExtension('WEBGL_compressed_texture_etc1'),\n pvrtc: gl.getExtension('WEBGL_compressed_texture_pvrtc')\n || gl.getExtension('WEBKIT_WEBGL_compressed_texture_pvrtc'),\n atc: gl.getExtension('WEBGL_compressed_texture_atc'),\n astc: gl.getExtension('WEBGL_compressed_texture_astc')\n };\n if (this.webGLVersion === 1) {\n Object.assign(this.extensions, common, {\n drawBuffers: gl.getExtension('WEBGL_draw_buffers'),\n depthTexture: gl.getExtension('WEBGL_depth_texture'),\n loseContext: gl.getExtension('WEBGL_lose_context'),\n vertexArrayObject: gl.getExtension('OES_vertex_array_object')\n || gl.getExtension('MOZ_OES_vertex_array_object')\n || gl.getExtension('WEBKIT_OES_vertex_array_object'),\n uint32ElementIndex: gl.getExtension('OES_element_index_uint'),\n // Floats and half-floats\n floatTexture: gl.getExtension('OES_texture_float'),\n floatTextureLinear: gl.getExtension('OES_texture_float_linear'),\n textureHalfFloat: gl.getExtension('OES_texture_half_float'),\n textureHalfFloatLinear: gl.getExtension('OES_texture_half_float_linear'),\n });\n }\n else if (this.webGLVersion === 2) {\n Object.assign(this.extensions, common, {\n // Floats and half-floats\n colorBufferFloat: gl.getExtension('EXT_color_buffer_float')\n });\n }\n };\n /**\n * Handles a lost webgl context\n * @param {WebGLContextEvent} event - The context lost event.\n */\n ContextSystem.prototype.handleContextLost = function (event) {\n event.preventDefault();\n };\n /** Handles a restored webgl context. */\n ContextSystem.prototype.handleContextRestored = function () {\n this.renderer.runners.contextChange.emit(this.gl);\n };\n ContextSystem.prototype.destroy = function () {\n var view = this.renderer.view;\n this.renderer = null;\n // remove listeners\n view.removeEventListener('webglcontextlost', this.handleContextLost);\n view.removeEventListener('webglcontextrestored', this.handleContextRestored);\n this.gl.useProgram(null);\n if (this.extensions.loseContext) {\n this.extensions.loseContext.loseContext();\n }\n };\n /** Handle the post-render runner event. */\n ContextSystem.prototype.postrender = function () {\n if (this.renderer.renderingToScreen) {\n this.gl.flush();\n }\n };\n /**\n * Validate context.\n * @param {WebGLRenderingContext} gl - Render context.\n */\n ContextSystem.prototype.validateContext = function (gl) {\n var attributes = gl.getContextAttributes();\n var isWebGl2 = 'WebGL2RenderingContext' in globalThis && gl instanceof globalThis.WebGL2RenderingContext;\n if (isWebGl2) {\n this.webGLVersion = 2;\n }\n // this is going to be fairly simple for now.. but at least we have room to grow!\n if (attributes && !attributes.stencil) {\n /* eslint-disable max-len, no-console */\n console.warn('Provided WebGL context does not have a stencil buffer, masks may not render correctly');\n /* eslint-enable max-len, no-console */\n }\n var hasuint32 = isWebGl2 || !!gl.getExtension('OES_element_index_uint');\n this.supports.uint32Indices = hasuint32;\n if (!hasuint32) {\n /* eslint-disable max-len, no-console */\n console.warn('Provided WebGL context does not support 32 index buffer, complex graphics may not render correctly');\n /* eslint-enable max-len, no-console */\n }\n };\n return ContextSystem;\n}());\n\n/**\n * Internal framebuffer for WebGL context.\n * @memberof PIXI\n */\nvar GLFramebuffer = /** @class */ (function () {\n function GLFramebuffer(framebuffer) {\n this.framebuffer = framebuffer;\n this.stencil = null;\n this.dirtyId = -1;\n this.dirtyFormat = -1;\n this.dirtySize = -1;\n this.multisample = MSAA_QUALITY.NONE;\n this.msaaBuffer = null;\n this.blitFramebuffer = null;\n this.mipLevel = 0;\n }\n return GLFramebuffer;\n}());\n\nvar tempRectangle = new Rectangle();\n/**\n * System plugin to the renderer to manage framebuffers.\n * @memberof PIXI\n */\nvar FramebufferSystem = /** @class */ (function () {\n /**\n * @param renderer - The renderer this System works for.\n */\n function FramebufferSystem(renderer) {\n this.renderer = renderer;\n this.managedFramebuffers = [];\n this.unknownFramebuffer = new Framebuffer(10, 10);\n this.msaaSamples = null;\n }\n /** Sets up the renderer context and necessary buffers. */\n FramebufferSystem.prototype.contextChange = function () {\n var gl = this.gl = this.renderer.gl;\n this.CONTEXT_UID = this.renderer.CONTEXT_UID;\n this.current = this.unknownFramebuffer;\n this.viewport = new Rectangle();\n this.hasMRT = true;\n this.writeDepthTexture = true;\n this.disposeAll(true);\n // webgl2\n if (this.renderer.context.webGLVersion === 1) {\n // webgl 1!\n var nativeDrawBuffersExtension_1 = this.renderer.context.extensions.drawBuffers;\n var nativeDepthTextureExtension = this.renderer.context.extensions.depthTexture;\n if (settings.PREFER_ENV === ENV.WEBGL_LEGACY) {\n nativeDrawBuffersExtension_1 = null;\n nativeDepthTextureExtension = null;\n }\n if (nativeDrawBuffersExtension_1) {\n gl.drawBuffers = function (activeTextures) {\n return nativeDrawBuffersExtension_1.drawBuffersWEBGL(activeTextures);\n };\n }\n else {\n this.hasMRT = false;\n gl.drawBuffers = function () {\n // empty\n };\n }\n if (!nativeDepthTextureExtension) {\n this.writeDepthTexture = false;\n }\n }\n else {\n // WebGL2\n // cache possible MSAA samples\n this.msaaSamples = gl.getInternalformatParameter(gl.RENDERBUFFER, gl.RGBA8, gl.SAMPLES);\n }\n };\n /**\n * Bind a framebuffer.\n * @param framebuffer\n * @param frame - frame, default is framebuffer size\n * @param mipLevel - optional mip level to set on the framebuffer - defaults to 0\n */\n FramebufferSystem.prototype.bind = function (framebuffer, frame, mipLevel) {\n if (mipLevel === void 0) { mipLevel = 0; }\n var gl = this.gl;\n if (framebuffer) {\n // TODO caching layer!\n var fbo = framebuffer.glFramebuffers[this.CONTEXT_UID] || this.initFramebuffer(framebuffer);\n if (this.current !== framebuffer) {\n this.current = framebuffer;\n gl.bindFramebuffer(gl.FRAMEBUFFER, fbo.framebuffer);\n }\n // make sure all textures are unbound..\n if (fbo.mipLevel !== mipLevel) {\n framebuffer.dirtyId++;\n framebuffer.dirtyFormat++;\n fbo.mipLevel = mipLevel;\n }\n // now check for updates...\n if (fbo.dirtyId !== framebuffer.dirtyId) {\n fbo.dirtyId = framebuffer.dirtyId;\n if (fbo.dirtyFormat !== framebuffer.dirtyFormat) {\n fbo.dirtyFormat = framebuffer.dirtyFormat;\n fbo.dirtySize = framebuffer.dirtySize;\n this.updateFramebuffer(framebuffer, mipLevel);\n }\n else if (fbo.dirtySize !== framebuffer.dirtySize) {\n fbo.dirtySize = framebuffer.dirtySize;\n this.resizeFramebuffer(framebuffer);\n }\n }\n for (var i = 0; i < framebuffer.colorTextures.length; i++) {\n var tex = framebuffer.colorTextures[i];\n this.renderer.texture.unbind(tex.parentTextureArray || tex);\n }\n if (framebuffer.depthTexture) {\n this.renderer.texture.unbind(framebuffer.depthTexture);\n }\n if (frame) {\n var mipWidth = (frame.width >> mipLevel);\n var mipHeight = (frame.height >> mipLevel);\n var scale = mipWidth / frame.width;\n this.setViewport(frame.x * scale, frame.y * scale, mipWidth, mipHeight);\n }\n else {\n var mipWidth = (framebuffer.width >> mipLevel);\n var mipHeight = (framebuffer.height >> mipLevel);\n this.setViewport(0, 0, mipWidth, mipHeight);\n }\n }\n else {\n if (this.current) {\n this.current = null;\n gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n }\n if (frame) {\n this.setViewport(frame.x, frame.y, frame.width, frame.height);\n }\n else {\n this.setViewport(0, 0, this.renderer.width, this.renderer.height);\n }\n }\n };\n /**\n * Set the WebGLRenderingContext's viewport.\n * @param x - X position of viewport\n * @param y - Y position of viewport\n * @param width - Width of viewport\n * @param height - Height of viewport\n */\n FramebufferSystem.prototype.setViewport = function (x, y, width, height) {\n var v = this.viewport;\n x = Math.round(x);\n y = Math.round(y);\n width = Math.round(width);\n height = Math.round(height);\n if (v.width !== width || v.height !== height || v.x !== x || v.y !== y) {\n v.x = x;\n v.y = y;\n v.width = width;\n v.height = height;\n this.gl.viewport(x, y, width, height);\n }\n };\n Object.defineProperty(FramebufferSystem.prototype, \"size\", {\n /**\n * Get the size of the current width and height. Returns object with `width` and `height` values.\n * @readonly\n */\n get: function () {\n if (this.current) {\n // TODO store temp\n return { x: 0, y: 0, width: this.current.width, height: this.current.height };\n }\n return { x: 0, y: 0, width: this.renderer.width, height: this.renderer.height };\n },\n enumerable: false,\n configurable: true\n });\n /**\n * Clear the color of the context\n * @param r - Red value from 0 to 1\n * @param g - Green value from 0 to 1\n * @param b - Blue value from 0 to 1\n * @param a - Alpha value from 0 to 1\n * @param {PIXI.BUFFER_BITS} [mask=BUFFER_BITS.COLOR | BUFFER_BITS.DEPTH] - Bitwise OR of masks\n * that indicate the buffers to be cleared, by default COLOR and DEPTH buffers.\n */\n FramebufferSystem.prototype.clear = function (r, g, b, a, mask) {\n if (mask === void 0) { mask = BUFFER_BITS.COLOR | BUFFER_BITS.DEPTH; }\n var gl = this.gl;\n // TODO clear color can be set only one right?\n gl.clearColor(r, g, b, a);\n gl.clear(mask);\n };\n /**\n * Initialize framebuffer for this context\n * @protected\n * @param framebuffer\n * @returns - created GLFramebuffer\n */\n FramebufferSystem.prototype.initFramebuffer = function (framebuffer) {\n var gl = this.gl;\n var fbo = new GLFramebuffer(gl.createFramebuffer());\n fbo.multisample = this.detectSamples(framebuffer.multisample);\n framebuffer.glFramebuffers[this.CONTEXT_UID] = fbo;\n this.managedFramebuffers.push(framebuffer);\n framebuffer.disposeRunner.add(this);\n return fbo;\n };\n /**\n * Resize the framebuffer\n * @param framebuffer\n * @protected\n */\n FramebufferSystem.prototype.resizeFramebuffer = function (framebuffer) {\n var gl = this.gl;\n var fbo = framebuffer.glFramebuffers[this.CONTEXT_UID];\n if (fbo.msaaBuffer) {\n gl.bindRenderbuffer(gl.RENDERBUFFER, fbo.msaaBuffer);\n gl.renderbufferStorageMultisample(gl.RENDERBUFFER, fbo.multisample, gl.RGBA8, framebuffer.width, framebuffer.height);\n }\n if (fbo.stencil) {\n gl.bindRenderbuffer(gl.RENDERBUFFER, fbo.stencil);\n if (fbo.msaaBuffer) {\n gl.renderbufferStorageMultisample(gl.RENDERBUFFER, fbo.multisample, gl.DEPTH24_STENCIL8, framebuffer.width, framebuffer.height);\n }\n else {\n gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, framebuffer.width, framebuffer.height);\n }\n }\n var colorTextures = framebuffer.colorTextures;\n var count = colorTextures.length;\n if (!gl.drawBuffers) {\n count = Math.min(count, 1);\n }\n for (var i = 0; i < count; i++) {\n var texture = colorTextures[i];\n var parentTexture = texture.parentTextureArray || texture;\n this.renderer.texture.bind(parentTexture, 0);\n }\n if (framebuffer.depthTexture && this.writeDepthTexture) {\n this.renderer.texture.bind(framebuffer.depthTexture, 0);\n }\n };\n /**\n * Update the framebuffer\n * @param framebuffer\n * @param mipLevel\n * @protected\n */\n FramebufferSystem.prototype.updateFramebuffer = function (framebuffer, mipLevel) {\n var gl = this.gl;\n var fbo = framebuffer.glFramebuffers[this.CONTEXT_UID];\n // bind the color texture\n var colorTextures = framebuffer.colorTextures;\n var count = colorTextures.length;\n if (!gl.drawBuffers) {\n count = Math.min(count, 1);\n }\n if (fbo.multisample > 1 && this.canMultisampleFramebuffer(framebuffer)) {\n fbo.msaaBuffer = fbo.msaaBuffer || gl.createRenderbuffer();\n gl.bindRenderbuffer(gl.RENDERBUFFER, fbo.msaaBuffer);\n gl.renderbufferStorageMultisample(gl.RENDERBUFFER, fbo.multisample, gl.RGBA8, framebuffer.width, framebuffer.height);\n gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, fbo.msaaBuffer);\n }\n else if (fbo.msaaBuffer) {\n gl.deleteRenderbuffer(fbo.msaaBuffer);\n fbo.msaaBuffer = null;\n if (fbo.blitFramebuffer) {\n fbo.blitFramebuffer.dispose();\n fbo.blitFramebuffer = null;\n }\n }\n var activeTextures = [];\n for (var i = 0; i < count; i++) {\n var texture = colorTextures[i];\n var parentTexture = texture.parentTextureArray || texture;\n this.renderer.texture.bind(parentTexture, 0);\n if (i === 0 && fbo.msaaBuffer) {\n continue;\n }\n gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + i, texture.target, parentTexture._glTextures[this.CONTEXT_UID].texture, mipLevel);\n activeTextures.push(gl.COLOR_ATTACHMENT0 + i);\n }\n if (activeTextures.length > 1) {\n gl.drawBuffers(activeTextures);\n }\n if (framebuffer.depthTexture) {\n var writeDepthTexture = this.writeDepthTexture;\n if (writeDepthTexture) {\n var depthTexture = framebuffer.depthTexture;\n this.renderer.texture.bind(depthTexture, 0);\n gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, depthTexture._glTextures[this.CONTEXT_UID].texture, mipLevel);\n }\n }\n if ((framebuffer.stencil || framebuffer.depth) && !(framebuffer.depthTexture && this.writeDepthTexture)) {\n fbo.stencil = fbo.stencil || gl.createRenderbuffer();\n gl.bindRenderbuffer(gl.RENDERBUFFER, fbo.stencil);\n if (fbo.msaaBuffer) {\n gl.renderbufferStorageMultisample(gl.RENDERBUFFER, fbo.multisample, gl.DEPTH24_STENCIL8, framebuffer.width, framebuffer.height);\n }\n else {\n gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, framebuffer.width, framebuffer.height);\n }\n gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, fbo.stencil);\n }\n else if (fbo.stencil) {\n gl.deleteRenderbuffer(fbo.stencil);\n fbo.stencil = null;\n }\n };\n /**\n * Returns true if the frame buffer can be multisampled.\n * @param framebuffer\n */\n FramebufferSystem.prototype.canMultisampleFramebuffer = function (framebuffer) {\n return this.renderer.context.webGLVersion !== 1\n && framebuffer.colorTextures.length <= 1 && !framebuffer.depthTexture;\n };\n /**\n * Detects number of samples that is not more than a param but as close to it as possible\n * @param samples - number of samples\n * @returns - recommended number of samples\n */\n FramebufferSystem.prototype.detectSamples = function (samples) {\n var msaaSamples = this.msaaSamples;\n var res = MSAA_QUALITY.NONE;\n if (samples <= 1 || msaaSamples === null) {\n return res;\n }\n for (var i = 0; i < msaaSamples.length; i++) {\n if (msaaSamples[i] <= samples) {\n res = msaaSamples[i];\n break;\n }\n }\n if (res === 1) {\n res = MSAA_QUALITY.NONE;\n }\n return res;\n };\n /**\n * Only works with WebGL2\n *\n * blits framebuffer to another of the same or bigger size\n * after that target framebuffer is bound\n *\n * Fails with WebGL warning if blits multisample framebuffer to different size\n * @param framebuffer - by default it blits \"into itself\", from renderBuffer to texture.\n * @param sourcePixels - source rectangle in pixels\n * @param destPixels - dest rectangle in pixels, assumed to be the same as sourcePixels\n */\n FramebufferSystem.prototype.blit = function (framebuffer, sourcePixels, destPixels) {\n var _a = this, current = _a.current, renderer = _a.renderer, gl = _a.gl, CONTEXT_UID = _a.CONTEXT_UID;\n if (renderer.context.webGLVersion !== 2) {\n return;\n }\n if (!current) {\n return;\n }\n var fbo = current.glFramebuffers[CONTEXT_UID];\n if (!fbo) {\n return;\n }\n if (!framebuffer) {\n if (!fbo.msaaBuffer) {\n return;\n }\n var colorTexture = current.colorTextures[0];\n if (!colorTexture) {\n return;\n }\n if (!fbo.blitFramebuffer) {\n fbo.blitFramebuffer = new Framebuffer(current.width, current.height);\n fbo.blitFramebuffer.addColorTexture(0, colorTexture);\n }\n framebuffer = fbo.blitFramebuffer;\n if (framebuffer.colorTextures[0] !== colorTexture) {\n framebuffer.colorTextures[0] = colorTexture;\n framebuffer.dirtyId++;\n framebuffer.dirtyFormat++;\n }\n if (framebuffer.width !== current.width || framebuffer.height !== current.height) {\n framebuffer.width = current.width;\n framebuffer.height = current.height;\n framebuffer.dirtyId++;\n framebuffer.dirtySize++;\n }\n }\n if (!sourcePixels) {\n sourcePixels = tempRectangle;\n sourcePixels.width = current.width;\n sourcePixels.height = current.height;\n }\n if (!destPixels) {\n destPixels = sourcePixels;\n }\n var sameSize = sourcePixels.width === destPixels.width && sourcePixels.height === destPixels.height;\n this.bind(framebuffer);\n gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo.framebuffer);\n gl.blitFramebuffer(sourcePixels.left, sourcePixels.top, sourcePixels.right, sourcePixels.bottom, destPixels.left, destPixels.top, destPixels.right, destPixels.bottom, gl.COLOR_BUFFER_BIT, sameSize ? gl.NEAREST : gl.LINEAR);\n };\n /**\n * Disposes framebuffer.\n * @param framebuffer - framebuffer that has to be disposed of\n * @param contextLost - If context was lost, we suppress all delete function calls\n */\n FramebufferSystem.prototype.disposeFramebuffer = function (framebuffer, contextLost) {\n var fbo = framebuffer.glFramebuffers[this.CONTEXT_UID];\n var gl = this.gl;\n if (!fbo) {\n return;\n }\n delete framebuffer.glFramebuffers[this.CONTEXT_UID];\n var index = this.managedFramebuffers.indexOf(framebuffer);\n if (index >= 0) {\n this.managedFramebuffers.splice(index, 1);\n }\n framebuffer.disposeRunner.remove(this);\n if (!contextLost) {\n gl.deleteFramebuffer(fbo.framebuffer);\n if (fbo.msaaBuffer) {\n gl.deleteRenderbuffer(fbo.msaaBuffer);\n }\n if (fbo.stencil) {\n gl.deleteRenderbuffer(fbo.stencil);\n }\n }\n if (fbo.blitFramebuffer) {\n fbo.blitFramebuffer.dispose();\n }\n };\n /**\n * Disposes all framebuffers, but not textures bound to them.\n * @param [contextLost=false] - If context was lost, we suppress all delete function calls\n */\n FramebufferSystem.prototype.disposeAll = function (contextLost) {\n var list = this.managedFramebuffers;\n this.managedFramebuffers = [];\n for (var i = 0; i < list.length; i++) {\n this.disposeFramebuffer(list[i], contextLost);\n }\n };\n /**\n * Forcing creation of stencil buffer for current framebuffer, if it wasn't done before.\n * Used by MaskSystem, when its time to use stencil mask for Graphics element.\n *\n * Its an alternative for public lazy `framebuffer.enableStencil`, in case we need stencil without rebind.\n * @private\n */\n FramebufferSystem.prototype.forceStencil = function () {\n var framebuffer = this.current;\n if (!framebuffer) {\n return;\n }\n var fbo = framebuffer.glFramebuffers[this.CONTEXT_UID];\n if (!fbo || fbo.stencil) {\n return;\n }\n framebuffer.stencil = true;\n var w = framebuffer.width;\n var h = framebuffer.height;\n var gl = this.gl;\n var stencil = gl.createRenderbuffer();\n gl.bindRenderbuffer(gl.RENDERBUFFER, stencil);\n if (fbo.msaaBuffer) {\n gl.renderbufferStorageMultisample(gl.RENDERBUFFER, fbo.multisample, gl.DEPTH24_STENCIL8, w, h);\n }\n else {\n gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, w, h);\n }\n fbo.stencil = stencil;\n gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, stencil);\n };\n /** Resets framebuffer stored state, binds screen framebuffer. Should be called before renderTexture reset(). */\n FramebufferSystem.prototype.reset = function () {\n this.current = this.unknownFramebuffer;\n this.viewport = new Rectangle();\n };\n FramebufferSystem.prototype.destroy = function () {\n this.renderer = null;\n };\n return FramebufferSystem;\n}());\n\nvar byteSizeMap = { 5126: 4, 5123: 2, 5121: 1 };\n/**\n * System plugin to the renderer to manage geometry.\n * @memberof PIXI\n */\nvar GeometrySystem = /** @class */ (function () {\n /** @param renderer - The renderer this System works for. */\n function GeometrySystem(renderer) {\n this.renderer = renderer;\n this._activeGeometry = null;\n this._activeVao = null;\n this.hasVao = true;\n this.hasInstance = true;\n this.canUseUInt32ElementIndex = false;\n this.managedGeometries = {};\n }\n /** Sets up the renderer context and necessary buffers. */\n GeometrySystem.prototype.contextChange = function () {\n this.disposeAll(true);\n var gl = this.gl = this.renderer.gl;\n var context = this.renderer.context;\n this.CONTEXT_UID = this.renderer.CONTEXT_UID;\n // webgl2\n if (context.webGLVersion !== 2) {\n // webgl 1!\n var nativeVaoExtension_1 = this.renderer.context.extensions.vertexArrayObject;\n if (settings.PREFER_ENV === ENV.WEBGL_LEGACY) {\n nativeVaoExtension_1 = null;\n }\n if (nativeVaoExtension_1) {\n gl.createVertexArray = function () {\n return nativeVaoExtension_1.createVertexArrayOES();\n };\n gl.bindVertexArray = function (vao) {\n return nativeVaoExtension_1.bindVertexArrayOES(vao);\n };\n gl.deleteVertexArray = function (vao) {\n return nativeVaoExtension_1.deleteVertexArrayOES(vao);\n };\n }\n else {\n this.hasVao = false;\n gl.createVertexArray = function () {\n return null;\n };\n gl.bindVertexArray = function () {\n return null;\n };\n gl.deleteVertexArray = function () {\n return null;\n };\n }\n }\n if (context.webGLVersion !== 2) {\n var instanceExt_1 = gl.getExtension('ANGLE_instanced_arrays');\n if (instanceExt_1) {\n gl.vertexAttribDivisor = function (a, b) {\n return instanceExt_1.vertexAttribDivisorANGLE(a, b);\n };\n gl.drawElementsInstanced = function (a, b, c, d, e) {\n return instanceExt_1.drawElementsInstancedANGLE(a, b, c, d, e);\n };\n gl.drawArraysInstanced = function (a, b, c, d) {\n return instanceExt_1.drawArraysInstancedANGLE(a, b, c, d);\n };\n }\n else {\n this.hasInstance = false;\n }\n }\n this.canUseUInt32ElementIndex = context.webGLVersion === 2 || !!context.extensions.uint32ElementIndex;\n };\n /**\n * Binds geometry so that is can be drawn. Creating a Vao if required\n * @param geometry - Instance of geometry to bind.\n * @param shader - Instance of shader to use vao for.\n */\n GeometrySystem.prototype.bind = function (geometry, shader) {\n shader = shader || this.renderer.shader.shader;\n var gl = this.gl;\n // not sure the best way to address this..\n // currently different shaders require different VAOs for the same geometry\n // Still mulling over the best way to solve this one..\n // will likely need to modify the shader attribute locations at run time!\n var vaos = geometry.glVertexArrayObjects[this.CONTEXT_UID];\n var incRefCount = false;\n if (!vaos) {\n this.managedGeometries[geometry.id] = geometry;\n geometry.disposeRunner.add(this);\n geometry.glVertexArrayObjects[this.CONTEXT_UID] = vaos = {};\n incRefCount = true;\n }\n var vao = vaos[shader.program.id] || this.initGeometryVao(geometry, shader, incRefCount);\n this._activeGeometry = geometry;\n if (this._activeVao !== vao) {\n this._activeVao = vao;\n if (this.hasVao) {\n gl.bindVertexArray(vao);\n }\n else {\n this.activateVao(geometry, shader.program);\n }\n }\n // TODO - optimise later!\n // don't need to loop through if nothing changed!\n // maybe look to add an 'autoupdate' to geometry?\n this.updateBuffers();\n };\n /** Reset and unbind any active VAO and geometry. */\n GeometrySystem.prototype.reset = function () {\n this.unbind();\n };\n /** Update buffers of the currently bound geometry. */\n GeometrySystem.prototype.updateBuffers = function () {\n var geometry = this._activeGeometry;\n var bufferSystem = this.renderer.buffer;\n for (var i = 0; i < geometry.buffers.length; i++) {\n var buffer = geometry.buffers[i];\n bufferSystem.update(buffer);\n }\n };\n /**\n * Check compatibility between a geometry and a program\n * @param geometry - Geometry instance.\n * @param program - Program instance.\n */\n GeometrySystem.prototype.checkCompatibility = function (geometry, program) {\n // geometry must have at least all the attributes that the shader requires.\n var geometryAttributes = geometry.attributes;\n var shaderAttributes = program.attributeData;\n for (var j in shaderAttributes) {\n if (!geometryAttributes[j]) {\n throw new Error(\"shader and geometry incompatible, geometry missing the \\\"\" + j + \"\\\" attribute\");\n }\n }\n };\n /**\n * Takes a geometry and program and generates a unique signature for them.\n * @param geometry - To get signature from.\n * @param program - To test geometry against.\n * @returns - Unique signature of the geometry and program\n */\n GeometrySystem.prototype.getSignature = function (geometry, program) {\n var attribs = geometry.attributes;\n var shaderAttributes = program.attributeData;\n var strings = ['g', geometry.id];\n for (var i in attribs) {\n if (shaderAttributes[i]) {\n strings.push(i, shaderAttributes[i].location);\n }\n }\n return strings.join('-');\n };\n /**\n * Creates or gets Vao with the same structure as the geometry and stores it on the geometry.\n * If vao is created, it is bound automatically. We use a shader to infer what and how to set up the\n * attribute locations.\n * @param geometry - Instance of geometry to to generate Vao for.\n * @param shader - Instance of the shader.\n * @param incRefCount - Increment refCount of all geometry buffers.\n */\n GeometrySystem.prototype.initGeometryVao = function (geometry, shader, incRefCount) {\n if (incRefCount === void 0) { incRefCount = true; }\n var gl = this.gl;\n var CONTEXT_UID = this.CONTEXT_UID;\n var bufferSystem = this.renderer.buffer;\n var program = shader.program;\n if (!program.glPrograms[CONTEXT_UID]) {\n this.renderer.shader.generateProgram(shader);\n }\n this.checkCompatibility(geometry, program);\n var signature = this.getSignature(geometry, program);\n var vaoObjectHash = geometry.glVertexArrayObjects[this.CONTEXT_UID];\n var vao = vaoObjectHash[signature];\n if (vao) {\n // this will give us easy access to the vao\n vaoObjectHash[program.id] = vao;\n return vao;\n }\n var buffers = geometry.buffers;\n var attributes = geometry.attributes;\n var tempStride = {};\n var tempStart = {};\n for (var j in buffers) {\n tempStride[j] = 0;\n tempStart[j] = 0;\n }\n for (var j in attributes) {\n if (!attributes[j].size && program.attributeData[j]) {\n attributes[j].size = program.attributeData[j].size;\n }\n else if (!attributes[j].size) {\n console.warn(\"PIXI Geometry attribute '\" + j + \"' size cannot be determined (likely the bound shader does not have the attribute)\"); // eslint-disable-line\n }\n tempStride[attributes[j].buffer] += attributes[j].size * byteSizeMap[attributes[j].type];\n }\n for (var j in attributes) {\n var attribute = attributes[j];\n var attribSize = attribute.size;\n if (attribute.stride === undefined) {\n if (tempStride[attribute.buffer] === attribSize * byteSizeMap[attribute.type]) {\n attribute.stride = 0;\n }\n else {\n attribute.stride = tempStride[attribute.buffer];\n }\n }\n if (attribute.start === undefined) {\n attribute.start = tempStart[attribute.buffer];\n tempStart[attribute.buffer] += attribSize * byteSizeMap[attribute.type];\n }\n }\n vao = gl.createVertexArray();\n gl.bindVertexArray(vao);\n // first update - and create the buffers!\n // only create a gl buffer if it actually gets\n for (var i = 0; i < buffers.length; i++) {\n var buffer = buffers[i];\n bufferSystem.bind(buffer);\n if (incRefCount) {\n buffer._glBuffers[CONTEXT_UID].refCount++;\n }\n }\n // TODO - maybe make this a data object?\n // lets wait to see if we need to first!\n this.activateVao(geometry, program);\n this._activeVao = vao;\n // add it to the cache!\n vaoObjectHash[program.id] = vao;\n vaoObjectHash[signature] = vao;\n return vao;\n };\n /**\n * Disposes geometry.\n * @param geometry - Geometry with buffers. Only VAO will be disposed\n * @param [contextLost=false] - If context was lost, we suppress deleteVertexArray\n */\n GeometrySystem.prototype.disposeGeometry = function (geometry, contextLost) {\n var _a;\n if (!this.managedGeometries[geometry.id]) {\n return;\n }\n delete this.managedGeometries[geometry.id];\n var vaos = geometry.glVertexArrayObjects[this.CONTEXT_UID];\n var gl = this.gl;\n var buffers = geometry.buffers;\n var bufferSystem = (_a = this.renderer) === null || _a === void 0 ? void 0 : _a.buffer;\n geometry.disposeRunner.remove(this);\n if (!vaos) {\n return;\n }\n // bufferSystem may have already been destroyed..\n // if this is the case, there is no need to destroy the geometry buffers...\n // they already have been!\n if (bufferSystem) {\n for (var i = 0; i < buffers.length; i++) {\n var buf = buffers[i]._glBuffers[this.CONTEXT_UID];\n // my be null as context may have changed right before the dispose is called\n if (buf) {\n buf.refCount--;\n if (buf.refCount === 0 && !contextLost) {\n bufferSystem.dispose(buffers[i], contextLost);\n }\n }\n }\n }\n if (!contextLost) {\n for (var vaoId in vaos) {\n // delete only signatures, everything else are copies\n if (vaoId[0] === 'g') {\n var vao = vaos[vaoId];\n if (this._activeVao === vao) {\n this.unbind();\n }\n gl.deleteVertexArray(vao);\n }\n }\n }\n delete geometry.glVertexArrayObjects[this.CONTEXT_UID];\n };\n /**\n * Dispose all WebGL resources of all managed geometries.\n * @param [contextLost=false] - If context was lost, we suppress `gl.delete` calls\n */\n GeometrySystem.prototype.disposeAll = function (contextLost) {\n var all = Object.keys(this.managedGeometries);\n for (var i = 0; i < all.length; i++) {\n this.disposeGeometry(this.managedGeometries[all[i]], contextLost);\n }\n };\n /**\n * Activate vertex array object.\n * @param geometry - Geometry instance.\n * @param program - Shader program instance.\n */\n GeometrySystem.prototype.activateVao = function (geometry, program) {\n var gl = this.gl;\n var CONTEXT_UID = this.CONTEXT_UID;\n var bufferSystem = this.renderer.buffer;\n var buffers = geometry.buffers;\n var attributes = geometry.attributes;\n if (geometry.indexBuffer) {\n // first update the index buffer if we have one..\n bufferSystem.bind(geometry.indexBuffer);\n }\n var lastBuffer = null;\n // add a new one!\n for (var j in attributes) {\n var attribute = attributes[j];\n var buffer = buffers[attribute.buffer];\n var glBuffer = buffer._glBuffers[CONTEXT_UID];\n if (program.attributeData[j]) {\n if (lastBuffer !== glBuffer) {\n bufferSystem.bind(buffer);\n lastBuffer = glBuffer;\n }\n var location = program.attributeData[j].location;\n // TODO introduce state again\n // we can optimise this for older devices that have no VAOs\n gl.enableVertexAttribArray(location);\n gl.vertexAttribPointer(location, attribute.size, attribute.type || gl.FLOAT, attribute.normalized, attribute.stride, attribute.start);\n if (attribute.instance) {\n // TODO calculate instance count based of this...\n if (this.hasInstance) {\n gl.vertexAttribDivisor(location, 1);\n }\n else {\n throw new Error('geometry error, GPU Instancing is not supported on this device');\n }\n }\n }\n }\n };\n /**\n * Draws the currently bound geometry.\n * @param type - The type primitive to render.\n * @param size - The number of elements to be rendered. If not specified, all vertices after the\n * starting vertex will be drawn.\n * @param start - The starting vertex in the geometry to start drawing from. If not specified,\n * drawing will start from the first vertex.\n * @param instanceCount - The number of instances of the set of elements to execute. If not specified,\n * all instances will be drawn.\n */\n GeometrySystem.prototype.draw = function (type, size, start, instanceCount) {\n var gl = this.gl;\n var geometry = this._activeGeometry;\n // TODO.. this should not change so maybe cache the function?\n if (geometry.indexBuffer) {\n var byteSize = geometry.indexBuffer.data.BYTES_PER_ELEMENT;\n var glType = byteSize === 2 ? gl.UNSIGNED_SHORT : gl.UNSIGNED_INT;\n if (byteSize === 2 || (byteSize === 4 && this.canUseUInt32ElementIndex)) {\n if (geometry.instanced) {\n /* eslint-disable max-len */\n gl.drawElementsInstanced(type, size || geometry.indexBuffer.data.length, glType, (start || 0) * byteSize, instanceCount || 1);\n /* eslint-enable max-len */\n }\n else {\n /* eslint-disable max-len */\n gl.drawElements(type, size || geometry.indexBuffer.data.length, glType, (start || 0) * byteSize);\n /* eslint-enable max-len */\n }\n }\n else {\n console.warn('unsupported index buffer type: uint32');\n }\n }\n else if (geometry.instanced) {\n // TODO need a better way to calculate size..\n gl.drawArraysInstanced(type, start, size || geometry.getSize(), instanceCount || 1);\n }\n else {\n gl.drawArrays(type, start, size || geometry.getSize());\n }\n return this;\n };\n /** Unbind/reset everything. */\n GeometrySystem.prototype.unbind = function () {\n this.gl.bindVertexArray(null);\n this._activeVao = null;\n this._activeGeometry = null;\n };\n GeometrySystem.prototype.destroy = function () {\n this.renderer = null;\n };\n return GeometrySystem;\n}());\n\n/**\n * Component for masked elements.\n *\n * Holds mask mode and temporary data about current mask.\n * @memberof PIXI\n */\nvar MaskData = /** @class */ (function () {\n /**\n * Create MaskData\n * @param {PIXI.DisplayObject} [maskObject=null] - object that describes the mask\n */\n function MaskData(maskObject) {\n if (maskObject === void 0) { maskObject = null; }\n this.type = MASK_TYPES.NONE;\n this.autoDetect = true;\n this.maskObject = maskObject || null;\n this.pooled = false;\n this.isMaskData = true;\n this.resolution = null;\n this.multisample = settings.FILTER_MULTISAMPLE;\n this.enabled = true;\n this.colorMask = 0xf;\n this._filters = null;\n this._stencilCounter = 0;\n this._scissorCounter = 0;\n this._scissorRect = null;\n this._scissorRectLocal = null;\n this._colorMask = 0xf;\n this._target = null;\n }\n Object.defineProperty(MaskData.prototype, \"filter\", {\n /**\n * The sprite mask filter.\n * If set to `null`, the default sprite mask filter is used.\n * @default null\n */\n get: function () {\n return this._filters ? this._filters[0] : null;\n },\n set: function (value) {\n if (value) {\n if (this._filters) {\n this._filters[0] = value;\n }\n else {\n this._filters = [value];\n }\n }\n else {\n this._filters = null;\n }\n },\n enumerable: false,\n configurable: true\n });\n /** Resets the mask data after popMask(). */\n MaskData.prototype.reset = function () {\n if (this.pooled) {\n this.maskObject = null;\n this.type = MASK_TYPES.NONE;\n this.autoDetect = true;\n }\n this._target = null;\n this._scissorRectLocal = null;\n };\n /**\n * Copies counters from maskData above, called from pushMask().\n * @param maskAbove\n */\n MaskData.prototype.copyCountersOrReset = function (maskAbove) {\n if (maskAbove) {\n this._stencilCounter = maskAbove._stencilCounter;\n this._scissorCounter = maskAbove._scissorCounter;\n this._scissorRect = maskAbove._scissorRect;\n }\n else {\n this._stencilCounter = 0;\n this._scissorCounter = 0;\n this._scissorRect = null;\n }\n };\n return MaskData;\n}());\n\n/**\n * @private\n * @param {WebGLRenderingContext} gl - The current WebGL context {WebGLProgram}\n * @param {number} type - the type, can be either VERTEX_SHADER or FRAGMENT_SHADER\n * @param {string} src - The vertex shader source as an array of strings.\n * @returns {WebGLShader} the shader\n */\nfunction compileShader(gl, type, src) {\n var shader = gl.createShader(type);\n gl.shaderSource(shader, src);\n gl.compileShader(shader);\n return shader;\n}\n\n/**\n * will log a shader error highlighting the lines with the error\n * also will add numbers along the side.\n * @param gl - the WebGLContext\n * @param shader - the shader to log errors for\n */\nfunction logPrettyShaderError(gl, shader) {\n var shaderSrc = gl.getShaderSource(shader)\n .split('\\n')\n .map(function (line, index) { return index + \": \" + line; });\n var shaderLog = gl.getShaderInfoLog(shader);\n var splitShader = shaderLog.split('\\n');\n var dedupe = {};\n var lineNumbers = splitShader.map(function (line) { return parseFloat(line.replace(/^ERROR\\: 0\\:([\\d]+)\\:.*$/, '$1')); })\n .filter(function (n) {\n if (n && !dedupe[n]) {\n dedupe[n] = true;\n return true;\n }\n return false;\n });\n var logArgs = [''];\n lineNumbers.forEach(function (number) {\n shaderSrc[number - 1] = \"%c\" + shaderSrc[number - 1] + \"%c\";\n logArgs.push('background: #FF0000; color:#FFFFFF; font-size: 10px', 'font-size: 10px');\n });\n var fragmentSourceToLog = shaderSrc\n .join('\\n');\n logArgs[0] = fragmentSourceToLog;\n console.error(shaderLog);\n // eslint-disable-next-line no-console\n console.groupCollapsed('click to view full shader code');\n console.warn.apply(console, logArgs);\n // eslint-disable-next-line no-console\n console.groupEnd();\n}\n/**\n *\n * logs out any program errors\n * @param gl - The current WebGL context\n * @param program - the WebGL program to display errors for\n * @param vertexShader - the fragment WebGL shader program\n * @param fragmentShader - the vertex WebGL shader program\n */\nfunction logProgramError(gl, program, vertexShader, fragmentShader) {\n // if linking fails, then log and cleanup\n if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {\n logPrettyShaderError(gl, vertexShader);\n }\n if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {\n logPrettyShaderError(gl, fragmentShader);\n }\n console.error('PixiJS Error: Could not initialize shader.');\n // if there is a program info log, log it\n if (gl.getProgramInfoLog(program) !== '') {\n console.warn('PixiJS Warning: gl.getProgramInfoLog()', gl.getProgramInfoLog(program));\n }\n }\n}\n\nfunction booleanArray(size) {\n var array = new Array(size);\n for (var i = 0; i < array.length; i++) {\n array[i] = false;\n }\n return array;\n}\n/**\n * @method defaultValue\n * @memberof PIXI.glCore.shader\n * @param {string} type - Type of value\n * @param {number} size\n * @private\n */\nfunction defaultValue(type, size) {\n switch (type) {\n case 'float':\n return 0;\n case 'vec2':\n return new Float32Array(2 * size);\n case 'vec3':\n return new Float32Array(3 * size);\n case 'vec4':\n return new Float32Array(4 * size);\n case 'int':\n case 'uint':\n case 'sampler2D':\n case 'sampler2DArray':\n return 0;\n case 'ivec2':\n return new Int32Array(2 * size);\n case 'ivec3':\n return new Int32Array(3 * size);\n case 'ivec4':\n return new Int32Array(4 * size);\n case 'uvec2':\n return new Uint32Array(2 * size);\n case 'uvec3':\n return new Uint32Array(3 * size);\n case 'uvec4':\n return new Uint32Array(4 * size);\n case 'bool':\n return false;\n case 'bvec2':\n return booleanArray(2 * size);\n case 'bvec3':\n return booleanArray(3 * size);\n case 'bvec4':\n return booleanArray(4 * size);\n case 'mat2':\n return new Float32Array([1, 0,\n 0, 1]);\n case 'mat3':\n return new Float32Array([1, 0, 0,\n 0, 1, 0,\n 0, 0, 1]);\n case 'mat4':\n return new Float32Array([1, 0, 0, 0,\n 0, 1, 0, 0,\n 0, 0, 1, 0,\n 0, 0, 0, 1]);\n }\n return null;\n}\n\nvar unknownContext = {};\nvar context = unknownContext;\n/**\n * returns a little WebGL context to use for program inspection.\n * @static\n * @private\n * @returns {WebGLRenderingContext} a gl context to test with\n */\nfunction getTestContext() {\n if (context === unknownContext || (context && context.isContextLost())) {\n var canvas = settings.ADAPTER.createCanvas();\n var gl = void 0;\n if (settings.PREFER_ENV >= ENV.WEBGL2) {\n gl = canvas.getContext('webgl2', {});\n }\n if (!gl) {\n gl = (canvas.getContext('webgl', {})\n || canvas.getContext('experimental-webgl', {}));\n if (!gl) {\n // fail, not able to get a context\n gl = null;\n }\n else {\n // for shader testing..\n gl.getExtension('WEBGL_draw_buffers');\n }\n }\n context = gl;\n }\n return context;\n}\n\nvar maxFragmentPrecision;\nfunction getMaxFragmentPrecision() {\n if (!maxFragmentPrecision) {\n maxFragmentPrecision = PRECISION.MEDIUM;\n var gl = getTestContext();\n if (gl) {\n if (gl.getShaderPrecisionFormat) {\n var shaderFragment = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT);\n maxFragmentPrecision = shaderFragment.precision ? PRECISION.HIGH : PRECISION.MEDIUM;\n }\n }\n }\n return maxFragmentPrecision;\n}\n\n/**\n * Sets the float precision on the shader, ensuring the device supports the request precision.\n * If the precision is already present, it just ensures that the device is able to handle it.\n * @private\n * @param {string} src - The shader source\n * @param {PIXI.PRECISION} requestedPrecision - The request float precision of the shader.\n * @param {PIXI.PRECISION} maxSupportedPrecision - The maximum precision the shader supports.\n * @returns {string} modified shader source\n */\nfunction setPrecision(src, requestedPrecision, maxSupportedPrecision) {\n if (src.substring(0, 9) !== 'precision') {\n // no precision supplied, so PixiJS will add the requested level.\n var precision = requestedPrecision;\n // If highp is requested but not supported, downgrade precision to a level all devices support.\n if (requestedPrecision === PRECISION.HIGH && maxSupportedPrecision !== PRECISION.HIGH) {\n precision = PRECISION.MEDIUM;\n }\n return \"precision \" + precision + \" float;\\n\" + src;\n }\n else if (maxSupportedPrecision !== PRECISION.HIGH && src.substring(0, 15) === 'precision highp') {\n // precision was supplied, but at a level this device does not support, so downgrading to mediump.\n return src.replace('precision highp', 'precision mediump');\n }\n return src;\n}\n\nvar GLSL_TO_SIZE = {\n float: 1,\n vec2: 2,\n vec3: 3,\n vec4: 4,\n int: 1,\n ivec2: 2,\n ivec3: 3,\n ivec4: 4,\n uint: 1,\n uvec2: 2,\n uvec3: 3,\n uvec4: 4,\n bool: 1,\n bvec2: 2,\n bvec3: 3,\n bvec4: 4,\n mat2: 4,\n mat3: 9,\n mat4: 16,\n sampler2D: 1,\n};\n/**\n * @private\n * @method mapSize\n * @memberof PIXI.glCore.shader\n * @param {string} type\n */\nfunction mapSize(type) {\n return GLSL_TO_SIZE[type];\n}\n\nvar GL_TABLE = null;\nvar GL_TO_GLSL_TYPES = {\n FLOAT: 'float',\n FLOAT_VEC2: 'vec2',\n FLOAT_VEC3: 'vec3',\n FLOAT_VEC4: 'vec4',\n INT: 'int',\n INT_VEC2: 'ivec2',\n INT_VEC3: 'ivec3',\n INT_VEC4: 'ivec4',\n UNSIGNED_INT: 'uint',\n UNSIGNED_INT_VEC2: 'uvec2',\n UNSIGNED_INT_VEC3: 'uvec3',\n UNSIGNED_INT_VEC4: 'uvec4',\n BOOL: 'bool',\n BOOL_VEC2: 'bvec2',\n BOOL_VEC3: 'bvec3',\n BOOL_VEC4: 'bvec4',\n FLOAT_MAT2: 'mat2',\n FLOAT_MAT3: 'mat3',\n FLOAT_MAT4: 'mat4',\n SAMPLER_2D: 'sampler2D',\n INT_SAMPLER_2D: 'sampler2D',\n UNSIGNED_INT_SAMPLER_2D: 'sampler2D',\n SAMPLER_CUBE: 'samplerCube',\n INT_SAMPLER_CUBE: 'samplerCube',\n UNSIGNED_INT_SAMPLER_CUBE: 'samplerCube',\n SAMPLER_2D_ARRAY: 'sampler2DArray',\n INT_SAMPLER_2D_ARRAY: 'sampler2DArray',\n UNSIGNED_INT_SAMPLER_2D_ARRAY: 'sampler2DArray',\n};\n// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types\nfunction mapType(gl, type) {\n if (!GL_TABLE) {\n var typeNames = Object.keys(GL_TO_GLSL_TYPES);\n GL_TABLE = {};\n for (var i = 0; i < typeNames.length; ++i) {\n var tn = typeNames[i];\n GL_TABLE[gl[tn]] = GL_TO_GLSL_TYPES[tn];\n }\n }\n return GL_TABLE[type];\n}\n\n/* eslint-disable @typescript-eslint/explicit-module-boundary-types */\n// Parsers, each one of these will take a look at the type of shader property and uniform.\n// if they pass the test function then the code function is called that returns a the shader upload code for that uniform.\n// Shader upload code is automagically generated with these parsers.\n// If no parser is valid then the default upload functions are used.\n// exposing Parsers means that custom upload logic can be added to pixi's shaders.\n// A good example would be a pixi rectangle can be directly set on a uniform.\n// If the shader sees it it knows how to upload the rectangle structure as a vec4\n// format is as follows:\n//\n// {\n// test: (data, uniform) => {} <--- test is this code should be used for this uniform\n// code: (name, uniform) => {} <--- returns the string of the piece of code that uploads the uniform\n// codeUbo: (name, uniform) => {} <--- returns the string of the piece of code that uploads the\n// uniform to a uniform buffer\n// }\nvar uniformParsers = [\n // a float cache layer\n {\n test: function (data) {\n return data.type === 'float' && data.size === 1 && !data.isArray;\n },\n code: function (name) {\n return \"\\n if(uv[\\\"\" + name + \"\\\"] !== ud[\\\"\" + name + \"\\\"].value)\\n {\\n ud[\\\"\" + name + \"\\\"].value = uv[\\\"\" + name + \"\\\"]\\n gl.uniform1f(ud[\\\"\" + name + \"\\\"].location, uv[\\\"\" + name + \"\\\"])\\n }\\n \";\n },\n },\n // handling samplers\n {\n test: function (data, uniform) {\n // eslint-disable-next-line max-len,no-eq-null,eqeqeq\n return (data.type === 'sampler2D' || data.type === 'samplerCube' || data.type === 'sampler2DArray') && data.size === 1 && !data.isArray && (uniform == null || uniform.castToBaseTexture !== undefined);\n },\n code: function (name) { return \"t = syncData.textureCount++;\\n\\n renderer.texture.bind(uv[\\\"\" + name + \"\\\"], t);\\n\\n if(ud[\\\"\" + name + \"\\\"].value !== t)\\n {\\n ud[\\\"\" + name + \"\\\"].value = t;\\n gl.uniform1i(ud[\\\"\" + name + \"\\\"].location, t);\\n; // eslint-disable-line max-len\\n }\"; },\n },\n // uploading pixi matrix object to mat3\n {\n test: function (data, uniform) {\n return data.type === 'mat3' && data.size === 1 && !data.isArray && uniform.a !== undefined;\n },\n code: function (name) {\n // TODO and some smart caching dirty ids here!\n return \"\\n gl.uniformMatrix3fv(ud[\\\"\" + name + \"\\\"].location, false, uv[\\\"\" + name + \"\\\"].toArray(true));\\n \";\n },\n codeUbo: function (name) {\n return \"\\n var \" + name + \"_matrix = uv.\" + name + \".toArray(true);\\n\\n data[offset] = \" + name + \"_matrix[0];\\n data[offset+1] = \" + name + \"_matrix[1];\\n data[offset+2] = \" + name + \"_matrix[2];\\n \\n data[offset + 4] = \" + name + \"_matrix[3];\\n data[offset + 5] = \" + name + \"_matrix[4];\\n data[offset + 6] = \" + name + \"_matrix[5];\\n \\n data[offset + 8] = \" + name + \"_matrix[6];\\n data[offset + 9] = \" + name + \"_matrix[7];\\n data[offset + 10] = \" + name + \"_matrix[8];\\n \";\n },\n },\n // uploading a pixi point as a vec2 with caching layer\n {\n test: function (data, uniform) {\n return data.type === 'vec2' && data.size === 1 && !data.isArray && uniform.x !== undefined;\n },\n code: function (name) {\n return \"\\n cv = ud[\\\"\" + name + \"\\\"].value;\\n v = uv[\\\"\" + name + \"\\\"];\\n\\n if(cv[0] !== v.x || cv[1] !== v.y)\\n {\\n cv[0] = v.x;\\n cv[1] = v.y;\\n gl.uniform2f(ud[\\\"\" + name + \"\\\"].location, v.x, v.y);\\n }\";\n },\n codeUbo: function (name) {\n return \"\\n v = uv.\" + name + \";\\n\\n data[offset] = v.x;\\n data[offset+1] = v.y;\\n \";\n }\n },\n // caching layer for a vec2\n {\n test: function (data) {\n return data.type === 'vec2' && data.size === 1 && !data.isArray;\n },\n code: function (name) {\n return \"\\n cv = ud[\\\"\" + name + \"\\\"].value;\\n v = uv[\\\"\" + name + \"\\\"];\\n\\n if(cv[0] !== v[0] || cv[1] !== v[1])\\n {\\n cv[0] = v[0];\\n cv[1] = v[1];\\n gl.uniform2f(ud[\\\"\" + name + \"\\\"].location, v[0], v[1]);\\n }\\n \";\n },\n },\n // upload a pixi rectangle as a vec4 with caching layer\n {\n test: function (data, uniform) {\n return data.type === 'vec4' && data.size === 1 && !data.isArray && uniform.width !== undefined;\n },\n code: function (name) {\n return \"\\n cv = ud[\\\"\" + name + \"\\\"].value;\\n v = uv[\\\"\" + name + \"\\\"];\\n\\n if(cv[0] !== v.x || cv[1] !== v.y || cv[2] !== v.width || cv[3] !== v.height)\\n {\\n cv[0] = v.x;\\n cv[1] = v.y;\\n cv[2] = v.width;\\n cv[3] = v.height;\\n gl.uniform4f(ud[\\\"\" + name + \"\\\"].location, v.x, v.y, v.width, v.height)\\n }\";\n },\n codeUbo: function (name) {\n return \"\\n v = uv.\" + name + \";\\n\\n data[offset] = v.x;\\n data[offset+1] = v.y;\\n data[offset+2] = v.width;\\n data[offset+3] = v.height;\\n \";\n }\n },\n // a caching layer for vec4 uploading\n {\n test: function (data) {\n return data.type === 'vec4' && data.size === 1 && !data.isArray;\n },\n code: function (name) {\n return \"\\n cv = ud[\\\"\" + name + \"\\\"].value;\\n v = uv[\\\"\" + name + \"\\\"];\\n\\n if(cv[0] !== v[0] || cv[1] !== v[1] || cv[2] !== v[2] || cv[3] !== v[3])\\n {\\n cv[0] = v[0];\\n cv[1] = v[1];\\n cv[2] = v[2];\\n cv[3] = v[3];\\n\\n gl.uniform4f(ud[\\\"\" + name + \"\\\"].location, v[0], v[1], v[2], v[3])\\n }\";\n },\n } ];\n\n// cu = Cached value's uniform data field\n// cv = Cached value\n// v = value to upload\n// ud = uniformData\n// uv = uniformValue\n// l = location\nvar GLSL_TO_SINGLE_SETTERS_CACHED = {\n float: \"\\n if (cv !== v)\\n {\\n cu.value = v;\\n gl.uniform1f(location, v);\\n }\",\n vec2: \"\\n if (cv[0] !== v[0] || cv[1] !== v[1])\\n {\\n cv[0] = v[0];\\n cv[1] = v[1];\\n\\n gl.uniform2f(location, v[0], v[1])\\n }\",\n vec3: \"\\n if (cv[0] !== v[0] || cv[1] !== v[1] || cv[2] !== v[2])\\n {\\n cv[0] = v[0];\\n cv[1] = v[1];\\n cv[2] = v[2];\\n\\n gl.uniform3f(location, v[0], v[1], v[2])\\n }\",\n vec4: \"\\n if (cv[0] !== v[0] || cv[1] !== v[1] || cv[2] !== v[2] || cv[3] !== v[3])\\n {\\n cv[0] = v[0];\\n cv[1] = v[1];\\n cv[2] = v[2];\\n cv[3] = v[3];\\n\\n gl.uniform4f(location, v[0], v[1], v[2], v[3]);\\n }\",\n int: \"\\n if (cv !== v)\\n {\\n cu.value = v;\\n\\n gl.uniform1i(location, v);\\n }\",\n ivec2: \"\\n if (cv[0] !== v[0] || cv[1] !== v[1])\\n {\\n cv[0] = v[0];\\n cv[1] = v[1];\\n\\n gl.uniform2i(location, v[0], v[1]);\\n }\",\n ivec3: \"\\n if (cv[0] !== v[0] || cv[1] !== v[1] || cv[2] !== v[2])\\n {\\n cv[0] = v[0];\\n cv[1] = v[1];\\n cv[2] = v[2];\\n\\n gl.uniform3i(location, v[0], v[1], v[2]);\\n }\",\n ivec4: \"\\n if (cv[0] !== v[0] || cv[1] !== v[1] || cv[2] !== v[2] || cv[3] !== v[3])\\n {\\n cv[0] = v[0];\\n cv[1] = v[1];\\n cv[2] = v[2];\\n cv[3] = v[3];\\n\\n gl.uniform4i(location, v[0], v[1], v[2], v[3]);\\n }\",\n uint: \"\\n if (cv !== v)\\n {\\n cu.value = v;\\n\\n gl.uniform1ui(location, v);\\n }\",\n uvec2: \"\\n if (cv[0] !== v[0] || cv[1] !== v[1])\\n {\\n cv[0] = v[0];\\n cv[1] = v[1];\\n\\n gl.uniform2ui(location, v[0], v[1]);\\n }\",\n uvec3: \"\\n if (cv[0] !== v[0] || cv[1] !== v[1] || cv[2] !== v[2])\\n {\\n cv[0] = v[0];\\n cv[1] = v[1];\\n cv[2] = v[2];\\n\\n gl.uniform3ui(location, v[0], v[1], v[2]);\\n }\",\n uvec4: \"\\n if (cv[0] !== v[0] || cv[1] !== v[1] || cv[2] !== v[2] || cv[3] !== v[3])\\n {\\n cv[0] = v[0];\\n cv[1] = v[1];\\n cv[2] = v[2];\\n cv[3] = v[3];\\n\\n gl.uniform4ui(location, v[0], v[1], v[2], v[3]);\\n }\",\n bool: \"\\n if (cv !== v)\\n {\\n cu.value = v;\\n gl.uniform1i(location, v);\\n }\",\n bvec2: \"\\n if (cv[0] != v[0] || cv[1] != v[1])\\n {\\n cv[0] = v[0];\\n cv[1] = v[1];\\n\\n gl.uniform2i(location, v[0], v[1]);\\n }\",\n bvec3: \"\\n if (cv[0] !== v[0] || cv[1] !== v[1] || cv[2] !== v[2])\\n {\\n cv[0] = v[0];\\n cv[1] = v[1];\\n cv[2] = v[2];\\n\\n gl.uniform3i(location, v[0], v[1], v[2]);\\n }\",\n bvec4: \"\\n if (cv[0] !== v[0] || cv[1] !== v[1] || cv[2] !== v[2] || cv[3] !== v[3])\\n {\\n cv[0] = v[0];\\n cv[1] = v[1];\\n cv[2] = v[2];\\n cv[3] = v[3];\\n\\n gl.uniform4i(location, v[0], v[1], v[2], v[3]);\\n }\",\n mat2: 'gl.uniformMatrix2fv(location, false, v)',\n mat3: 'gl.uniformMatrix3fv(location, false, v)',\n mat4: 'gl.uniformMatrix4fv(location, false, v)',\n sampler2D: \"\\n if (cv !== v)\\n {\\n cu.value = v;\\n\\n gl.uniform1i(location, v);\\n }\",\n samplerCube: \"\\n if (cv !== v)\\n {\\n cu.value = v;\\n\\n gl.uniform1i(location, v);\\n }\",\n sampler2DArray: \"\\n if (cv !== v)\\n {\\n cu.value = v;\\n\\n gl.uniform1i(location, v);\\n }\",\n};\nvar GLSL_TO_ARRAY_SETTERS = {\n float: \"gl.uniform1fv(location, v)\",\n vec2: \"gl.uniform2fv(location, v)\",\n vec3: \"gl.uniform3fv(location, v)\",\n vec4: 'gl.uniform4fv(location, v)',\n mat4: 'gl.uniformMatrix4fv(location, false, v)',\n mat3: 'gl.uniformMatrix3fv(location, false, v)',\n mat2: 'gl.uniformMatrix2fv(location, false, v)',\n int: 'gl.uniform1iv(location, v)',\n ivec2: 'gl.uniform2iv(location, v)',\n ivec3: 'gl.uniform3iv(location, v)',\n ivec4: 'gl.uniform4iv(location, v)',\n uint: 'gl.uniform1uiv(location, v)',\n uvec2: 'gl.uniform2uiv(location, v)',\n uvec3: 'gl.uniform3uiv(location, v)',\n uvec4: 'gl.uniform4uiv(location, v)',\n bool: 'gl.uniform1iv(location, v)',\n bvec2: 'gl.uniform2iv(location, v)',\n bvec3: 'gl.uniform3iv(location, v)',\n bvec4: 'gl.uniform4iv(location, v)',\n sampler2D: 'gl.uniform1iv(location, v)',\n samplerCube: 'gl.uniform1iv(location, v)',\n sampler2DArray: 'gl.uniform1iv(location, v)',\n};\nfunction generateUniformsSync(group, uniformData) {\n var _a;\n var funcFragments = [\"\\n var v = null;\\n var cv = null;\\n var cu = null;\\n var t = 0;\\n var gl = renderer.gl;\\n \"];\n for (var i in group.uniforms) {\n var data = uniformData[i];\n if (!data) {\n if ((_a = group.uniforms[i]) === null || _a === void 0 ? void 0 : _a.group) {\n if (group.uniforms[i].ubo) {\n funcFragments.push(\"\\n renderer.shader.syncUniformBufferGroup(uv.\" + i + \", '\" + i + \"');\\n \");\n }\n else {\n funcFragments.push(\"\\n renderer.shader.syncUniformGroup(uv.\" + i + \", syncData);\\n \");\n }\n }\n continue;\n }\n var uniform = group.uniforms[i];\n var parsed = false;\n for (var j = 0; j < uniformParsers.length; j++) {\n if (uniformParsers[j].test(data, uniform)) {\n funcFragments.push(uniformParsers[j].code(i, uniform));\n parsed = true;\n break;\n }\n }\n if (!parsed) {\n var templateType = data.size === 1 && !data.isArray ? GLSL_TO_SINGLE_SETTERS_CACHED : GLSL_TO_ARRAY_SETTERS;\n var template = templateType[data.type].replace('location', \"ud[\\\"\" + i + \"\\\"].location\");\n funcFragments.push(\"\\n cu = ud[\\\"\" + i + \"\\\"];\\n cv = cu.value;\\n v = uv[\\\"\" + i + \"\\\"];\\n \" + template + \";\");\n }\n }\n /*\n * the introduction of syncData is to solve an issue where textures in uniform groups are not set correctly\n * the texture count was always starting from 0 in each group. This needs to increment each time a texture is used\n * no matter which group is being used\n *\n */\n // eslint-disable-next-line no-new-func\n return new Function('ud', 'uv', 'renderer', 'syncData', funcFragments.join('\\n'));\n}\n\nvar fragTemplate = [\n 'precision mediump float;',\n 'void main(void){',\n 'float test = 0.1;',\n '%forloop%',\n 'gl_FragColor = vec4(0.0);',\n '}' ].join('\\n');\nfunction generateIfTestSrc(maxIfs) {\n var src = '';\n for (var i = 0; i < maxIfs; ++i) {\n if (i > 0) {\n src += '\\nelse ';\n }\n if (i < maxIfs - 1) {\n src += \"if(test == \" + i + \".0){}\";\n }\n }\n return src;\n}\nfunction checkMaxIfStatementsInShader(maxIfs, gl) {\n if (maxIfs === 0) {\n throw new Error('Invalid value of `0` passed to `checkMaxIfStatementsInShader`');\n }\n var shader = gl.createShader(gl.FRAGMENT_SHADER);\n while (true) // eslint-disable-line no-constant-condition\n {\n var fragmentSrc = fragTemplate.replace(/%forloop%/gi, generateIfTestSrc(maxIfs));\n gl.shaderSource(shader, fragmentSrc);\n gl.compileShader(shader);\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n maxIfs = (maxIfs / 2) | 0;\n }\n else {\n // valid!\n break;\n }\n }\n return maxIfs;\n}\n\n// Cache the result to prevent running this over and over\nvar unsafeEval;\n/**\n * Not all platforms allow to generate function code (e.g., `new Function`).\n * this provides the platform-level detection.\n * @private\n * @returns {boolean} `true` if `new Function` is supported.\n */\nfunction unsafeEvalSupported() {\n if (typeof unsafeEval === 'boolean') {\n return unsafeEval;\n }\n try {\n /* eslint-disable no-new-func */\n var func = new Function('param1', 'param2', 'param3', 'return param1[param2] === param3;');\n /* eslint-enable no-new-func */\n unsafeEval = func({ a: 'b' }, 'a', 'b') === true;\n }\n catch (e) {\n unsafeEval = false;\n }\n return unsafeEval;\n}\n\nvar defaultFragment$2 = \"varying vec2 vTextureCoord;\\n\\nuniform sampler2D uSampler;\\n\\nvoid main(void){\\n gl_FragColor *= texture2D(uSampler, vTextureCoord);\\n}\";\n\nvar defaultVertex$3 = \"attribute vec2 aVertexPosition;\\nattribute vec2 aTextureCoord;\\n\\nuniform mat3 projectionMatrix;\\n\\nvarying vec2 vTextureCoord;\\n\\nvoid main(void){\\n gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\\n vTextureCoord = aTextureCoord;\\n}\\n\";\n\nvar UID$1 = 0;\nvar nameCache = {};\n/**\n * Helper class to create a shader program.\n * @memberof PIXI\n */\nvar Program = /** @class */ (function () {\n /**\n * @param vertexSrc - The source of the vertex shader.\n * @param fragmentSrc - The source of the fragment shader.\n * @param name - Name for shader\n */\n function Program(vertexSrc, fragmentSrc, name) {\n if (name === void 0) { name = 'pixi-shader'; }\n this.id = UID$1++;\n this.vertexSrc = vertexSrc || Program.defaultVertexSrc;\n this.fragmentSrc = fragmentSrc || Program.defaultFragmentSrc;\n this.vertexSrc = this.vertexSrc.trim();\n this.fragmentSrc = this.fragmentSrc.trim();\n if (this.vertexSrc.substring(0, 8) !== '#version') {\n name = name.replace(/\\s+/g, '-');\n if (nameCache[name]) {\n nameCache[name]++;\n name += \"-\" + nameCache[name];\n }\n else {\n nameCache[name] = 1;\n }\n this.vertexSrc = \"#define SHADER_NAME \" + name + \"\\n\" + this.vertexSrc;\n this.fragmentSrc = \"#define SHADER_NAME \" + name + \"\\n\" + this.fragmentSrc;\n this.vertexSrc = setPrecision(this.vertexSrc, settings.PRECISION_VERTEX, PRECISION.HIGH);\n this.fragmentSrc = setPrecision(this.fragmentSrc, settings.PRECISION_FRAGMENT, getMaxFragmentPrecision());\n }\n // currently this does not extract structs only default types\n // this is where we store shader references..\n this.glPrograms = {};\n this.syncUniforms = null;\n }\n Object.defineProperty(Program, \"defaultVertexSrc\", {\n /**\n * The default vertex shader source.\n * @constant\n */\n get: function () {\n return defaultVertex$3;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Program, \"defaultFragmentSrc\", {\n /**\n * The default fragment shader source.\n * @constant\n */\n get: function () {\n return defaultFragment$2;\n },\n enumerable: false,\n configurable: true\n });\n /**\n * A short hand function to create a program based of a vertex and fragment shader.\n *\n * This method will also check to see if there is a cached program.\n * @param vertexSrc - The source of the vertex shader.\n * @param fragmentSrc - The source of the fragment shader.\n * @param name - Name for shader\n * @returns A shiny new PixiJS shader program!\n */\n Program.from = function (vertexSrc, fragmentSrc, name) {\n var key = vertexSrc + fragmentSrc;\n var program = ProgramCache[key];\n if (!program) {\n ProgramCache[key] = program = new Program(vertexSrc, fragmentSrc, name);\n }\n return program;\n };\n return Program;\n}());\n\n/**\n * A helper class for shaders.\n * @memberof PIXI\n */\nvar Shader = /** @class */ (function () {\n /**\n * @param program - The program the shader will use.\n * @param uniforms - Custom uniforms to use to augment the built-in ones.\n */\n function Shader(program, uniforms) {\n /**\n * Used internally to bind uniform buffer objects.\n * @ignore\n */\n this.uniformBindCount = 0;\n this.program = program;\n // lets see whats been passed in\n // uniforms should be converted to a uniform group\n if (uniforms) {\n if (uniforms instanceof UniformGroup) {\n this.uniformGroup = uniforms;\n }\n else {\n this.uniformGroup = new UniformGroup(uniforms);\n }\n }\n else {\n this.uniformGroup = new UniformGroup({});\n }\n this.disposeRunner = new Runner('disposeShader');\n }\n // TODO move to shader system..\n Shader.prototype.checkUniformExists = function (name, group) {\n if (group.uniforms[name]) {\n return true;\n }\n for (var i in group.uniforms) {\n var uniform = group.uniforms[i];\n if (uniform.group) {\n if (this.checkUniformExists(name, uniform)) {\n return true;\n }\n }\n }\n return false;\n };\n Shader.prototype.destroy = function () {\n // usage count on programs?\n // remove if not used!\n this.uniformGroup = null;\n this.disposeRunner.emit(this);\n this.disposeRunner.destroy();\n };\n Object.defineProperty(Shader.prototype, \"uniforms\", {\n /**\n * Shader uniform values, shortcut for `uniformGroup.uniforms`.\n * @readonly\n */\n get: function () {\n return this.uniformGroup.uniforms;\n },\n enumerable: false,\n configurable: true\n });\n /**\n * A short hand function to create a shader based of a vertex and fragment shader.\n * @param vertexSrc - The source of the vertex shader.\n * @param fragmentSrc - The source of the fragment shader.\n * @param uniforms - Custom uniforms to use to augment the built-in ones.\n * @returns A shiny new PixiJS shader!\n */\n Shader.from = function (vertexSrc, fragmentSrc, uniforms) {\n var program = Program.from(vertexSrc, fragmentSrc);\n return new Shader(program, uniforms);\n };\n return Shader;\n}());\n\n/* eslint-disable max-len */\nvar BLEND$1 = 0;\nvar OFFSET$1 = 1;\nvar CULLING$1 = 2;\nvar DEPTH_TEST$1 = 3;\nvar WINDING$1 = 4;\nvar DEPTH_MASK$1 = 5;\n/**\n * This is a WebGL state, and is is passed to {@link PIXI.StateSystem}.\n *\n * Each mesh rendered may require WebGL to be in a different state.\n * For example you may want different blend mode or to enable polygon offsets\n * @memberof PIXI\n */\nvar State = /** @class */ (function () {\n function State() {\n this.data = 0;\n this.blendMode = BLEND_MODES.NORMAL;\n this.polygonOffset = 0;\n this.blend = true;\n this.depthMask = true;\n // this.depthTest = true;\n }\n Object.defineProperty(State.prototype, \"blend\", {\n /**\n * Activates blending of the computed fragment color values.\n * @default true\n */\n get: function () {\n return !!(this.data & (1 << BLEND$1));\n },\n set: function (value) {\n if (!!(this.data & (1 << BLEND$1)) !== value) {\n this.data ^= (1 << BLEND$1);\n }\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(State.prototype, \"offsets\", {\n /**\n * Activates adding an offset to depth values of polygon's fragments\n * @default false\n */\n get: function () {\n return !!(this.data & (1 << OFFSET$1));\n },\n set: function (value) {\n if (!!(this.data & (1 << OFFSET$1)) !== value) {\n this.data ^= (1 << OFFSET$1);\n }\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(State.prototype, \"culling\", {\n /**\n * Activates culling of polygons.\n * @default false\n */\n get: function () {\n return !!(this.data & (1 << CULLING$1));\n },\n set: function (value) {\n if (!!(this.data & (1 << CULLING$1)) !== value) {\n this.data ^= (1 << CULLING$1);\n }\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(State.prototype, \"depthTest\", {\n /**\n * Activates depth comparisons and updates to the depth buffer.\n * @default false\n */\n get: function () {\n return !!(this.data & (1 << DEPTH_TEST$1));\n },\n set: function (value) {\n if (!!(this.data & (1 << DEPTH_TEST$1)) !== value) {\n this.data ^= (1 << DEPTH_TEST$1);\n }\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(State.prototype, \"depthMask\", {\n /**\n * Enables or disables writing to the depth buffer.\n * @default true\n */\n get: function () {\n return !!(this.data & (1 << DEPTH_MASK$1));\n },\n set: function (value) {\n if (!!(this.data & (1 << DEPTH_MASK$1)) !== value) {\n this.data ^= (1 << DEPTH_MASK$1);\n }\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(State.prototype, \"clockwiseFrontFace\", {\n /**\n * Specifies whether or not front or back-facing polygons can be culled.\n * @default false\n */\n get: function () {\n return !!(this.data & (1 << WINDING$1));\n },\n set: function (value) {\n if (!!(this.data & (1 << WINDING$1)) !== value) {\n this.data ^= (1 << WINDING$1);\n }\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(State.prototype, \"blendMode\", {\n /**\n * The blend mode to be applied when this state is set. Apply a value of `PIXI.BLEND_MODES.NORMAL` to reset the blend mode.\n * Setting this mode to anything other than NO_BLEND will automatically switch blending on.\n * @default PIXI.BLEND_MODES.NORMAL\n */\n get: function () {\n return this._blendMode;\n },\n set: function (value) {\n this.blend = (value !== BLEND_MODES.NONE);\n this._blendMode = value;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(State.prototype, \"polygonOffset\", {\n /**\n * The polygon offset. Setting this property to anything other than 0 will automatically enable polygon offset fill.\n * @default 0\n */\n get: function () {\n return this._polygonOffset;\n },\n set: function (value) {\n this.offsets = !!value;\n this._polygonOffset = value;\n },\n enumerable: false,\n configurable: true\n });\n State.prototype.toString = function () {\n return \"[@pixi/core:State \"\n + (\"blendMode=\" + this.blendMode + \" \")\n + (\"clockwiseFrontFace=\" + this.clockwiseFrontFace + \" \")\n + (\"culling=\" + this.culling + \" \")\n + (\"depthMask=\" + this.depthMask + \" \")\n + (\"polygonOffset=\" + this.polygonOffset)\n + \"]\";\n };\n State.for2d = function () {\n var state = new State();\n state.depthTest = false;\n state.blend = true;\n return state;\n };\n return State;\n}());\n\nvar defaultFragment$1 = \"varying vec2 vTextureCoord;\\n\\nuniform sampler2D uSampler;\\n\\nvoid main(void){\\n gl_FragColor = texture2D(uSampler, vTextureCoord);\\n}\\n\";\n\nvar defaultVertex$2 = \"attribute vec2 aVertexPosition;\\n\\nuniform mat3 projectionMatrix;\\n\\nvarying vec2 vTextureCoord;\\n\\nuniform vec4 inputSize;\\nuniform vec4 outputFrame;\\n\\nvec4 filterVertexPosition( void )\\n{\\n vec2 position = aVertexPosition * max(outputFrame.zw, vec2(0.)) + outputFrame.xy;\\n\\n return vec4((projectionMatrix * vec3(position, 1.0)).xy, 0.0, 1.0);\\n}\\n\\nvec2 filterTextureCoord( void )\\n{\\n return aVertexPosition * (outputFrame.zw * inputSize.zw);\\n}\\n\\nvoid main(void)\\n{\\n gl_Position = filterVertexPosition();\\n vTextureCoord = filterTextureCoord();\\n}\\n\";\n\n/**\n * A filter is a special shader that applies post-processing effects to an input texture and writes into an output\n * render-target.\n *\n * {@link http://pixijs.io/examples/#/filters/blur-filter.js Example} of the\n * {@link PIXI.filters.BlurFilter BlurFilter}.\n *\n * ### Usage\n * Filters can be applied to any DisplayObject or Container.\n * PixiJS' `FilterSystem` renders the container into temporary Framebuffer,\n * then filter renders it to the screen.\n * Multiple filters can be added to the `filters` array property and stacked on each other.\n *\n * ```\n * const filter = new PIXI.Filter(myShaderVert, myShaderFrag, { myUniform: 0.5 });\n * const container = new PIXI.Container();\n * container.filters = [filter];\n * ```\n *\n * ### Previous Version Differences\n *\n * In PixiJS **v3**, a filter was always applied to _whole screen_.\n *\n * In PixiJS **v4**, a filter can be applied _only part of the screen_.\n * Developers had to create a set of uniforms to deal with coordinates.\n *\n * In PixiJS **v5** combines _both approaches_.\n * Developers can use normal coordinates of v3 and then allow filter to use partial Framebuffers,\n * bringing those extra uniforms into account.\n *\n * Also be aware that we have changed default vertex shader, please consult\n * {@link https://github.com/pixijs/pixi.js/wiki/v5-Creating-filters Wiki}.\n *\n * ### Frames\n *\n * The following table summarizes the coordinate spaces used in the filtering pipeline:\n *\n * <table>\n * <thead>\n * <tr>\n * <th>Coordinate Space</th>\n * <th>Description</th>\n * </tr>\n * </thead>\n * <tbody>\n * <tr>\n * <td>Texture Coordinates</td>\n * <td>\n * The texture (or UV) coordinates in the input base-texture's space. These are normalized into the (0,1) range along\n * both axes.\n * </td>\n * </tr>\n * <tr>\n * <td>World Space</td>\n * <td>\n * A point in the same space as the world bounds of any display-object (i.e. in the scene graph's space).\n * </td>\n * </tr>\n * <tr>\n * <td>Physical Pixels</td>\n * <td>\n * This is base-texture's space with the origin on the top-left. You can calculate these by multiplying the texture\n * coordinates by the dimensions of the texture.\n * </td>\n * </tr>\n * </tbody>\n * </table>\n *\n * ### Built-in Uniforms\n *\n * PixiJS viewport uses screen (CSS) coordinates, `(0, 0, renderer.screen.width, renderer.screen.height)`,\n * and `projectionMatrix` uniform maps it to the gl viewport.\n *\n * **uSampler**\n *\n * The most important uniform is the input texture that container was rendered into.\n * _Important note: as with all Framebuffers in PixiJS, both input and output are\n * premultiplied by alpha._\n *\n * By default, input normalized coordinates are passed to fragment shader with `vTextureCoord`.\n * Use it to sample the input.\n *\n * ```\n * const fragment = `\n * varying vec2 vTextureCoord;\n * uniform sampler2D uSampler;\n * void main(void)\n * {\n * gl_FragColor = texture2D(uSampler, vTextureCoord);\n * }\n * `;\n *\n * const myFilter = new PIXI.Filter(null, fragment);\n * ```\n *\n * This filter is just one uniform less than {@link PIXI.filters.AlphaFilter AlphaFilter}.\n *\n * **outputFrame**\n *\n * The `outputFrame` holds the rectangle where filter is applied in screen (CSS) coordinates.\n * It's the same as `renderer.screen` for a fullscreen filter.\n * Only a part of `outputFrame.zw` size of temporary Framebuffer is used,\n * `(0, 0, outputFrame.width, outputFrame.height)`,\n *\n * Filters uses this quad to normalized (0-1) space, its passed into `aVertexPosition` attribute.\n * To calculate vertex position in screen space using normalized (0-1) space:\n *\n * ```\n * vec4 filterVertexPosition( void )\n * {\n * vec2 position = aVertexPosition * max(outputFrame.zw, vec2(0.)) + outputFrame.xy;\n * return vec4((projectionMatrix * vec3(position, 1.0)).xy, 0.0, 1.0);\n * }\n * ```\n *\n * **inputSize**\n *\n * Temporary framebuffer is different, it can be either the size of screen, either power-of-two.\n * The `inputSize.xy` are size of temporary framebuffer that holds input.\n * The `inputSize.zw` is inverted, it's a shortcut to evade division inside the shader.\n *\n * Set `inputSize.xy = outputFrame.zw` for a fullscreen filter.\n *\n * To calculate input normalized coordinate, you have to map it to filter normalized space.\n * Multiply by `outputFrame.zw` to get input coordinate.\n * Divide by `inputSize.xy` to get input normalized coordinate.\n *\n * ```\n * vec2 filterTextureCoord( void )\n * {\n * return aVertexPosition * (outputFrame.zw * inputSize.zw); // same as /inputSize.xy\n * }\n * ```\n * **resolution**\n *\n * The `resolution` is the ratio of screen (CSS) pixels to real pixels.\n *\n * **inputPixel**\n *\n * `inputPixel.xy` is the size of framebuffer in real pixels, same as `inputSize.xy * resolution`\n * `inputPixel.zw` is inverted `inputPixel.xy`.\n *\n * It's handy for filters that use neighbour pixels, like {@link PIXI.filters.FXAAFilter FXAAFilter}.\n *\n * **inputClamp**\n *\n * If you try to get info from outside of used part of Framebuffer - you'll get undefined behaviour.\n * For displacements, coordinates has to be clamped.\n *\n * The `inputClamp.xy` is left-top pixel center, you may ignore it, because we use left-top part of Framebuffer\n * `inputClamp.zw` is bottom-right pixel center.\n *\n * ```\n * vec4 color = texture2D(uSampler, clamp(modifiedTextureCoord, inputClamp.xy, inputClamp.zw))\n * ```\n * OR\n * ```\n * vec4 color = texture2D(uSampler, min(modifigedTextureCoord, inputClamp.zw))\n * ```\n *\n * ### Additional Information\n *\n * Complete documentation on Filter usage is located in the\n * {@link https://github.com/pixijs/pixi.js/wiki/v5-Creating-filters Wiki}.\n *\n * Since PixiJS only had a handful of built-in filters, additional filters can be downloaded\n * {@link https://github.com/pixijs/pixi-filters here} from the PixiJS Filters repository.\n * @memberof PIXI\n */\nvar Filter = /** @class */ (function (_super) {\n __extends(Filter, _super);\n /**\n * @param vertexSrc - The source of the vertex shader.\n * @param fragmentSrc - The source of the fragment shader.\n * @param uniforms - Custom uniforms to use to augment the built-in ones.\n */\n function Filter(vertexSrc, fragmentSrc, uniforms) {\n var _this = this;\n var program = Program.from(vertexSrc || Filter.defaultVertexSrc, fragmentSrc || Filter.defaultFragmentSrc);\n _this = _super.call(this, program, uniforms) || this;\n _this.padding = 0;\n _this.resolution = settings.FILTER_RESOLUTION;\n _this.multisample = settings.FILTER_MULTISAMPLE;\n _this.enabled = true;\n _this.autoFit = true;\n _this.state = new State();\n return _this;\n }\n /**\n * Applies the filter\n * @param {PIXI.FilterSystem} filterManager - The renderer to retrieve the filter from\n * @param {PIXI.RenderTexture} input - The input render target.\n * @param {PIXI.RenderTexture} output - The target to output to.\n * @param {PIXI.CLEAR_MODES} [clearMode] - Should the output be cleared before rendering to it.\n * @param {object} [_currentState] - It's current state of filter.\n * There are some useful properties in the currentState :\n * target, filters, sourceFrame, destinationFrame, renderTarget, resolution\n */\n Filter.prototype.apply = function (filterManager, input, output, clearMode, _currentState) {\n // do as you please!\n filterManager.applyFilter(this, input, output, clearMode);\n // or just do a regular render..\n };\n Object.defineProperty(Filter.prototype, \"blendMode\", {\n /**\n * Sets the blend mode of the filter.\n * @default PIXI.BLEND_MODES.NORMAL\n */\n get: function () {\n return this.state.blendMode;\n },\n set: function (value) {\n this.state.blendMode = value;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Filter.prototype, \"resolution\", {\n /**\n * The resolution of the filter. Setting this to be lower will lower the quality but\n * increase the performance of the filter.\n */\n get: function () {\n return this._resolution;\n },\n set: function (value) {\n this._resolution = value;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Filter, \"defaultVertexSrc\", {\n /**\n * The default vertex shader source\n * @constant\n */\n get: function () {\n return defaultVertex$2;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Filter, \"defaultFragmentSrc\", {\n /**\n * The default fragment shader source\n * @constant\n */\n get: function () {\n return defaultFragment$1;\n },\n enumerable: false,\n configurable: true\n });\n return Filter;\n}(Shader));\n\nvar vertex = \"attribute vec2 aVertexPosition;\\nattribute vec2 aTextureCoord;\\n\\nuniform mat3 projectionMatrix;\\nuniform mat3 otherMatrix;\\n\\nvarying vec2 vMaskCoord;\\nvarying vec2 vTextureCoord;\\n\\nvoid main(void)\\n{\\n gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\\n\\n vTextureCoord = aTextureCoord;\\n vMaskCoord = ( otherMatrix * vec3( aTextureCoord, 1.0) ).xy;\\n}\\n\";\n\nvar fragment = \"varying vec2 vMaskCoord;\\nvarying vec2 vTextureCoord;\\n\\nuniform sampler2D uSampler;\\nuniform sampler2D mask;\\nuniform float alpha;\\nuniform float npmAlpha;\\nuniform vec4 maskClamp;\\n\\nvoid main(void)\\n{\\n float clip = step(3.5,\\n step(maskClamp.x, vMaskCoord.x) +\\n step(maskClamp.y, vMaskCoord.y) +\\n step(vMaskCoord.x, maskClamp.z) +\\n step(vMaskCoord.y, maskClamp.w));\\n\\n vec4 original = texture2D(uSampler, vTextureCoord);\\n vec4 masky = texture2D(mask, vMaskCoord);\\n float alphaMul = 1.0 - npmAlpha * (1.0 - masky.a);\\n\\n original *= (alphaMul * masky.r * alpha * clip);\\n\\n gl_FragColor = original;\\n}\\n\";\n\nvar tempMat = new Matrix();\n/**\n * Class controls uv mapping from Texture normal space to BaseTexture normal space.\n *\n * Takes `trim` and `rotate` into account. May contain clamp settings for Meshes and TilingSprite.\n *\n * Can be used in Texture `uvMatrix` field, or separately, you can use different clamp settings on the same texture.\n * If you want to add support for texture region of certain feature or filter, that's what you're looking for.\n *\n * Takes track of Texture changes through `_lastTextureID` private field.\n * Use `update()` method call to track it from outside.\n * @see PIXI.Texture\n * @see PIXI.Mesh\n * @see PIXI.TilingSprite\n * @memberof PIXI\n */\nvar TextureMatrix = /** @class */ (function () {\n /**\n * @param texture - observed texture\n * @param clampMargin - Changes frame clamping, 0.5 by default. Use -0.5 for extra border.\n */\n function TextureMatrix(texture, clampMargin) {\n this._texture = texture;\n this.mapCoord = new Matrix();\n this.uClampFrame = new Float32Array(4);\n this.uClampOffset = new Float32Array(2);\n this._textureID = -1;\n this._updateID = 0;\n this.clampOffset = 0;\n this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;\n this.isSimple = false;\n }\n Object.defineProperty(TextureMatrix.prototype, \"texture\", {\n /** Texture property. */\n get: function () {\n return this._texture;\n },\n set: function (value) {\n this._texture = value;\n this._textureID = -1;\n },\n enumerable: false,\n configurable: true\n });\n /**\n * Multiplies uvs array to transform\n * @param uvs - mesh uvs\n * @param [out=uvs] - output\n * @returns - output\n */\n TextureMatrix.prototype.multiplyUvs = function (uvs, out) {\n if (out === undefined) {\n out = uvs;\n }\n var mat = this.mapCoord;\n for (var i = 0; i < uvs.length; i += 2) {\n var x = uvs[i];\n var y = uvs[i + 1];\n out[i] = (x * mat.a) + (y * mat.c) + mat.tx;\n out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;\n }\n return out;\n };\n /**\n * Updates matrices if texture was changed.\n * @param [forceUpdate=false] - if true, matrices will be updated any case\n * @returns - Whether or not it was updated\n */\n TextureMatrix.prototype.update = function (forceUpdate) {\n var tex = this._texture;\n if (!tex || !tex.valid) {\n return false;\n }\n if (!forceUpdate\n && this._textureID === tex._updateID) {\n return false;\n }\n this._textureID = tex._updateID;\n this._updateID++;\n var uvs = tex._uvs;\n this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);\n var orig = tex.orig;\n var trim = tex.trim;\n if (trim) {\n tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height, -trim.x / trim.width, -trim.y / trim.height);\n this.mapCoord.append(tempMat);\n }\n var texBase = tex.baseTexture;\n var frame = this.uClampFrame;\n var margin = this.clampMargin / texBase.resolution;\n var offset = this.clampOffset;\n frame[0] = (tex._frame.x + margin + offset) / texBase.width;\n frame[1] = (tex._frame.y + margin + offset) / texBase.height;\n frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;\n frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;\n this.uClampOffset[0] = offset / texBase.realWidth;\n this.uClampOffset[1] = offset / texBase.realHeight;\n this.isSimple = tex._frame.width === texBase.width\n && tex._frame.height === texBase.height\n && tex.rotate === 0;\n return true;\n };\n return TextureMatrix;\n}());\n\n/**\n * This handles a Sprite acting as a mask, as opposed to a Graphic.\n *\n * WebGL only.\n * @memberof PIXI\n */\nvar SpriteMaskFilter = /** @class */ (function (_super) {\n __extends(SpriteMaskFilter, _super);\n /** @ignore */\n function SpriteMaskFilter(vertexSrc, fragmentSrc, uniforms) {\n var _this = this;\n var sprite = null;\n if (typeof vertexSrc !== 'string' && fragmentSrc === undefined && uniforms === undefined) {\n sprite = vertexSrc;\n vertexSrc = undefined;\n fragmentSrc = undefined;\n uniforms = undefined;\n }\n _this = _super.call(this, vertexSrc || vertex, fragmentSrc || fragment, uniforms) || this;\n _this.maskSprite = sprite;\n _this.maskMatrix = new Matrix();\n return _this;\n }\n Object.defineProperty(SpriteMaskFilter.prototype, \"maskSprite\", {\n /**\n * Sprite mask\n * @type {PIXI.DisplayObject}\n */\n get: function () {\n return this._maskSprite;\n },\n set: function (value) {\n this._maskSprite = value;\n if (this._maskSprite) {\n this._maskSprite.renderable = false;\n }\n },\n enumerable: false,\n configurable: true\n });\n /**\n * Applies the filter\n * @param filterManager - The renderer to retrieve the filter from\n * @param input - The input render target.\n * @param output - The target to output to.\n * @param clearMode - Should the output be cleared before rendering to it.\n */\n SpriteMaskFilter.prototype.apply = function (filterManager, input, output, clearMode) {\n var maskSprite = this._maskSprite;\n var tex = maskSprite._texture;\n if (!tex.valid) {\n return;\n }\n if (!tex.uvMatrix) {\n // margin = 0.0, let it bleed a bit, shader code becomes easier\n // assuming that atlas textures were made with 1-pixel padding\n tex.uvMatrix = new TextureMatrix(tex, 0.0);\n }\n tex.uvMatrix.update();\n this.uniforms.npmAlpha = tex.baseTexture.alphaMode ? 0.0 : 1.0;\n this.uniforms.mask = tex;\n // get _normalized sprite texture coords_ and convert them to _normalized atlas texture coords_ with `prepend`\n this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite)\n .prepend(tex.uvMatrix.mapCoord);\n this.uniforms.alpha = maskSprite.worldAlpha;\n this.uniforms.maskClamp = tex.uvMatrix.uClampFrame;\n filterManager.applyFilter(this, input, output, clearMode);\n };\n return SpriteMaskFilter;\n}(Filter));\n\n/**\n * System plugin to the renderer to manage masks.\n *\n * There are three built-in types of masking:\n * **Scissor Masking**: Scissor masking discards pixels that are outside of a rectangle called the scissor box. It is\n * the most performant as the scissor test is inexpensive. However, it can only be used when the mask is rectangular.\n * **Stencil Masking**: Stencil masking discards pixels that don't overlap with the pixels rendered into the stencil\n * buffer. It is the next fastest option as it does not require rendering into a separate framebuffer. However, it does\n * cause the mask to be rendered **twice** for each masking operation; hence, minimize the rendering cost of your masks.\n * **Sprite Mask Filtering**: Sprite mask filtering discards pixels based on the red channel of the sprite-mask's\n * texture. (Generally, the masking texture is grayscale). Using advanced techniques, you might be able to embed this\n * type of masking in a custom shader - and hence, bypassing the masking system fully for performance wins.\n *\n * The best type of masking is auto-detected when you `push` one. To use scissor masking, you must pass in a `Graphics`\n * object with just a rectangle drawn.\n *\n * ## Mask Stacks\n *\n * In the scene graph, masks can be applied recursively, i.e. a mask can be applied during a masking operation. The mask\n * stack stores the currently applied masks in order. Each {@link PIXI.BaseRenderTexture} holds its own mask stack, i.e.\n * when you switch render-textures, the old masks only applied when you switch back to rendering to the old render-target.\n * @memberof PIXI\n */\nvar MaskSystem = /** @class */ (function () {\n /**\n * @param renderer - The renderer this System works for.\n */\n function MaskSystem(renderer) {\n this.renderer = renderer;\n this.enableScissor = true;\n this.alphaMaskPool = [];\n this.maskDataPool = [];\n this.maskStack = [];\n this.alphaMaskIndex = 0;\n }\n /**\n * Changes the mask stack that is used by this System.\n * @param maskStack - The mask stack\n */\n MaskSystem.prototype.setMaskStack = function (maskStack) {\n this.maskStack = maskStack;\n this.renderer.scissor.setMaskStack(maskStack);\n this.renderer.stencil.setMaskStack(maskStack);\n };\n /**\n * Enables the mask and appends it to the current mask stack.\n *\n * NOTE: The batch renderer should be flushed beforehand to prevent pending renders from being masked.\n * @param {PIXI.DisplayObject} target - Display Object to push the mask to\n * @param {PIXI.MaskData|PIXI.Sprite|PIXI.Graphics|PIXI.DisplayObject} maskDataOrTarget - The masking data.\n */\n MaskSystem.prototype.push = function (target, maskDataOrTarget) {\n var maskData = maskDataOrTarget;\n if (!maskData.isMaskData) {\n var d = this.maskDataPool.pop() || new MaskData();\n d.pooled = true;\n d.maskObject = maskDataOrTarget;\n maskData = d;\n }\n var maskAbove = this.maskStack.length !== 0 ? this.maskStack[this.maskStack.length - 1] : null;\n maskData.copyCountersOrReset(maskAbove);\n maskData._colorMask = maskAbove ? maskAbove._colorMask : 0xf;\n if (maskData.autoDetect) {\n this.detect(maskData);\n }\n maskData._target = target;\n if (maskData.type !== MASK_TYPES.SPRITE) {\n this.maskStack.push(maskData);\n }\n if (maskData.enabled) {\n switch (maskData.type) {\n case MASK_TYPES.SCISSOR:\n this.renderer.scissor.push(maskData);\n break;\n case MASK_TYPES.STENCIL:\n this.renderer.stencil.push(maskData);\n break;\n case MASK_TYPES.SPRITE:\n maskData.copyCountersOrReset(null);\n this.pushSpriteMask(maskData);\n break;\n case MASK_TYPES.COLOR:\n this.pushColorMask(maskData);\n break;\n }\n }\n if (maskData.type === MASK_TYPES.SPRITE) {\n this.maskStack.push(maskData);\n }\n };\n /**\n * Removes the last mask from the mask stack and doesn't return it.\n *\n * NOTE: The batch renderer should be flushed beforehand to render the masked contents before the mask is removed.\n * @param {PIXI.IMaskTarget} target - Display Object to pop the mask from\n */\n MaskSystem.prototype.pop = function (target) {\n var maskData = this.maskStack.pop();\n if (!maskData || maskData._target !== target) {\n // TODO: add an assert when we have it\n return;\n }\n if (maskData.enabled) {\n switch (maskData.type) {\n case MASK_TYPES.SCISSOR:\n this.renderer.scissor.pop(maskData);\n break;\n case MASK_TYPES.STENCIL:\n this.renderer.stencil.pop(maskData.maskObject);\n break;\n case MASK_TYPES.SPRITE:\n this.popSpriteMask(maskData);\n break;\n case MASK_TYPES.COLOR:\n this.popColorMask(maskData);\n break;\n }\n }\n maskData.reset();\n if (maskData.pooled) {\n this.maskDataPool.push(maskData);\n }\n if (this.maskStack.length !== 0) {\n var maskCurrent = this.maskStack[this.maskStack.length - 1];\n if (maskCurrent.type === MASK_TYPES.SPRITE && maskCurrent._filters) {\n maskCurrent._filters[0].maskSprite = maskCurrent.maskObject;\n }\n }\n };\n /**\n * Sets type of MaskData based on its maskObject.\n * @param maskData\n */\n MaskSystem.prototype.detect = function (maskData) {\n var maskObject = maskData.maskObject;\n if (!maskObject) {\n maskData.type = MASK_TYPES.COLOR;\n }\n else if (maskObject.isSprite) {\n maskData.type = MASK_TYPES.SPRITE;\n }\n else if (this.enableScissor && this.renderer.scissor.testScissor(maskData)) {\n maskData.type = MASK_TYPES.SCISSOR;\n }\n else {\n maskData.type = MASK_TYPES.STENCIL;\n }\n };\n /**\n * Applies the Mask and adds it to the current filter stack.\n * @param maskData - Sprite to be used as the mask.\n */\n MaskSystem.prototype.pushSpriteMask = function (maskData) {\n var _a, _b;\n var maskObject = maskData.maskObject;\n var target = maskData._target;\n var alphaMaskFilter = maskData._filters;\n if (!alphaMaskFilter) {\n alphaMaskFilter = this.alphaMaskPool[this.alphaMaskIndex];\n if (!alphaMaskFilter) {\n alphaMaskFilter = this.alphaMaskPool[this.alphaMaskIndex] = [new SpriteMaskFilter()];\n }\n }\n var renderer = this.renderer;\n var renderTextureSystem = renderer.renderTexture;\n var resolution;\n var multisample;\n if (renderTextureSystem.current) {\n var renderTexture = renderTextureSystem.current;\n resolution = maskData.resolution || renderTexture.resolution;\n multisample = (_a = maskData.multisample) !== null && _a !== void 0 ? _a : renderTexture.multisample;\n }\n else {\n resolution = maskData.resolution || renderer.resolution;\n multisample = (_b = maskData.multisample) !== null && _b !== void 0 ? _b : renderer.multisample;\n }\n alphaMaskFilter[0].resolution = resolution;\n alphaMaskFilter[0].multisample = multisample;\n alphaMaskFilter[0].maskSprite = maskObject;\n var stashFilterArea = target.filterArea;\n target.filterArea = maskObject.getBounds(true);\n renderer.filter.push(target, alphaMaskFilter);\n target.filterArea = stashFilterArea;\n if (!maskData._filters) {\n this.alphaMaskIndex++;\n }\n };\n /**\n * Removes the last filter from the filter stack and doesn't return it.\n * @param maskData - Sprite to be used as the mask.\n */\n MaskSystem.prototype.popSpriteMask = function (maskData) {\n this.renderer.filter.pop();\n if (maskData._filters) {\n maskData._filters[0].maskSprite = null;\n }\n else {\n this.alphaMaskIndex--;\n this.alphaMaskPool[this.alphaMaskIndex][0].maskSprite = null;\n }\n };\n /**\n * Pushes the color mask.\n * @param maskData - The mask data\n */\n MaskSystem.prototype.pushColorMask = function (maskData) {\n var currColorMask = maskData._colorMask;\n var nextColorMask = maskData._colorMask = currColorMask & maskData.colorMask;\n if (nextColorMask !== currColorMask) {\n this.renderer.gl.colorMask((nextColorMask & 0x1) !== 0, (nextColorMask & 0x2) !== 0, (nextColorMask & 0x4) !== 0, (nextColorMask & 0x8) !== 0);\n }\n };\n /**\n * Pops the color mask.\n * @param maskData - The mask data\n */\n MaskSystem.prototype.popColorMask = function (maskData) {\n var currColorMask = maskData._colorMask;\n var nextColorMask = this.maskStack.length > 0\n ? this.maskStack[this.maskStack.length - 1]._colorMask : 0xf;\n if (nextColorMask !== currColorMask) {\n this.renderer.gl.colorMask((nextColorMask & 0x1) !== 0, (nextColorMask & 0x2) !== 0, (nextColorMask & 0x4) !== 0, (nextColorMask & 0x8) !== 0);\n }\n };\n MaskSystem.prototype.destroy = function () {\n this.renderer = null;\n };\n return MaskSystem;\n}());\n\n/**\n * System plugin to the renderer to manage specific types of masking operations.\n * @memberof PIXI\n */\nvar AbstractMaskSystem = /** @class */ (function () {\n /**\n * @param renderer - The renderer this System works for.\n */\n function AbstractMaskSystem(renderer) {\n this.renderer = renderer;\n this.maskStack = [];\n this.glConst = 0;\n }\n /** Gets count of masks of certain type. */\n AbstractMaskSystem.prototype.getStackLength = function () {\n return this.maskStack.length;\n };\n /**\n * Changes the mask stack that is used by this System.\n * @param {PIXI.MaskData[]} maskStack - The mask stack\n */\n AbstractMaskSystem.prototype.setMaskStack = function (maskStack) {\n var gl = this.renderer.gl;\n var curStackLen = this.getStackLength();\n this.maskStack = maskStack;\n var newStackLen = this.getStackLength();\n if (newStackLen !== curStackLen) {\n if (newStackLen === 0) {\n gl.disable(this.glConst);\n }\n else {\n gl.enable(this.glConst);\n this._useCurrent();\n }\n }\n };\n /**\n * Setup renderer to use the current mask data.\n * @private\n */\n AbstractMaskSystem.prototype._useCurrent = function () {\n // OVERWRITE;\n };\n /** Destroys the mask stack. */\n AbstractMaskSystem.prototype.destroy = function () {\n this.renderer = null;\n this.maskStack = null;\n };\n return AbstractMaskSystem;\n}());\n\nvar tempMatrix$1 = new Matrix();\nvar rectPool = [];\n/**\n * System plugin to the renderer to manage scissor masking.\n *\n * Scissor masking discards pixels outside of a rectangle called the scissor box. The scissor box is in the framebuffer\n * viewport's space; however, the mask's rectangle is projected from world-space to viewport space automatically\n * by this system.\n * @memberof PIXI\n */\nvar ScissorSystem = /** @class */ (function (_super) {\n __extends(ScissorSystem, _super);\n /**\n * @param {PIXI.Renderer} renderer - The renderer this System works for.\n */\n function ScissorSystem(renderer) {\n var _this = _super.call(this, renderer) || this;\n _this.glConst = settings.ADAPTER.getWebGLRenderingContext().SCISSOR_TEST;\n return _this;\n }\n ScissorSystem.prototype.getStackLength = function () {\n var maskData = this.maskStack[this.maskStack.length - 1];\n if (maskData) {\n return maskData._scissorCounter;\n }\n return 0;\n };\n /**\n * evaluates _boundsTransformed, _scissorRect for MaskData\n * @param maskData\n */\n ScissorSystem.prototype.calcScissorRect = function (maskData) {\n var _a;\n if (maskData._scissorRectLocal) {\n return;\n }\n var prevData = maskData._scissorRect;\n var maskObject = maskData.maskObject;\n var renderer = this.renderer;\n var renderTextureSystem = renderer.renderTexture;\n var rect = maskObject.getBounds(true, (_a = rectPool.pop()) !== null && _a !== void 0 ? _a : new Rectangle());\n this.roundFrameToPixels(rect, renderTextureSystem.current ? renderTextureSystem.current.resolution : renderer.resolution, renderTextureSystem.sourceFrame, renderTextureSystem.destinationFrame, renderer.projection.transform);\n if (prevData) {\n rect.fit(prevData);\n }\n maskData._scissorRectLocal = rect;\n };\n ScissorSystem.isMatrixRotated = function (matrix) {\n if (!matrix) {\n return false;\n }\n var a = matrix.a, b = matrix.b, c = matrix.c, d = matrix.d;\n // Skip if skew/rotation present in matrix, except for multiple of 90° rotation. If rotation\n // is a multiple of 90°, then either pair of (b,c) or (a,d) will be (0,0).\n return ((Math.abs(b) > 1e-4 || Math.abs(c) > 1e-4)\n && (Math.abs(a) > 1e-4 || Math.abs(d) > 1e-4));\n };\n /**\n * Test, whether the object can be scissor mask with current renderer projection.\n * Calls \"calcScissorRect()\" if its true.\n * @param maskData - mask data\n * @returns whether Whether the object can be scissor mask\n */\n ScissorSystem.prototype.testScissor = function (maskData) {\n var maskObject = maskData.maskObject;\n if (!maskObject.isFastRect || !maskObject.isFastRect()) {\n return false;\n }\n if (ScissorSystem.isMatrixRotated(maskObject.worldTransform)) {\n return false;\n }\n if (ScissorSystem.isMatrixRotated(this.renderer.projection.transform)) {\n return false;\n }\n this.calcScissorRect(maskData);\n var rect = maskData._scissorRectLocal;\n return rect.width > 0 && rect.height > 0;\n };\n ScissorSystem.prototype.roundFrameToPixels = function (frame, resolution, bindingSourceFrame, bindingDestinationFrame, transform) {\n if (ScissorSystem.isMatrixRotated(transform)) {\n return;\n }\n transform = transform ? tempMatrix$1.copyFrom(transform) : tempMatrix$1.identity();\n // Get forward transform from world space to screen space\n transform\n .translate(-bindingSourceFrame.x, -bindingSourceFrame.y)\n .scale(bindingDestinationFrame.width / bindingSourceFrame.width, bindingDestinationFrame.height / bindingSourceFrame.height)\n .translate(bindingDestinationFrame.x, bindingDestinationFrame.y);\n // Convert frame to screen space\n this.renderer.filter.transformAABB(transform, frame);\n frame.fit(bindingDestinationFrame);\n frame.x = Math.round(frame.x * resolution);\n frame.y = Math.round(frame.y * resolution);\n frame.width = Math.round(frame.width * resolution);\n frame.height = Math.round(frame.height * resolution);\n };\n /**\n * Applies the Mask and adds it to the current stencil stack.\n * @author alvin\n * @param maskData - The mask data.\n */\n ScissorSystem.prototype.push = function (maskData) {\n if (!maskData._scissorRectLocal) {\n this.calcScissorRect(maskData);\n }\n var gl = this.renderer.gl;\n if (!maskData._scissorRect) {\n gl.enable(gl.SCISSOR_TEST);\n }\n maskData._scissorCounter++;\n maskData._scissorRect = maskData._scissorRectLocal;\n this._useCurrent();\n };\n /**\n * This should be called after a mask is popped off the mask stack. It will rebind the scissor box to be latest with the\n * last mask in the stack.\n *\n * This can also be called when you directly modify the scissor box and want to restore PixiJS state.\n * @param maskData - The mask data.\n */\n ScissorSystem.prototype.pop = function (maskData) {\n var gl = this.renderer.gl;\n if (maskData) {\n rectPool.push(maskData._scissorRectLocal);\n }\n if (this.getStackLength() > 0) {\n this._useCurrent();\n }\n else {\n gl.disable(gl.SCISSOR_TEST);\n }\n };\n /**\n * Setup renderer to use the current scissor data.\n * @private\n */\n ScissorSystem.prototype._useCurrent = function () {\n var rect = this.maskStack[this.maskStack.length - 1]._scissorRect;\n var y;\n if (this.renderer.renderTexture.current) {\n y = rect.y;\n }\n else {\n // flipY. In future we'll have it over renderTextures as an option\n y = this.renderer.height - rect.height - rect.y;\n }\n this.renderer.gl.scissor(rect.x, y, rect.width, rect.height);\n };\n return ScissorSystem;\n}(AbstractMaskSystem));\n\n/**\n * System plugin to the renderer to manage stencils (used for masks).\n * @memberof PIXI\n */\nvar StencilSystem = /** @class */ (function (_super) {\n __extends(StencilSystem, _super);\n /**\n * @param renderer - The renderer this System works for.\n */\n function StencilSystem(renderer) {\n var _this = _super.call(this, renderer) || this;\n _this.glConst = settings.ADAPTER.getWebGLRenderingContext().STENCIL_TEST;\n return _this;\n }\n StencilSystem.prototype.getStackLength = function () {\n var maskData = this.maskStack[this.maskStack.length - 1];\n if (maskData) {\n return maskData._stencilCounter;\n }\n return 0;\n };\n /**\n * Applies the Mask and adds it to the current stencil stack.\n * @param maskData - The mask data\n */\n StencilSystem.prototype.push = function (maskData) {\n var maskObject = maskData.maskObject;\n var gl = this.renderer.gl;\n var prevMaskCount = maskData._stencilCounter;\n if (prevMaskCount === 0) {\n // force use stencil texture in current framebuffer\n this.renderer.framebuffer.forceStencil();\n gl.clearStencil(0);\n gl.clear(gl.STENCIL_BUFFER_BIT);\n gl.enable(gl.STENCIL_TEST);\n }\n maskData._stencilCounter++;\n var colorMask = maskData._colorMask;\n if (colorMask !== 0) {\n maskData._colorMask = 0;\n gl.colorMask(false, false, false, false);\n }\n // Increment the reference stencil value where the new mask overlaps with the old ones.\n gl.stencilFunc(gl.EQUAL, prevMaskCount, 0xFFFFFFFF);\n gl.stencilOp(gl.KEEP, gl.KEEP, gl.INCR);\n maskObject.renderable = true;\n maskObject.render(this.renderer);\n this.renderer.batch.flush();\n maskObject.renderable = false;\n if (colorMask !== 0) {\n maskData._colorMask = colorMask;\n gl.colorMask((colorMask & 1) !== 0, (colorMask & 2) !== 0, (colorMask & 4) !== 0, (colorMask & 8) !== 0);\n }\n this._useCurrent();\n };\n /**\n * Pops stencil mask. MaskData is already removed from stack\n * @param {PIXI.DisplayObject} maskObject - object of popped mask data\n */\n StencilSystem.prototype.pop = function (maskObject) {\n var gl = this.renderer.gl;\n if (this.getStackLength() === 0) {\n // the stack is empty!\n gl.disable(gl.STENCIL_TEST);\n }\n else {\n var maskData = this.maskStack.length !== 0 ? this.maskStack[this.maskStack.length - 1] : null;\n var colorMask = maskData ? maskData._colorMask : 0xf;\n if (colorMask !== 0) {\n maskData._colorMask = 0;\n gl.colorMask(false, false, false, false);\n }\n // Decrement the reference stencil value where the popped mask overlaps with the other ones\n gl.stencilOp(gl.KEEP, gl.KEEP, gl.DECR);\n maskObject.renderable = true;\n maskObject.render(this.renderer);\n this.renderer.batch.flush();\n maskObject.renderable = false;\n if (colorMask !== 0) {\n maskData._colorMask = colorMask;\n gl.colorMask((colorMask & 0x1) !== 0, (colorMask & 0x2) !== 0, (colorMask & 0x4) !== 0, (colorMask & 0x8) !== 0);\n }\n this._useCurrent();\n }\n };\n /**\n * Setup renderer to use the current stencil data.\n * @private\n */\n StencilSystem.prototype._useCurrent = function () {\n var gl = this.renderer.gl;\n gl.stencilFunc(gl.EQUAL, this.getStackLength(), 0xFFFFFFFF);\n gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);\n };\n return StencilSystem;\n}(AbstractMaskSystem));\n\n/**\n * System plugin to the renderer to manage the projection matrix.\n *\n * The `projectionMatrix` is a global uniform provided to all shaders. It is used to transform points in world space to\n * normalized device coordinates.\n * @memberof PIXI\n */\nvar ProjectionSystem = /** @class */ (function () {\n /** @param renderer - The renderer this System works for. */\n function ProjectionSystem(renderer) {\n this.renderer = renderer;\n this.destinationFrame = null;\n this.sourceFrame = null;\n this.defaultFrame = null;\n this.projectionMatrix = new Matrix();\n this.transform = null;\n }\n /**\n * Updates the projection-matrix based on the sourceFrame → destinationFrame mapping provided.\n *\n * NOTE: It is expected you call `renderer.framebuffer.setViewport(destinationFrame)` after this. This is because\n * the framebuffer viewport converts shader vertex output in normalized device coordinates to window coordinates.\n *\n * NOTE-2: {@link RenderTextureSystem#bind} updates the projection-matrix when you bind a render-texture. It is expected\n * that you dirty the current bindings when calling this manually.\n * @param destinationFrame - The rectangle in the render-target to render the contents into. If rendering to the canvas,\n * the origin is on the top-left; if rendering to a render-texture, the origin is on the bottom-left.\n * @param sourceFrame - The rectangle in world space that contains the contents being rendered.\n * @param resolution - The resolution of the render-target, which is the ratio of\n * world-space (or CSS) pixels to physical pixels.\n * @param root - Whether the render-target is the screen. This is required because rendering to textures\n * is y-flipped (i.e. upside down relative to the screen).\n */\n ProjectionSystem.prototype.update = function (destinationFrame, sourceFrame, resolution, root) {\n this.destinationFrame = destinationFrame || this.destinationFrame || this.defaultFrame;\n this.sourceFrame = sourceFrame || this.sourceFrame || destinationFrame;\n // Calculate object-space to clip-space projection\n this.calculateProjection(this.destinationFrame, this.sourceFrame, resolution, root);\n if (this.transform) {\n this.projectionMatrix.append(this.transform);\n }\n var renderer = this.renderer;\n renderer.globalUniforms.uniforms.projectionMatrix = this.projectionMatrix;\n renderer.globalUniforms.update();\n // this will work for now\n // but would be sweet to stick and even on the global uniforms..\n if (renderer.shader.shader) {\n renderer.shader.syncUniformGroup(renderer.shader.shader.uniforms.globals);\n }\n };\n /**\n * Calculates the `projectionMatrix` to map points inside `sourceFrame` to inside `destinationFrame`.\n * @param _destinationFrame - The destination frame in the render-target.\n * @param sourceFrame - The source frame in world space.\n * @param _resolution - The render-target's resolution, i.e. ratio of CSS to physical pixels.\n * @param root - Whether rendering into the screen. Otherwise, if rendering to a framebuffer, the projection\n * is y-flipped.\n */\n ProjectionSystem.prototype.calculateProjection = function (_destinationFrame, sourceFrame, _resolution, root) {\n var pm = this.projectionMatrix;\n var sign = !root ? 1 : -1;\n pm.identity();\n pm.a = (1 / sourceFrame.width * 2);\n pm.d = sign * (1 / sourceFrame.height * 2);\n pm.tx = -1 - (sourceFrame.x * pm.a);\n pm.ty = -sign - (sourceFrame.y * pm.d);\n };\n /**\n * Sets the transform of the active render target to the given matrix.\n * @param _matrix - The transformation matrix\n */\n ProjectionSystem.prototype.setTransform = function (_matrix) {\n // this._activeRenderTarget.transform = matrix;\n };\n ProjectionSystem.prototype.destroy = function () {\n this.renderer = null;\n };\n return ProjectionSystem;\n}());\n\n// Temporary rectangle for assigned sourceFrame or destinationFrame\nvar tempRect = new Rectangle();\n// Temporary rectangle for renderTexture destinationFrame\nvar tempRect2 = new Rectangle();\n/* eslint-disable max-len */\n/**\n * System plugin to the renderer to manage render textures.\n *\n * Should be added after FramebufferSystem\n *\n * ### Frames\n *\n * The `RenderTextureSystem` holds a sourceFrame → destinationFrame projection. The following table explains the different\n * coordinate spaces used:\n *\n * | Frame | Description | Coordinate System |\n * | ---------------------- | ---------------------------------------------------------------- | ------------------------------------------------------- |\n * | sourceFrame | The rectangle inside of which display-objects are being rendered | **World Space**: The origin on the top-left |\n * | destinationFrame | The rectangle in the render-target (canvas or texture) into which contents should be rendered | If rendering to the canvas, this is in screen space and the origin is on the top-left. If rendering to a render-texture, this is in its base-texture's space with the origin on the bottom-left. |\n * | viewportFrame | The framebuffer viewport corresponding to the destination-frame | **Window Coordinates**: The origin is always on the bottom-left. |\n * @memberof PIXI\n */\nvar RenderTextureSystem = /** @class */ (function () {\n /**\n * @param renderer - The renderer this System works for.\n */\n function RenderTextureSystem(renderer) {\n this.renderer = renderer;\n this.clearColor = renderer._backgroundColorRgba;\n this.defaultMaskStack = [];\n this.current = null;\n this.sourceFrame = new Rectangle();\n this.destinationFrame = new Rectangle();\n this.viewportFrame = new Rectangle();\n }\n /**\n * Bind the current render texture.\n * @param renderTexture - RenderTexture to bind, by default its `null` - the screen.\n * @param sourceFrame - Part of world that is mapped to the renderTexture.\n * @param destinationFrame - Part of renderTexture, by default it has the same size as sourceFrame.\n */\n RenderTextureSystem.prototype.bind = function (renderTexture, sourceFrame, destinationFrame) {\n if (renderTexture === void 0) { renderTexture = null; }\n var renderer = this.renderer;\n this.current = renderTexture;\n var baseTexture;\n var framebuffer;\n var resolution;\n if (renderTexture) {\n baseTexture = renderTexture.baseTexture;\n resolution = baseTexture.resolution;\n if (!sourceFrame) {\n tempRect.width = renderTexture.frame.width;\n tempRect.height = renderTexture.frame.height;\n sourceFrame = tempRect;\n }\n if (!destinationFrame) {\n tempRect2.x = renderTexture.frame.x;\n tempRect2.y = renderTexture.frame.y;\n tempRect2.width = sourceFrame.width;\n tempRect2.height = sourceFrame.height;\n destinationFrame = tempRect2;\n }\n framebuffer = baseTexture.framebuffer;\n }\n else {\n resolution = renderer.resolution;\n if (!sourceFrame) {\n tempRect.width = renderer.screen.width;\n tempRect.height = renderer.screen.height;\n sourceFrame = tempRect;\n }\n if (!destinationFrame) {\n destinationFrame = tempRect;\n destinationFrame.width = sourceFrame.width;\n destinationFrame.height = sourceFrame.height;\n }\n }\n var viewportFrame = this.viewportFrame;\n viewportFrame.x = destinationFrame.x * resolution;\n viewportFrame.y = destinationFrame.y * resolution;\n viewportFrame.width = destinationFrame.width * resolution;\n viewportFrame.height = destinationFrame.height * resolution;\n if (!renderTexture) {\n viewportFrame.y = renderer.view.height - (viewportFrame.y + viewportFrame.height);\n }\n viewportFrame.ceil();\n this.renderer.framebuffer.bind(framebuffer, viewportFrame);\n this.renderer.projection.update(destinationFrame, sourceFrame, resolution, !framebuffer);\n if (renderTexture) {\n this.renderer.mask.setMaskStack(baseTexture.maskStack);\n }\n else {\n this.renderer.mask.setMaskStack(this.defaultMaskStack);\n }\n this.sourceFrame.copyFrom(sourceFrame);\n this.destinationFrame.copyFrom(destinationFrame);\n };\n /**\n * Erases the render texture and fills the drawing area with a colour.\n * @param clearColor - The color as rgba, default to use the renderer backgroundColor\n * @param [mask=BUFFER_BITS.COLOR | BUFFER_BITS.DEPTH] - Bitwise OR of masks\n * that indicate the buffers to be cleared, by default COLOR and DEPTH buffers.\n */\n RenderTextureSystem.prototype.clear = function (clearColor, mask) {\n if (this.current) {\n clearColor = clearColor || this.current.baseTexture.clearColor;\n }\n else {\n clearColor = clearColor || this.clearColor;\n }\n var destinationFrame = this.destinationFrame;\n var baseFrame = this.current ? this.current.baseTexture : this.renderer.screen;\n var clearMask = destinationFrame.width !== baseFrame.width || destinationFrame.height !== baseFrame.height;\n if (clearMask) {\n var _a = this.viewportFrame, x = _a.x, y = _a.y, width = _a.width, height = _a.height;\n x = Math.round(x);\n y = Math.round(y);\n width = Math.round(width);\n height = Math.round(height);\n // TODO: ScissorSystem should cache whether the scissor test is enabled or not.\n this.renderer.gl.enable(this.renderer.gl.SCISSOR_TEST);\n this.renderer.gl.scissor(x, y, width, height);\n }\n this.renderer.framebuffer.clear(clearColor[0], clearColor[1], clearColor[2], clearColor[3], mask);\n if (clearMask) {\n // Restore the scissor box\n this.renderer.scissor.pop();\n }\n };\n RenderTextureSystem.prototype.resize = function () {\n // resize the root only!\n this.bind(null);\n };\n /** Resets render-texture state. */\n RenderTextureSystem.prototype.reset = function () {\n this.bind(null);\n };\n RenderTextureSystem.prototype.destroy = function () {\n this.renderer = null;\n };\n return RenderTextureSystem;\n}());\n\nfunction uboUpdate(_ud, _uv, _renderer, _syncData, buffer) {\n _renderer.buffer.update(buffer);\n}\n// cv = CachedValue\n// v = value\n// ud = uniformData\n// uv = uniformValue\n// l = location\nvar UBO_TO_SINGLE_SETTERS = {\n float: \"\\n data[offset] = v;\\n \",\n vec2: \"\\n data[offset] = v[0];\\n data[offset+1] = v[1];\\n \",\n vec3: \"\\n data[offset] = v[0];\\n data[offset+1] = v[1];\\n data[offset+2] = v[2];\\n\\n \",\n vec4: \"\\n data[offset] = v[0];\\n data[offset+1] = v[1];\\n data[offset+2] = v[2];\\n data[offset+3] = v[3];\\n \",\n mat2: \"\\n data[offset] = v[0];\\n data[offset+1] = v[1];\\n\\n data[offset+4] = v[2];\\n data[offset+5] = v[3];\\n \",\n mat3: \"\\n data[offset] = v[0];\\n data[offset+1] = v[1];\\n data[offset+2] = v[2];\\n\\n data[offset + 4] = v[3];\\n data[offset + 5] = v[4];\\n data[offset + 6] = v[5];\\n\\n data[offset + 8] = v[6];\\n data[offset + 9] = v[7];\\n data[offset + 10] = v[8];\\n \",\n mat4: \"\\n for(var i = 0; i < 16; i++)\\n {\\n data[offset + i] = v[i];\\n }\\n \"\n};\nvar GLSL_TO_STD40_SIZE = {\n float: 4,\n vec2: 8,\n vec3: 12,\n vec4: 16,\n int: 4,\n ivec2: 8,\n ivec3: 12,\n ivec4: 16,\n uint: 4,\n uvec2: 8,\n uvec3: 12,\n uvec4: 16,\n bool: 4,\n bvec2: 8,\n bvec3: 12,\n bvec4: 16,\n mat2: 16 * 2,\n mat3: 16 * 3,\n mat4: 16 * 4,\n};\n/**\n * logic originally from here: https://github.com/sketchpunk/FunWithWebGL2/blob/master/lesson_022/Shaders.js\n * rewrote it, but this was a great starting point to get a solid understanding of whats going on :)\n * @ignore\n * @param uniformData\n */\nfunction createUBOElements(uniformData) {\n var uboElements = uniformData.map(function (data) {\n return ({\n data: data,\n offset: 0,\n dataLen: 0,\n dirty: 0\n });\n });\n var size = 0;\n var chunkSize = 0;\n var offset = 0;\n for (var i = 0; i < uboElements.length; i++) {\n var uboElement = uboElements[i];\n size = GLSL_TO_STD40_SIZE[uboElement.data.type];\n if (uboElement.data.size > 1) {\n size = Math.max(size, 16) * uboElement.data.size;\n }\n uboElement.dataLen = size;\n // add some size offset..\n // must align to the nearest 16 bytes or internally nearest round size\n if (chunkSize % size !== 0 && chunkSize < 16) {\n // diff required to line up..\n var lineUpValue = (chunkSize % size) % 16;\n chunkSize += lineUpValue;\n offset += lineUpValue;\n }\n if ((chunkSize + size) > 16) {\n offset = Math.ceil(offset / 16) * 16;\n uboElement.offset = offset;\n offset += size;\n chunkSize = size;\n }\n else {\n uboElement.offset = offset;\n chunkSize += size;\n offset += size;\n }\n }\n offset = Math.ceil(offset / 16) * 16;\n return { uboElements: uboElements, size: offset };\n}\nfunction getUBOData(uniforms, uniformData) {\n var usedUniformDatas = [];\n // build..\n for (var i in uniforms) {\n if (uniformData[i]) {\n usedUniformDatas.push(uniformData[i]);\n }\n }\n // sort them out by index!\n usedUniformDatas.sort(function (a, b) { return a.index - b.index; });\n return usedUniformDatas;\n}\nfunction generateUniformBufferSync(group, uniformData) {\n if (!group.autoManage) {\n // if the group is nott automatically managed, we don't need to generate a special function for it...\n return { size: 0, syncFunc: uboUpdate };\n }\n var usedUniformDatas = getUBOData(group.uniforms, uniformData);\n var _a = createUBOElements(usedUniformDatas), uboElements = _a.uboElements, size = _a.size;\n var funcFragments = [\"\\n var v = null;\\n var v2 = null;\\n var cv = null;\\n var t = 0;\\n var gl = renderer.gl\\n var index = 0;\\n var data = buffer.data;\\n \"];\n for (var i = 0; i < uboElements.length; i++) {\n var uboElement = uboElements[i];\n var uniform = group.uniforms[uboElement.data.name];\n var name = uboElement.data.name;\n var parsed = false;\n for (var j = 0; j < uniformParsers.length; j++) {\n var uniformParser = uniformParsers[j];\n if (uniformParser.codeUbo && uniformParser.test(uboElement.data, uniform)) {\n funcFragments.push(\"offset = \" + uboElement.offset / 4 + \";\", uniformParsers[j].codeUbo(uboElement.data.name, uniform));\n parsed = true;\n break;\n }\n }\n if (!parsed) {\n if (uboElement.data.size > 1) {\n var size_1 = mapSize(uboElement.data.type);\n var rowSize = Math.max(GLSL_TO_STD40_SIZE[uboElement.data.type] / 16, 1);\n var elementSize = size_1 / rowSize;\n var remainder = (4 - (elementSize % 4)) % 4;\n funcFragments.push(\"\\n cv = ud.\" + name + \".value;\\n v = uv.\" + name + \";\\n offset = \" + uboElement.offset / 4 + \";\\n\\n t = 0;\\n\\n for(var i=0; i < \" + uboElement.data.size * rowSize + \"; i++)\\n {\\n for(var j = 0; j < \" + elementSize + \"; j++)\\n {\\n data[offset++] = v[t++];\\n }\\n offset += \" + remainder + \";\\n }\\n\\n \");\n }\n else {\n var template = UBO_TO_SINGLE_SETTERS[uboElement.data.type];\n funcFragments.push(\"\\n cv = ud.\" + name + \".value;\\n v = uv.\" + name + \";\\n offset = \" + uboElement.offset / 4 + \";\\n \" + template + \";\\n \");\n }\n }\n }\n funcFragments.push(\"\\n renderer.buffer.update(buffer);\\n \");\n return {\n size: size,\n // eslint-disable-next-line no-new-func\n syncFunc: new Function('ud', 'uv', 'renderer', 'syncData', 'buffer', funcFragments.join('\\n'))\n };\n}\n\n/**\n * @private\n */\nvar IGLUniformData = /** @class */ (function () {\n function IGLUniformData() {\n }\n return IGLUniformData;\n}());\n/**\n * Helper class to create a WebGL Program\n * @memberof PIXI\n */\nvar GLProgram = /** @class */ (function () {\n /**\n * Makes a new Pixi program.\n * @param program - webgl program\n * @param uniformData - uniforms\n */\n function GLProgram(program, uniformData) {\n this.program = program;\n this.uniformData = uniformData;\n this.uniformGroups = {};\n this.uniformDirtyGroups = {};\n this.uniformBufferBindings = {};\n }\n /** Destroys this program. */\n GLProgram.prototype.destroy = function () {\n this.uniformData = null;\n this.uniformGroups = null;\n this.uniformDirtyGroups = null;\n this.uniformBufferBindings = null;\n this.program = null;\n };\n return GLProgram;\n}());\n\n/**\n * returns the attribute data from the program\n * @private\n * @param {WebGLProgram} [program] - the WebGL program\n * @param {WebGLRenderingContext} [gl] - the WebGL context\n * @returns {object} the attribute data for this program\n */\nfunction getAttributeData(program, gl) {\n var attributes = {};\n var totalAttributes = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);\n for (var i = 0; i < totalAttributes; i++) {\n var attribData = gl.getActiveAttrib(program, i);\n if (attribData.name.indexOf('gl_') === 0) {\n continue;\n }\n var type = mapType(gl, attribData.type);\n var data = {\n type: type,\n name: attribData.name,\n size: mapSize(type),\n location: gl.getAttribLocation(program, attribData.name),\n };\n attributes[attribData.name] = data;\n }\n return attributes;\n}\n\n/**\n * returns the uniform data from the program\n * @private\n * @param program - the webgl program\n * @param gl - the WebGL context\n * @returns {object} the uniform data for this program\n */\nfunction getUniformData(program, gl) {\n var uniforms = {};\n var totalUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);\n for (var i = 0; i < totalUniforms; i++) {\n var uniformData = gl.getActiveUniform(program, i);\n var name = uniformData.name.replace(/\\[.*?\\]$/, '');\n var isArray = !!(uniformData.name.match(/\\[.*?\\]$/));\n var type = mapType(gl, uniformData.type);\n uniforms[name] = {\n name: name,\n index: i,\n type: type,\n size: uniformData.size,\n isArray: isArray,\n value: defaultValue(type, uniformData.size),\n };\n }\n return uniforms;\n}\n\n/**\n * generates a WebGL Program object from a high level Pixi Program.\n * @param gl - a rendering context on which to generate the program\n * @param program - the high level Pixi Program.\n */\nfunction generateProgram(gl, program) {\n var glVertShader = compileShader(gl, gl.VERTEX_SHADER, program.vertexSrc);\n var glFragShader = compileShader(gl, gl.FRAGMENT_SHADER, program.fragmentSrc);\n var webGLProgram = gl.createProgram();\n gl.attachShader(webGLProgram, glVertShader);\n gl.attachShader(webGLProgram, glFragShader);\n gl.linkProgram(webGLProgram);\n if (!gl.getProgramParameter(webGLProgram, gl.LINK_STATUS)) {\n logProgramError(gl, webGLProgram, glVertShader, glFragShader);\n }\n program.attributeData = getAttributeData(webGLProgram, gl);\n program.uniformData = getUniformData(webGLProgram, gl);\n // GLSL 1.00: bind attributes sorted by name in ascending order\n // GLSL 3.00: don't change the attribute locations that where chosen by the compiler\n // or assigned by the layout specifier in the shader source code\n if (!(/^[ \\t]*#[ \\t]*version[ \\t]+300[ \\t]+es[ \\t]*$/m).test(program.vertexSrc)) {\n var keys = Object.keys(program.attributeData);\n keys.sort(function (a, b) { return (a > b) ? 1 : -1; }); // eslint-disable-line no-confusing-arrow\n for (var i = 0; i < keys.length; i++) {\n program.attributeData[keys[i]].location = i;\n gl.bindAttribLocation(webGLProgram, i, keys[i]);\n }\n gl.linkProgram(webGLProgram);\n }\n gl.deleteShader(glVertShader);\n gl.deleteShader(glFragShader);\n var uniformData = {};\n for (var i in program.uniformData) {\n var data = program.uniformData[i];\n uniformData[i] = {\n location: gl.getUniformLocation(webGLProgram, i),\n value: defaultValue(data.type, data.size),\n };\n }\n var glProgram = new GLProgram(webGLProgram, uniformData);\n return glProgram;\n}\n\nvar UID = 0;\n// default sync data so we don't create a new one each time!\nvar defaultSyncData = { textureCount: 0, uboCount: 0 };\n/**\n * System plugin to the renderer to manage shaders.\n * @memberof PIXI\n */\nvar ShaderSystem = /** @class */ (function () {\n /** @param renderer - The renderer this System works for. */\n function ShaderSystem(renderer) {\n this.destroyed = false;\n this.renderer = renderer;\n // Validation check that this environment support `new Function`\n this.systemCheck();\n this.gl = null;\n this.shader = null;\n this.program = null;\n this.cache = {};\n this._uboCache = {};\n this.id = UID++;\n }\n /**\n * Overrideable function by `@pixi/unsafe-eval` to silence\n * throwing an error if platform doesn't support unsafe-evals.\n * @private\n */\n ShaderSystem.prototype.systemCheck = function () {\n if (!unsafeEvalSupported()) {\n throw new Error('Current environment does not allow unsafe-eval, '\n + 'please use @pixi/unsafe-eval module to enable support.');\n }\n };\n ShaderSystem.prototype.contextChange = function (gl) {\n this.gl = gl;\n this.reset();\n };\n /**\n * Changes the current shader to the one given in parameter.\n * @param shader - the new shader\n * @param dontSync - false if the shader should automatically sync its uniforms.\n * @returns the glProgram that belongs to the shader.\n */\n ShaderSystem.prototype.bind = function (shader, dontSync) {\n shader.disposeRunner.add(this);\n shader.uniforms.globals = this.renderer.globalUniforms;\n var program = shader.program;\n var glProgram = program.glPrograms[this.renderer.CONTEXT_UID] || this.generateProgram(shader);\n this.shader = shader;\n // TODO - some current Pixi plugins bypass this.. so it not safe to use yet..\n if (this.program !== program) {\n this.program = program;\n this.gl.useProgram(glProgram.program);\n }\n if (!dontSync) {\n defaultSyncData.textureCount = 0;\n defaultSyncData.uboCount = 0;\n this.syncUniformGroup(shader.uniformGroup, defaultSyncData);\n }\n return glProgram;\n };\n /**\n * Uploads the uniforms values to the currently bound shader.\n * @param uniforms - the uniforms values that be applied to the current shader\n */\n ShaderSystem.prototype.setUniforms = function (uniforms) {\n var shader = this.shader.program;\n var glProgram = shader.glPrograms[this.renderer.CONTEXT_UID];\n shader.syncUniforms(glProgram.uniformData, uniforms, this.renderer);\n };\n /* eslint-disable @typescript-eslint/explicit-module-boundary-types */\n /**\n * Syncs uniforms on the group\n * @param group - the uniform group to sync\n * @param syncData - this is data that is passed to the sync function and any nested sync functions\n */\n ShaderSystem.prototype.syncUniformGroup = function (group, syncData) {\n var glProgram = this.getGlProgram();\n if (!group.static || group.dirtyId !== glProgram.uniformDirtyGroups[group.id]) {\n glProgram.uniformDirtyGroups[group.id] = group.dirtyId;\n this.syncUniforms(group, glProgram, syncData);\n }\n };\n /**\n * Overrideable by the @pixi/unsafe-eval package to use static syncUniforms instead.\n * @param group\n * @param glProgram\n * @param syncData\n */\n ShaderSystem.prototype.syncUniforms = function (group, glProgram, syncData) {\n var syncFunc = group.syncUniforms[this.shader.program.id] || this.createSyncGroups(group);\n syncFunc(glProgram.uniformData, group.uniforms, this.renderer, syncData);\n };\n ShaderSystem.prototype.createSyncGroups = function (group) {\n var id = this.getSignature(group, this.shader.program.uniformData, 'u');\n if (!this.cache[id]) {\n this.cache[id] = generateUniformsSync(group, this.shader.program.uniformData);\n }\n group.syncUniforms[this.shader.program.id] = this.cache[id];\n return group.syncUniforms[this.shader.program.id];\n };\n /**\n * Syncs uniform buffers\n * @param group - the uniform buffer group to sync\n * @param name - the name of the uniform buffer\n */\n ShaderSystem.prototype.syncUniformBufferGroup = function (group, name) {\n var glProgram = this.getGlProgram();\n if (!group.static || group.dirtyId !== 0 || !glProgram.uniformGroups[group.id]) {\n group.dirtyId = 0;\n var syncFunc = glProgram.uniformGroups[group.id]\n || this.createSyncBufferGroup(group, glProgram, name);\n // TODO wrap update in a cache??\n group.buffer.update();\n syncFunc(glProgram.uniformData, group.uniforms, this.renderer, defaultSyncData, group.buffer);\n }\n this.renderer.buffer.bindBufferBase(group.buffer, glProgram.uniformBufferBindings[name]);\n };\n /**\n * Will create a function that uploads a uniform buffer using the STD140 standard.\n * The upload function will then be cached for future calls\n * If a group is manually managed, then a simple upload function is generated\n * @param group - the uniform buffer group to sync\n * @param glProgram - the gl program to attach the uniform bindings to\n * @param name - the name of the uniform buffer (must exist on the shader)\n */\n ShaderSystem.prototype.createSyncBufferGroup = function (group, glProgram, name) {\n var gl = this.renderer.gl;\n this.renderer.buffer.bind(group.buffer);\n // bind them...\n var uniformBlockIndex = this.gl.getUniformBlockIndex(glProgram.program, name);\n glProgram.uniformBufferBindings[name] = this.shader.uniformBindCount;\n gl.uniformBlockBinding(glProgram.program, uniformBlockIndex, this.shader.uniformBindCount);\n this.shader.uniformBindCount++;\n var id = this.getSignature(group, this.shader.program.uniformData, 'ubo');\n var uboData = this._uboCache[id];\n if (!uboData) {\n uboData = this._uboCache[id] = generateUniformBufferSync(group, this.shader.program.uniformData);\n }\n if (group.autoManage) {\n var data = new Float32Array(uboData.size / 4);\n group.buffer.update(data);\n }\n glProgram.uniformGroups[group.id] = uboData.syncFunc;\n return glProgram.uniformGroups[group.id];\n };\n /**\n * Takes a uniform group and data and generates a unique signature for them.\n * @param group - The uniform group to get signature of\n * @param group.uniforms\n * @param uniformData - Uniform information generated by the shader\n * @param preFix\n * @returns Unique signature of the uniform group\n */\n ShaderSystem.prototype.getSignature = function (group, uniformData, preFix) {\n var uniforms = group.uniforms;\n var strings = [preFix + \"-\"];\n for (var i in uniforms) {\n strings.push(i);\n if (uniformData[i]) {\n strings.push(uniformData[i].type);\n }\n }\n return strings.join('-');\n };\n /**\n * Returns the underlying GLShade rof the currently bound shader.\n *\n * This can be handy for when you to have a little more control over the setting of your uniforms.\n * @returns The glProgram for the currently bound Shader for this context\n */\n ShaderSystem.prototype.getGlProgram = function () {\n if (this.shader) {\n return this.shader.program.glPrograms[this.renderer.CONTEXT_UID];\n }\n return null;\n };\n /**\n * Generates a glProgram version of the Shader provided.\n * @param shader - The shader that the glProgram will be based on.\n * @returns A shiny new glProgram!\n */\n ShaderSystem.prototype.generateProgram = function (shader) {\n var gl = this.gl;\n var program = shader.program;\n var glProgram = generateProgram(gl, program);\n program.glPrograms[this.renderer.CONTEXT_UID] = glProgram;\n return glProgram;\n };\n /** Resets ShaderSystem state, does not affect WebGL state. */\n ShaderSystem.prototype.reset = function () {\n this.program = null;\n this.shader = null;\n };\n /**\n * Disposes shader.\n * If disposing one equals with current shader, set current as null.\n * @param shader - Shader object\n */\n ShaderSystem.prototype.disposeShader = function (shader) {\n if (this.shader === shader) {\n this.shader = null;\n }\n };\n /** Destroys this System and removes all its textures. */\n ShaderSystem.prototype.destroy = function () {\n this.renderer = null;\n // TODO implement destroy method for ShaderSystem\n this.destroyed = true;\n };\n return ShaderSystem;\n}());\n\n/**\n * Maps gl blend combinations to WebGL.\n * @memberof PIXI\n * @function mapWebGLBlendModesToPixi\n * @private\n * @param {WebGLRenderingContext} gl - The rendering context.\n * @param {number[][]} [array=[]] - The array to output into.\n * @returns {number[][]} Mapped modes.\n */\nfunction mapWebGLBlendModesToPixi(gl, array) {\n if (array === void 0) { array = []; }\n // TODO - premultiply alpha would be different.\n // add a boolean for that!\n array[BLEND_MODES.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];\n array[BLEND_MODES.ADD] = [gl.ONE, gl.ONE];\n array[BLEND_MODES.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA];\n array[BLEND_MODES.SCREEN] = [gl.ONE, gl.ONE_MINUS_SRC_COLOR, gl.ONE, gl.ONE_MINUS_SRC_ALPHA];\n array[BLEND_MODES.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];\n array[BLEND_MODES.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];\n array[BLEND_MODES.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];\n array[BLEND_MODES.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];\n array[BLEND_MODES.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];\n array[BLEND_MODES.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];\n array[BLEND_MODES.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];\n array[BLEND_MODES.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];\n array[BLEND_MODES.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];\n array[BLEND_MODES.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];\n array[BLEND_MODES.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];\n array[BLEND_MODES.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];\n array[BLEND_MODES.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA];\n array[BLEND_MODES.NONE] = [0, 0];\n // not-premultiplied blend modes\n array[BLEND_MODES.NORMAL_NPM] = [gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA];\n array[BLEND_MODES.ADD_NPM] = [gl.SRC_ALPHA, gl.ONE, gl.ONE, gl.ONE];\n array[BLEND_MODES.SCREEN_NPM] = [gl.SRC_ALPHA, gl.ONE_MINUS_SRC_COLOR, gl.ONE, gl.ONE_MINUS_SRC_ALPHA];\n // composite operations\n array[BLEND_MODES.SRC_IN] = [gl.DST_ALPHA, gl.ZERO];\n array[BLEND_MODES.SRC_OUT] = [gl.ONE_MINUS_DST_ALPHA, gl.ZERO];\n array[BLEND_MODES.SRC_ATOP] = [gl.DST_ALPHA, gl.ONE_MINUS_SRC_ALPHA];\n array[BLEND_MODES.DST_OVER] = [gl.ONE_MINUS_DST_ALPHA, gl.ONE];\n array[BLEND_MODES.DST_IN] = [gl.ZERO, gl.SRC_ALPHA];\n array[BLEND_MODES.DST_OUT] = [gl.ZERO, gl.ONE_MINUS_SRC_ALPHA];\n array[BLEND_MODES.DST_ATOP] = [gl.ONE_MINUS_DST_ALPHA, gl.SRC_ALPHA];\n array[BLEND_MODES.XOR] = [gl.ONE_MINUS_DST_ALPHA, gl.ONE_MINUS_SRC_ALPHA];\n // SUBTRACT from flash\n array[BLEND_MODES.SUBTRACT] = [gl.ONE, gl.ONE, gl.ONE, gl.ONE, gl.FUNC_REVERSE_SUBTRACT, gl.FUNC_ADD];\n return array;\n}\n\nvar BLEND = 0;\nvar OFFSET = 1;\nvar CULLING = 2;\nvar DEPTH_TEST = 3;\nvar WINDING = 4;\nvar DEPTH_MASK = 5;\n/**\n * System plugin to the renderer to manage WebGL state machines.\n * @memberof PIXI\n */\nvar StateSystem = /** @class */ (function () {\n function StateSystem() {\n this.gl = null;\n this.stateId = 0;\n this.polygonOffset = 0;\n this.blendMode = BLEND_MODES.NONE;\n this._blendEq = false;\n // map functions for when we set state..\n this.map = [];\n this.map[BLEND] = this.setBlend;\n this.map[OFFSET] = this.setOffset;\n this.map[CULLING] = this.setCullFace;\n this.map[DEPTH_TEST] = this.setDepthTest;\n this.map[WINDING] = this.setFrontFace;\n this.map[DEPTH_MASK] = this.setDepthMask;\n this.checks = [];\n this.defaultState = new State();\n this.defaultState.blend = true;\n }\n StateSystem.prototype.contextChange = function (gl) {\n this.gl = gl;\n this.blendModes = mapWebGLBlendModesToPixi(gl);\n this.set(this.defaultState);\n this.reset();\n };\n /**\n * Sets the current state\n * @param {*} state - The state to set.\n */\n StateSystem.prototype.set = function (state) {\n state = state || this.defaultState;\n // TODO maybe to an object check? ( this.state === state )?\n if (this.stateId !== state.data) {\n var diff = this.stateId ^ state.data;\n var i = 0;\n // order from least to most common\n while (diff) {\n if (diff & 1) {\n // state change!\n this.map[i].call(this, !!(state.data & (1 << i)));\n }\n diff = diff >> 1;\n i++;\n }\n this.stateId = state.data;\n }\n // based on the above settings we check for specific modes..\n // for example if blend is active we check and set the blend modes\n // or of polygon offset is active we check the poly depth.\n for (var i = 0; i < this.checks.length; i++) {\n this.checks[i](this, state);\n }\n };\n /**\n * Sets the state, when previous state is unknown.\n * @param {*} state - The state to set\n */\n StateSystem.prototype.forceState = function (state) {\n state = state || this.defaultState;\n for (var i = 0; i < this.map.length; i++) {\n this.map[i].call(this, !!(state.data & (1 << i)));\n }\n for (var i = 0; i < this.checks.length; i++) {\n this.checks[i](this, state);\n }\n this.stateId = state.data;\n };\n /**\n * Sets whether to enable or disable blending.\n * @param value - Turn on or off WebGl blending.\n */\n StateSystem.prototype.setBlend = function (value) {\n this.updateCheck(StateSystem.checkBlendMode, value);\n this.gl[value ? 'enable' : 'disable'](this.gl.BLEND);\n };\n /**\n * Sets whether to enable or disable polygon offset fill.\n * @param value - Turn on or off webgl polygon offset testing.\n */\n StateSystem.prototype.setOffset = function (value) {\n this.updateCheck(StateSystem.checkPolygonOffset, value);\n this.gl[value ? 'enable' : 'disable'](this.gl.POLYGON_OFFSET_FILL);\n };\n /**\n * Sets whether to enable or disable depth test.\n * @param value - Turn on or off webgl depth testing.\n */\n StateSystem.prototype.setDepthTest = function (value) {\n this.gl[value ? 'enable' : 'disable'](this.gl.DEPTH_TEST);\n };\n /**\n * Sets whether to enable or disable depth mask.\n * @param value - Turn on or off webgl depth mask.\n */\n StateSystem.prototype.setDepthMask = function (value) {\n this.gl.depthMask(value);\n };\n /**\n * Sets whether to enable or disable cull face.\n * @param {boolean} value - Turn on or off webgl cull face.\n */\n StateSystem.prototype.setCullFace = function (value) {\n this.gl[value ? 'enable' : 'disable'](this.gl.CULL_FACE);\n };\n /**\n * Sets the gl front face.\n * @param {boolean} value - true is clockwise and false is counter-clockwise\n */\n StateSystem.prototype.setFrontFace = function (value) {\n this.gl.frontFace(this.gl[value ? 'CW' : 'CCW']);\n };\n /**\n * Sets the blend mode.\n * @param {number} value - The blend mode to set to.\n */\n StateSystem.prototype.setBlendMode = function (value) {\n if (value === this.blendMode) {\n return;\n }\n this.blendMode = value;\n var mode = this.blendModes[value];\n var gl = this.gl;\n if (mode.length === 2) {\n gl.blendFunc(mode[0], mode[1]);\n }\n else {\n gl.blendFuncSeparate(mode[0], mode[1], mode[2], mode[3]);\n }\n if (mode.length === 6) {\n this._blendEq = true;\n gl.blendEquationSeparate(mode[4], mode[5]);\n }\n else if (this._blendEq) {\n this._blendEq = false;\n gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD);\n }\n };\n /**\n * Sets the polygon offset.\n * @param {number} value - the polygon offset\n * @param {number} scale - the polygon offset scale\n */\n StateSystem.prototype.setPolygonOffset = function (value, scale) {\n this.gl.polygonOffset(value, scale);\n };\n // used\n /** Resets all the logic and disables the VAOs. */\n StateSystem.prototype.reset = function () {\n this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, false);\n this.forceState(this.defaultState);\n this._blendEq = true;\n this.blendMode = -1;\n this.setBlendMode(0);\n };\n /**\n * Checks to see which updates should be checked based on which settings have been activated.\n *\n * For example, if blend is enabled then we should check the blend modes each time the state is changed\n * or if polygon fill is activated then we need to check if the polygon offset changes.\n * The idea is that we only check what we have too.\n * @param func - the checking function to add or remove\n * @param value - should the check function be added or removed.\n */\n StateSystem.prototype.updateCheck = function (func, value) {\n var index = this.checks.indexOf(func);\n if (value && index === -1) {\n this.checks.push(func);\n }\n else if (!value && index !== -1) {\n this.checks.splice(index, 1);\n }\n };\n /**\n * A private little wrapper function that we call to check the blend mode.\n * @param system - the System to perform the state check on\n * @param state - the state that the blendMode will pulled from\n */\n StateSystem.checkBlendMode = function (system, state) {\n system.setBlendMode(state.blendMode);\n };\n /**\n * A private little wrapper function that we call to check the polygon offset.\n * @param system - the System to perform the state check on\n * @param state - the state that the blendMode will pulled from\n */\n StateSystem.checkPolygonOffset = function (system, state) {\n system.setPolygonOffset(1, state.polygonOffset);\n };\n /**\n * @ignore\n */\n StateSystem.prototype.destroy = function () {\n this.gl = null;\n };\n return StateSystem;\n}());\n\n/**\n * System plugin to the renderer to manage texture garbage collection on the GPU,\n * ensuring that it does not get clogged up with textures that are no longer being used.\n * @memberof PIXI\n */\nvar TextureGCSystem = /** @class */ (function () {\n /** @param renderer - The renderer this System works for. */\n function TextureGCSystem(renderer) {\n this.renderer = renderer;\n this.count = 0;\n this.checkCount = 0;\n this.maxIdle = settings.GC_MAX_IDLE;\n this.checkCountMax = settings.GC_MAX_CHECK_COUNT;\n this.mode = settings.GC_MODE;\n }\n /**\n * Checks to see when the last time a texture was used\n * if the texture has not been used for a specified amount of time it will be removed from the GPU\n */\n TextureGCSystem.prototype.postrender = function () {\n if (!this.renderer.renderingToScreen) {\n return;\n }\n this.count++;\n if (this.mode === GC_MODES.MANUAL) {\n return;\n }\n this.checkCount++;\n if (this.checkCount > this.checkCountMax) {\n this.checkCount = 0;\n this.run();\n }\n };\n /**\n * Checks to see when the last time a texture was used\n * if the texture has not been used for a specified amount of time it will be removed from the GPU\n */\n TextureGCSystem.prototype.run = function () {\n var tm = this.renderer.texture;\n var managedTextures = tm.managedTextures;\n var wasRemoved = false;\n for (var i = 0; i < managedTextures.length; i++) {\n var texture = managedTextures[i];\n // only supports non generated textures at the moment!\n if (!texture.framebuffer && this.count - texture.touched > this.maxIdle) {\n tm.destroyTexture(texture, true);\n managedTextures[i] = null;\n wasRemoved = true;\n }\n }\n if (wasRemoved) {\n var j = 0;\n for (var i = 0; i < managedTextures.length; i++) {\n if (managedTextures[i] !== null) {\n managedTextures[j++] = managedTextures[i];\n }\n }\n managedTextures.length = j;\n }\n };\n /**\n * Removes all the textures within the specified displayObject and its children from the GPU\n * @param {PIXI.DisplayObject} displayObject - the displayObject to remove the textures from.\n */\n TextureGCSystem.prototype.unload = function (displayObject) {\n var tm = this.renderer.texture;\n var texture = displayObject._texture;\n // only destroy non generated textures\n if (texture && !texture.framebuffer) {\n tm.destroyTexture(texture);\n }\n for (var i = displayObject.children.length - 1; i >= 0; i--) {\n this.unload(displayObject.children[i]);\n }\n };\n TextureGCSystem.prototype.destroy = function () {\n this.renderer = null;\n };\n return TextureGCSystem;\n}());\n\n/**\n * Returns a lookup table that maps each type-format pair to a compatible internal format.\n * @memberof PIXI\n * @function mapTypeAndFormatToInternalFormat\n * @private\n * @param {WebGLRenderingContext} gl - The rendering context.\n * @returns Lookup table.\n */\nfunction mapTypeAndFormatToInternalFormat(gl) {\n var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;\n var table;\n if ('WebGL2RenderingContext' in globalThis && gl instanceof globalThis.WebGL2RenderingContext) {\n table = (_a = {},\n _a[TYPES.UNSIGNED_BYTE] = (_b = {},\n _b[FORMATS.RGBA] = gl.RGBA8,\n _b[FORMATS.RGB] = gl.RGB8,\n _b[FORMATS.RG] = gl.RG8,\n _b[FORMATS.RED] = gl.R8,\n _b[FORMATS.RGBA_INTEGER] = gl.RGBA8UI,\n _b[FORMATS.RGB_INTEGER] = gl.RGB8UI,\n _b[FORMATS.RG_INTEGER] = gl.RG8UI,\n _b[FORMATS.RED_INTEGER] = gl.R8UI,\n _b[FORMATS.ALPHA] = gl.ALPHA,\n _b[FORMATS.LUMINANCE] = gl.LUMINANCE,\n _b[FORMATS.LUMINANCE_ALPHA] = gl.LUMINANCE_ALPHA,\n _b),\n _a[TYPES.BYTE] = (_c = {},\n _c[FORMATS.RGBA] = gl.RGBA8_SNORM,\n _c[FORMATS.RGB] = gl.RGB8_SNORM,\n _c[FORMATS.RG] = gl.RG8_SNORM,\n _c[FORMATS.RED] = gl.R8_SNORM,\n _c[FORMATS.RGBA_INTEGER] = gl.RGBA8I,\n _c[FORMATS.RGB_INTEGER] = gl.RGB8I,\n _c[FORMATS.RG_INTEGER] = gl.RG8I,\n _c[FORMATS.RED_INTEGER] = gl.R8I,\n _c),\n _a[TYPES.UNSIGNED_SHORT] = (_d = {},\n _d[FORMATS.RGBA_INTEGER] = gl.RGBA16UI,\n _d[FORMATS.RGB_INTEGER] = gl.RGB16UI,\n _d[FORMATS.RG_INTEGER] = gl.RG16UI,\n _d[FORMATS.RED_INTEGER] = gl.R16UI,\n _d[FORMATS.DEPTH_COMPONENT] = gl.DEPTH_COMPONENT16,\n _d),\n _a[TYPES.SHORT] = (_e = {},\n _e[FORMATS.RGBA_INTEGER] = gl.RGBA16I,\n _e[FORMATS.RGB_INTEGER] = gl.RGB16I,\n _e[FORMATS.RG_INTEGER] = gl.RG16I,\n _e[FORMATS.RED_INTEGER] = gl.R16I,\n _e),\n _a[TYPES.UNSIGNED_INT] = (_f = {},\n _f[FORMATS.RGBA_INTEGER] = gl.RGBA32UI,\n _f[FORMATS.RGB_INTEGER] = gl.RGB32UI,\n _f[FORMATS.RG_INTEGER] = gl.RG32UI,\n _f[FORMATS.RED_INTEGER] = gl.R32UI,\n _f[FORMATS.DEPTH_COMPONENT] = gl.DEPTH_COMPONENT24,\n _f),\n _a[TYPES.INT] = (_g = {},\n _g[FORMATS.RGBA_INTEGER] = gl.RGBA32I,\n _g[FORMATS.RGB_INTEGER] = gl.RGB32I,\n _g[FORMATS.RG_INTEGER] = gl.RG32I,\n _g[FORMATS.RED_INTEGER] = gl.R32I,\n _g),\n _a[TYPES.FLOAT] = (_h = {},\n _h[FORMATS.RGBA] = gl.RGBA32F,\n _h[FORMATS.RGB] = gl.RGB32F,\n _h[FORMATS.RG] = gl.RG32F,\n _h[FORMATS.RED] = gl.R32F,\n _h[FORMATS.DEPTH_COMPONENT] = gl.DEPTH_COMPONENT32F,\n _h),\n _a[TYPES.HALF_FLOAT] = (_j = {},\n _j[FORMATS.RGBA] = gl.RGBA16F,\n _j[FORMATS.RGB] = gl.RGB16F,\n _j[FORMATS.RG] = gl.RG16F,\n _j[FORMATS.RED] = gl.R16F,\n _j),\n _a[TYPES.UNSIGNED_SHORT_5_6_5] = (_k = {},\n _k[FORMATS.RGB] = gl.RGB565,\n _k),\n _a[TYPES.UNSIGNED_SHORT_4_4_4_4] = (_l = {},\n _l[FORMATS.RGBA] = gl.RGBA4,\n _l),\n _a[TYPES.UNSIGNED_SHORT_5_5_5_1] = (_m = {},\n _m[FORMATS.RGBA] = gl.RGB5_A1,\n _m),\n _a[TYPES.UNSIGNED_INT_2_10_10_10_REV] = (_o = {},\n _o[FORMATS.RGBA] = gl.RGB10_A2,\n _o[FORMATS.RGBA_INTEGER] = gl.RGB10_A2UI,\n _o),\n _a[TYPES.UNSIGNED_INT_10F_11F_11F_REV] = (_p = {},\n _p[FORMATS.RGB] = gl.R11F_G11F_B10F,\n _p),\n _a[TYPES.UNSIGNED_INT_5_9_9_9_REV] = (_q = {},\n _q[FORMATS.RGB] = gl.RGB9_E5,\n _q),\n _a[TYPES.UNSIGNED_INT_24_8] = (_r = {},\n _r[FORMATS.DEPTH_STENCIL] = gl.DEPTH24_STENCIL8,\n _r),\n _a[TYPES.FLOAT_32_UNSIGNED_INT_24_8_REV] = (_s = {},\n _s[FORMATS.DEPTH_STENCIL] = gl.DEPTH32F_STENCIL8,\n _s),\n _a);\n }\n else {\n table = (_t = {},\n _t[TYPES.UNSIGNED_BYTE] = (_u = {},\n _u[FORMATS.RGBA] = gl.RGBA,\n _u[FORMATS.RGB] = gl.RGB,\n _u[FORMATS.ALPHA] = gl.ALPHA,\n _u[FORMATS.LUMINANCE] = gl.LUMINANCE,\n _u[FORMATS.LUMINANCE_ALPHA] = gl.LUMINANCE_ALPHA,\n _u),\n _t[TYPES.UNSIGNED_SHORT_5_6_5] = (_v = {},\n _v[FORMATS.RGB] = gl.RGB,\n _v),\n _t[TYPES.UNSIGNED_SHORT_4_4_4_4] = (_w = {},\n _w[FORMATS.RGBA] = gl.RGBA,\n _w),\n _t[TYPES.UNSIGNED_SHORT_5_5_5_1] = (_x = {},\n _x[FORMATS.RGBA] = gl.RGBA,\n _x),\n _t);\n }\n return table;\n}\n\n/**\n * Internal texture for WebGL context.\n * @memberof PIXI\n */\nvar GLTexture = /** @class */ (function () {\n function GLTexture(texture) {\n this.texture = texture;\n this.width = -1;\n this.height = -1;\n this.dirtyId = -1;\n this.dirtyStyleId = -1;\n this.mipmap = false;\n this.wrapMode = 33071;\n this.type = TYPES.UNSIGNED_BYTE;\n this.internalFormat = FORMATS.RGBA;\n this.samplerType = 0;\n }\n return GLTexture;\n}());\n\n/**\n * System plugin to the renderer to manage textures.\n * @memberof PIXI\n */\nvar TextureSystem = /** @class */ (function () {\n /**\n * @param renderer - The renderer this system works for.\n */\n function TextureSystem(renderer) {\n this.renderer = renderer;\n // TODO set to max textures...\n this.boundTextures = [];\n this.currentLocation = -1;\n this.managedTextures = [];\n this._unknownBoundTextures = false;\n this.unknownTexture = new BaseTexture();\n this.hasIntegerTextures = false;\n }\n /** Sets up the renderer context and necessary buffers. */\n TextureSystem.prototype.contextChange = function () {\n var gl = this.gl = this.renderer.gl;\n this.CONTEXT_UID = this.renderer.CONTEXT_UID;\n this.webGLVersion = this.renderer.context.webGLVersion;\n this.internalFormats = mapTypeAndFormatToInternalFormat(gl);\n var maxTextures = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);\n this.boundTextures.length = maxTextures;\n for (var i = 0; i < maxTextures; i++) {\n this.boundTextures[i] = null;\n }\n // TODO move this.. to a nice make empty textures class..\n this.emptyTextures = {};\n var emptyTexture2D = new GLTexture(gl.createTexture());\n gl.bindTexture(gl.TEXTURE_2D, emptyTexture2D.texture);\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(4));\n this.emptyTextures[gl.TEXTURE_2D] = emptyTexture2D;\n this.emptyTextures[gl.TEXTURE_CUBE_MAP] = new GLTexture(gl.createTexture());\n gl.bindTexture(gl.TEXTURE_CUBE_MAP, this.emptyTextures[gl.TEXTURE_CUBE_MAP].texture);\n for (var i = 0; i < 6; i++) {\n gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);\n }\n gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n for (var i = 0; i < this.boundTextures.length; i++) {\n this.bind(null, i);\n }\n };\n /**\n * Bind a texture to a specific location\n *\n * If you want to unbind something, please use `unbind(texture)` instead of `bind(null, textureLocation)`\n * @param texture - Texture to bind\n * @param [location=0] - Location to bind at\n */\n TextureSystem.prototype.bind = function (texture, location) {\n if (location === void 0) { location = 0; }\n var gl = this.gl;\n texture = texture === null || texture === void 0 ? void 0 : texture.castToBaseTexture();\n // cannot bind partial texture\n // TODO: report a warning\n if (texture && texture.valid && !texture.parentTextureArray) {\n texture.touched = this.renderer.textureGC.count;\n var glTexture = texture._glTextures[this.CONTEXT_UID] || this.initTexture(texture);\n if (this.boundTextures[location] !== texture) {\n if (this.currentLocation !== location) {\n this.currentLocation = location;\n gl.activeTexture(gl.TEXTURE0 + location);\n }\n gl.bindTexture(texture.target, glTexture.texture);\n }\n if (glTexture.dirtyId !== texture.dirtyId) {\n if (this.currentLocation !== location) {\n this.currentLocation = location;\n gl.activeTexture(gl.TEXTURE0 + location);\n }\n this.updateTexture(texture);\n }\n else if (glTexture.dirtyStyleId !== texture.dirtyStyleId) {\n this.updateTextureStyle(texture);\n }\n this.boundTextures[location] = texture;\n }\n else {\n if (this.currentLocation !== location) {\n this.currentLocation = location;\n gl.activeTexture(gl.TEXTURE0 + location);\n }\n gl.bindTexture(gl.TEXTURE_2D, this.emptyTextures[gl.TEXTURE_2D].texture);\n this.boundTextures[location] = null;\n }\n };\n /** Resets texture location and bound textures Actual `bind(null, i)` calls will be performed at next `unbind()` call */\n TextureSystem.prototype.reset = function () {\n this._unknownBoundTextures = true;\n this.hasIntegerTextures = false;\n this.currentLocation = -1;\n for (var i = 0; i < this.boundTextures.length; i++) {\n this.boundTextures[i] = this.unknownTexture;\n }\n };\n /**\n * Unbind a texture.\n * @param texture - Texture to bind\n */\n TextureSystem.prototype.unbind = function (texture) {\n var _a = this, gl = _a.gl, boundTextures = _a.boundTextures;\n if (this._unknownBoundTextures) {\n this._unknownBoundTextures = false;\n // someone changed webGL state,\n // we have to be sure that our texture does not appear in multi-texture renderer samplers\n for (var i = 0; i < boundTextures.length; i++) {\n if (boundTextures[i] === this.unknownTexture) {\n this.bind(null, i);\n }\n }\n }\n for (var i = 0; i < boundTextures.length; i++) {\n if (boundTextures[i] === texture) {\n if (this.currentLocation !== i) {\n gl.activeTexture(gl.TEXTURE0 + i);\n this.currentLocation = i;\n }\n gl.bindTexture(texture.target, this.emptyTextures[texture.target].texture);\n boundTextures[i] = null;\n }\n }\n };\n /**\n * Ensures that current boundTextures all have FLOAT sampler type,\n * see {@link PIXI.SAMPLER_TYPES} for explanation.\n * @param maxTextures - number of locations to check\n */\n TextureSystem.prototype.ensureSamplerType = function (maxTextures) {\n var _a = this, boundTextures = _a.boundTextures, hasIntegerTextures = _a.hasIntegerTextures, CONTEXT_UID = _a.CONTEXT_UID;\n if (!hasIntegerTextures) {\n return;\n }\n for (var i = maxTextures - 1; i >= 0; --i) {\n var tex = boundTextures[i];\n if (tex) {\n var glTexture = tex._glTextures[CONTEXT_UID];\n if (glTexture.samplerType !== SAMPLER_TYPES.FLOAT) {\n this.renderer.texture.unbind(tex);\n }\n }\n }\n };\n /**\n * Initialize a texture\n * @private\n * @param texture - Texture to initialize\n */\n TextureSystem.prototype.initTexture = function (texture) {\n var glTexture = new GLTexture(this.gl.createTexture());\n // guarantee an update..\n glTexture.dirtyId = -1;\n texture._glTextures[this.CONTEXT_UID] = glTexture;\n this.managedTextures.push(texture);\n texture.on('dispose', this.destroyTexture, this);\n return glTexture;\n };\n TextureSystem.prototype.initTextureType = function (texture, glTexture) {\n var _a, _b;\n glTexture.internalFormat = (_b = (_a = this.internalFormats[texture.type]) === null || _a === void 0 ? void 0 : _a[texture.format]) !== null && _b !== void 0 ? _b : texture.format;\n if (this.webGLVersion === 2 && texture.type === TYPES.HALF_FLOAT) {\n // TYPES.HALF_FLOAT is WebGL1 HALF_FLOAT_OES\n // we have to convert it to WebGL HALF_FLOAT\n glTexture.type = this.gl.HALF_FLOAT;\n }\n else {\n glTexture.type = texture.type;\n }\n };\n /**\n * Update a texture\n * @private\n * @param {PIXI.BaseTexture} texture - Texture to initialize\n */\n TextureSystem.prototype.updateTexture = function (texture) {\n var glTexture = texture._glTextures[this.CONTEXT_UID];\n if (!glTexture) {\n return;\n }\n var renderer = this.renderer;\n this.initTextureType(texture, glTexture);\n if (texture.resource && texture.resource.upload(renderer, texture, glTexture)) {\n // texture is uploaded, dont do anything!\n if (glTexture.samplerType !== SAMPLER_TYPES.FLOAT) {\n this.hasIntegerTextures = true;\n }\n }\n else {\n // default, renderTexture-like logic\n var width = texture.realWidth;\n var height = texture.realHeight;\n var gl = renderer.gl;\n if (glTexture.width !== width\n || glTexture.height !== height\n || glTexture.dirtyId < 0) {\n glTexture.width = width;\n glTexture.height = height;\n gl.texImage2D(texture.target, 0, glTexture.internalFormat, width, height, 0, texture.format, glTexture.type, null);\n }\n }\n // lets only update what changes..\n if (texture.dirtyStyleId !== glTexture.dirtyStyleId) {\n this.updateTextureStyle(texture);\n }\n glTexture.dirtyId = texture.dirtyId;\n };\n /**\n * Deletes the texture from WebGL\n * @private\n * @param texture - the texture to destroy\n * @param [skipRemove=false] - Whether to skip removing the texture from the TextureManager.\n */\n TextureSystem.prototype.destroyTexture = function (texture, skipRemove) {\n var gl = this.gl;\n texture = texture.castToBaseTexture();\n if (texture._glTextures[this.CONTEXT_UID]) {\n this.unbind(texture);\n gl.deleteTexture(texture._glTextures[this.CONTEXT_UID].texture);\n texture.off('dispose', this.destroyTexture, this);\n delete texture._glTextures[this.CONTEXT_UID];\n if (!skipRemove) {\n var i = this.managedTextures.indexOf(texture);\n if (i !== -1) {\n removeItems(this.managedTextures, i, 1);\n }\n }\n }\n };\n /**\n * Update texture style such as mipmap flag\n * @private\n * @param {PIXI.BaseTexture} texture - Texture to update\n */\n TextureSystem.prototype.updateTextureStyle = function (texture) {\n var glTexture = texture._glTextures[this.CONTEXT_UID];\n if (!glTexture) {\n return;\n }\n if ((texture.mipmap === MIPMAP_MODES.POW2 || this.webGLVersion !== 2) && !texture.isPowerOfTwo) {\n glTexture.mipmap = false;\n }\n else {\n glTexture.mipmap = texture.mipmap >= 1;\n }\n if (this.webGLVersion !== 2 && !texture.isPowerOfTwo) {\n glTexture.wrapMode = WRAP_MODES.CLAMP;\n }\n else {\n glTexture.wrapMode = texture.wrapMode;\n }\n if (texture.resource && texture.resource.style(this.renderer, texture, glTexture)) ;\n else {\n this.setStyle(texture, glTexture);\n }\n glTexture.dirtyStyleId = texture.dirtyStyleId;\n };\n /**\n * Set style for texture\n * @private\n * @param texture - Texture to update\n * @param glTexture\n */\n TextureSystem.prototype.setStyle = function (texture, glTexture) {\n var gl = this.gl;\n if (glTexture.mipmap && texture.mipmap !== MIPMAP_MODES.ON_MANUAL) {\n gl.generateMipmap(texture.target);\n }\n gl.texParameteri(texture.target, gl.TEXTURE_WRAP_S, glTexture.wrapMode);\n gl.texParameteri(texture.target, gl.TEXTURE_WRAP_T, glTexture.wrapMode);\n if (glTexture.mipmap) {\n /* eslint-disable max-len */\n gl.texParameteri(texture.target, gl.TEXTURE_MIN_FILTER, texture.scaleMode === SCALE_MODES.LINEAR ? gl.LINEAR_MIPMAP_LINEAR : gl.NEAREST_MIPMAP_NEAREST);\n /* eslint-disable max-len */\n var anisotropicExt = this.renderer.context.extensions.anisotropicFiltering;\n if (anisotropicExt && texture.anisotropicLevel > 0 && texture.scaleMode === SCALE_MODES.LINEAR) {\n var level = Math.min(texture.anisotropicLevel, gl.getParameter(anisotropicExt.MAX_TEXTURE_MAX_ANISOTROPY_EXT));\n gl.texParameterf(texture.target, anisotropicExt.TEXTURE_MAX_ANISOTROPY_EXT, level);\n }\n }\n else {\n gl.texParameteri(texture.target, gl.TEXTURE_MIN_FILTER, texture.scaleMode === SCALE_MODES.LINEAR ? gl.LINEAR : gl.NEAREST);\n }\n gl.texParameteri(texture.target, gl.TEXTURE_MAG_FILTER, texture.scaleMode === SCALE_MODES.LINEAR ? gl.LINEAR : gl.NEAREST);\n };\n TextureSystem.prototype.destroy = function () {\n this.renderer = null;\n };\n return TextureSystem;\n}());\n\nvar _systems = {\n __proto__: null,\n FilterSystem: FilterSystem,\n BatchSystem: BatchSystem,\n ContextSystem: ContextSystem,\n FramebufferSystem: FramebufferSystem,\n GeometrySystem: GeometrySystem,\n MaskSystem: MaskSystem,\n ScissorSystem: ScissorSystem,\n StencilSystem: StencilSystem,\n ProjectionSystem: ProjectionSystem,\n RenderTextureSystem: RenderTextureSystem,\n ShaderSystem: ShaderSystem,\n StateSystem: StateSystem,\n TextureGCSystem: TextureGCSystem,\n TextureSystem: TextureSystem\n};\n\nvar tempMatrix = new Matrix();\n/**\n * The AbstractRenderer is the base for a PixiJS Renderer. It is extended by the {@link PIXI.CanvasRenderer}\n * and {@link PIXI.Renderer} which can be used for rendering a PixiJS scene.\n * @abstract\n * @class\n * @extends PIXI.utils.EventEmitter\n * @memberof PIXI\n */\nvar AbstractRenderer = /** @class */ (function (_super) {\n __extends(AbstractRenderer, _super);\n /**\n * @param type - The renderer type.\n * @param [options] - The optional renderer parameters.\n * @param {number} [options.width=800] - The width of the screen.\n * @param {number} [options.height=600] - The height of the screen.\n * @param {HTMLCanvasElement} [options.view] - The canvas to use as a view, optional.\n * @param {boolean} [options.useContextAlpha=true] - Pass-through value for canvas' context `alpha` property.\n * If you want to set transparency, please use `backgroundAlpha`. This option is for cases where the\n * canvas needs to be opaque, possibly for performance reasons on some older devices.\n * @param {boolean} [options.autoDensity=false] - Resizes renderer view in CSS pixels to allow for\n * resolutions other than 1.\n * @param {boolean} [options.antialias=false] - Sets antialias\n * @param {number} [options.resolution=PIXI.settings.RESOLUTION] - The resolution / device pixel ratio of the renderer.\n * @param {boolean} [options.preserveDrawingBuffer=false] - Enables drawing buffer preservation,\n * enable this if you need to call toDataUrl on the WebGL context.\n * @param {boolean} [options.clearBeforeRender=true] - This sets if the renderer will clear the canvas or\n * not before the new render pass.\n * @param {number} [options.backgroundColor=0x000000] - The background color of the rendered area\n * (shown if not transparent).\n * @param {number} [options.backgroundAlpha=1] - Value from 0 (fully transparent) to 1 (fully opaque).\n */\n function AbstractRenderer(type, options) {\n if (type === void 0) { type = RENDERER_TYPE.UNKNOWN; }\n var _this = _super.call(this) || this;\n // Add the default render options\n options = Object.assign({}, settings.RENDER_OPTIONS, options);\n /**\n * The supplied constructor options.\n * @member {object}\n * @readonly\n */\n _this.options = options;\n /**\n * The type of the renderer.\n * @member {number}\n * @default PIXI.RENDERER_TYPE.UNKNOWN\n * @see PIXI.RENDERER_TYPE\n */\n _this.type = type;\n /**\n * Measurements of the screen. (0, 0, screenWidth, screenHeight).\n *\n * Its safe to use as filterArea or hitArea for the whole stage.\n * @member {PIXI.Rectangle}\n */\n _this.screen = new Rectangle(0, 0, options.width, options.height);\n /**\n * The canvas element that everything is drawn to.\n * @member {HTMLCanvasElement}\n */\n _this.view = options.view || settings.ADAPTER.createCanvas();\n /**\n * The resolution / device pixel ratio of the renderer.\n * @member {number}\n * @default PIXI.settings.RESOLUTION\n */\n _this.resolution = options.resolution || settings.RESOLUTION;\n /**\n * Pass-thru setting for the canvas' context `alpha` property. This is typically\n * not something you need to fiddle with. If you want transparency, use `backgroundAlpha`.\n * @member {boolean}\n */\n _this.useContextAlpha = options.useContextAlpha;\n /**\n * Whether CSS dimensions of canvas view should be resized to screen dimensions automatically.\n * @member {boolean}\n */\n _this.autoDensity = !!options.autoDensity;\n /**\n * The value of the preserveDrawingBuffer flag affects whether or not the contents of\n * the stencil buffer is retained after rendering.\n * @member {boolean}\n */\n _this.preserveDrawingBuffer = options.preserveDrawingBuffer;\n /**\n * This sets if the CanvasRenderer will clear the canvas or not before the new render pass.\n * If the scene is NOT transparent PixiJS will use a canvas sized fillRect operation every\n * frame to set the canvas background color. If the scene is transparent PixiJS will use clearRect\n * to clear the canvas every frame. Disable this by setting this to false. For example, if\n * your game has a canvas filling background image you often don't need this set.\n * @member {boolean}\n * @default\n */\n _this.clearBeforeRender = options.clearBeforeRender;\n /**\n * The background color as a number.\n * @member {number}\n * @protected\n */\n _this._backgroundColor = 0x000000;\n /**\n * The background color as an [R, G, B, A] array.\n * @member {number[]}\n * @protected\n */\n _this._backgroundColorRgba = [0, 0, 0, 1];\n /**\n * The background color as a string.\n * @member {string}\n * @protected\n */\n _this._backgroundColorString = '#000000';\n _this.backgroundColor = options.backgroundColor || _this._backgroundColor; // run bg color setter\n _this.backgroundAlpha = options.backgroundAlpha;\n // @deprecated\n if (options.transparent !== undefined) {\n deprecation('6.0.0', 'Option transparent is deprecated, please use backgroundAlpha instead.');\n _this.useContextAlpha = options.transparent;\n _this.backgroundAlpha = options.transparent ? 0 : 1;\n }\n /**\n * The last root object that the renderer tried to render.\n * @member {PIXI.DisplayObject}\n * @protected\n */\n _this._lastObjectRendered = null;\n /**\n * Collection of plugins.\n * @readonly\n * @member {object}\n */\n _this.plugins = {};\n return _this;\n }\n /**\n * Initialize the plugins.\n * @protected\n * @param {object} staticMap - The dictionary of statically saved plugins.\n */\n AbstractRenderer.prototype.initPlugins = function (staticMap) {\n for (var o in staticMap) {\n this.plugins[o] = new (staticMap[o])(this);\n }\n };\n Object.defineProperty(AbstractRenderer.prototype, \"width\", {\n /**\n * Same as view.width, actual number of pixels in the canvas by horizontal.\n * @member {number}\n * @readonly\n * @default 800\n */\n get: function () {\n return this.view.width;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(AbstractRenderer.prototype, \"height\", {\n /**\n * Same as view.height, actual number of pixels in the canvas by vertical.\n * @member {number}\n * @readonly\n * @default 600\n */\n get: function () {\n return this.view.height;\n },\n enumerable: false,\n configurable: true\n });\n /**\n * Resizes the screen and canvas as close as possible to the specified width and height.\n * Canvas dimensions are multiplied by resolution and rounded to the nearest integers.\n * The new canvas dimensions divided by the resolution become the new screen dimensions.\n * @param desiredScreenWidth - The desired width of the screen.\n * @param desiredScreenHeight - The desired height of the screen.\n */\n AbstractRenderer.prototype.resize = function (desiredScreenWidth, desiredScreenHeight) {\n this.view.width = Math.round(desiredScreenWidth * this.resolution);\n this.view.height = Math.round(desiredScreenHeight * this.resolution);\n var screenWidth = this.view.width / this.resolution;\n var screenHeight = this.view.height / this.resolution;\n this.screen.width = screenWidth;\n this.screen.height = screenHeight;\n if (this.autoDensity) {\n this.view.style.width = screenWidth + \"px\";\n this.view.style.height = screenHeight + \"px\";\n }\n /**\n * Fired after view has been resized.\n * @event PIXI.Renderer#resize\n * @param {number} screenWidth - The new width of the screen.\n * @param {number} screenHeight - The new height of the screen.\n */\n this.emit('resize', screenWidth, screenHeight);\n };\n /**\n * @ignore\n */\n AbstractRenderer.prototype.generateTexture = function (displayObject, options, resolution, region) {\n if (options === void 0) { options = {}; }\n // @deprecated parameters spread, use options instead\n if (typeof options === 'number') {\n deprecation('6.1.0', 'generateTexture options (scaleMode, resolution, region) are now object options.');\n options = { scaleMode: options, resolution: resolution, region: region };\n }\n var manualRegion = options.region, textureOptions = __rest(options, [\"region\"]);\n region = manualRegion || displayObject.getLocalBounds(null, true);\n // minimum texture size is 1x1, 0x0 will throw an error\n if (region.width === 0)\n { region.width = 1; }\n if (region.height === 0)\n { region.height = 1; }\n var renderTexture = RenderTexture.create(__assign({ width: region.width, height: region.height }, textureOptions));\n tempMatrix.tx = -region.x;\n tempMatrix.ty = -region.y;\n this.render(displayObject, {\n renderTexture: renderTexture,\n clear: false,\n transform: tempMatrix,\n skipUpdateTransform: !!displayObject.parent\n });\n return renderTexture;\n };\n /**\n * Removes everything from the renderer and optionally removes the Canvas DOM element.\n * @param [removeView=false] - Removes the Canvas element from the DOM.\n */\n AbstractRenderer.prototype.destroy = function (removeView) {\n for (var o in this.plugins) {\n this.plugins[o].destroy();\n this.plugins[o] = null;\n }\n if (removeView && this.view.parentNode) {\n this.view.parentNode.removeChild(this.view);\n }\n var thisAny = this;\n // null-ing all objects, that's a tradition!\n thisAny.plugins = null;\n thisAny.type = RENDERER_TYPE.UNKNOWN;\n thisAny.view = null;\n thisAny.screen = null;\n thisAny._tempDisplayObjectParent = null;\n thisAny.options = null;\n this._backgroundColorRgba = null;\n this._backgroundColorString = null;\n this._lastObjectRendered = null;\n };\n Object.defineProperty(AbstractRenderer.prototype, \"backgroundColor\", {\n /**\n * The background color to fill if not transparent\n * @member {number}\n */\n get: function () {\n return this._backgroundColor;\n },\n set: function (value) {\n this._backgroundColor = value;\n this._backgroundColorString = hex2string(value);\n hex2rgb(value, this._backgroundColorRgba);\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(AbstractRenderer.prototype, \"backgroundAlpha\", {\n /**\n * The background color alpha. Setting this to 0 will make the canvas transparent.\n * @member {number}\n */\n get: function () {\n return this._backgroundColorRgba[3];\n },\n set: function (value) {\n this._backgroundColorRgba[3] = value;\n },\n enumerable: false,\n configurable: true\n });\n return AbstractRenderer;\n}(EventEmitter));\n\nvar GLBuffer = /** @class */ (function () {\n function GLBuffer(buffer) {\n this.buffer = buffer || null;\n this.updateID = -1;\n this.byteLength = -1;\n this.refCount = 0;\n }\n return GLBuffer;\n}());\n\n/**\n * System plugin to the renderer to manage buffers.\n *\n * WebGL uses Buffers as a way to store objects to the GPU.\n * This system makes working with them a lot easier.\n *\n * Buffers are used in three main places in WebGL\n * - geometry information\n * - Uniform information (via uniform buffer objects - a WebGL 2 only feature)\n * - Transform feedback information. (WebGL 2 only feature)\n *\n * This system will handle the binding of buffers to the GPU as well as uploading\n * them. With this system, you never need to work directly with GPU buffers, but instead work with\n * the PIXI.Buffer class.\n * @class\n * @memberof PIXI\n */\nvar BufferSystem = /** @class */ (function () {\n /**\n * @param {PIXI.Renderer} renderer - The renderer this System works for.\n */\n function BufferSystem(renderer) {\n this.renderer = renderer;\n this.managedBuffers = {};\n this.boundBufferBases = {};\n }\n /**\n * @ignore\n */\n BufferSystem.prototype.destroy = function () {\n this.renderer = null;\n };\n /** Sets up the renderer context and necessary buffers. */\n BufferSystem.prototype.contextChange = function () {\n this.disposeAll(true);\n this.gl = this.renderer.gl;\n // TODO fill out...\n this.CONTEXT_UID = this.renderer.CONTEXT_UID;\n };\n /**\n * This binds specified buffer. On first run, it will create the webGL buffers for the context too\n * @param buffer - the buffer to bind to the renderer\n */\n BufferSystem.prototype.bind = function (buffer) {\n var _a = this, gl = _a.gl, CONTEXT_UID = _a.CONTEXT_UID;\n var glBuffer = buffer._glBuffers[CONTEXT_UID] || this.createGLBuffer(buffer);\n gl.bindBuffer(buffer.type, glBuffer.buffer);\n };\n /**\n * Binds an uniform buffer to at the given index.\n *\n * A cache is used so a buffer will not be bound again if already bound.\n * @param buffer - the buffer to bind\n * @param index - the base index to bind it to.\n */\n BufferSystem.prototype.bindBufferBase = function (buffer, index) {\n var _a = this, gl = _a.gl, CONTEXT_UID = _a.CONTEXT_UID;\n if (this.boundBufferBases[index] !== buffer) {\n var glBuffer = buffer._glBuffers[CONTEXT_UID] || this.createGLBuffer(buffer);\n this.boundBufferBases[index] = buffer;\n gl.bindBufferBase(gl.UNIFORM_BUFFER, index, glBuffer.buffer);\n }\n };\n /**\n * Binds a buffer whilst also binding its range.\n * This will make the buffer start from the offset supplied rather than 0 when it is read.\n * @param buffer - the buffer to bind\n * @param index - the base index to bind at, defaults to 0\n * @param offset - the offset to bind at (this is blocks of 256). 0 = 0, 1 = 256, 2 = 512 etc\n */\n BufferSystem.prototype.bindBufferRange = function (buffer, index, offset) {\n var _a = this, gl = _a.gl, CONTEXT_UID = _a.CONTEXT_UID;\n offset = offset || 0;\n var glBuffer = buffer._glBuffers[CONTEXT_UID] || this.createGLBuffer(buffer);\n gl.bindBufferRange(gl.UNIFORM_BUFFER, index || 0, glBuffer.buffer, offset * 256, 256);\n };\n /**\n * Will ensure the data in the buffer is uploaded to the GPU.\n * @param {PIXI.Buffer} buffer - the buffer to update\n */\n BufferSystem.prototype.update = function (buffer) {\n var _a = this, gl = _a.gl, CONTEXT_UID = _a.CONTEXT_UID;\n var glBuffer = buffer._glBuffers[CONTEXT_UID];\n if (buffer._updateID === glBuffer.updateID) {\n return;\n }\n glBuffer.updateID = buffer._updateID;\n gl.bindBuffer(buffer.type, glBuffer.buffer);\n if (glBuffer.byteLength >= buffer.data.byteLength) {\n // offset is always zero for now!\n gl.bufferSubData(buffer.type, 0, buffer.data);\n }\n else {\n var drawType = buffer.static ? gl.STATIC_DRAW : gl.DYNAMIC_DRAW;\n glBuffer.byteLength = buffer.data.byteLength;\n gl.bufferData(buffer.type, buffer.data, drawType);\n }\n };\n /**\n * Disposes buffer\n * @param {PIXI.Buffer} buffer - buffer with data\n * @param {boolean} [contextLost=false] - If context was lost, we suppress deleteVertexArray\n */\n BufferSystem.prototype.dispose = function (buffer, contextLost) {\n if (!this.managedBuffers[buffer.id]) {\n return;\n }\n delete this.managedBuffers[buffer.id];\n var glBuffer = buffer._glBuffers[this.CONTEXT_UID];\n var gl = this.gl;\n buffer.disposeRunner.remove(this);\n if (!glBuffer) {\n return;\n }\n if (!contextLost) {\n gl.deleteBuffer(glBuffer.buffer);\n }\n delete buffer._glBuffers[this.CONTEXT_UID];\n };\n /**\n * dispose all WebGL resources of all managed buffers\n * @param {boolean} [contextLost=false] - If context was lost, we suppress `gl.delete` calls\n */\n BufferSystem.prototype.disposeAll = function (contextLost) {\n var all = Object.keys(this.managedBuffers);\n for (var i = 0; i < all.length; i++) {\n this.dispose(this.managedBuffers[all[i]], contextLost);\n }\n };\n /**\n * creates and attaches a GLBuffer object tied to the current context.\n * @param buffer\n * @protected\n */\n BufferSystem.prototype.createGLBuffer = function (buffer) {\n var _a = this, CONTEXT_UID = _a.CONTEXT_UID, gl = _a.gl;\n buffer._glBuffers[CONTEXT_UID] = new GLBuffer(gl.createBuffer());\n this.managedBuffers[buffer.id] = buffer;\n buffer.disposeRunner.add(this);\n return buffer._glBuffers[CONTEXT_UID];\n };\n return BufferSystem;\n}());\n\n/**\n * The Renderer draws the scene and all its content onto a WebGL enabled canvas.\n *\n * This renderer should be used for browsers that support WebGL.\n *\n * This renderer works by automatically managing WebGLBatchesm, so no need for Sprite Batches or Sprite Clouds.\n * Don't forget to add the view to your DOM or you will not see anything!\n *\n * Renderer is composed of systems that manage specific tasks. The following systems are added by default\n * whenever you create a renderer:\n *\n * | System | Description |\n * | ------------------------------------ | ----------------------------------------------------------------------------- |\n * | {@link PIXI.BatchSystem} | This manages object renderers that defer rendering until a flush. |\n * | {@link PIXI.ContextSystem} | This manages the WebGL context and extensions. |\n * | {@link PIXI.EventSystem} | This manages UI events. |\n * | {@link PIXI.FilterSystem} | This manages the filtering pipeline for post-processing effects. |\n * | {@link PIXI.FramebufferSystem} | This manages framebuffers, which are used for offscreen rendering. |\n * | {@link PIXI.GeometrySystem} | This manages geometries & buffers, which are used to draw object meshes. |\n * | {@link PIXI.MaskSystem} | This manages masking operations. |\n * | {@link PIXI.ProjectionSystem} | This manages the `projectionMatrix`, used by shaders to get NDC coordinates. |\n * | {@link PIXI.RenderTextureSystem} | This manages render-textures, which are an abstraction over framebuffers. |\n * | {@link PIXI.ScissorSystem} | This handles scissor masking, and is used internally by {@link MaskSystem} |\n * | {@link PIXI.ShaderSystem} | This manages shaders, programs that run on the GPU to calculate 'em pixels. |\n * | {@link PIXI.StateSystem} | This manages the WebGL state variables like blend mode, depth testing, etc. |\n * | {@link PIXI.StencilSystem} | This handles stencil masking, and is used internally by {@link MaskSystem} |\n * | {@link PIXI.TextureSystem} | This manages textures and their resources on the GPU. |\n * | {@link PIXI.TextureGCSystem} | This will automatically remove textures from the GPU if they are not used. |\n *\n * The breadth of the API surface provided by the renderer is contained within these systems.\n * @memberof PIXI\n */\nvar Renderer = /** @class */ (function (_super) {\n __extends(Renderer, _super);\n /**\n * @param [options] - The optional renderer parameters.\n * @param {number} [options.width=800] - The width of the screen.\n * @param {number} [options.height=600] - The height of the screen.\n * @param {HTMLCanvasElement} [options.view] - The canvas to use as a view, optional.\n * @param {boolean} [options.useContextAlpha=true] - Pass-through value for canvas' context `alpha` property.\n * If you want to set transparency, please use `backgroundAlpha`. This option is for cases where the\n * canvas needs to be opaque, possibly for performance reasons on some older devices.\n * @param {boolean} [options.autoDensity=false] - Resizes renderer view in CSS pixels to allow for\n * resolutions other than 1.\n * @param {boolean} [options.antialias=false] - Sets antialias. If not available natively then FXAA\n * antialiasing is used.\n * @param {number} [options.resolution=PIXI.settings.RESOLUTION] - The resolution / device pixel ratio of the renderer.\n * @param {boolean} [options.clearBeforeRender=true] - This sets if the renderer will clear\n * the canvas or not before the new render pass. If you wish to set this to false, you *must* set\n * preserveDrawingBuffer to `true`.\n * @param {boolean} [options.preserveDrawingBuffer=false] - Enables drawing buffer preservation,\n * enable this if you need to call toDataUrl on the WebGL context.\n * @param {number} [options.backgroundColor=0x000000] - The background color of the rendered area\n * (shown if not transparent).\n * @param {number} [options.backgroundAlpha=1] - Value from 0 (fully transparent) to 1 (fully opaque).\n * @param {string} [options.powerPreference] - Parameter passed to WebGL context, set to \"high-performance\"\n * for devices with dual graphics card.\n * @param {object} [options.context] - If WebGL context already exists, all parameters must be taken from it.\n */\n function Renderer(options) {\n var _this = _super.call(this, RENDERER_TYPE.WEBGL, options) || this;\n // the options will have been modified here in the super constructor with pixi's default settings..\n options = _this.options;\n _this.gl = null;\n _this.CONTEXT_UID = 0;\n _this.runners = {\n destroy: new Runner('destroy'),\n contextChange: new Runner('contextChange'),\n reset: new Runner('reset'),\n update: new Runner('update'),\n postrender: new Runner('postrender'),\n prerender: new Runner('prerender'),\n resize: new Runner('resize'),\n };\n _this.runners.contextChange.add(_this);\n _this.globalUniforms = new UniformGroup({\n projectionMatrix: new Matrix(),\n }, true);\n _this.addSystem(MaskSystem, 'mask')\n .addSystem(ContextSystem, 'context')\n .addSystem(StateSystem, 'state')\n .addSystem(ShaderSystem, 'shader')\n .addSystem(TextureSystem, 'texture')\n .addSystem(BufferSystem, 'buffer')\n .addSystem(GeometrySystem, 'geometry')\n .addSystem(FramebufferSystem, 'framebuffer')\n .addSystem(ScissorSystem, 'scissor')\n .addSystem(StencilSystem, 'stencil')\n .addSystem(ProjectionSystem, 'projection')\n .addSystem(TextureGCSystem, 'textureGC')\n .addSystem(FilterSystem, 'filter')\n .addSystem(RenderTextureSystem, 'renderTexture')\n .addSystem(BatchSystem, 'batch');\n _this.initPlugins(Renderer.__plugins);\n _this.multisample = undefined;\n /*\n * The options passed in to create a new WebGL context.\n */\n if (options.context) {\n _this.context.initFromContext(options.context);\n }\n else {\n _this.context.initFromOptions({\n alpha: !!_this.useContextAlpha,\n antialias: options.antialias,\n premultipliedAlpha: _this.useContextAlpha && _this.useContextAlpha !== 'notMultiplied',\n stencil: true,\n preserveDrawingBuffer: options.preserveDrawingBuffer,\n powerPreference: _this.options.powerPreference,\n });\n }\n _this.renderingToScreen = true;\n sayHello(_this.context.webGLVersion === 2 ? 'WebGL 2' : 'WebGL 1');\n _this.resize(_this.options.width, _this.options.height);\n return _this;\n }\n /**\n * Create renderer if WebGL is available. Overrideable\n * by the **@pixi/canvas-renderer** package to allow fallback.\n * throws error if WebGL is not available.\n * @param options\n * @private\n */\n Renderer.create = function (options) {\n if (isWebGLSupported()) {\n return new Renderer(options);\n }\n throw new Error('WebGL unsupported in this browser, use \"pixi.js-legacy\" for fallback canvas2d support.');\n };\n Renderer.prototype.contextChange = function () {\n var gl = this.gl;\n var samples;\n if (this.context.webGLVersion === 1) {\n var framebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING);\n gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n samples = gl.getParameter(gl.SAMPLES);\n gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);\n }\n else {\n var framebuffer = gl.getParameter(gl.DRAW_FRAMEBUFFER_BINDING);\n gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);\n samples = gl.getParameter(gl.SAMPLES);\n gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, framebuffer);\n }\n if (samples >= MSAA_QUALITY.HIGH) {\n this.multisample = MSAA_QUALITY.HIGH;\n }\n else if (samples >= MSAA_QUALITY.MEDIUM) {\n this.multisample = MSAA_QUALITY.MEDIUM;\n }\n else if (samples >= MSAA_QUALITY.LOW) {\n this.multisample = MSAA_QUALITY.LOW;\n }\n else {\n this.multisample = MSAA_QUALITY.NONE;\n }\n };\n /**\n * Add a new system to the renderer.\n * @param ClassRef - Class reference\n * @param name - Property name for system, if not specified\n * will use a static `name` property on the class itself. This\n * name will be assigned as s property on the Renderer so make\n * sure it doesn't collide with properties on Renderer.\n * @returns Return instance of renderer\n */\n Renderer.prototype.addSystem = function (ClassRef, name) {\n var system = new ClassRef(this);\n if (this[name]) {\n throw new Error(\"Whoops! The name \\\"\" + name + \"\\\" is already in use\");\n }\n this[name] = system;\n for (var i in this.runners) {\n this.runners[i].add(system);\n }\n /**\n * Fired after rendering finishes.\n * @event PIXI.Renderer#postrender\n */\n /**\n * Fired before rendering starts.\n * @event PIXI.Renderer#prerender\n */\n /**\n * Fired when the WebGL context is set.\n * @event PIXI.Renderer#context\n * @param {WebGLRenderingContext} gl - WebGL context.\n */\n return this;\n };\n /**\n * @ignore\n */\n Renderer.prototype.render = function (displayObject, options) {\n var renderTexture;\n var clear;\n var transform;\n var skipUpdateTransform;\n if (options) {\n if (options instanceof RenderTexture) {\n deprecation('6.0.0', 'Renderer#render arguments changed, use options instead.');\n /* eslint-disable prefer-rest-params */\n renderTexture = options;\n clear = arguments[2];\n transform = arguments[3];\n skipUpdateTransform = arguments[4];\n /* eslint-enable prefer-rest-params */\n }\n else {\n renderTexture = options.renderTexture;\n clear = options.clear;\n transform = options.transform;\n skipUpdateTransform = options.skipUpdateTransform;\n }\n }\n // can be handy to know!\n this.renderingToScreen = !renderTexture;\n this.runners.prerender.emit();\n this.emit('prerender');\n // apply a transform at a GPU level\n this.projection.transform = transform;\n // no point rendering if our context has been blown up!\n if (this.context.isLost) {\n return;\n }\n if (!renderTexture) {\n this._lastObjectRendered = displayObject;\n }\n if (!skipUpdateTransform) {\n // update the scene graph\n var cacheParent = displayObject.enableTempParent();\n displayObject.updateTransform();\n displayObject.disableTempParent(cacheParent);\n // displayObject.hitArea = //TODO add a temp hit area\n }\n this.renderTexture.bind(renderTexture);\n this.batch.currentRenderer.start();\n if (clear !== undefined ? clear : this.clearBeforeRender) {\n this.renderTexture.clear();\n }\n displayObject.render(this);\n // apply transform..\n this.batch.currentRenderer.flush();\n if (renderTexture) {\n renderTexture.baseTexture.update();\n }\n this.runners.postrender.emit();\n // reset transform after render\n this.projection.transform = null;\n this.emit('postrender');\n };\n /**\n * @override\n * @ignore\n */\n Renderer.prototype.generateTexture = function (displayObject, options, resolution, region) {\n if (options === void 0) { options = {}; }\n var renderTexture = _super.prototype.generateTexture.call(this, displayObject, options, resolution, region);\n this.framebuffer.blit();\n return renderTexture;\n };\n /**\n * Resizes the WebGL view to the specified width and height.\n * @param desiredScreenWidth - The desired width of the screen.\n * @param desiredScreenHeight - The desired height of the screen.\n */\n Renderer.prototype.resize = function (desiredScreenWidth, desiredScreenHeight) {\n _super.prototype.resize.call(this, desiredScreenWidth, desiredScreenHeight);\n this.runners.resize.emit(this.screen.height, this.screen.width);\n };\n /**\n * Resets the WebGL state so you can render things however you fancy!\n * @returns Returns itself.\n */\n Renderer.prototype.reset = function () {\n this.runners.reset.emit();\n return this;\n };\n /** Clear the frame buffer. */\n Renderer.prototype.clear = function () {\n this.renderTexture.bind();\n this.renderTexture.clear();\n };\n /**\n * Removes everything from the renderer (event listeners, spritebatch, etc...)\n * @param [removeView=false] - Removes the Canvas element from the DOM.\n * See: https://github.com/pixijs/pixi.js/issues/2233\n */\n Renderer.prototype.destroy = function (removeView) {\n this.runners.destroy.emit();\n for (var r in this.runners) {\n this.runners[r].destroy();\n }\n // call base destroy\n _super.prototype.destroy.call(this, removeView);\n // TODO nullify all the managers..\n this.gl = null;\n };\n Object.defineProperty(Renderer.prototype, \"extract\", {\n /**\n * Please use `plugins.extract` instead.\n * @member {PIXI.Extract} extract\n * @deprecated since 6.0.0\n * @readonly\n */\n get: function () {\n deprecation('6.0.0', 'Renderer#extract has been deprecated, please use Renderer#plugins.extract instead.');\n return this.plugins.extract;\n },\n enumerable: false,\n configurable: true\n });\n /**\n * Use the {@link PIXI.extensions.add} API to register plugins.\n * @deprecated since 6.5.0\n * @param pluginName - The name of the plugin.\n * @param ctor - The constructor function or class for the plugin.\n */\n Renderer.registerPlugin = function (pluginName, ctor) {\n deprecation('6.5.0', 'Renderer.registerPlugin() has been deprecated, please use extensions.add() instead.');\n extensions$1.add({\n name: pluginName,\n type: ExtensionType.RendererPlugin,\n ref: ctor,\n });\n };\n /**\n * Collection of installed plugins. These are included by default in PIXI, but can be excluded\n * by creating a custom build. Consult the README for more information about creating custom\n * builds and excluding plugins.\n * @readonly\n * @property {PIXI.AccessibilityManager} accessibility Support tabbing interactive elements.\n * @property {PIXI.Extract} extract Extract image data from renderer.\n * @property {PIXI.InteractionManager} interaction Handles mouse, touch and pointer events.\n * @property {PIXI.ParticleRenderer} particle Renderer for ParticleContainer objects.\n * @property {PIXI.Prepare} prepare Pre-render display objects.\n * @property {PIXI.BatchRenderer} batch Batching of Sprite, Graphics and Mesh objects.\n * @property {PIXI.TilingSpriteRenderer} tilingSprite Renderer for TilingSprite objects.\n */\n Renderer.__plugins = {};\n return Renderer;\n}(AbstractRenderer));\n// Handle registration of extensions\nextensions$1.handleByMap(ExtensionType.RendererPlugin, Renderer.__plugins);\n\n/**\n * This helper function will automatically detect which renderer you should be using.\n * WebGL is the preferred renderer as it is a lot faster. If WebGL is not supported by\n * the browser then this function will return a canvas renderer\n * @memberof PIXI\n * @function autoDetectRenderer\n * @param {object} [options] - The optional renderer parameters\n * @param {number} [options.width=800] - the width of the renderers view\n * @param {number} [options.height=600] - the height of the renderers view\n * @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional\n * @param {boolean} [options.useContextAlpha=true] - Pass-through value for canvas' context `alpha` property.\n * If you want to set transparency, please use `backgroundAlpha`. This option is for cases where the\n * canvas needs to be opaque, possibly for performance reasons on some older devices.\n * @param {boolean} [options.autoDensity=false] - Resizes renderer view in CSS pixels to allow for\n * resolutions other than 1\n * @param {boolean} [options.antialias=false] - sets antialias\n * @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you\n * need to call toDataUrl on the webgl context\n * @param {number} [options.backgroundColor=0x000000] - The background color of the rendered area\n * (shown if not transparent).\n * @param {number} [options.backgroundAlpha=1] - Value from 0 (fully transparent) to 1 (fully opaque).\n * @param {boolean} [options.clearBeforeRender=true] - This sets if the renderer will clear the canvas or\n * not before the new render pass.\n * @param {number} [options.resolution=PIXI.settings.RESOLUTION] - The resolution / device pixel ratio of the renderer.\n * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present, this\n * option only is available when using **pixi.js-legacy** or **@pixi/canvas-renderer** modules, otherwise\n * it is ignored.\n * @param {string} [options.powerPreference] - Parameter passed to webgl context, set to \"high-performance\"\n * for devices with dual graphics card **webgl only**\n * @returns {PIXI.Renderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer\n */\nfunction autoDetectRenderer(options) {\n return Renderer.create(options);\n}\n\nvar $defaultVertex = \"attribute vec2 aVertexPosition;\\nattribute vec2 aTextureCoord;\\n\\nuniform mat3 projectionMatrix;\\n\\nvarying vec2 vTextureCoord;\\n\\nvoid main(void)\\n{\\n gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\\n vTextureCoord = aTextureCoord;\\n}\";\n\nvar $defaultFilterVertex = \"attribute vec2 aVertexPosition;\\n\\nuniform mat3 projectionMatrix;\\n\\nvarying vec2 vTextureCoord;\\n\\nuniform vec4 inputSize;\\nuniform vec4 outputFrame;\\n\\nvec4 filterVertexPosition( void )\\n{\\n vec2 position = aVertexPosition * max(outputFrame.zw, vec2(0.)) + outputFrame.xy;\\n\\n return vec4((projectionMatrix * vec3(position, 1.0)).xy, 0.0, 1.0);\\n}\\n\\nvec2 filterTextureCoord( void )\\n{\\n return aVertexPosition * (outputFrame.zw * inputSize.zw);\\n}\\n\\nvoid main(void)\\n{\\n gl_Position = filterVertexPosition();\\n vTextureCoord = filterTextureCoord();\\n}\\n\";\n\n/**\n * Default vertex shader\n * @memberof PIXI\n * @member {string} defaultVertex\n */\n/**\n * Default filter vertex shader\n * @memberof PIXI\n * @member {string} defaultFilterVertex\n */\n// NOTE: This black magic is so that @microsoft/api-extractor does not complain! This explicitly specifies the types\n// of defaultVertex, defaultFilterVertex.\nvar defaultVertex$1 = $defaultVertex;\nvar defaultFilterVertex = $defaultFilterVertex;\n\n/**\n * Use the ISystem interface instead.\n * @deprecated since 6.1.0\n * @memberof PIXI\n */\nvar System = /** @class */ (function () {\n /**\n * @param renderer - Reference to Renderer\n */\n function System(renderer) {\n deprecation('6.1.0', 'System class is deprecated, implemement ISystem interface instead.');\n this.renderer = renderer;\n }\n /** Destroy and don't use after this. */\n System.prototype.destroy = function () {\n this.renderer = null;\n };\n return System;\n}());\n\n/**\n * Used by the batcher to draw batches.\n * Each one of these contains all information required to draw a bound geometry.\n * @memberof PIXI\n */\nvar BatchDrawCall = /** @class */ (function () {\n function BatchDrawCall() {\n this.texArray = null;\n this.blend = 0;\n this.type = DRAW_MODES.TRIANGLES;\n this.start = 0;\n this.size = 0;\n this.data = null;\n }\n return BatchDrawCall;\n}());\n\n/**\n * Used by the batcher to build texture batches.\n * Holds list of textures and their respective locations.\n * @memberof PIXI\n */\nvar BatchTextureArray = /** @class */ (function () {\n function BatchTextureArray() {\n this.elements = [];\n this.ids = [];\n this.count = 0;\n }\n BatchTextureArray.prototype.clear = function () {\n for (var i = 0; i < this.count; i++) {\n this.elements[i] = null;\n }\n this.count = 0;\n };\n return BatchTextureArray;\n}());\n\n/**\n * Flexible wrapper around `ArrayBuffer` that also provides typed array views on demand.\n * @memberof PIXI\n */\nvar ViewableBuffer = /** @class */ (function () {\n function ViewableBuffer(sizeOrBuffer) {\n if (typeof sizeOrBuffer === 'number') {\n this.rawBinaryData = new ArrayBuffer(sizeOrBuffer);\n }\n else if (sizeOrBuffer instanceof Uint8Array) {\n this.rawBinaryData = sizeOrBuffer.buffer;\n }\n else {\n this.rawBinaryData = sizeOrBuffer;\n }\n this.uint32View = new Uint32Array(this.rawBinaryData);\n this.float32View = new Float32Array(this.rawBinaryData);\n }\n Object.defineProperty(ViewableBuffer.prototype, \"int8View\", {\n /** View on the raw binary data as a `Int8Array`. */\n get: function () {\n if (!this._int8View) {\n this._int8View = new Int8Array(this.rawBinaryData);\n }\n return this._int8View;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(ViewableBuffer.prototype, \"uint8View\", {\n /** View on the raw binary data as a `Uint8Array`. */\n get: function () {\n if (!this._uint8View) {\n this._uint8View = new Uint8Array(this.rawBinaryData);\n }\n return this._uint8View;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(ViewableBuffer.prototype, \"int16View\", {\n /** View on the raw binary data as a `Int16Array`. */\n get: function () {\n if (!this._int16View) {\n this._int16View = new Int16Array(this.rawBinaryData);\n }\n return this._int16View;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(ViewableBuffer.prototype, \"uint16View\", {\n /** View on the raw binary data as a `Uint16Array`. */\n get: function () {\n if (!this._uint16View) {\n this._uint16View = new Uint16Array(this.rawBinaryData);\n }\n return this._uint16View;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(ViewableBuffer.prototype, \"int32View\", {\n /** View on the raw binary data as a `Int32Array`. */\n get: function () {\n if (!this._int32View) {\n this._int32View = new Int32Array(this.rawBinaryData);\n }\n return this._int32View;\n },\n enumerable: false,\n configurable: true\n });\n /**\n * Returns the view of the given type.\n * @param type - One of `int8`, `uint8`, `int16`,\n * `uint16`, `int32`, `uint32`, and `float32`.\n * @returns - typed array of given type\n */\n ViewableBuffer.prototype.view = function (type) {\n return this[type + \"View\"];\n };\n /** Destroys all buffer references. Do not use after calling this. */\n ViewableBuffer.prototype.destroy = function () {\n this.rawBinaryData = null;\n this._int8View = null;\n this._uint8View = null;\n this._int16View = null;\n this._uint16View = null;\n this._int32View = null;\n this.uint32View = null;\n this.float32View = null;\n };\n ViewableBuffer.sizeOf = function (type) {\n switch (type) {\n case 'int8':\n case 'uint8':\n return 1;\n case 'int16':\n case 'uint16':\n return 2;\n case 'int32':\n case 'uint32':\n case 'float32':\n return 4;\n default:\n throw new Error(type + \" isn't a valid view type\");\n }\n };\n return ViewableBuffer;\n}());\n\n/**\n * Renderer dedicated to drawing and batching sprites.\n *\n * This is the default batch renderer. It buffers objects\n * with texture-based geometries and renders them in\n * batches. It uploads multiple textures to the GPU to\n * reduce to the number of draw calls.\n * @memberof PIXI\n */\nvar AbstractBatchRenderer = /** @class */ (function (_super) {\n __extends(AbstractBatchRenderer, _super);\n /**\n * This will hook onto the renderer's `contextChange`\n * and `prerender` signals.\n * @param {PIXI.Renderer} renderer - The renderer this works for.\n */\n function AbstractBatchRenderer(renderer) {\n var _this = _super.call(this, renderer) || this;\n _this.shaderGenerator = null;\n _this.geometryClass = null;\n _this.vertexSize = null;\n _this.state = State.for2d();\n _this.size = settings.SPRITE_BATCH_SIZE * 4;\n _this._vertexCount = 0;\n _this._indexCount = 0;\n _this._bufferedElements = [];\n _this._bufferedTextures = [];\n _this._bufferSize = 0;\n _this._shader = null;\n _this._packedGeometries = [];\n _this._packedGeometryPoolSize = 2;\n _this._flushId = 0;\n _this._aBuffers = {};\n _this._iBuffers = {};\n _this.MAX_TEXTURES = 1;\n _this.renderer.on('prerender', _this.onPrerender, _this);\n renderer.runners.contextChange.add(_this);\n _this._dcIndex = 0;\n _this._aIndex = 0;\n _this._iIndex = 0;\n _this._attributeBuffer = null;\n _this._indexBuffer = null;\n _this._tempBoundTextures = [];\n return _this;\n }\n /**\n * Handles the `contextChange` signal.\n *\n * It calculates `this.MAX_TEXTURES` and allocating the packed-geometry object pool.\n */\n AbstractBatchRenderer.prototype.contextChange = function () {\n var gl = this.renderer.gl;\n if (settings.PREFER_ENV === ENV.WEBGL_LEGACY) {\n this.MAX_TEXTURES = 1;\n }\n else {\n // step 1: first check max textures the GPU can handle.\n this.MAX_TEXTURES = Math.min(gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS), settings.SPRITE_MAX_TEXTURES);\n // step 2: check the maximum number of if statements the shader can have too..\n this.MAX_TEXTURES = checkMaxIfStatementsInShader(this.MAX_TEXTURES, gl);\n }\n this._shader = this.shaderGenerator.generateShader(this.MAX_TEXTURES);\n // we use the second shader as the first one depending on your browser\n // may omit aTextureId as it is not used by the shader so is optimized out.\n for (var i = 0; i < this._packedGeometryPoolSize; i++) {\n /* eslint-disable max-len */\n this._packedGeometries[i] = new (this.geometryClass)();\n }\n this.initFlushBuffers();\n };\n /** Makes sure that static and dynamic flush pooled objects have correct dimensions. */\n AbstractBatchRenderer.prototype.initFlushBuffers = function () {\n var _drawCallPool = AbstractBatchRenderer._drawCallPool, _textureArrayPool = AbstractBatchRenderer._textureArrayPool;\n // max draw calls\n var MAX_SPRITES = this.size / 4;\n // max texture arrays\n var MAX_TA = Math.floor(MAX_SPRITES / this.MAX_TEXTURES) + 1;\n while (_drawCallPool.length < MAX_SPRITES) {\n _drawCallPool.push(new BatchDrawCall());\n }\n while (_textureArrayPool.length < MAX_TA) {\n _textureArrayPool.push(new BatchTextureArray());\n }\n for (var i = 0; i < this.MAX_TEXTURES; i++) {\n this._tempBoundTextures[i] = null;\n }\n };\n /** Handles the `prerender` signal. It ensures that flushes start from the first geometry object again. */\n AbstractBatchRenderer.prototype.onPrerender = function () {\n this._flushId = 0;\n };\n /**\n * Buffers the \"batchable\" object. It need not be rendered immediately.\n * @param {PIXI.DisplayObject} element - the element to render when\n * using this renderer\n */\n AbstractBatchRenderer.prototype.render = function (element) {\n if (!element._texture.valid) {\n return;\n }\n if (this._vertexCount + (element.vertexData.length / 2) > this.size) {\n this.flush();\n }\n this._vertexCount += element.vertexData.length / 2;\n this._indexCount += element.indices.length;\n this._bufferedTextures[this._bufferSize] = element._texture.baseTexture;\n this._bufferedElements[this._bufferSize++] = element;\n };\n AbstractBatchRenderer.prototype.buildTexturesAndDrawCalls = function () {\n var _a = this, textures = _a._bufferedTextures, MAX_TEXTURES = _a.MAX_TEXTURES;\n var textureArrays = AbstractBatchRenderer._textureArrayPool;\n var batch = this.renderer.batch;\n var boundTextures = this._tempBoundTextures;\n var touch = this.renderer.textureGC.count;\n var TICK = ++BaseTexture._globalBatch;\n var countTexArrays = 0;\n var texArray = textureArrays[0];\n var start = 0;\n batch.copyBoundTextures(boundTextures, MAX_TEXTURES);\n for (var i = 0; i < this._bufferSize; ++i) {\n var tex = textures[i];\n textures[i] = null;\n if (tex._batchEnabled === TICK) {\n continue;\n }\n if (texArray.count >= MAX_TEXTURES) {\n batch.boundArray(texArray, boundTextures, TICK, MAX_TEXTURES);\n this.buildDrawCalls(texArray, start, i);\n start = i;\n texArray = textureArrays[++countTexArrays];\n ++TICK;\n }\n tex._batchEnabled = TICK;\n tex.touched = touch;\n texArray.elements[texArray.count++] = tex;\n }\n if (texArray.count > 0) {\n batch.boundArray(texArray, boundTextures, TICK, MAX_TEXTURES);\n this.buildDrawCalls(texArray, start, this._bufferSize);\n ++countTexArrays;\n ++TICK;\n }\n // Clean-up\n for (var i = 0; i < boundTextures.length; i++) {\n boundTextures[i] = null;\n }\n BaseTexture._globalBatch = TICK;\n };\n /**\n * Populating drawcalls for rendering\n * @param texArray\n * @param start\n * @param finish\n */\n AbstractBatchRenderer.prototype.buildDrawCalls = function (texArray, start, finish) {\n var _a = this, elements = _a._bufferedElements, _attributeBuffer = _a._attributeBuffer, _indexBuffer = _a._indexBuffer, vertexSize = _a.vertexSize;\n var drawCalls = AbstractBatchRenderer._drawCallPool;\n var dcIndex = this._dcIndex;\n var aIndex = this._aIndex;\n var iIndex = this._iIndex;\n var drawCall = drawCalls[dcIndex];\n drawCall.start = this._iIndex;\n drawCall.texArray = texArray;\n for (var i = start; i < finish; ++i) {\n var sprite = elements[i];\n var tex = sprite._texture.baseTexture;\n var spriteBlendMode = premultiplyBlendMode[tex.alphaMode ? 1 : 0][sprite.blendMode];\n elements[i] = null;\n if (start < i && drawCall.blend !== spriteBlendMode) {\n drawCall.size = iIndex - drawCall.start;\n start = i;\n drawCall = drawCalls[++dcIndex];\n drawCall.texArray = texArray;\n drawCall.start = iIndex;\n }\n this.packInterleavedGeometry(sprite, _attributeBuffer, _indexBuffer, aIndex, iIndex);\n aIndex += sprite.vertexData.length / 2 * vertexSize;\n iIndex += sprite.indices.length;\n drawCall.blend = spriteBlendMode;\n }\n if (start < finish) {\n drawCall.size = iIndex - drawCall.start;\n ++dcIndex;\n }\n this._dcIndex = dcIndex;\n this._aIndex = aIndex;\n this._iIndex = iIndex;\n };\n /**\n * Bind textures for current rendering\n * @param texArray\n */\n AbstractBatchRenderer.prototype.bindAndClearTexArray = function (texArray) {\n var textureSystem = this.renderer.texture;\n for (var j = 0; j < texArray.count; j++) {\n textureSystem.bind(texArray.elements[j], texArray.ids[j]);\n texArray.elements[j] = null;\n }\n texArray.count = 0;\n };\n AbstractBatchRenderer.prototype.updateGeometry = function () {\n var _a = this, packedGeometries = _a._packedGeometries, attributeBuffer = _a._attributeBuffer, indexBuffer = _a._indexBuffer;\n if (!settings.CAN_UPLOAD_SAME_BUFFER) { /* Usually on iOS devices, where the browser doesn't\n like uploads to the same buffer in a single frame. */\n if (this._packedGeometryPoolSize <= this._flushId) {\n this._packedGeometryPoolSize++;\n packedGeometries[this._flushId] = new (this.geometryClass)();\n }\n packedGeometries[this._flushId]._buffer.update(attributeBuffer.rawBinaryData);\n packedGeometries[this._flushId]._indexBuffer.update(indexBuffer);\n this.renderer.geometry.bind(packedGeometries[this._flushId]);\n this.renderer.geometry.updateBuffers();\n this._flushId++;\n }\n else {\n // lets use the faster option, always use buffer number 0\n packedGeometries[this._flushId]._buffer.update(attributeBuffer.rawBinaryData);\n packedGeometries[this._flushId]._indexBuffer.update(indexBuffer);\n this.renderer.geometry.updateBuffers();\n }\n };\n AbstractBatchRenderer.prototype.drawBatches = function () {\n var dcCount = this._dcIndex;\n var _a = this.renderer, gl = _a.gl, stateSystem = _a.state;\n var drawCalls = AbstractBatchRenderer._drawCallPool;\n var curTexArray = null;\n // Upload textures and do the draw calls\n for (var i = 0; i < dcCount; i++) {\n var _b = drawCalls[i], texArray = _b.texArray, type = _b.type, size = _b.size, start = _b.start, blend = _b.blend;\n if (curTexArray !== texArray) {\n curTexArray = texArray;\n this.bindAndClearTexArray(texArray);\n }\n this.state.blendMode = blend;\n stateSystem.set(this.state);\n gl.drawElements(type, size, gl.UNSIGNED_SHORT, start * 2);\n }\n };\n /** Renders the content _now_ and empties the current batch. */\n AbstractBatchRenderer.prototype.flush = function () {\n if (this._vertexCount === 0) {\n return;\n }\n this._attributeBuffer = this.getAttributeBuffer(this._vertexCount);\n this._indexBuffer = this.getIndexBuffer(this._indexCount);\n this._aIndex = 0;\n this._iIndex = 0;\n this._dcIndex = 0;\n this.buildTexturesAndDrawCalls();\n this.updateGeometry();\n this.drawBatches();\n // reset elements buffer for the next flush\n this._bufferSize = 0;\n this._vertexCount = 0;\n this._indexCount = 0;\n };\n /** Starts a new sprite batch. */\n AbstractBatchRenderer.prototype.start = function () {\n this.renderer.state.set(this.state);\n this.renderer.texture.ensureSamplerType(this.MAX_TEXTURES);\n this.renderer.shader.bind(this._shader);\n if (settings.CAN_UPLOAD_SAME_BUFFER) {\n // bind buffer #0, we don't need others\n this.renderer.geometry.bind(this._packedGeometries[this._flushId]);\n }\n };\n /** Stops and flushes the current batch. */\n AbstractBatchRenderer.prototype.stop = function () {\n this.flush();\n };\n /** Destroys this `AbstractBatchRenderer`. It cannot be used again. */\n AbstractBatchRenderer.prototype.destroy = function () {\n for (var i = 0; i < this._packedGeometryPoolSize; i++) {\n if (this._packedGeometries[i]) {\n this._packedGeometries[i].destroy();\n }\n }\n this.renderer.off('prerender', this.onPrerender, this);\n this._aBuffers = null;\n this._iBuffers = null;\n this._packedGeometries = null;\n this._attributeBuffer = null;\n this._indexBuffer = null;\n if (this._shader) {\n this._shader.destroy();\n this._shader = null;\n }\n _super.prototype.destroy.call(this);\n };\n /**\n * Fetches an attribute buffer from `this._aBuffers` that can hold atleast `size` floats.\n * @param size - minimum capacity required\n * @returns - buffer than can hold atleast `size` floats\n */\n AbstractBatchRenderer.prototype.getAttributeBuffer = function (size) {\n // 8 vertices is enough for 2 quads\n var roundedP2 = nextPow2(Math.ceil(size / 8));\n var roundedSizeIndex = log2(roundedP2);\n var roundedSize = roundedP2 * 8;\n if (this._aBuffers.length <= roundedSizeIndex) {\n this._iBuffers.length = roundedSizeIndex + 1;\n }\n var buffer = this._aBuffers[roundedSize];\n if (!buffer) {\n this._aBuffers[roundedSize] = buffer = new ViewableBuffer(roundedSize * this.vertexSize * 4);\n }\n return buffer;\n };\n /**\n * Fetches an index buffer from `this._iBuffers` that can\n * have at least `size` capacity.\n * @param size - minimum required capacity\n * @returns - buffer that can fit `size` indices.\n */\n AbstractBatchRenderer.prototype.getIndexBuffer = function (size) {\n // 12 indices is enough for 2 quads\n var roundedP2 = nextPow2(Math.ceil(size / 12));\n var roundedSizeIndex = log2(roundedP2);\n var roundedSize = roundedP2 * 12;\n if (this._iBuffers.length <= roundedSizeIndex) {\n this._iBuffers.length = roundedSizeIndex + 1;\n }\n var buffer = this._iBuffers[roundedSizeIndex];\n if (!buffer) {\n this._iBuffers[roundedSizeIndex] = buffer = new Uint16Array(roundedSize);\n }\n return buffer;\n };\n /**\n * Takes the four batching parameters of `element`, interleaves\n * and pushes them into the batching attribute/index buffers given.\n *\n * It uses these properties: `vertexData` `uvs`, `textureId` and\n * `indicies`. It also uses the \"tint\" of the base-texture, if\n * present.\n * @param {PIXI.DisplayObject} element - element being rendered\n * @param attributeBuffer - attribute buffer.\n * @param indexBuffer - index buffer\n * @param aIndex - number of floats already in the attribute buffer\n * @param iIndex - number of indices already in `indexBuffer`\n */\n AbstractBatchRenderer.prototype.packInterleavedGeometry = function (element, attributeBuffer, indexBuffer, aIndex, iIndex) {\n var uint32View = attributeBuffer.uint32View, float32View = attributeBuffer.float32View;\n var packedVertices = aIndex / this.vertexSize;\n var uvs = element.uvs;\n var indicies = element.indices;\n var vertexData = element.vertexData;\n var textureId = element._texture.baseTexture._batchLocation;\n var alpha = Math.min(element.worldAlpha, 1.0);\n var argb = (alpha < 1.0\n && element._texture.baseTexture.alphaMode)\n ? premultiplyTint(element._tintRGB, alpha)\n : element._tintRGB + (alpha * 255 << 24);\n // lets not worry about tint! for now..\n for (var i = 0; i < vertexData.length; i += 2) {\n float32View[aIndex++] = vertexData[i];\n float32View[aIndex++] = vertexData[i + 1];\n float32View[aIndex++] = uvs[i];\n float32View[aIndex++] = uvs[i + 1];\n uint32View[aIndex++] = argb;\n float32View[aIndex++] = textureId;\n }\n for (var i = 0; i < indicies.length; i++) {\n indexBuffer[iIndex++] = packedVertices + indicies[i];\n }\n };\n /**\n * Pool of `BatchDrawCall` objects that `flush` used\n * to create \"batches\" of the objects being rendered.\n *\n * These are never re-allocated again.\n * Shared between all batch renderers because it can be only one \"flush\" working at the moment.\n * @member {PIXI.BatchDrawCall[]}\n */\n AbstractBatchRenderer._drawCallPool = [];\n /**\n * Pool of `BatchDrawCall` objects that `flush` used\n * to create \"batches\" of the objects being rendered.\n *\n * These are never re-allocated again.\n * Shared between all batch renderers because it can be only one \"flush\" working at the moment.\n * @member {PIXI.BatchTextureArray[]}\n */\n AbstractBatchRenderer._textureArrayPool = [];\n return AbstractBatchRenderer;\n}(ObjectRenderer));\n\n/**\n * Helper that generates batching multi-texture shader. Use it with your new BatchRenderer\n * @memberof PIXI\n */\nvar BatchShaderGenerator = /** @class */ (function () {\n /**\n * @param vertexSrc - Vertex shader\n * @param fragTemplate - Fragment shader template\n */\n function BatchShaderGenerator(vertexSrc, fragTemplate) {\n this.vertexSrc = vertexSrc;\n this.fragTemplate = fragTemplate;\n this.programCache = {};\n this.defaultGroupCache = {};\n if (fragTemplate.indexOf('%count%') < 0) {\n throw new Error('Fragment template must contain \"%count%\".');\n }\n if (fragTemplate.indexOf('%forloop%') < 0) {\n throw new Error('Fragment template must contain \"%forloop%\".');\n }\n }\n BatchShaderGenerator.prototype.generateShader = function (maxTextures) {\n if (!this.programCache[maxTextures]) {\n var sampleValues = new Int32Array(maxTextures);\n for (var i = 0; i < maxTextures; i++) {\n sampleValues[i] = i;\n }\n this.defaultGroupCache[maxTextures] = UniformGroup.from({ uSamplers: sampleValues }, true);\n var fragmentSrc = this.fragTemplate;\n fragmentSrc = fragmentSrc.replace(/%count%/gi, \"\" + maxTextures);\n fragmentSrc = fragmentSrc.replace(/%forloop%/gi, this.generateSampleSrc(maxTextures));\n this.programCache[maxTextures] = new Program(this.vertexSrc, fragmentSrc);\n }\n var uniforms = {\n tint: new Float32Array([1, 1, 1, 1]),\n translationMatrix: new Matrix(),\n default: this.defaultGroupCache[maxTextures],\n };\n return new Shader(this.programCache[maxTextures], uniforms);\n };\n BatchShaderGenerator.prototype.generateSampleSrc = function (maxTextures) {\n var src = '';\n src += '\\n';\n src += '\\n';\n for (var i = 0; i < maxTextures; i++) {\n if (i > 0) {\n src += '\\nelse ';\n }\n if (i < maxTextures - 1) {\n src += \"if(vTextureId < \" + i + \".5)\";\n }\n src += '\\n{';\n src += \"\\n\\tcolor = texture2D(uSamplers[\" + i + \"], vTextureCoord);\";\n src += '\\n}';\n }\n src += '\\n';\n src += '\\n';\n return src;\n };\n return BatchShaderGenerator;\n}());\n\n/**\n * Geometry used to batch standard PIXI content (e.g. Mesh, Sprite, Graphics objects).\n * @memberof PIXI\n */\nvar BatchGeometry = /** @class */ (function (_super) {\n __extends(BatchGeometry, _super);\n /**\n * @param {boolean} [_static=false] - Optimization flag, where `false`\n * is updated every frame, `true` doesn't change frame-to-frame.\n */\n function BatchGeometry(_static) {\n if (_static === void 0) { _static = false; }\n var _this = _super.call(this) || this;\n _this._buffer = new Buffer(null, _static, false);\n _this._indexBuffer = new Buffer(null, _static, true);\n _this.addAttribute('aVertexPosition', _this._buffer, 2, false, TYPES.FLOAT)\n .addAttribute('aTextureCoord', _this._buffer, 2, false, TYPES.FLOAT)\n .addAttribute('aColor', _this._buffer, 4, true, TYPES.UNSIGNED_BYTE)\n .addAttribute('aTextureId', _this._buffer, 1, true, TYPES.FLOAT)\n .addIndex(_this._indexBuffer);\n return _this;\n }\n return BatchGeometry;\n}(Geometry));\n\nvar defaultVertex = \"precision highp float;\\nattribute vec2 aVertexPosition;\\nattribute vec2 aTextureCoord;\\nattribute vec4 aColor;\\nattribute float aTextureId;\\n\\nuniform mat3 projectionMatrix;\\nuniform mat3 translationMatrix;\\nuniform vec4 tint;\\n\\nvarying vec2 vTextureCoord;\\nvarying vec4 vColor;\\nvarying float vTextureId;\\n\\nvoid main(void){\\n gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\\n\\n vTextureCoord = aTextureCoord;\\n vTextureId = aTextureId;\\n vColor = aColor * tint;\\n}\\n\";\n\nvar defaultFragment = \"varying vec2 vTextureCoord;\\nvarying vec4 vColor;\\nvarying float vTextureId;\\nuniform sampler2D uSamplers[%count%];\\n\\nvoid main(void){\\n vec4 color;\\n %forloop%\\n gl_FragColor = color * vColor;\\n}\\n\";\n\n/** @memberof PIXI */\nvar BatchPluginFactory = /** @class */ (function () {\n function BatchPluginFactory() {\n }\n /**\n * Create a new BatchRenderer plugin for Renderer. this convenience can provide an easy way\n * to extend BatchRenderer with all the necessary pieces.\n * @example\n * const fragment = `\n * varying vec2 vTextureCoord;\n * varying vec4 vColor;\n * varying float vTextureId;\n * uniform sampler2D uSamplers[%count%];\n *\n * void main(void){\n * vec4 color;\n * %forloop%\n * gl_FragColor = vColor * vec4(color.a - color.rgb, color.a);\n * }\n * `;\n * const InvertBatchRenderer = PIXI.BatchPluginFactory.create({ fragment });\n * PIXI.extensions.add({\n * name: 'invert',\n * ref: InvertBatchRenderer,\n * type: PIXI.ExtensionType.RendererPlugin,\n * });\n * const sprite = new PIXI.Sprite();\n * sprite.pluginName = 'invert';\n * @param {object} [options]\n * @param {string} [options.vertex=PIXI.BatchPluginFactory.defaultVertexSrc] - Vertex shader source\n * @param {string} [options.fragment=PIXI.BatchPluginFactory.defaultFragmentTemplate] - Fragment shader template\n * @param {number} [options.vertexSize=6] - Vertex size\n * @param {object} [options.geometryClass=PIXI.BatchGeometry]\n * @returns {*} New batch renderer plugin\n */\n BatchPluginFactory.create = function (options) {\n var _a = Object.assign({\n vertex: defaultVertex,\n fragment: defaultFragment,\n geometryClass: BatchGeometry,\n vertexSize: 6,\n }, options), vertex = _a.vertex, fragment = _a.fragment, vertexSize = _a.vertexSize, geometryClass = _a.geometryClass;\n return /** @class */ (function (_super) {\n __extends(BatchPlugin, _super);\n function BatchPlugin(renderer) {\n var _this = _super.call(this, renderer) || this;\n _this.shaderGenerator = new BatchShaderGenerator(vertex, fragment);\n _this.geometryClass = geometryClass;\n _this.vertexSize = vertexSize;\n return _this;\n }\n return BatchPlugin;\n }(AbstractBatchRenderer));\n };\n Object.defineProperty(BatchPluginFactory, \"defaultVertexSrc\", {\n /**\n * The default vertex shader source\n * @readonly\n */\n get: function () {\n return defaultVertex;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(BatchPluginFactory, \"defaultFragmentTemplate\", {\n /**\n * The default fragment shader source\n * @readonly\n */\n get: function () {\n return defaultFragment;\n },\n enumerable: false,\n configurable: true\n });\n return BatchPluginFactory;\n}());\n// Setup the default BatchRenderer plugin, this is what\n// we'll actually export at the root level\nvar BatchRenderer = BatchPluginFactory.create();\nObject.assign(BatchRenderer, {\n extension: {\n name: 'batch',\n type: ExtensionType.RendererPlugin,\n },\n});\n\n/**\n * @memberof PIXI\n * @namespace resources\n * @see PIXI\n * @deprecated since 6.0.0\n */\nvar resources = {};\nvar _loop_1 = function (name) {\n Object.defineProperty(resources, name, {\n get: function () {\n deprecation('6.0.0', \"PIXI.systems.\" + name + \" has moved to PIXI.\" + name);\n return _resources[name];\n },\n });\n};\nfor (var name in _resources) {\n _loop_1(name);\n}\n/**\n * @memberof PIXI\n * @namespace systems\n * @see PIXI\n * @deprecated since 6.0.0\n */\nvar systems = {};\nvar _loop_2 = function (name) {\n Object.defineProperty(systems, name, {\n get: function () {\n deprecation('6.0.0', \"PIXI.resources.\" + name + \" has moved to PIXI.\" + name);\n return _systems[name];\n },\n });\n};\nfor (var name in _systems) {\n _loop_2(name);\n}\n\n/**\n * @namespace PIXI\n */\n/**\n * String of the current PIXI version.\n * @memberof PIXI\n */\nvar VERSION = '6.5.8';\n\nexport { AbstractBatchRenderer, AbstractMultiResource, AbstractRenderer, ArrayResource, Attribute, BaseImageResource, BaseRenderTexture, BaseTexture, BatchDrawCall, BatchGeometry, BatchPluginFactory, BatchRenderer, BatchShaderGenerator, BatchSystem, BatchTextureArray, Buffer, BufferResource, CanvasResource, ContextSystem, CubeResource, Filter, FilterState, FilterSystem, Framebuffer, FramebufferSystem, GLFramebuffer, GLProgram, GLTexture, Geometry, GeometrySystem, IGLUniformData, INSTALLED, ImageBitmapResource, ImageResource, MaskData, MaskSystem, ObjectRenderer, Program, ProjectionSystem, Quad, QuadUv, RenderTexture, RenderTexturePool, RenderTextureSystem, Renderer, Resource, SVGResource, ScissorSystem, Shader, ShaderSystem, SpriteMaskFilter, State, StateSystem, StencilSystem, System, Texture, TextureGCSystem, TextureMatrix, TextureSystem, TextureUvs, UniformGroup, VERSION, VideoResource, ViewableBuffer, autoDetectRenderer, autoDetectResource, checkMaxIfStatementsInShader, createUBOElements, defaultFilterVertex, defaultVertex$1 as defaultVertex, generateProgram, generateUniformBufferSync, getTestContext, getUBOData, resources, systems, uniformParsers };\n//# sourceMappingURL=core.mjs.map\n","/*!\n * @pixi/accessibility - v6.5.8\n * Compiled Sun, 23 Oct 2022 23:01:45 UTC\n *\n * @pixi/accessibility is licensed under the MIT License.\n * http://www.opensource.org/licenses/mit-license\n */\nimport { DisplayObject } from '@pixi/display';\nimport { isMobile, removeItems } from '@pixi/utils';\nimport { ExtensionType } from '@pixi/core';\n\n/**\n * Default property values of accessible objects\n * used by {@link PIXI.AccessibilityManager}.\n * @private\n * @function accessibleTarget\n * @memberof PIXI\n * @type {object}\n * @example\n * function MyObject() {}\n *\n * Object.assign(\n * MyObject.prototype,\n * PIXI.accessibleTarget\n * );\n */\nvar accessibleTarget = {\n /**\n * Flag for if the object is accessible. If true AccessibilityManager will overlay a\n * shadow div with attributes set\n * @member {boolean}\n * @memberof PIXI.DisplayObject#\n */\n accessible: false,\n /**\n * Sets the title attribute of the shadow div\n * If accessibleTitle AND accessibleHint has not been this will default to 'displayObject [tabIndex]'\n * @member {?string}\n * @memberof PIXI.DisplayObject#\n */\n accessibleTitle: null,\n /**\n * Sets the aria-label attribute of the shadow div\n * @member {string}\n * @memberof PIXI.DisplayObject#\n */\n accessibleHint: null,\n /**\n * @member {number}\n * @memberof PIXI.DisplayObject#\n * @private\n * @todo Needs docs.\n */\n tabIndex: 0,\n /**\n * @member {boolean}\n * @memberof PIXI.DisplayObject#\n * @todo Needs docs.\n */\n _accessibleActive: false,\n /**\n * @member {boolean}\n * @memberof PIXI.DisplayObject#\n * @todo Needs docs.\n */\n _accessibleDiv: null,\n /**\n * Specify the type of div the accessible layer is. Screen readers treat the element differently\n * depending on this type. Defaults to button.\n * @member {string}\n * @memberof PIXI.DisplayObject#\n * @default 'button'\n */\n accessibleType: 'button',\n /**\n * Specify the pointer-events the accessible div will use\n * Defaults to auto.\n * @member {string}\n * @memberof PIXI.DisplayObject#\n * @default 'auto'\n */\n accessiblePointerEvents: 'auto',\n /**\n * Setting to false will prevent any children inside this container to\n * be accessible. Defaults to true.\n * @member {boolean}\n * @memberof PIXI.DisplayObject#\n * @default true\n */\n accessibleChildren: true,\n renderId: -1,\n};\n\n// add some extra variables to the container..\nDisplayObject.mixin(accessibleTarget);\nvar KEY_CODE_TAB = 9;\nvar DIV_TOUCH_SIZE = 100;\nvar DIV_TOUCH_POS_X = 0;\nvar DIV_TOUCH_POS_Y = 0;\nvar DIV_TOUCH_ZINDEX = 2;\nvar DIV_HOOK_SIZE = 1;\nvar DIV_HOOK_POS_X = -1000;\nvar DIV_HOOK_POS_Y = -1000;\nvar DIV_HOOK_ZINDEX = 2;\n/**\n * The Accessibility manager recreates the ability to tab and have content read by screen readers.\n * This is very important as it can possibly help people with disabilities access PixiJS content.\n *\n * A DisplayObject can be made accessible just like it can be made interactive. This manager will map the\n * events as if the mouse was being used, minimizing the effort required to implement.\n *\n * An instance of this class is automatically created by default, and can be found at `renderer.plugins.accessibility`\n * @class\n * @memberof PIXI\n */\nvar AccessibilityManager = /** @class */ (function () {\n /**\n * @param {PIXI.CanvasRenderer|PIXI.Renderer} renderer - A reference to the current renderer\n */\n function AccessibilityManager(renderer) {\n /** Setting this to true will visually show the divs. */\n this.debug = false;\n /** Internal variable, see isActive getter. */\n this._isActive = false;\n /** Internal variable, see isMobileAccessibility getter. */\n this._isMobileAccessibility = false;\n /** A simple pool for storing divs. */\n this.pool = [];\n /** This is a tick used to check if an object is no longer being rendered. */\n this.renderId = 0;\n /** The array of currently active accessible items. */\n this.children = [];\n /** Count to throttle div updates on android devices. */\n this.androidUpdateCount = 0;\n /** The frequency to update the div elements. */\n this.androidUpdateFrequency = 500; // 2fps\n this._hookDiv = null;\n if (isMobile.tablet || isMobile.phone) {\n this.createTouchHook();\n }\n // first we create a div that will sit over the PixiJS element. This is where the div overlays will go.\n var div = document.createElement('div');\n div.style.width = DIV_TOUCH_SIZE + \"px\";\n div.style.height = DIV_TOUCH_SIZE + \"px\";\n div.style.position = 'absolute';\n div.style.top = DIV_TOUCH_POS_X + \"px\";\n div.style.left = DIV_TOUCH_POS_Y + \"px\";\n div.style.zIndex = DIV_TOUCH_ZINDEX.toString();\n this.div = div;\n this.renderer = renderer;\n /**\n * pre-bind the functions\n * @type {Function}\n * @private\n */\n this._onKeyDown = this._onKeyDown.bind(this);\n /**\n * pre-bind the functions\n * @type {Function}\n * @private\n */\n this._onMouseMove = this._onMouseMove.bind(this);\n // let listen for tab.. once pressed we can fire up and show the accessibility layer\n globalThis.addEventListener('keydown', this._onKeyDown, false);\n }\n Object.defineProperty(AccessibilityManager.prototype, \"isActive\", {\n /**\n * Value of `true` if accessibility is currently active and accessibility layers are showing.\n * @member {boolean}\n * @readonly\n */\n get: function () {\n return this._isActive;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(AccessibilityManager.prototype, \"isMobileAccessibility\", {\n /**\n * Value of `true` if accessibility is enabled for touch devices.\n * @member {boolean}\n * @readonly\n */\n get: function () {\n return this._isMobileAccessibility;\n },\n enumerable: false,\n configurable: true\n });\n /**\n * Creates the touch hooks.\n * @private\n */\n AccessibilityManager.prototype.createTouchHook = function () {\n var _this = this;\n var hookDiv = document.createElement('button');\n hookDiv.style.width = DIV_HOOK_SIZE + \"px\";\n hookDiv.style.height = DIV_HOOK_SIZE + \"px\";\n hookDiv.style.position = 'absolute';\n hookDiv.style.top = DIV_HOOK_POS_X + \"px\";\n hookDiv.style.left = DIV_HOOK_POS_Y + \"px\";\n hookDiv.style.zIndex = DIV_HOOK_ZINDEX.toString();\n hookDiv.style.backgroundColor = '#FF0000';\n hookDiv.title = 'select to enable accessibility for this content';\n hookDiv.addEventListener('focus', function () {\n _this._isMobileAccessibility = true;\n _this.activate();\n _this.destroyTouchHook();\n });\n document.body.appendChild(hookDiv);\n this._hookDiv = hookDiv;\n };\n /**\n * Destroys the touch hooks.\n * @private\n */\n AccessibilityManager.prototype.destroyTouchHook = function () {\n if (!this._hookDiv) {\n return;\n }\n document.body.removeChild(this._hookDiv);\n this._hookDiv = null;\n };\n /**\n * Activating will cause the Accessibility layer to be shown.\n * This is called when a user presses the tab key.\n * @private\n */\n AccessibilityManager.prototype.activate = function () {\n var _a;\n if (this._isActive) {\n return;\n }\n this._isActive = true;\n globalThis.document.addEventListener('mousemove', this._onMouseMove, true);\n globalThis.removeEventListener('keydown', this._onKeyDown, false);\n this.renderer.on('postrender', this.update, this);\n (_a = this.renderer.view.parentNode) === null || _a === void 0 ? void 0 : _a.appendChild(this.div);\n };\n /**\n * Deactivating will cause the Accessibility layer to be hidden.\n * This is called when a user moves the mouse.\n * @private\n */\n AccessibilityManager.prototype.deactivate = function () {\n var _a;\n if (!this._isActive || this._isMobileAccessibility) {\n return;\n }\n this._isActive = false;\n globalThis.document.removeEventListener('mousemove', this._onMouseMove, true);\n globalThis.addEventListener('keydown', this._onKeyDown, false);\n this.renderer.off('postrender', this.update);\n (_a = this.div.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(this.div);\n };\n /**\n * This recursive function will run through the scene graph and add any new accessible objects to the DOM layer.\n * @private\n * @param {PIXI.Container} displayObject - The DisplayObject to check.\n */\n AccessibilityManager.prototype.updateAccessibleObjects = function (displayObject) {\n if (!displayObject.visible || !displayObject.accessibleChildren) {\n return;\n }\n if (displayObject.accessible && displayObject.interactive) {\n if (!displayObject._accessibleActive) {\n this.addChild(displayObject);\n }\n displayObject.renderId = this.renderId;\n }\n var children = displayObject.children;\n if (children) {\n for (var i = 0; i < children.length; i++) {\n this.updateAccessibleObjects(children[i]);\n }\n }\n };\n /**\n * Before each render this function will ensure that all divs are mapped correctly to their DisplayObjects.\n * @private\n */\n AccessibilityManager.prototype.update = function () {\n /* On Android default web browser, tab order seems to be calculated by position rather than tabIndex,\n * moving buttons can cause focus to flicker between two buttons making it hard/impossible to navigate,\n * so I am just running update every half a second, seems to fix it.\n */\n var now = performance.now();\n if (isMobile.android.device && now < this.androidUpdateCount) {\n return;\n }\n this.androidUpdateCount = now + this.androidUpdateFrequency;\n if (!this.renderer.renderingToScreen) {\n return;\n }\n // update children...\n if (this.renderer._lastObjectRendered) {\n this.updateAccessibleObjects(this.renderer._lastObjectRendered);\n }\n var _a = this.renderer.view.getBoundingClientRect(), left = _a.left, top = _a.top, width = _a.width, height = _a.height;\n var _b = this.renderer, viewWidth = _b.width, viewHeight = _b.height, resolution = _b.resolution;\n var sx = (width / viewWidth) * resolution;\n var sy = (height / viewHeight) * resolution;\n var div = this.div;\n div.style.left = left + \"px\";\n div.style.top = top + \"px\";\n div.style.width = viewWidth + \"px\";\n div.style.height = viewHeight + \"px\";\n for (var i = 0; i < this.children.length; i++) {\n var child = this.children[i];\n if (child.renderId !== this.renderId) {\n child._accessibleActive = false;\n removeItems(this.children, i, 1);\n this.div.removeChild(child._accessibleDiv);\n this.pool.push(child._accessibleDiv);\n child._accessibleDiv = null;\n i--;\n }\n else {\n // map div to display..\n div = child._accessibleDiv;\n var hitArea = child.hitArea;\n var wt = child.worldTransform;\n if (child.hitArea) {\n div.style.left = (wt.tx + (hitArea.x * wt.a)) * sx + \"px\";\n div.style.top = (wt.ty + (hitArea.y * wt.d)) * sy + \"px\";\n div.style.width = hitArea.width * wt.a * sx + \"px\";\n div.style.height = hitArea.height * wt.d * sy + \"px\";\n }\n else {\n hitArea = child.getBounds();\n this.capHitArea(hitArea);\n div.style.left = hitArea.x * sx + \"px\";\n div.style.top = hitArea.y * sy + \"px\";\n div.style.width = hitArea.width * sx + \"px\";\n div.style.height = hitArea.height * sy + \"px\";\n // update button titles and hints if they exist and they've changed\n if (div.title !== child.accessibleTitle && child.accessibleTitle !== null) {\n div.title = child.accessibleTitle;\n }\n if (div.getAttribute('aria-label') !== child.accessibleHint\n && child.accessibleHint !== null) {\n div.setAttribute('aria-label', child.accessibleHint);\n }\n }\n // the title or index may have changed, if so lets update it!\n if (child.accessibleTitle !== div.title || child.tabIndex !== div.tabIndex) {\n div.title = child.accessibleTitle;\n div.tabIndex = child.tabIndex;\n if (this.debug)\n { this.updateDebugHTML(div); }\n }\n }\n }\n // increment the render id..\n this.renderId++;\n };\n /**\n * private function that will visually add the information to the\n * accessability div\n * @param {HTMLElement} div -\n */\n AccessibilityManager.prototype.updateDebugHTML = function (div) {\n div.innerHTML = \"type: \" + div.type + \"</br> title : \" + div.title + \"</br> tabIndex: \" + div.tabIndex;\n };\n /**\n * Adjust the hit area based on the bounds of a display object\n * @param {PIXI.Rectangle} hitArea - Bounds of the child\n */\n AccessibilityManager.prototype.capHitArea = function (hitArea) {\n if (hitArea.x < 0) {\n hitArea.width += hitArea.x;\n hitArea.x = 0;\n }\n if (hitArea.y < 0) {\n hitArea.height += hitArea.y;\n hitArea.y = 0;\n }\n var _a = this.renderer, viewWidth = _a.width, viewHeight = _a.height;\n if (hitArea.x + hitArea.width > viewWidth) {\n hitArea.width = viewWidth - hitArea.x;\n }\n if (hitArea.y + hitArea.height > viewHeight) {\n hitArea.height = viewHeight - hitArea.y;\n }\n };\n /**\n * Adds a DisplayObject to the accessibility manager\n * @private\n * @param {PIXI.DisplayObject} displayObject - The child to make accessible.\n */\n AccessibilityManager.prototype.addChild = function (displayObject) {\n // this.activate();\n var div = this.pool.pop();\n if (!div) {\n div = document.createElement('button');\n div.style.width = DIV_TOUCH_SIZE + \"px\";\n div.style.height = DIV_TOUCH_SIZE + \"px\";\n div.style.backgroundColor = this.debug ? 'rgba(255,255,255,0.5)' : 'transparent';\n div.style.position = 'absolute';\n div.style.zIndex = DIV_TOUCH_ZINDEX.toString();\n div.style.borderStyle = 'none';\n // ARIA attributes ensure that button title and hint updates are announced properly\n if (navigator.userAgent.toLowerCase().indexOf('chrome') > -1) {\n // Chrome doesn't need aria-live to work as intended; in fact it just gets more confused.\n div.setAttribute('aria-live', 'off');\n }\n else {\n div.setAttribute('aria-live', 'polite');\n }\n if (navigator.userAgent.match(/rv:.*Gecko\\//)) {\n // FireFox needs this to announce only the new button name\n div.setAttribute('aria-relevant', 'additions');\n }\n else {\n // required by IE, other browsers don't much care\n div.setAttribute('aria-relevant', 'text');\n }\n div.addEventListener('click', this._onClick.bind(this));\n div.addEventListener('focus', this._onFocus.bind(this));\n div.addEventListener('focusout', this._onFocusOut.bind(this));\n }\n // set pointer events\n div.style.pointerEvents = displayObject.accessiblePointerEvents;\n // set the type, this defaults to button!\n div.type = displayObject.accessibleType;\n if (displayObject.accessibleTitle && displayObject.accessibleTitle !== null) {\n div.title = displayObject.accessibleTitle;\n }\n else if (!displayObject.accessibleHint\n || displayObject.accessibleHint === null) {\n div.title = \"displayObject \" + displayObject.tabIndex;\n }\n if (displayObject.accessibleHint\n && displayObject.accessibleHint !== null) {\n div.setAttribute('aria-label', displayObject.accessibleHint);\n }\n if (this.debug)\n { this.updateDebugHTML(div); }\n displayObject._accessibleActive = true;\n displayObject._accessibleDiv = div;\n div.displayObject = displayObject;\n this.children.push(displayObject);\n this.div.appendChild(displayObject._accessibleDiv);\n displayObject._accessibleDiv.tabIndex = displayObject.tabIndex;\n };\n /**\n * Maps the div button press to pixi's InteractionManager (click)\n * @private\n * @param {MouseEvent} e - The click event.\n */\n AccessibilityManager.prototype._onClick = function (e) {\n var interactionManager = this.renderer.plugins.interaction;\n var displayObject = e.target.displayObject;\n var eventData = interactionManager.eventData;\n interactionManager.dispatchEvent(displayObject, 'click', eventData);\n interactionManager.dispatchEvent(displayObject, 'pointertap', eventData);\n interactionManager.dispatchEvent(displayObject, 'tap', eventData);\n };\n /**\n * Maps the div focus events to pixi's InteractionManager (mouseover)\n * @private\n * @param {FocusEvent} e - The focus event.\n */\n AccessibilityManager.prototype._onFocus = function (e) {\n if (!e.target.getAttribute('aria-live')) {\n e.target.setAttribute('aria-live', 'assertive');\n }\n var interactionManager = this.renderer.plugins.interaction;\n var displayObject = e.target.displayObject;\n var eventData = interactionManager.eventData;\n interactionManager.dispatchEvent(displayObject, 'mouseover', eventData);\n };\n /**\n * Maps the div focus events to pixi's InteractionManager (mouseout)\n * @private\n * @param {FocusEvent} e - The focusout event.\n */\n AccessibilityManager.prototype._onFocusOut = function (e) {\n if (!e.target.getAttribute('aria-live')) {\n e.target.setAttribute('aria-live', 'polite');\n }\n var interactionManager = this.renderer.plugins.interaction;\n var displayObject = e.target.displayObject;\n var eventData = interactionManager.eventData;\n interactionManager.dispatchEvent(displayObject, 'mouseout', eventData);\n };\n /**\n * Is called when a key is pressed\n * @private\n * @param {KeyboardEvent} e - The keydown event.\n */\n AccessibilityManager.prototype._onKeyDown = function (e) {\n if (e.keyCode !== KEY_CODE_TAB) {\n return;\n }\n this.activate();\n };\n /**\n * Is called when the mouse moves across the renderer element\n * @private\n * @param {MouseEvent} e - The mouse event.\n */\n AccessibilityManager.prototype._onMouseMove = function (e) {\n if (e.movementX === 0 && e.movementY === 0) {\n return;\n }\n this.deactivate();\n };\n /** Destroys the accessibility manager */\n AccessibilityManager.prototype.destroy = function () {\n this.destroyTouchHook();\n this.div = null;\n globalThis.document.removeEventListener('mousemove', this._onMouseMove, true);\n globalThis.removeEventListener('keydown', this._onKeyDown);\n this.pool = null;\n this.children = null;\n this.renderer = null;\n };\n /** @ignore */\n AccessibilityManager.extension = {\n name: 'accessibility',\n type: [\n ExtensionType.RendererPlugin,\n ExtensionType.CanvasRendererPlugin ],\n };\n return AccessibilityManager;\n}());\n\nexport { AccessibilityManager, accessibleTarget };\n//# sourceMappingURL=accessibility.mjs.map\n","/*!\n * @pixi/particle-container - v6.5.8\n * Compiled Sun, 23 Oct 2022 23:01:45 UTC\n *\n * @pixi/particle-container is licensed under the MIT License.\n * http://www.opensource.org/licenses/mit-license\n */\nimport { BLEND_MODES, TYPES } from '@pixi/constants';\nimport { Container } from '@pixi/display';\nimport { hex2rgb, createIndicesForQuads, correctBlendMode, premultiplyRgba, premultiplyTint } from '@pixi/utils';\nimport { Geometry, Buffer, ExtensionType, ObjectRenderer, Shader, State } from '@pixi/core';\nimport { Matrix } from '@pixi/math';\n\n/*! *****************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n/* global Reflect, Promise */\r\n\r\nvar extendStatics = function(d, b) {\r\n extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) { if (b.hasOwnProperty(p)) { d[p] = b[p]; } } };\r\n return extendStatics(d, b);\r\n};\r\n\r\nfunction __extends(d, b) {\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n}\n\n/**\n * The ParticleContainer class is a really fast version of the Container built solely for speed,\n * so use when you need a lot of sprites or particles.\n *\n * The tradeoff of the ParticleContainer is that most advanced functionality will not work.\n * ParticleContainer implements the basic object transform (position, scale, rotation)\n * and some advanced functionality like tint (as of v4.5.6).\n *\n * Other more advanced functionality like masking, children, filters, etc will not work on sprites in this batch.\n *\n * It's extremely easy to use:\n * ```js\n * let container = new ParticleContainer();\n *\n * for (let i = 0; i < 100; ++i)\n * {\n * let sprite = PIXI.Sprite.from(\"myImage.png\");\n * container.addChild(sprite);\n * }\n * ```\n *\n * And here you have a hundred sprites that will be rendered at the speed of light.\n * @memberof PIXI\n */\nvar ParticleContainer = /** @class */ (function (_super) {\n __extends(ParticleContainer, _super);\n /**\n * @param maxSize - The maximum number of particles that can be rendered by the container.\n * Affects size of allocated buffers.\n * @param properties - The properties of children that should be uploaded to the gpu and applied.\n * @param {boolean} [properties.vertices=false] - When true, vertices be uploaded and applied.\n * if sprite's ` scale/anchor/trim/frame/orig` is dynamic, please set `true`.\n * @param {boolean} [properties.position=true] - When true, position be uploaded and applied.\n * @param {boolean} [properties.rotation=false] - When true, rotation be uploaded and applied.\n * @param {boolean} [properties.uvs=false] - When true, uvs be uploaded and applied.\n * @param {boolean} [properties.tint=false] - When true, alpha and tint be uploaded and applied.\n * @param {number} [batchSize=16384] - Number of particles per batch. If less than maxSize, it uses maxSize instead.\n * @param {boolean} [autoResize=false] - If true, container allocates more batches in case\n * there are more than `maxSize` particles.\n */\n function ParticleContainer(maxSize, properties, batchSize, autoResize) {\n if (maxSize === void 0) { maxSize = 1500; }\n if (batchSize === void 0) { batchSize = 16384; }\n if (autoResize === void 0) { autoResize = false; }\n var _this = _super.call(this) || this;\n // Making sure the batch size is valid\n // 65535 is max vertex index in the index buffer (see ParticleRenderer)\n // so max number of particles is 65536 / 4 = 16384\n var maxBatchSize = 16384;\n if (batchSize > maxBatchSize) {\n batchSize = maxBatchSize;\n }\n _this._properties = [false, true, false, false, false];\n _this._maxSize = maxSize;\n _this._batchSize = batchSize;\n _this._buffers = null;\n _this._bufferUpdateIDs = [];\n _this._updateID = 0;\n _this.interactiveChildren = false;\n _this.blendMode = BLEND_MODES.NORMAL;\n _this.autoResize = autoResize;\n _this.roundPixels = true;\n _this.baseTexture = null;\n _this.setProperties(properties);\n _this._tint = 0;\n _this.tintRgb = new Float32Array(4);\n _this.tint = 0xFFFFFF;\n return _this;\n }\n /**\n * Sets the private properties array to dynamic / static based on the passed properties object\n * @param properties - The properties to be uploaded\n */\n ParticleContainer.prototype.setProperties = function (properties) {\n if (properties) {\n this._properties[0] = 'vertices' in properties || 'scale' in properties\n ? !!properties.vertices || !!properties.scale : this._properties[0];\n this._properties[1] = 'position' in properties ? !!properties.position : this._properties[1];\n this._properties[2] = 'rotation' in properties ? !!properties.rotation : this._properties[2];\n this._properties[3] = 'uvs' in properties ? !!properties.uvs : this._properties[3];\n this._properties[4] = 'tint' in properties || 'alpha' in properties\n ? !!properties.tint || !!properties.alpha : this._properties[4];\n }\n };\n ParticleContainer.prototype.updateTransform = function () {\n // TODO don't need to!\n this.displayObjectUpdateTransform();\n };\n Object.defineProperty(ParticleContainer.prototype, \"tint\", {\n /**\n * The tint applied to the container. This is a hex value.\n * A value of 0xFFFFFF will remove any tint effect.\n * IMPORTANT: This is a WebGL only feature and will be ignored by the canvas renderer.\n * @default 0xFFFFFF\n */\n get: function () {\n return this._tint;\n },\n set: function (value) {\n this._tint = value;\n hex2rgb(value, this.tintRgb);\n },\n enumerable: false,\n configurable: true\n });\n /**\n * Renders the container using the WebGL renderer.\n * @param renderer - The WebGL renderer.\n */\n ParticleContainer.prototype.render = function (renderer) {\n var _this = this;\n if (!this.visible || this.worldAlpha <= 0 || !this.children.length || !this.renderable) {\n return;\n }\n if (!this.baseTexture) {\n this.baseTexture = this.children[0]._texture.baseTexture;\n if (!this.baseTexture.valid) {\n this.baseTexture.once('update', function () { return _this.onChildrenChange(0); });\n }\n }\n renderer.batch.setObjectRenderer(renderer.plugins.particle);\n renderer.plugins.particle.render(this);\n };\n /**\n * Set the flag that static data should be updated to true\n * @param smallestChildIndex - The smallest child index.\n */\n ParticleContainer.prototype.onChildrenChange = function (smallestChildIndex) {\n var bufferIndex = Math.floor(smallestChildIndex / this._batchSize);\n while (this._bufferUpdateIDs.length < bufferIndex) {\n this._bufferUpdateIDs.push(0);\n }\n this._bufferUpdateIDs[bufferIndex] = ++this._updateID;\n };\n ParticleContainer.prototype.dispose = function () {\n if (this._buffers) {\n for (var i = 0; i < this._buffers.length; ++i) {\n this._buffers[i].destroy();\n }\n this._buffers = null;\n }\n };\n /**\n * Destroys the container\n * @param options - Options parameter. A boolean will act as if all options\n * have been set to that value\n * @param {boolean} [options.children=false] - if set to true, all the children will have their\n * destroy method called as well. 'options' will be passed on to those calls.\n * @param {boolean} [options.texture=false] - Only used for child Sprites if options.children is set to true\n * Should it destroy the texture of the child sprite\n * @param {boolean} [options.baseTexture=false] - Only used for child Sprites if options.children is set to true\n * Should it destroy the base texture of the child sprite\n */\n ParticleContainer.prototype.destroy = function (options) {\n _super.prototype.destroy.call(this, options);\n this.dispose();\n this._properties = null;\n this._buffers = null;\n this._bufferUpdateIDs = null;\n };\n return ParticleContainer;\n}(Container));\n\n/*\n * @author Mat Groves\n *\n * Big thanks to the very clever Matt DesLauriers <mattdesl> https://github.com/mattdesl/\n * for creating the original PixiJS version!\n * Also a thanks to https://github.com/bchevalier for tweaking the tint and alpha so that\n * they now share 4 bytes on the vertex buffer\n *\n * Heavily inspired by LibGDX's ParticleBuffer:\n * https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/ParticleBuffer.java\n */\n/**\n * The particle buffer manages the static and dynamic buffers for a particle container.\n * @private\n * @memberof PIXI\n */\nvar ParticleBuffer = /** @class */ (function () {\n /**\n * @param {object} properties - The properties to upload.\n * @param {boolean[]} dynamicPropertyFlags - Flags for which properties are dynamic.\n * @param {number} size - The size of the batch.\n */\n function ParticleBuffer(properties, dynamicPropertyFlags, size) {\n this.geometry = new Geometry();\n this.indexBuffer = null;\n this.size = size;\n this.dynamicProperties = [];\n this.staticProperties = [];\n for (var i = 0; i < properties.length; ++i) {\n var property = properties[i];\n // Make copy of properties object so that when we edit the offset it doesn't\n // change all other instances of the object literal\n property = {\n attributeName: property.attributeName,\n size: property.size,\n uploadFunction: property.uploadFunction,\n type: property.type || TYPES.FLOAT,\n offset: property.offset,\n };\n if (dynamicPropertyFlags[i]) {\n this.dynamicProperties.push(property);\n }\n else {\n this.staticProperties.push(property);\n }\n }\n this.staticStride = 0;\n this.staticBuffer = null;\n this.staticData = null;\n this.staticDataUint32 = null;\n this.dynamicStride = 0;\n this.dynamicBuffer = null;\n this.dynamicData = null;\n this.dynamicDataUint32 = null;\n this._updateID = 0;\n this.initBuffers();\n }\n /** Sets up the renderer context and necessary buffers. */\n ParticleBuffer.prototype.initBuffers = function () {\n var geometry = this.geometry;\n var dynamicOffset = 0;\n this.indexBuffer = new Buffer(createIndicesForQuads(this.size), true, true);\n geometry.addIndex(this.indexBuffer);\n this.dynamicStride = 0;\n for (var i = 0; i < this.dynamicProperties.length; ++i) {\n var property = this.dynamicProperties[i];\n property.offset = dynamicOffset;\n dynamicOffset += property.size;\n this.dynamicStride += property.size;\n }\n var dynBuffer = new ArrayBuffer(this.size * this.dynamicStride * 4 * 4);\n this.dynamicData = new Float32Array(dynBuffer);\n this.dynamicDataUint32 = new Uint32Array(dynBuffer);\n this.dynamicBuffer = new Buffer(this.dynamicData, false, false);\n // static //\n var staticOffset = 0;\n this.staticStride = 0;\n for (var i = 0; i < this.staticProperties.length; ++i) {\n var property = this.staticProperties[i];\n property.offset = staticOffset;\n staticOffset += property.size;\n this.staticStride += property.size;\n }\n var statBuffer = new ArrayBuffer(this.size * this.staticStride * 4 * 4);\n this.staticData = new Float32Array(statBuffer);\n this.staticDataUint32 = new Uint32Array(statBuffer);\n this.staticBuffer = new Buffer(this.staticData, true, false);\n for (var i = 0; i < this.dynamicProperties.length; ++i) {\n var property = this.dynamicProperties[i];\n geometry.addAttribute(property.attributeName, this.dynamicBuffer, 0, property.type === TYPES.UNSIGNED_BYTE, property.type, this.dynamicStride * 4, property.offset * 4);\n }\n for (var i = 0; i < this.staticProperties.length; ++i) {\n var property = this.staticProperties[i];\n geometry.addAttribute(property.attributeName, this.staticBuffer, 0, property.type === TYPES.UNSIGNED_BYTE, property.type, this.staticStride * 4, property.offset * 4);\n }\n };\n /**\n * Uploads the dynamic properties.\n * @param children - The children to upload.\n * @param startIndex - The index to start at.\n * @param amount - The number to upload.\n */\n ParticleBuffer.prototype.uploadDynamic = function (children, startIndex, amount) {\n for (var i = 0; i < this.dynamicProperties.length; i++) {\n var property = this.dynamicProperties[i];\n property.uploadFunction(children, startIndex, amount, property.type === TYPES.UNSIGNED_BYTE ? this.dynamicDataUint32 : this.dynamicData, this.dynamicStride, property.offset);\n }\n this.dynamicBuffer._updateID++;\n };\n /**\n * Uploads the static properties.\n * @param children - The children to upload.\n * @param startIndex - The index to start at.\n * @param amount - The number to upload.\n */\n ParticleBuffer.prototype.uploadStatic = function (children, startIndex, amount) {\n for (var i = 0; i < this.staticProperties.length; i++) {\n var property = this.staticProperties[i];\n property.uploadFunction(children, startIndex, amount, property.type === TYPES.UNSIGNED_BYTE ? this.staticDataUint32 : this.staticData, this.staticStride, property.offset);\n }\n this.staticBuffer._updateID++;\n };\n /** Destroys the ParticleBuffer. */\n ParticleBuffer.prototype.destroy = function () {\n this.indexBuffer = null;\n this.dynamicProperties = null;\n this.dynamicBuffer = null;\n this.dynamicData = null;\n this.dynamicDataUint32 = null;\n this.staticProperties = null;\n this.staticBuffer = null;\n this.staticData = null;\n this.staticDataUint32 = null;\n // all buffers are destroyed inside geometry\n this.geometry.destroy();\n };\n return ParticleBuffer;\n}());\n\nvar fragment = \"varying vec2 vTextureCoord;\\nvarying vec4 vColor;\\n\\nuniform sampler2D uSampler;\\n\\nvoid main(void){\\n vec4 color = texture2D(uSampler, vTextureCoord) * vColor;\\n gl_FragColor = color;\\n}\";\n\nvar vertex = \"attribute vec2 aVertexPosition;\\nattribute vec2 aTextureCoord;\\nattribute vec4 aColor;\\n\\nattribute vec2 aPositionCoord;\\nattribute float aRotation;\\n\\nuniform mat3 translationMatrix;\\nuniform vec4 uColor;\\n\\nvarying vec2 vTextureCoord;\\nvarying vec4 vColor;\\n\\nvoid main(void){\\n float x = (aVertexPosition.x) * cos(aRotation) - (aVertexPosition.y) * sin(aRotation);\\n float y = (aVertexPosition.x) * sin(aRotation) + (aVertexPosition.y) * cos(aRotation);\\n\\n vec2 v = vec2(x, y);\\n v = v + aPositionCoord;\\n\\n gl_Position = vec4((translationMatrix * vec3(v, 1.0)).xy, 0.0, 1.0);\\n\\n vTextureCoord = aTextureCoord;\\n vColor = aColor * uColor;\\n}\\n\";\n\n/*\n * @author Mat Groves\n *\n * Big thanks to the very clever Matt DesLauriers <mattdesl> https://github.com/mattdesl/\n * for creating the original PixiJS version!\n * Also a thanks to https://github.com/bchevalier for tweaking the tint and alpha so that they now\n * share 4 bytes on the vertex buffer\n *\n * Heavily inspired by LibGDX's ParticleRenderer:\n * https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/ParticleRenderer.java\n */\n/**\n * Renderer for Particles that is designer for speed over feature set.\n * @memberof PIXI\n */\nvar ParticleRenderer = /** @class */ (function (_super) {\n __extends(ParticleRenderer, _super);\n /**\n * @param renderer - The renderer this sprite batch works for.\n */\n function ParticleRenderer(renderer) {\n var _this = _super.call(this, renderer) || this;\n // 65535 is max vertex index in the index buffer (see ParticleRenderer)\n // so max number of particles is 65536 / 4 = 16384\n // and max number of element in the index buffer is 16384 * 6 = 98304\n // Creating a full index buffer, overhead is 98304 * 2 = 196Ko\n // let numIndices = 98304;\n _this.shader = null;\n _this.properties = null;\n _this.tempMatrix = new Matrix();\n _this.properties = [\n // verticesData\n {\n attributeName: 'aVertexPosition',\n size: 2,\n uploadFunction: _this.uploadVertices,\n offset: 0,\n },\n // positionData\n {\n attributeName: 'aPositionCoord',\n size: 2,\n uploadFunction: _this.uploadPosition,\n offset: 0,\n },\n // rotationData\n {\n attributeName: 'aRotation',\n size: 1,\n uploadFunction: _this.uploadRotation,\n offset: 0,\n },\n // uvsData\n {\n attributeName: 'aTextureCoord',\n size: 2,\n uploadFunction: _this.uploadUvs,\n offset: 0,\n },\n // tintData\n {\n attributeName: 'aColor',\n size: 1,\n type: TYPES.UNSIGNED_BYTE,\n uploadFunction: _this.uploadTint,\n offset: 0,\n } ];\n _this.shader = Shader.from(vertex, fragment, {});\n _this.state = State.for2d();\n return _this;\n }\n /**\n * Renders the particle container object.\n * @param container - The container to render using this ParticleRenderer.\n */\n ParticleRenderer.prototype.render = function (container) {\n var children = container.children;\n var maxSize = container._maxSize;\n var batchSize = container._batchSize;\n var renderer = this.renderer;\n var totalChildren = children.length;\n if (totalChildren === 0) {\n return;\n }\n else if (totalChildren > maxSize && !container.autoResize) {\n totalChildren = maxSize;\n }\n var buffers = container._buffers;\n if (!buffers) {\n buffers = container._buffers = this.generateBuffers(container);\n }\n var baseTexture = children[0]._texture.baseTexture;\n var premultiplied = baseTexture.alphaMode > 0;\n // if the uvs have not updated then no point rendering just yet!\n this.state.blendMode = correctBlendMode(container.blendMode, premultiplied);\n renderer.state.set(this.state);\n var gl = renderer.gl;\n var m = container.worldTransform.copyTo(this.tempMatrix);\n m.prepend(renderer.globalUniforms.uniforms.projectionMatrix);\n this.shader.uniforms.translationMatrix = m.toArray(true);\n this.shader.uniforms.uColor = premultiplyRgba(container.tintRgb, container.worldAlpha, this.shader.uniforms.uColor, premultiplied);\n this.shader.uniforms.uSampler = baseTexture;\n this.renderer.shader.bind(this.shader);\n var updateStatic = false;\n // now lets upload and render the buffers..\n for (var i = 0, j = 0; i < totalChildren; i += batchSize, j += 1) {\n var amount = (totalChildren - i);\n if (amount > batchSize) {\n amount = batchSize;\n }\n if (j >= buffers.length) {\n buffers.push(this._generateOneMoreBuffer(container));\n }\n var buffer = buffers[j];\n // we always upload the dynamic\n buffer.uploadDynamic(children, i, amount);\n var bid = container._bufferUpdateIDs[j] || 0;\n updateStatic = updateStatic || (buffer._updateID < bid);\n // we only upload the static content when we have to!\n if (updateStatic) {\n buffer._updateID = container._updateID;\n buffer.uploadStatic(children, i, amount);\n }\n // bind the buffer\n renderer.geometry.bind(buffer.geometry);\n gl.drawElements(gl.TRIANGLES, amount * 6, gl.UNSIGNED_SHORT, 0);\n }\n };\n /**\n * Creates one particle buffer for each child in the container we want to render and updates internal properties.\n * @param container - The container to render using this ParticleRenderer\n * @returns - The buffers\n */\n ParticleRenderer.prototype.generateBuffers = function (container) {\n var buffers = [];\n var size = container._maxSize;\n var batchSize = container._batchSize;\n var dynamicPropertyFlags = container._properties;\n for (var i = 0; i < size; i += batchSize) {\n buffers.push(new ParticleBuffer(this.properties, dynamicPropertyFlags, batchSize));\n }\n return buffers;\n };\n /**\n * Creates one more particle buffer, because container has autoResize feature.\n * @param container - The container to render using this ParticleRenderer\n * @returns - The generated buffer\n */\n ParticleRenderer.prototype._generateOneMoreBuffer = function (container) {\n var batchSize = container._batchSize;\n var dynamicPropertyFlags = container._properties;\n return new ParticleBuffer(this.properties, dynamicPropertyFlags, batchSize);\n };\n /**\n * Uploads the vertices.\n * @param children - the array of sprites to render\n * @param startIndex - the index to start from in the children array\n * @param amount - the amount of children that will have their vertices uploaded\n * @param array - The vertices to upload.\n * @param stride - Stride to use for iteration.\n * @param offset - Offset to start at.\n */\n ParticleRenderer.prototype.uploadVertices = function (children, startIndex, amount, array, stride, offset) {\n var w0 = 0;\n var w1 = 0;\n var h0 = 0;\n var h1 = 0;\n for (var i = 0; i < amount; ++i) {\n var sprite = children[startIndex + i];\n var texture = sprite._texture;\n var sx = sprite.scale.x;\n var sy = sprite.scale.y;\n var trim = texture.trim;\n var orig = texture.orig;\n if (trim) {\n // if the sprite is trimmed and is not a tilingsprite then we need to add the\n // extra space before transforming the sprite coords..\n w1 = trim.x - (sprite.anchor.x * orig.width);\n w0 = w1 + trim.width;\n h1 = trim.y - (sprite.anchor.y * orig.height);\n h0 = h1 + trim.height;\n }\n else {\n w0 = (orig.width) * (1 - sprite.anchor.x);\n w1 = (orig.width) * -sprite.anchor.x;\n h0 = orig.height * (1 - sprite.anchor.y);\n h1 = orig.height * -sprite.anchor.y;\n }\n array[offset] = w1 * sx;\n array[offset + 1] = h1 * sy;\n array[offset + stride] = w0 * sx;\n array[offset + stride + 1] = h1 * sy;\n array[offset + (stride * 2)] = w0 * sx;\n array[offset + (stride * 2) + 1] = h0 * sy;\n array[offset + (stride * 3)] = w1 * sx;\n array[offset + (stride * 3) + 1] = h0 * sy;\n offset += stride * 4;\n }\n };\n /**\n * Uploads the position.\n * @param children - the array of sprites to render\n * @param startIndex - the index to start from in the children array\n * @param amount - the amount of children that will have their positions uploaded\n * @param array - The vertices to upload.\n * @param stride - Stride to use for iteration.\n * @param offset - Offset to start at.\n */\n ParticleRenderer.prototype.uploadPosition = function (children, startIndex, amount, array, stride, offset) {\n for (var i = 0; i < amount; i++) {\n var spritePosition = children[startIndex + i].position;\n array[offset] = spritePosition.x;\n array[offset + 1] = spritePosition.y;\n array[offset + stride] = spritePosition.x;\n array[offset + stride + 1] = spritePosition.y;\n array[offset + (stride * 2)] = spritePosition.x;\n array[offset + (stride * 2) + 1] = spritePosition.y;\n array[offset + (stride * 3)] = spritePosition.x;\n array[offset + (stride * 3) + 1] = spritePosition.y;\n offset += stride * 4;\n }\n };\n /**\n * Uploads the rotation.\n * @param children - the array of sprites to render\n * @param startIndex - the index to start from in the children array\n * @param amount - the amount of children that will have their rotation uploaded\n * @param array - The vertices to upload.\n * @param stride - Stride to use for iteration.\n * @param offset - Offset to start at.\n */\n ParticleRenderer.prototype.uploadRotation = function (children, startIndex, amount, array, stride, offset) {\n for (var i = 0; i < amount; i++) {\n var spriteRotation = children[startIndex + i].rotation;\n array[offset] = spriteRotation;\n array[offset + stride] = spriteRotation;\n array[offset + (stride * 2)] = spriteRotation;\n array[offset + (stride * 3)] = spriteRotation;\n offset += stride * 4;\n }\n };\n /**\n * Uploads the UVs.\n * @param children - the array of sprites to render\n * @param startIndex - the index to start from in the children array\n * @param amount - the amount of children that will have their rotation uploaded\n * @param array - The vertices to upload.\n * @param stride - Stride to use for iteration.\n * @param offset - Offset to start at.\n */\n ParticleRenderer.prototype.uploadUvs = function (children, startIndex, amount, array, stride, offset) {\n for (var i = 0; i < amount; ++i) {\n var textureUvs = children[startIndex + i]._texture._uvs;\n if (textureUvs) {\n array[offset] = textureUvs.x0;\n array[offset + 1] = textureUvs.y0;\n array[offset + stride] = textureUvs.x1;\n array[offset + stride + 1] = textureUvs.y1;\n array[offset + (stride * 2)] = textureUvs.x2;\n array[offset + (stride * 2) + 1] = textureUvs.y2;\n array[offset + (stride * 3)] = textureUvs.x3;\n array[offset + (stride * 3) + 1] = textureUvs.y3;\n offset += stride * 4;\n }\n else {\n // TODO you know this can be easier!\n array[offset] = 0;\n array[offset + 1] = 0;\n array[offset + stride] = 0;\n array[offset + stride + 1] = 0;\n array[offset + (stride * 2)] = 0;\n array[offset + (stride * 2) + 1] = 0;\n array[offset + (stride * 3)] = 0;\n array[offset + (stride * 3) + 1] = 0;\n offset += stride * 4;\n }\n }\n };\n /**\n * Uploads the tint.\n * @param children - the array of sprites to render\n * @param startIndex - the index to start from in the children array\n * @param amount - the amount of children that will have their rotation uploaded\n * @param array - The vertices to upload.\n * @param stride - Stride to use for iteration.\n * @param offset - Offset to start at.\n */\n ParticleRenderer.prototype.uploadTint = function (children, startIndex, amount, array, stride, offset) {\n for (var i = 0; i < amount; ++i) {\n var sprite = children[startIndex + i];\n var premultiplied = sprite._texture.baseTexture.alphaMode > 0;\n var alpha = sprite.alpha;\n // we dont call extra function if alpha is 1.0, that's faster\n var argb = alpha < 1.0 && premultiplied\n ? premultiplyTint(sprite._tintRGB, alpha) : sprite._tintRGB + (alpha * 255 << 24);\n array[offset] = argb;\n array[offset + stride] = argb;\n array[offset + (stride * 2)] = argb;\n array[offset + (stride * 3)] = argb;\n offset += stride * 4;\n }\n };\n /** Destroys the ParticleRenderer. */\n ParticleRenderer.prototype.destroy = function () {\n _super.prototype.destroy.call(this);\n if (this.shader) {\n this.shader.destroy();\n this.shader = null;\n }\n this.tempMatrix = null;\n };\n /** @ignore */\n ParticleRenderer.extension = {\n name: 'particle',\n type: ExtensionType.RendererPlugin,\n };\n return ParticleRenderer;\n}(ObjectRenderer));\n\nexport { ParticleContainer, ParticleRenderer };\n//# sourceMappingURL=particle-container.mjs.map\n","/*!\n * @pixi/prepare - v6.5.8\n * Compiled Sun, 23 Oct 2022 23:01:45 UTC\n *\n * @pixi/prepare is licensed under the MIT License.\n * http://www.opensource.org/licenses/mit-license\n */\nimport { settings } from '@pixi/settings';\nimport { Texture, BaseTexture, ExtensionType } from '@pixi/core';\nimport { Graphics } from '@pixi/graphics';\nimport { Ticker, UPDATE_PRIORITY } from '@pixi/ticker';\nimport { Container } from '@pixi/display';\nimport { Text, TextStyle, TextMetrics } from '@pixi/text';\nimport { deprecation } from '@pixi/utils';\n\n/**\n * Default number of uploads per frame using prepare plugin.\n * @static\n * @memberof PIXI.settings\n * @name UPLOADS_PER_FRAME\n * @type {number}\n * @default 4\n */\nsettings.UPLOADS_PER_FRAME = 4;\n\n/*! *****************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n/* global Reflect, Promise */\r\n\r\nvar extendStatics = function(d, b) {\r\n extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) { if (b.hasOwnProperty(p)) { d[p] = b[p]; } } };\r\n return extendStatics(d, b);\r\n};\r\n\r\nfunction __extends(d, b) {\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n}\n\n/**\n * CountLimiter limits the number of items handled by a {@link PIXI.BasePrepare} to a specified\n * number of items per frame.\n * @memberof PIXI\n */\nvar CountLimiter = /** @class */ (function () {\n /**\n * @param maxItemsPerFrame - The maximum number of items that can be prepared each frame.\n */\n function CountLimiter(maxItemsPerFrame) {\n this.maxItemsPerFrame = maxItemsPerFrame;\n this.itemsLeft = 0;\n }\n /** Resets any counting properties to start fresh on a new frame. */\n CountLimiter.prototype.beginFrame = function () {\n this.itemsLeft = this.maxItemsPerFrame;\n };\n /**\n * Checks to see if another item can be uploaded. This should only be called once per item.\n * @returns If the item is allowed to be uploaded.\n */\n CountLimiter.prototype.allowedToUpload = function () {\n return this.itemsLeft-- > 0;\n };\n return CountLimiter;\n}());\n\n/**\n * Built-in hook to find multiple textures from objects like AnimatedSprites.\n * @private\n * @param item - Display object to check\n * @param queue - Collection of items to upload\n * @returns If a PIXI.Texture object was found.\n */\nfunction findMultipleBaseTextures(item, queue) {\n var result = false;\n // Objects with multiple textures\n if (item && item._textures && item._textures.length) {\n for (var i = 0; i < item._textures.length; i++) {\n if (item._textures[i] instanceof Texture) {\n var baseTexture = item._textures[i].baseTexture;\n if (queue.indexOf(baseTexture) === -1) {\n queue.push(baseTexture);\n result = true;\n }\n }\n }\n }\n return result;\n}\n/**\n * Built-in hook to find BaseTextures from Texture.\n * @private\n * @param item - Display object to check\n * @param queue - Collection of items to upload\n * @returns If a PIXI.Texture object was found.\n */\nfunction findBaseTexture(item, queue) {\n if (item.baseTexture instanceof BaseTexture) {\n var texture = item.baseTexture;\n if (queue.indexOf(texture) === -1) {\n queue.push(texture);\n }\n return true;\n }\n return false;\n}\n/**\n * Built-in hook to find textures from objects.\n * @private\n * @param item - Display object to check\n * @param queue - Collection of items to upload\n * @returns If a PIXI.Texture object was found.\n */\nfunction findTexture(item, queue) {\n if (item._texture && item._texture instanceof Texture) {\n var texture = item._texture.baseTexture;\n if (queue.indexOf(texture) === -1) {\n queue.push(texture);\n }\n return true;\n }\n return false;\n}\n/**\n * Built-in hook to draw PIXI.Text to its texture.\n * @private\n * @param _helper - Not used by this upload handler\n * @param item - Item to check\n * @returns If item was uploaded.\n */\nfunction drawText(_helper, item) {\n if (item instanceof Text) {\n // updating text will return early if it is not dirty\n item.updateText(true);\n return true;\n }\n return false;\n}\n/**\n * Built-in hook to calculate a text style for a PIXI.Text object.\n * @private\n * @param _helper - Not used by this upload handler\n * @param item - Item to check\n * @returns If item was uploaded.\n */\nfunction calculateTextStyle(_helper, item) {\n if (item instanceof TextStyle) {\n var font = item.toFontString();\n TextMetrics.measureFont(font);\n return true;\n }\n return false;\n}\n/**\n * Built-in hook to find Text objects.\n * @private\n * @param item - Display object to check\n * @param queue - Collection of items to upload\n * @returns if a PIXI.Text object was found.\n */\nfunction findText(item, queue) {\n if (item instanceof Text) {\n // push the text style to prepare it - this can be really expensive\n if (queue.indexOf(item.style) === -1) {\n queue.push(item.style);\n }\n // also push the text object so that we can render it (to canvas/texture) if needed\n if (queue.indexOf(item) === -1) {\n queue.push(item);\n }\n // also push the Text's texture for upload to GPU\n var texture = item._texture.baseTexture;\n if (queue.indexOf(texture) === -1) {\n queue.push(texture);\n }\n return true;\n }\n return false;\n}\n/**\n * Built-in hook to find TextStyle objects.\n * @private\n * @param item - Display object to check\n * @param queue - Collection of items to upload\n * @returns If a PIXI.TextStyle object was found.\n */\nfunction findTextStyle(item, queue) {\n if (item instanceof TextStyle) {\n if (queue.indexOf(item) === -1) {\n queue.push(item);\n }\n return true;\n }\n return false;\n}\n/**\n * The prepare manager provides functionality to upload content to the GPU.\n *\n * BasePrepare handles basic queuing functionality and is extended by\n * {@link PIXI.Prepare} and {@link PIXI.CanvasPrepare}\n * to provide preparation capabilities specific to their respective renderers.\n * @example\n * // Create a sprite\n * const sprite = PIXI.Sprite.from('something.png');\n *\n * // Load object into GPU\n * app.renderer.plugins.prepare.upload(sprite, () => {\n *\n * //Texture(s) has been uploaded to GPU\n * app.stage.addChild(sprite);\n *\n * })\n * @abstract\n * @memberof PIXI\n */\nvar BasePrepare = /** @class */ (function () {\n /**\n * @param {PIXI.AbstractRenderer} renderer - A reference to the current renderer\n */\n function BasePrepare(renderer) {\n var _this = this;\n this.limiter = new CountLimiter(settings.UPLOADS_PER_FRAME);\n this.renderer = renderer;\n this.uploadHookHelper = null;\n this.queue = [];\n this.addHooks = [];\n this.uploadHooks = [];\n this.completes = [];\n this.ticking = false;\n this.delayedTick = function () {\n // unlikely, but in case we were destroyed between tick() and delayedTick()\n if (!_this.queue) {\n return;\n }\n _this.prepareItems();\n };\n // hooks to find the correct texture\n this.registerFindHook(findText);\n this.registerFindHook(findTextStyle);\n this.registerFindHook(findMultipleBaseTextures);\n this.registerFindHook(findBaseTexture);\n this.registerFindHook(findTexture);\n // upload hooks\n this.registerUploadHook(drawText);\n this.registerUploadHook(calculateTextStyle);\n }\n /** @ignore */\n BasePrepare.prototype.upload = function (item, done) {\n var _this = this;\n if (typeof item === 'function') {\n done = item;\n item = null;\n }\n if (done) {\n deprecation('6.5.0', 'BasePrepare.upload callback is deprecated, use the return Promise instead.');\n }\n return new Promise(function (resolve) {\n // If a display object, search for items\n // that we could upload\n if (item) {\n _this.add(item);\n }\n // TODO: remove done callback and just use resolve\n var complete = function () {\n done === null || done === void 0 ? void 0 : done();\n resolve();\n };\n // Get the items for upload from the display\n if (_this.queue.length) {\n _this.completes.push(complete);\n if (!_this.ticking) {\n _this.ticking = true;\n Ticker.system.addOnce(_this.tick, _this, UPDATE_PRIORITY.UTILITY);\n }\n }\n else {\n complete();\n }\n });\n };\n /**\n * Handle tick update\n * @private\n */\n BasePrepare.prototype.tick = function () {\n setTimeout(this.delayedTick, 0);\n };\n /**\n * Actually prepare items. This is handled outside of the tick because it will take a while\n * and we do NOT want to block the current animation frame from rendering.\n * @private\n */\n BasePrepare.prototype.prepareItems = function () {\n this.limiter.beginFrame();\n // Upload the graphics\n while (this.queue.length && this.limiter.allowedToUpload()) {\n var item = this.queue[0];\n var uploaded = false;\n if (item && !item._destroyed) {\n for (var i = 0, len = this.uploadHooks.length; i < len; i++) {\n if (this.uploadHooks[i](this.uploadHookHelper, item)) {\n this.queue.shift();\n uploaded = true;\n break;\n }\n }\n }\n if (!uploaded) {\n this.queue.shift();\n }\n }\n // We're finished\n if (!this.queue.length) {\n this.ticking = false;\n var completes = this.completes.slice(0);\n this.completes.length = 0;\n for (var i = 0, len = completes.length; i < len; i++) {\n completes[i]();\n }\n }\n else {\n // if we are not finished, on the next rAF do this again\n Ticker.system.addOnce(this.tick, this, UPDATE_PRIORITY.UTILITY);\n }\n };\n /**\n * Adds hooks for finding items.\n * @param {Function} addHook - Function call that takes two parameters: `item:*, queue:Array`\n * function must return `true` if it was able to add item to the queue.\n * @returns Instance of plugin for chaining.\n */\n BasePrepare.prototype.registerFindHook = function (addHook) {\n if (addHook) {\n this.addHooks.push(addHook);\n }\n return this;\n };\n /**\n * Adds hooks for uploading items.\n * @param {Function} uploadHook - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and\n * function must return `true` if it was able to handle upload of item.\n * @returns Instance of plugin for chaining.\n */\n BasePrepare.prototype.registerUploadHook = function (uploadHook) {\n if (uploadHook) {\n this.uploadHooks.push(uploadHook);\n }\n return this;\n };\n /**\n * Manually add an item to the uploading queue.\n * @param {PIXI.DisplayObject|PIXI.Container|PIXI.BaseTexture|PIXI.Texture|PIXI.Graphics|PIXI.Text|*} item - Object to\n * add to the queue\n * @returns Instance of plugin for chaining.\n */\n BasePrepare.prototype.add = function (item) {\n // Add additional hooks for finding elements on special\n // types of objects that\n for (var i = 0, len = this.addHooks.length; i < len; i++) {\n if (this.addHooks[i](item, this.queue)) {\n break;\n }\n }\n // Get children recursively\n if (item instanceof Container) {\n for (var i = item.children.length - 1; i >= 0; i--) {\n this.add(item.children[i]);\n }\n }\n return this;\n };\n /** Destroys the plugin, don't use after this. */\n BasePrepare.prototype.destroy = function () {\n if (this.ticking) {\n Ticker.system.remove(this.tick, this);\n }\n this.ticking = false;\n this.addHooks = null;\n this.uploadHooks = null;\n this.renderer = null;\n this.completes = null;\n this.queue = null;\n this.limiter = null;\n this.uploadHookHelper = null;\n };\n return BasePrepare;\n}());\n\n/**\n * Built-in hook to upload PIXI.Texture objects to the GPU.\n * @private\n * @param renderer - instance of the webgl renderer\n * @param item - Item to check\n * @returns If item was uploaded.\n */\nfunction uploadBaseTextures(renderer, item) {\n if (item instanceof BaseTexture) {\n // if the texture already has a GL texture, then the texture has been prepared or rendered\n // before now. If the texture changed, then the changer should be calling texture.update() which\n // reuploads the texture without need for preparing it again\n if (!item._glTextures[renderer.CONTEXT_UID]) {\n renderer.texture.bind(item);\n }\n return true;\n }\n return false;\n}\n/**\n * Built-in hook to upload PIXI.Graphics to the GPU.\n * @private\n * @param renderer - instance of the webgl renderer\n * @param item - Item to check\n * @returns If item was uploaded.\n */\nfunction uploadGraphics(renderer, item) {\n if (!(item instanceof Graphics)) {\n return false;\n }\n var geometry = item.geometry;\n // update dirty graphics to get batches\n item.finishPoly();\n geometry.updateBatches();\n var batches = geometry.batches;\n // upload all textures found in styles\n for (var i = 0; i < batches.length; i++) {\n var texture = batches[i].style.texture;\n if (texture) {\n uploadBaseTextures(renderer, texture.baseTexture);\n }\n }\n // if its not batchable - update vao for particular shader\n if (!geometry.batchable) {\n renderer.geometry.bind(geometry, item._resolveDirectShader(renderer));\n }\n return true;\n}\n/**\n * Built-in hook to find graphics.\n * @private\n * @param item - Display object to check\n * @param queue - Collection of items to upload\n * @returns if a PIXI.Graphics object was found.\n */\nfunction findGraphics(item, queue) {\n if (item instanceof Graphics) {\n queue.push(item);\n return true;\n }\n return false;\n}\n/**\n * The prepare plugin provides renderer-specific plugins for pre-rendering DisplayObjects. These plugins are useful for\n * asynchronously preparing and uploading to the GPU assets, textures, graphics waiting to be displayed.\n *\n * Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.\n * See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.Renderer#plugins}.\n * @example\n * // Create a new application\n * const app = new PIXI.Application();\n * document.body.appendChild(app.view);\n *\n * // Don't start rendering right away\n * app.stop();\n *\n * // create a display object\n * const rect = new PIXI.Graphics()\n * .beginFill(0x00ff00)\n * .drawRect(40, 40, 200, 200);\n *\n * // Add to the stage\n * app.stage.addChild(rect);\n *\n * // Don't start rendering until the graphic is uploaded to the GPU\n * app.renderer.plugins.prepare.upload(app.stage, () => {\n * app.start();\n * });\n * @memberof PIXI\n */\nvar Prepare = /** @class */ (function (_super) {\n __extends(Prepare, _super);\n /**\n * @param {PIXI.Renderer} renderer - A reference to the current renderer\n */\n function Prepare(renderer) {\n var _this = _super.call(this, renderer) || this;\n _this.uploadHookHelper = _this.renderer;\n // Add textures and graphics to upload\n _this.registerFindHook(findGraphics);\n _this.registerUploadHook(uploadBaseTextures);\n _this.registerUploadHook(uploadGraphics);\n return _this;\n }\n /** @ignore */\n Prepare.extension = {\n name: 'prepare',\n type: ExtensionType.RendererPlugin,\n };\n return Prepare;\n}(BasePrepare));\n\n/**\n * TimeLimiter limits the number of items handled by a {@link PIXI.BasePrepare} to a specified\n * number of milliseconds per frame.\n * @memberof PIXI\n */\nvar TimeLimiter = /** @class */ (function () {\n /** @param maxMilliseconds - The maximum milliseconds that can be spent preparing items each frame. */\n function TimeLimiter(maxMilliseconds) {\n this.maxMilliseconds = maxMilliseconds;\n this.frameStart = 0;\n }\n /** Resets any counting properties to start fresh on a new frame. */\n TimeLimiter.prototype.beginFrame = function () {\n this.frameStart = Date.now();\n };\n /**\n * Checks to see if another item can be uploaded. This should only be called once per item.\n * @returns - If the item is allowed to be uploaded.\n */\n TimeLimiter.prototype.allowedToUpload = function () {\n return Date.now() - this.frameStart < this.maxMilliseconds;\n };\n return TimeLimiter;\n}());\n\nexport { BasePrepare, CountLimiter, Prepare, TimeLimiter };\n//# sourceMappingURL=prepare.mjs.map\n","/*!\n * @pixi/sprite-tiling - v6.5.8\n * Compiled Sun, 23 Oct 2022 23:01:45 UTC\n *\n * @pixi/sprite-tiling is licensed under the MIT License.\n * http://www.opensource.org/licenses/mit-license\n */\nimport { Texture, TextureMatrix, Shader, ExtensionType, QuadUv, State, ObjectRenderer } from '@pixi/core';\nimport { Point, Rectangle, Transform, Matrix } from '@pixi/math';\nimport { Sprite } from '@pixi/sprite';\nimport { WRAP_MODES } from '@pixi/constants';\nimport { premultiplyTintToRgba, correctBlendMode } from '@pixi/utils';\n\n/*! *****************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n/* global Reflect, Promise */\r\n\r\nvar extendStatics = function(d, b) {\r\n extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) { if (b.hasOwnProperty(p)) { d[p] = b[p]; } } };\r\n return extendStatics(d, b);\r\n};\r\n\r\nfunction __extends(d, b) {\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n}\n\nvar tempPoint = new Point();\n/**\n * A tiling sprite is a fast way of rendering a tiling image.\n * @memberof PIXI\n */\nvar TilingSprite = /** @class */ (function (_super) {\n __extends(TilingSprite, _super);\n /**\n * @param texture - The texture of the tiling sprite.\n * @param width - The width of the tiling sprite.\n * @param height - The height of the tiling sprite.\n */\n function TilingSprite(texture, width, height) {\n if (width === void 0) { width = 100; }\n if (height === void 0) { height = 100; }\n var _this = _super.call(this, texture) || this;\n _this.tileTransform = new Transform();\n // The width of the tiling sprite\n _this._width = width;\n // The height of the tiling sprite\n _this._height = height;\n _this.uvMatrix = _this.texture.uvMatrix || new TextureMatrix(texture);\n /**\n * Plugin that is responsible for rendering this element.\n * Allows to customize the rendering process without overriding '_render' method.\n * @default 'tilingSprite'\n */\n _this.pluginName = 'tilingSprite';\n _this.uvRespectAnchor = false;\n return _this;\n }\n Object.defineProperty(TilingSprite.prototype, \"clampMargin\", {\n /**\n * Changes frame clamping in corresponding textureTransform, shortcut\n * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas\n * @default 0.5\n * @member {number}\n */\n get: function () {\n return this.uvMatrix.clampMargin;\n },\n set: function (value) {\n this.uvMatrix.clampMargin = value;\n this.uvMatrix.update(true);\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(TilingSprite.prototype, \"tileScale\", {\n /** The scaling of the image that is being tiled. */\n get: function () {\n return this.tileTransform.scale;\n },\n set: function (value) {\n this.tileTransform.scale.copyFrom(value);\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(TilingSprite.prototype, \"tilePosition\", {\n /** The offset of the image that is being tiled. */\n get: function () {\n return this.tileTransform.position;\n },\n set: function (value) {\n this.tileTransform.position.copyFrom(value);\n },\n enumerable: false,\n configurable: true\n });\n /**\n * @protected\n */\n TilingSprite.prototype._onTextureUpdate = function () {\n if (this.uvMatrix) {\n this.uvMatrix.texture = this._texture;\n }\n this._cachedTint = 0xFFFFFF;\n };\n /**\n * Renders the object using the WebGL renderer\n * @param renderer - The renderer\n */\n TilingSprite.prototype._render = function (renderer) {\n // tweak our texture temporarily..\n var texture = this._texture;\n if (!texture || !texture.valid) {\n return;\n }\n this.tileTransform.updateLocalTransform();\n this.uvMatrix.update();\n renderer.batch.setObjectRenderer(renderer.plugins[this.pluginName]);\n renderer.plugins[this.pluginName].render(this);\n };\n /** Updates the bounds of the tiling sprite. */\n TilingSprite.prototype._calculateBounds = function () {\n var minX = this._width * -this._anchor._x;\n var minY = this._height * -this._anchor._y;\n var maxX = this._width * (1 - this._anchor._x);\n var maxY = this._height * (1 - this._anchor._y);\n this._bounds.addFrame(this.transform, minX, minY, maxX, maxY);\n };\n /**\n * Gets the local bounds of the sprite object.\n * @param rect - Optional output rectangle.\n * @returns The bounds.\n */\n TilingSprite.prototype.getLocalBounds = function (rect) {\n // we can do a fast local bounds if the sprite has no children!\n if (this.children.length === 0) {\n this._bounds.minX = this._width * -this._anchor._x;\n this._bounds.minY = this._height * -this._anchor._y;\n this._bounds.maxX = this._width * (1 - this._anchor._x);\n this._bounds.maxY = this._height * (1 - this._anchor._y);\n if (!rect) {\n if (!this._localBoundsRect) {\n this._localBoundsRect = new Rectangle();\n }\n rect = this._localBoundsRect;\n }\n return this._bounds.getRectangle(rect);\n }\n return _super.prototype.getLocalBounds.call(this, rect);\n };\n /**\n * Checks if a point is inside this tiling sprite.\n * @param point - The point to check.\n * @returns Whether or not the sprite contains the point.\n */\n TilingSprite.prototype.containsPoint = function (point) {\n this.worldTransform.applyInverse(point, tempPoint);\n var width = this._width;\n var height = this._height;\n var x1 = -width * this.anchor._x;\n if (tempPoint.x >= x1 && tempPoint.x < x1 + width) {\n var y1 = -height * this.anchor._y;\n if (tempPoint.y >= y1 && tempPoint.y < y1 + height) {\n return true;\n }\n }\n return false;\n };\n /**\n * Destroys this sprite and optionally its texture and children\n * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options\n * have been set to that value\n * @param {boolean} [options.children=false] - if set to true, all the children will have their destroy\n * method called as well. 'options' will be passed on to those calls.\n * @param {boolean} [options.texture=false] - Should it destroy the current texture of the sprite as well\n * @param {boolean} [options.baseTexture=false] - Should it destroy the base texture of the sprite as well\n */\n TilingSprite.prototype.destroy = function (options) {\n _super.prototype.destroy.call(this, options);\n this.tileTransform = null;\n this.uvMatrix = null;\n };\n /**\n * Helper function that creates a new tiling sprite based on the source you provide.\n * The source can be - frame id, image url, video url, canvas element, video element, base texture\n * @static\n * @param {string|PIXI.Texture|HTMLCanvasElement|HTMLVideoElement} source - Source to create texture from\n * @param {object} options - See {@link PIXI.BaseTexture}'s constructor for options.\n * @param {number} options.width - required width of the tiling sprite\n * @param {number} options.height - required height of the tiling sprite\n * @returns {PIXI.TilingSprite} The newly created texture\n */\n TilingSprite.from = function (source, options) {\n var texture = (source instanceof Texture)\n ? source\n : Texture.from(source, options);\n return new TilingSprite(texture, options.width, options.height);\n };\n Object.defineProperty(TilingSprite.prototype, \"width\", {\n /** The width of the sprite, setting this will actually modify the scale to achieve the value set. */\n get: function () {\n return this._width;\n },\n set: function (value) {\n this._width = value;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(TilingSprite.prototype, \"height\", {\n /** The height of the TilingSprite, setting this will actually modify the scale to achieve the value set. */\n get: function () {\n return this._height;\n },\n set: function (value) {\n this._height = value;\n },\n enumerable: false,\n configurable: true\n });\n return TilingSprite;\n}(Sprite));\n\nvar fragmentSimpleSrc = \"#version 100\\n#define SHADER_NAME Tiling-Sprite-Simple-100\\n\\nprecision lowp float;\\n\\nvarying vec2 vTextureCoord;\\n\\nuniform sampler2D uSampler;\\nuniform vec4 uColor;\\n\\nvoid main(void)\\n{\\n vec4 texSample = texture2D(uSampler, vTextureCoord);\\n gl_FragColor = texSample * uColor;\\n}\\n\";\n\nvar gl1VertexSrc = \"#version 100\\n#define SHADER_NAME Tiling-Sprite-100\\n\\nprecision lowp float;\\n\\nattribute vec2 aVertexPosition;\\nattribute vec2 aTextureCoord;\\n\\nuniform mat3 projectionMatrix;\\nuniform mat3 translationMatrix;\\nuniform mat3 uTransform;\\n\\nvarying vec2 vTextureCoord;\\n\\nvoid main(void)\\n{\\n gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\\n\\n vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;\\n}\\n\";\n\nvar gl1FragmentSrc = \"#version 100\\n#ifdef GL_EXT_shader_texture_lod\\n #extension GL_EXT_shader_texture_lod : enable\\n#endif\\n#define SHADER_NAME Tiling-Sprite-100\\n\\nprecision lowp float;\\n\\nvarying vec2 vTextureCoord;\\n\\nuniform sampler2D uSampler;\\nuniform vec4 uColor;\\nuniform mat3 uMapCoord;\\nuniform vec4 uClampFrame;\\nuniform vec2 uClampOffset;\\n\\nvoid main(void)\\n{\\n vec2 coord = vTextureCoord + ceil(uClampOffset - vTextureCoord);\\n coord = (uMapCoord * vec3(coord, 1.0)).xy;\\n vec2 unclamped = coord;\\n coord = clamp(coord, uClampFrame.xy, uClampFrame.zw);\\n\\n #ifdef GL_EXT_shader_texture_lod\\n vec4 texSample = unclamped == coord\\n ? texture2D(uSampler, coord) \\n : texture2DLodEXT(uSampler, coord, 0);\\n #else\\n vec4 texSample = texture2D(uSampler, coord);\\n #endif\\n\\n gl_FragColor = texSample * uColor;\\n}\\n\";\n\nvar gl2VertexSrc = \"#version 300 es\\n#define SHADER_NAME Tiling-Sprite-300\\n\\nprecision lowp float;\\n\\nin vec2 aVertexPosition;\\nin vec2 aTextureCoord;\\n\\nuniform mat3 projectionMatrix;\\nuniform mat3 translationMatrix;\\nuniform mat3 uTransform;\\n\\nout vec2 vTextureCoord;\\n\\nvoid main(void)\\n{\\n gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\\n\\n vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;\\n}\\n\";\n\nvar gl2FragmentSrc = \"#version 300 es\\n#define SHADER_NAME Tiling-Sprite-100\\n\\nprecision lowp float;\\n\\nin vec2 vTextureCoord;\\n\\nout vec4 fragmentColor;\\n\\nuniform sampler2D uSampler;\\nuniform vec4 uColor;\\nuniform mat3 uMapCoord;\\nuniform vec4 uClampFrame;\\nuniform vec2 uClampOffset;\\n\\nvoid main(void)\\n{\\n vec2 coord = vTextureCoord + ceil(uClampOffset - vTextureCoord);\\n coord = (uMapCoord * vec3(coord, 1.0)).xy;\\n vec2 unclamped = coord;\\n coord = clamp(coord, uClampFrame.xy, uClampFrame.zw);\\n\\n vec4 texSample = texture(uSampler, coord, unclamped == coord ? 0.0f : -32.0f);// lod-bias very negative to force lod 0\\n\\n fragmentColor = texSample * uColor;\\n}\\n\";\n\nvar tempMat = new Matrix();\n/**\n * WebGL renderer plugin for tiling sprites\n * @class\n * @memberof PIXI\n * @extends PIXI.ObjectRenderer\n */\nvar TilingSpriteRenderer = /** @class */ (function (_super) {\n __extends(TilingSpriteRenderer, _super);\n /**\n * constructor for renderer\n * @param {PIXI.Renderer} renderer - The renderer this tiling awesomeness works for.\n */\n function TilingSpriteRenderer(renderer) {\n var _this = _super.call(this, renderer) || this;\n // WebGL version is not available during initialization!\n renderer.runners.contextChange.add(_this);\n _this.quad = new QuadUv();\n /**\n * The WebGL state in which this renderer will work.\n * @member {PIXI.State}\n * @readonly\n */\n _this.state = State.for2d();\n return _this;\n }\n /** Creates shaders when context is initialized. */\n TilingSpriteRenderer.prototype.contextChange = function () {\n var renderer = this.renderer;\n var uniforms = { globals: renderer.globalUniforms };\n this.simpleShader = Shader.from(gl1VertexSrc, fragmentSimpleSrc, uniforms);\n this.shader = renderer.context.webGLVersion > 1\n ? Shader.from(gl2VertexSrc, gl2FragmentSrc, uniforms)\n : Shader.from(gl1VertexSrc, gl1FragmentSrc, uniforms);\n };\n /**\n * @param {PIXI.TilingSprite} ts - tilingSprite to be rendered\n */\n TilingSpriteRenderer.prototype.render = function (ts) {\n var renderer = this.renderer;\n var quad = this.quad;\n var vertices = quad.vertices;\n vertices[0] = vertices[6] = (ts._width) * -ts.anchor.x;\n vertices[1] = vertices[3] = ts._height * -ts.anchor.y;\n vertices[2] = vertices[4] = (ts._width) * (1.0 - ts.anchor.x);\n vertices[5] = vertices[7] = ts._height * (1.0 - ts.anchor.y);\n var anchorX = ts.uvRespectAnchor ? ts.anchor.x : 0;\n var anchorY = ts.uvRespectAnchor ? ts.anchor.y : 0;\n vertices = quad.uvs;\n vertices[0] = vertices[6] = -anchorX;\n vertices[1] = vertices[3] = -anchorY;\n vertices[2] = vertices[4] = 1.0 - anchorX;\n vertices[5] = vertices[7] = 1.0 - anchorY;\n quad.invalidate();\n var tex = ts._texture;\n var baseTex = tex.baseTexture;\n var premultiplied = baseTex.alphaMode > 0;\n var lt = ts.tileTransform.localTransform;\n var uv = ts.uvMatrix;\n var isSimple = baseTex.isPowerOfTwo\n && tex.frame.width === baseTex.width && tex.frame.height === baseTex.height;\n // auto, force repeat wrapMode for big tiling textures\n if (isSimple) {\n if (!baseTex._glTextures[renderer.CONTEXT_UID]) {\n if (baseTex.wrapMode === WRAP_MODES.CLAMP) {\n baseTex.wrapMode = WRAP_MODES.REPEAT;\n }\n }\n else {\n isSimple = baseTex.wrapMode !== WRAP_MODES.CLAMP;\n }\n }\n var shader = isSimple ? this.simpleShader : this.shader;\n var w = tex.width;\n var h = tex.height;\n var W = ts._width;\n var H = ts._height;\n tempMat.set(lt.a * w / W, lt.b * w / H, lt.c * h / W, lt.d * h / H, lt.tx / W, lt.ty / H);\n // that part is the same as above:\n // tempMat.identity();\n // tempMat.scale(tex.width, tex.height);\n // tempMat.prepend(lt);\n // tempMat.scale(1.0 / ts._width, 1.0 / ts._height);\n tempMat.invert();\n if (isSimple) {\n tempMat.prepend(uv.mapCoord);\n }\n else {\n shader.uniforms.uMapCoord = uv.mapCoord.toArray(true);\n shader.uniforms.uClampFrame = uv.uClampFrame;\n shader.uniforms.uClampOffset = uv.uClampOffset;\n }\n shader.uniforms.uTransform = tempMat.toArray(true);\n shader.uniforms.uColor = premultiplyTintToRgba(ts.tint, ts.worldAlpha, shader.uniforms.uColor, premultiplied);\n shader.uniforms.translationMatrix = ts.transform.worldTransform.toArray(true);\n shader.uniforms.uSampler = tex;\n renderer.shader.bind(shader);\n renderer.geometry.bind(quad);\n this.state.blendMode = correctBlendMode(ts.blendMode, premultiplied);\n renderer.state.set(this.state);\n renderer.geometry.draw(this.renderer.gl.TRIANGLES, 6, 0);\n };\n /** @ignore */\n TilingSpriteRenderer.extension = {\n name: 'tilingSprite',\n type: ExtensionType.RendererPlugin,\n };\n return TilingSpriteRenderer;\n}(ObjectRenderer));\n\nexport { TilingSprite, TilingSpriteRenderer };\n//# sourceMappingURL=sprite-tiling.mjs.map\n","/*!\n * @pixi/filter-alpha - v6.5.8\n * Compiled Sun, 23 Oct 2022 23:01:45 UTC\n *\n * @pixi/filter-alpha is licensed under the MIT License.\n * http://www.opensource.org/licenses/mit-license\n */\nimport { defaultVertex, Filter } from '@pixi/core';\n\n/*! *****************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n/* global Reflect, Promise */\r\n\r\nvar extendStatics = function(d, b) {\r\n extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) { if (b.hasOwnProperty(p)) { d[p] = b[p]; } } };\r\n return extendStatics(d, b);\r\n};\r\n\r\nfunction __extends(d, b) {\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n}\n\nvar fragment = \"varying vec2 vTextureCoord;\\n\\nuniform sampler2D uSampler;\\nuniform float uAlpha;\\n\\nvoid main(void)\\n{\\n gl_FragColor = texture2D(uSampler, vTextureCoord) * uAlpha;\\n}\\n\";\n\n/**\n * Simplest filter - applies alpha.\n *\n * Use this instead of Container's alpha property to avoid visual layering of individual elements.\n * AlphaFilter applies alpha evenly across the entire display object and any opaque elements it contains.\n * If elements are not opaque, they will blend with each other anyway.\n *\n * Very handy if you want to use common features of all filters:\n *\n * 1. Assign a blendMode to this filter, blend all elements inside display object with background.\n *\n * 2. To use clipping in display coordinates, assign a filterArea to the same container that has this filter.\n * @memberof PIXI.filters\n */\nvar AlphaFilter = /** @class */ (function (_super) {\n __extends(AlphaFilter, _super);\n /**\n * @param alpha - Amount of alpha from 0 to 1, where 0 is transparent\n */\n function AlphaFilter(alpha) {\n if (alpha === void 0) { alpha = 1.0; }\n var _this = _super.call(this, defaultVertex, fragment, { uAlpha: 1 }) || this;\n _this.alpha = alpha;\n return _this;\n }\n Object.defineProperty(AlphaFilter.prototype, \"alpha\", {\n /**\n * Coefficient for alpha multiplication\n * @default 1\n */\n get: function () {\n return this.uniforms.uAlpha;\n },\n set: function (value) {\n this.uniforms.uAlpha = value;\n },\n enumerable: false,\n configurable: true\n });\n return AlphaFilter;\n}(Filter));\n\nexport { AlphaFilter };\n//# sourceMappingURL=filter-alpha.mjs.map\n"],"file":"threshold.min.js"}
|