{"version":3,"file":"lib-jitsi-meet.min.js","mappings":";CAAA,SAA2CA,EAAMC,GAC1B,iBAAZC,SAA0C,iBAAXC,OACxCA,OAAOD,QAAUD,IACQ,mBAAXG,QAAyBA,OAAOC,IAC9CD,OAAO,GAAIH,GACe,iBAAZC,QACdA,QAAqB,YAAID,IAEzBD,EAAkB,YAAIC,IARxB,CASGK,MAAM,WACT,mDCIA,IAAIC,EAAS,EAAQ,KAgDrB,SAASC,EAAaC,EAAYC,GAC9BC,KAAKF,WAAaA,EAClBE,KAAKC,oBAAmBF,IAAWA,EAAQE,mBAAmBF,EAAQE,iBACtED,KAAKE,cAAgBH,GAAWA,EAAQG,cAAgBH,EAAQG,cAAe,IAC/EF,KAAKG,eAAiBJ,GAAWA,EAAQI,eAAiBJ,EAAQI,eAAiB,IAGnFC,OAAOC,KAAKT,EAAOU,QAAQC,QAC3B,SAAUC,GAENR,KADiBJ,EAAOU,OAAOE,IACZ,WACfR,KAAKS,KAAKC,MAAMV,KAAMW,YACxBC,KAAKZ,KAAMQ,IACfI,KAAKZ,OAMPA,KAAKa,oBAAsB,KAM3Bb,KAAKc,MAAQ,GAKbd,KAAKe,SAAW,EAMhBf,KAAKgB,YAAc,GAiBvBnB,EAAaoB,UAAUC,UAAY,SAAUC,GACzC,IACI,OAAOC,KAAKF,UAAUC,GACxB,MAAOE,GACL,MAAO,iCAmBfxB,EAAaoB,UAAUK,iBAAmB,SAC1Cd,GAEI,IADA,IAAIe,EAAM,GACDC,EAAI,EAAGC,EAAMd,UAAUe,OAAQF,EAAIC,EAAKD,IAAK,CAClD,IAAIG,EAAMhB,UAAUa,IAEfxB,KAAKC,kBAAoBO,IAAaZ,EAAOU,OAAOsB,OACtC,iBAARD,IACPA,EAAM3B,KAAKkB,UAAUS,IAEzBJ,GAAOI,EACHH,IAAMC,EAAM,IACZF,GAAO,KAGf,OAAOA,EAAIG,OAASH,EAAM,MAS9B1B,EAAaoB,UAAUR,KAAO,WAG1B,IAAIoB,EAAYlB,UAAU,GACtBY,EAAMvB,KAAKsB,iBAAiBZ,MAAMV,KAAMW,WAC5C,GAAIY,EAAK,CAEL,IAAIO,EAAc9B,KAAKc,MAAMd,KAAKc,MAAMY,OAAS,GAC7CK,EAAkBD,GAAeA,EAAYE,KAC7CD,IAAoBR,EACpBO,EAAYG,OAAS,GAErBjC,KAAKc,MAAMoB,KAAK,CACZF,KAAMT,EACNM,UAAWA,EACXI,MAAO,IAEXjC,KAAKe,UAAYQ,EAAIG,QAIzB1B,KAAKe,UAAYf,KAAKG,gBACtBH,KAAKmC,QAAO,GAAkB,IAQtCtC,EAAaoB,UAAUmB,MAAQ,WAC3BpC,KAAKqC,8BAQTxC,EAAaoB,UAAUoB,2BAA6B,WAC5CrC,KAAKa,sBACLyB,OAAOC,aAAavC,KAAKa,qBACzBb,KAAKa,oBAAsB,MAG/Bb,KAAKa,oBAAsByB,OAAOE,WAC9BxC,KAAKmC,OAAOvB,KACRZ,MAAM,GAA0B,GACpCA,KAAKE,gBAObL,EAAaoB,UAAUwB,MAAQ,WAC3BzC,KAAKmC,QACD,GACA,IAcRtC,EAAaoB,UAAUkB,OAAS,SAASO,EAAOC,GAExC3C,KAAKe,SAAW,IAAMf,KAAKF,WAAW8C,WAAaF,KAG/C1C,KAAKF,WAAW8C,WAEZ5C,KAAKgB,YAAYU,SACjB1B,KAAKgB,YAAYT,QACb,SAAUsC,GACN7C,KAAKF,WAAWgD,UAAUD,IAC5BjC,KAAKZ,OAGXA,KAAKgB,YAAc,IAGvBhB,KAAKF,WAAWgD,UAAU9C,KAAKc,QAE/Bd,KAAKgB,YAAYkB,KAAKlC,KAAKc,OAG/Bd,KAAKc,MAAQ,GACbd,KAAKe,SAAW,GAGhB4B,GACA3C,KAAKqC,8BAQbxC,EAAaoB,UAAU8B,KAAO,WAE1B/C,KAAKmC,QAAO,GAA0B,IAG1C3C,EAAOD,QAAUM,WC/PjB,IAAIS,EAAS,CACT,MAAS,EACT,MAAS,EACT,KAAQ,EACR,IAAO,EACP,KAAQ,EACR,MAAS,GAObV,EAAOoD,iBAAmBC,QAM1B,IAAIC,EAAmB,CAAEtD,EAAOoD,kBAOhCpD,EAAOuD,mBAAqB,SAASC,IACY,IAAzCF,EAAiBG,QAAQD,IACzBF,EAAiBhB,KAAKkB,IAS9BxD,EAAO0D,sBAAwB,SAASF,GACpC,IAAIG,EAAeL,EAAiBG,QAAQD,IACtB,IAAlBG,GACAL,EAAiBM,OAAOD,EAAc,IAO9C,IAAIE,EAAgB,GAgBpB,SAASC,IACL,IAAIC,EAAa,CACbC,WAAY,GACZC,aAAc,GACdC,KAAM,KACNC,OAAQ,MAGR1C,EAAQ,IAAI2C,MACZC,EAAQ5C,EAAM4C,MAAO5C,EAAM4C,MAAMC,MAAM,MAAQ,GACnD,IAAID,GAASA,EAAMvC,OAAS,EACxB,OAAOiC,EAEX,IAAIQ,EAAI,KAIR,OAHGF,EAAM,KACLE,EAAIF,EAAM,GAAGG,MAAM,iDAEnBD,GAAKA,EAAEzC,QAAU,GAEe,IAA7BuC,EAAM,GAAGZ,QAAQ,QAEhBM,EAAWC,WAAaK,EAAM,GAAGI,OAAO,EAAGJ,EAAM,GAAGZ,QAAQ,MAG5DM,EAAWC,WAAaK,EAAM,GAAGI,OAAO,EAAGJ,EAAM,GAAGZ,QAAQ,MAEzDM,IAGXA,EAAWC,WAAaO,EAAE,GAC1BR,EAAWE,aAAeM,EAAE,GAC5BR,EAAWG,KAAOK,EAAE,GACpBR,EAAWI,OAASI,EAAE,GACfR,GASX,SAASW,IACL,IAAIC,EAAS5D,UAAU,GAAI6D,EAAQ7D,UAAU,GACzC8D,EAAOC,MAAMzD,UAAU0D,MAAMC,KAAKjE,UAAW,GACjD,KAAGL,EAAOkE,GAASD,EAAOC,OAQ1B,IAJA,IAAIb,IACIY,EAAOxE,QAAQ8E,mBAAqBpB,EAAcoB,oBAClDnB,IACJoB,EAAa5B,EAAiB6B,OAAOR,EAAOO,YACxCtD,EAAI,EAAGA,EAAIsD,EAAWpD,OAAQF,IAAK,CACvC,IAAIwD,EAAIF,EAAWtD,GACfyD,EAAID,EAAER,GACV,GAAGS,GAAmB,mBAAR,EAAoB,CAC9B,IAAIC,EAAc,GAElBA,EAAYhD,MAAK,IAAIiD,MAAOC,eAExBb,EAAOc,IACPH,EAAYhD,KAAK,IAAMqC,EAAOc,GAAK,KAGnC1B,GAAcA,EAAWC,WAAWlC,OAAS,GAC7CwD,EAAYhD,KAAK,IAAMyB,EAAWC,WAAa,OAGnD,IAAI0B,EAAeJ,EAAYH,OAAON,GAEtCQ,EAAErE,KAAKoE,GAAGtE,MAAMsE,EAAGM,KAiB/B,SAAS1F,EAAO4E,EAAOa,EAAIP,EAAY/E,GACnCC,KAAKqF,GAAKA,EACVrF,KAAKD,QAAUA,GAAW,GAC1BC,KAAK8E,WAAaA,EACd9E,KAAK8E,aACL9E,KAAK8E,WAAa,IAEtB9E,KAAKwE,MAAQlE,EAAOkE,GAEpB,IADA,IAAIe,EAAUnF,OAAOC,KAAKC,GAClBkB,EAAI,EAAGA,EAAI+D,EAAQ7D,OAAQF,IAC/BxB,KAAKuF,EAAQ/D,IACT8C,EAAI1D,KAAK,KAAMZ,KAAMuF,EAAQ/D,IA7GzC5B,EAAO4F,iBAAmB,SAASzF,GAC/B0D,EAAgB1D,GAAW,IAoH/BH,EAAOqB,UAAUwE,SAAW,SAAUjB,GAClCxE,KAAKwE,MAAQlE,EAAOkE,IAExBhF,EAAOD,QAAUK,EAKjBA,EAAOU,OAAS,CACZoF,MAAO,QACPC,MAAO,QACPC,KAAM,OACNC,IAAK,MACLC,KAAM,OACNlE,MAAO,uBC7LX,IAAIhC,EAAS,EAAQ,KACjBC,EAAe,EAAQ,KAwBvBkG,EAAY,GAKZC,EAAU,GAKVC,EAAWrG,EAAOU,OAAOoF,MAG7BlG,EAAOD,QAAU,CAMb4D,mBAAoB,SAASC,GACzBxD,EAAOuD,mBAAmBC,IAO9BE,sBAAuB,SAASF,GAC5BxD,EAAO0D,sBAAsBF,IAMjCoC,iBAAkB,SAASzF,GACvBH,EAAO4F,iBAAiBzF,IAM5BmG,UAAW,SAASb,EAAIP,EAAY/E,GAChC,IAAIwE,EAAS,IAAI3E,EAAOqG,EAAUZ,EAAIP,EAAY/E,GAOlD,OANGsF,GACCU,EAAUV,GAAMU,EAAUV,IAAO,GACjCU,EAAUV,GAAInD,KAAKqC,IAEnByB,EAAQ9D,KAAKqC,GAEVA,GAMX4B,mBAAoB,SAASd,EAAIP,EAAY/E,GACzC,OAAO,IAAIH,EAAOqG,EAAUZ,EAAIP,EAAY/E,IAShDqG,gBAAiB,SAAS5B,EAAOa,GAE7B,IADA,IAAIJ,EAAII,EAAKU,EAAUV,IAAO,GAAMW,EAC5BxE,EAAI,EAAGA,EAAIyD,EAAEvD,OAAQF,IACzByD,EAAEzD,GAAGiE,SAASjB,IAOtB6B,YAAa,SAAU7B,GACnByB,EAAWzB,EAEX,IADA,IAAIhD,EAAI,EACFA,EAAIwE,EAAQtE,OAAQF,IACtBwE,EAAQxE,GAAGiE,SAASjB,GAGxB,IAAI,IAAIa,KAAMU,EAAW,CACrB,IAAId,EAAIc,EAAUV,IAAO,GACzB,IAAI7D,EAAI,EAAGA,EAAIyD,EAAEvD,OAAQF,IACrByD,EAAEzD,GAAGiE,SAASjB,KAO1BlE,OAAQV,EAAOU,OAIfT,aAAcA,kBCxHlB,IAAIyG,EAAY,EAAQ,KACpBC,EAAiB,EAAQ,KACzBC,EAAaD,EAAeC,WAC5BC,EAAaF,EAAeE,WAQhC,SAASC,EAAkBC,EAAOC,EAAMC,GACpC,OAAOF,EACFG,MACAC,QAAO,SAASC,GAAY,OAAOA,EAAS3B,KAAOuB,KACnDG,QAAO,SAASC,GAAY,OAAOA,EAASC,YAAcJ,KAC1DK,KAAI,SAASF,GAAY,OAAOA,EAASG,SAAU,GAK5D,SAASC,EAAUrH,GAEfC,KAAKD,QAAUA,GAAoB,GAE9BC,KAAKD,QAAQsH,cACdrH,KAAKD,QAAQsH,YAnBO,GAqBxBpE,QAAQqB,IAAI,uBAAyBtE,KAAKD,QAAQsH,YAAc,WAMhErH,KAAKsH,UAAY,GAiBrB,SAASC,EAAaC,EAASC,GACZ,MAAXD,GAAoB9C,MAAMgD,QAAQF,EAAQG,QAI9CH,EAAQG,MAAMpH,SAAQ,SAAUoG,GACT,UAAfA,EAAMiB,MACNH,EAAOd,MAKnB,SAASkB,EAAoBC,GAEzB,OAAOA,GAAgB,MAARA,GACRA,EAAKF,MAAqB,IAAbE,EAAKF,MAClBE,EAAKC,KAAmB,IAAZD,EAAKC,IAkJ5BX,EAAUnG,UAAU+G,eAAiB,WACjChI,KAAKsH,UAAY,IAWrBF,EAAUnG,UAAUgH,aAAe,SAASnB,GACxC9G,KAAKsH,UAAYR,GAYrBM,EAAUnG,UAAUiH,gBAAkB,SAAUvB,GAC5C,IAAIwB,EAAWxB,EAAMyB,YACjBzB,EAAMyB,WAAWC,MAAK,SAASC,GAAS,MAA2B,QAApBA,EAAMC,aACzD,OAAIJ,EACOA,EAASrB,MACX5C,MAAM,KACNgD,KAAI,SAASsB,GAAW,OAAOC,SAASD,MAEtC,CAAC7B,EAAMG,MAAM,GAAGzB,KAI/B+B,EAAUnG,UAAUyH,sBAAwB,SAAUC,EAAaC,GAE/D,IADA,IAAIC,EAAU,GACLrH,EAAI,EAAGA,EAAImH,EAAYjH,SAAUF,EAAG,CACzC,IAAIsH,EAAUH,EAAYnH,GACtBuH,EAAUH,EAAYpH,IAAM,KAChCqH,EAAQC,GAAWC,EAEvB,OAAOF,GAGXzB,EAAUnG,UAAU+H,2BAA6B,SAASrC,GACtD1D,QAAQqB,IAAI,sCAAuCtE,KAAKsH,WACxD,IAAI2B,EAAcjJ,KAAKkI,gBAAgBvB,GACvC1D,QAAQqB,IAAI,sCAAuC2E,GACnD,IAAIC,EAAUxC,EAAiBC,EAAOsC,EAAY,GAAI,QAClDE,EAAWzC,EAAiBC,EAAOsC,EAAY,GAAI,SACnDG,EAAiBpJ,KAAK0I,sBAAsBO,EAAajJ,KAAKsH,WAClErE,QAAQqB,IAAI,uCAAwC8E,GAGpD,IAAIC,EAAarJ,KAAKsH,UACjBP,QAAO,SAASH,GAAQ,OAAwD,IAAjDxG,OAAOkJ,OAAOF,GAAgB/F,QAAQuD,MA2B1E,OA1BA3D,QAAQqB,IAAI,oCAAqC+E,GAGjD1C,EAAMG,MAAMvG,SAAQ,SAASqG,GACrBwC,EAAexC,EAAKvB,MACpBuB,EAAKvB,GAAK+D,EAAexC,EAAKvB,QAItCgE,EAAW9I,SAAQ,SAASqG,GACxBD,EAAMG,MAAM5E,KAAK,CACbmD,GAAIuB,EACJK,UAAW,OACXE,MAAO+B,IAEXvC,EAAMG,MAAM5E,KAAK,CACbmD,GAAIuB,EACJK,UAAW,QACXE,MAAOgC,OAGfxC,EAAMyB,WAAazB,EAAMyB,YAAc,GACvCzB,EAAMyB,WAAWlG,KAAK,CAClBqG,UAAW,MACXzB,MAAO9G,KAAKsH,UAAUiC,KAAK,OAExB5C,GAGXS,EAAUnG,UAAUuI,oBAAsB,SAAS7C,EAAO8C,GACtD,IAAIC,EAAsB,SAAS/C,EAAOC,GACtCD,EAAMG,MAAM5E,KAAK,CACbmD,GAAIuB,EACJK,UAAW,QACXE,MAAOwC,IAEXhD,EAAMG,MAAM5E,KAAK,CACbmD,GAAIuB,EACJK,UAAW,OACXE,MAAOyC,KAGXA,EAAkBlD,EAAiBC,EAAO8C,EAAa,QACvDE,EAAmBjD,EAAiBC,EAAO8C,EAAa,SAKxDzJ,KAAKD,QAAQ8J,kBAAoBD,IACjCA,EAAkBjD,EAAMmD,KACLnD,EAAMG,MACZvG,SAAQqG,IACjBD,EAAMG,MAAM5E,KAAK,CACbmD,GAAIuB,EAAKvB,GACT4B,UAAW,OACXE,MAAOyC,QAOnB,IADA,IAAIG,EAAW,GACNvI,EAAI,EAAGA,EAAIxB,KAAKD,QAAQsH,YAAc,IAAK7F,EAAG,CACnD,IAAIwI,EA/RDC,KAAKC,MAAsB,WAAhBD,KAAKE,UADb,EAiSNT,EAAoB/C,EAAOqD,GAC3BD,EAAS7H,KAAK8H,GAOlB,OALArD,EAAMyB,WAAazB,EAAMyB,YAAc,GACvCzB,EAAMyB,WAAWlG,KAAK,CAClBqG,UAAW,MACXzB,MAAO2C,EAAc,IAAMM,EAASR,KAAK,OAEtC5C,GAoBXS,EAAUnG,UAAUmJ,kBAAoB,SAASzD,GAG7C,IAAI8C,EACAY,EAAW1D,EAAMG,OAASH,EAAMG,MAC/BI,KAAI,SAASF,GAAY,OAAOA,EAAS3B,MACzC0B,QAAO,SAASH,EAAM0D,EAAOC,GAC1B,OAAOA,EAAMlH,QAAQuD,KAAU0D,KAElC5I,QAAU,EACX8I,EAAa7D,EAAMyB,YAAczB,EAAMyB,WAAW1G,QAAW,EAEjE,GAAiB,IAAb2I,GAAkBA,EAAW,EAE7B,OAAO1D,EAEX,GAAgB,GAAZ0D,GAA+B,IAAdG,EAEjB,OAAO7D,EAGX,GAAiB,IAAb0D,EACAZ,EAAc9C,EAAMG,MAAM,GAAGzB,OAC1B,CAGH,IAAIoF,EAAW9D,EAAMyB,WAAWrB,QAAO,SAASuB,GAAS,MAA2B,QAApBA,EAAMC,aAAwB,GAC9F,IAAIkC,EAIA,OAAO9D,EAHP8C,EAAchB,SAASgC,EAAS3D,MAAM5C,MAAM,KAAK,IAsBzD,OAhBAjB,QAAQqB,IAAI,qCAAsCtE,KAAKsH,WACvDrE,QAAQqB,IAAI,qCAAuCmF,IAEY,IAAzCzJ,KAAKsH,UAAUjE,QAAQoG,IAGzCxG,QAAQqB,IAAI,2EAEZqC,EAAQ3G,KAAKgJ,2BAA2BrC,KAExC1D,QAAQqB,IAAI,2EAEZqC,EAAQ3G,KAAKwJ,oBAAoB7C,EAAO8C,IAG5CzJ,KAAKsH,UAAYtH,KAAKkI,gBAAgBvB,GAC/BA,GAaXS,EAAUnG,UAAUyJ,uBAAyB,SAAU5C,EAAM6C,GAEzD,IAAK9C,EAAoBC,GACrB,OAAOA,EAGX,IAAIN,EAAUlB,EAAUsE,MAAM9C,EAAKC,KAE/BpI,EAAOK,KAqBX,OApBAuH,EAAaC,GAAS,SAAUb,GAGxBhH,EAAKI,QAAQ8K,uBAjXzB,SAAgClE,GAE5B,GAAKA,GAAUjC,MAAMgD,QAAQf,EAAMyB,YASnC,IALA,IAAI0C,EAAUtE,EAAWG,GACrBoE,EAAQ,GAGRC,EAAIrE,EAAMyB,WAAW1G,OAClBsJ,KAEH,GAAsC,QAAlCrE,EAAMyB,WAAW4C,GAAGzC,UAAxB,CAMA,IAFA,IAAI0C,EAAiBtE,EAAMyB,WAAW4C,GAAGlE,MAAM5C,MAAM,KAE5C1C,EAAI,EAAGA,EAAIyJ,EAAevJ,OAAQF,IAAK,CAE5C,IAAIoF,EAAOqE,EAAezJ,GAC1BuJ,EAAM7I,KAAK0E,GAEX,IAAIsE,EAAQJ,EAAQlE,GAAMkD,KAAK5F,MAAM,KACrC4G,EAAQlE,GAAMkD,KAAO,CAACoB,EAAM,GAAI,IAAK1J,EAAG,IAAK0J,EAAM,GAAI,IAAK1J,GAAG+H,KAAK,IACpEuB,EAAQlE,GAAMuE,MAAQ,CAACL,EAAQlE,GAAMuE,MAAO,IAAK3J,GAAG+H,KAAK,IAGzD5C,EAAMyB,WAAW7H,SAAQ,SAAU6K,GAC/B,GAA+B,QAA3BA,EAAa7C,UAAjB,CAIA,IAAI8C,EAAeD,EAAatE,MAAM5C,MAAM,MACR,IAAhCmH,EAAahI,QAAQuD,IAKzByE,EAAa9K,SAAQ,SAAU+K,GAC3BR,EAAQQ,GAAaxB,KAAOgB,EAAQlE,GAAMkD,KAC1CgB,EAAQQ,GAAaH,MAAQL,EAAQlE,GAAMuE,MACvCG,IAAgB1E,GAChBmE,EAAM7I,KAAKoJ,UAQ3B3E,EAAMG,MAAQL,EAAWqE,EAASC,GAClCpE,EAAMyB,WAAW5E,OAAOwH,EAAG,IA6TvBH,CAAuBlE,GAzTnC,SAAgCA,GAE5B,GAAKA,GAAUjC,MAAMgD,QAAQf,EAAMyB,YAAnC,CAMA,IAAI0C,EAAUtE,EAAWG,GAGzBA,EAAMyB,WAAW7H,SAAQ,SAAUgL,GAC/B,GAAiC,QAA7BA,EAAehD,UAAnB,CAIAtF,QAAQuI,KAAK,wBAA0BD,EAAezE,OAEtDyE,EAAeE,MAAO,EAKtB,IAHA,IAAIR,EAAiBM,EAAezE,MAAM5C,MAAM,KAGvC1C,EAAI,EAAGA,EAAIyJ,EAAevJ,OAAQF,IAAK,CAE5C,IAAIoF,EAAOqE,EAAezJ,UACnBsJ,EAAQlE,GAGfD,EAAMyB,WAAW7H,SAAQ,SAAU6K,GAC/B,GAA+B,QAA3BA,EAAa7C,UAAjB,CAIA,IAAI8C,EAAeD,EAAatE,MAAM5C,MAAM,MACR,IAAhCmH,EAAahI,QAAQuD,KAKzByE,EAAa9K,SAAQ,SAAU+K,UACpBR,EAAQQ,MAInBF,EAAaK,MAAO,YAOhC9E,EAAMG,MAAQL,EAAWqE,GAIzB,IADA,IAAItJ,EAAImF,EAAMyB,WAAW1G,OAClBF,KACCmF,EAAMyB,WAAW5G,GAAGiK,MACpB9E,EAAMyB,WAAW5E,OAAOhC,EAAG,QAvD/ByB,QAAQuI,KAAK,6DAwTTE,CAAuB/E,IAOtBhH,EAAKI,QAAQ8J,iBAAmBc,EA3P7C,SAA8BhE,GACrBA,IAIAjC,MAAMgD,QAAQf,EAAMgF,WACrBhF,EAAMgF,QAAU,IAGfhF,EAAMgF,QAAQC,MACX,SAAUpK,GAAK,MAAmB,6BAAZA,EAAE2F,UAC5BR,EAAMgF,QAAQzJ,KAAK,CAAC,MAAS,8BAiPzB2J,CAAqBlF,GApQjC,SAA8BA,GACrBA,QAAsC,IAAtBA,EAAMmF,cAI3BnF,EAAMmF,iBAAcC,GAiQZC,CAAqBrF,MAItB,IAAIsF,sBAAsB,CAC7BrE,KAAME,EAAKF,KACXG,IAAKzB,EAAU4F,MAAM1E,MAW7BJ,EAAUnG,UAAUkL,sBAAwB,SAAUrE,GAElD,IAAKD,EAAoBC,GACrB,OAAOA,EAGX,IAAIN,EAAUlB,EAAUsE,MAAM9C,EAAKC,KAE/BpI,EAAOK,KASX,OARAuH,EAAaC,GAAS,SAAUb,GACL,YAAnBA,EAAMyF,WAA8C,YAAnBzF,EAAMyF,WAI3CzM,EAAKyK,kBAAkBzD,MAGpB,IAAIsF,sBAAsB,CAC7BrE,KAAME,EAAKF,KACXG,IAAKzB,EAAU4F,MAAM1E,MAM7BhI,EAAOD,QAAU6H,eCrejB7H,EAAQkH,WAAa,SAASqE,EAASC,GACrC,IAAIjE,EAAQ,GAGZ,QAAuB,IAAZgE,GACyB,IAAhC1K,OAAOC,KAAKyK,GAASpJ,OAAc,CAEhCgD,MAAMgD,QAAQqD,KACjBA,EAAQ,IAIV,IAAK,IAAIvJ,EAAI,EAAGA,EAAIuJ,EAAMrJ,OAAQF,IAAK,CACrC,IAAIoF,EAAOmE,EAAMvJ,GACb6K,EAASvB,EAAQlE,GACrBxG,OAAOC,KAAKgM,GAAQ9L,SAAQ,SAAU0G,GACpCH,EAAM5E,KAAK,CACTmD,GAAIuB,EACJK,UAAWA,EACXE,MAAOkF,EAAOpF,QAMpB7G,OAAOC,KAAKyK,GAASvK,SAAQ,SAAUqG,GAErC,GADAA,EAAO6B,SAAS7B,KACZmE,EAAM1H,QAAQuD,IAAS,GAA3B,CAKA,IAAIyF,EAASvB,EAAQlE,GACrBxG,OAAOC,KAAKgM,GAAQ9L,SAAQ,SAAU0G,GACpCH,EAAM5E,KAAK,CACTmD,GAAIuB,EACJK,UAAWA,EACXE,MAAOkF,EAAOpF,YAMtB,OAAOH,GAGTvH,EAAQiH,WAAa,SAAUG,GAC7B,IAAImE,EAAU,GASd,YAP2B,IAAhBnE,EAAMG,OAAyBpC,MAAMgD,QAAQf,EAAMG,QAC5DH,EAAMG,MAAMvG,SAAQ,SAAUqG,GACvBkE,EAAQlE,EAAKvB,MAChByF,EAAQlE,EAAKvB,IAAM,IACrByF,EAAQlE,EAAKvB,IAAIuB,EAAKK,WAAaL,EAAKO,SAGrC2D,WChFT,IAAIwB,EAAU9M,EAAOD,QAAU,CAC7BgN,EAAG,CAAC,CACFC,KAAM,UACNC,IAAK,YAEPC,EAAG,CAAC,CAEFF,KAAM,SACNC,IAAK,wCACLE,MAAO,CAAC,WAAY,YAAa,iBAAkB,UAAW,QAAS,WACvEC,OAAQ,wBAGVC,EAAG,CAAC,CAAEL,KAAM,SACZhL,EAAG,CAAC,CAAEgL,KAAM,gBACZM,EAAG,CAAC,CAAEN,KAAM,QACZO,EAAG,CAAC,CAAEP,KAAM,UACZQ,EAAG,CAAC,CAAER,KAAM,UACZS,EAAG,CAAC,CAAET,KAAM,cACZU,EAAG,CAAC,CAAEV,KAAM,YAEZxH,EAAG,CAAC,CACFwH,KAAM,SACNC,IAAK,eACLE,MAAO,CAAC,QAAS,QACjBC,OAAQ,UAEVO,EAAG,CAAC,CACFX,KAAM,aACNC,IAAK,mBACLE,MAAO,CAAC,UAAW,MACnBC,OAAQ,eAEVQ,EAAG,CAAC,CACFlL,KAAM,YACNuK,IAAK,4BACLE,MAAO,CAAC,OAAQ,SAChBC,OAAQ,UAEVzI,EAAG,CAAC,CAGFsI,IAAK,mCACLE,MAAO,CAAC,OAAQ,OAAQ,WAAY,YACpCC,OAAQ,gBAEVS,EAAG,CACD,CACEnL,KAAM,MACNuK,IAAK,0DACLE,MAAO,CAAC,UAAW,QAAS,OAAQ,YACpCC,OAAQ,SAAUF,GAChB,OAAQA,EAAU,SAChB,qBACAA,EAAEY,KACF,kBACA,iBAGN,CAEEpL,KAAM,OACNuK,IAAK,wBACLE,MAAO,CAAC,UAAW,UACnBC,OAAQ,cAEV,CACEJ,KAAM,UACNC,IAAK,gBACLG,OAAQ,cAEV,CACEJ,KAAM,OACNC,IAAK,sCACLE,MAAO,CAAC,OAAQ,UAAW,QAAS,WACpCC,OAAQ,SAAUF,GAChB,OAAqB,MAAbA,EAAEa,QACR,qBACA,YAGN,CACErL,KAAM,eACNuK,IAAK,kCACLE,MAAO,CAAC,UAAW,SACnBC,OAAQ,yBAEV,CACE1K,KAAM,SACNuK,IAAK,6CACLE,MAAO,CAAC,UAAW,OAAQ,WAC3BC,OAAQ,SAAUF,GAChB,OAAqB,MAAbA,EAAEc,QACR,mBACA,kBAGN,CAEEtL,KAAM,MACNuK,IAAK,6CACLE,MAAO,CAAC,QAAS,YAAa,MAAO,UACrCC,OAAQ,SAAUF,GAChB,MAAO,aAAeA,EAAEN,UAAY,MAAQ,MAAQ,OAASM,EAAEe,OAAS,MAAQ,MAGpF,CACEvL,KAAM,SACNuK,IAAK,0CACLE,MAAO,CAAC,KAAM,QAAS,SAAU,iBACjCC,OAAQ,SAAUF,GAChB,OAA2B,MAAnBA,EAAEgB,cACR,qBACA,oBAGN,CACElB,KAAM,QACNC,IAAK,eACLG,OAAQ,YAEV,CACEJ,KAAM,MACNC,IAAK,gBACLG,OAAQ,UAEV,CACEJ,KAAM,OACNC,IAAK,aACLG,OAAQ,WAEV,CACEJ,KAAM,QACNC,IAAK,eACLG,OAAQ,YAEV,CACEJ,KAAM,WACNC,IAAK,kBACLG,OAAQ,eAEV,CACEJ,KAAM,YACNC,IAAK,0CAEP,CACED,KAAM,UACNC,IAAK,eAEP,CACED,KAAM,WACNC,IAAK,mBACLG,OAAQ,gBAEV,CACEJ,KAAM,SACNC,IAAK,iBACLG,OAAQ,cAEV,CACEJ,KAAM,cACNC,IAAK,2BACLE,MAAO,CAAC,OAAQ,QAChBC,OAAQ,qBAEV,CAKE1K,KAAK,aACLuK,IAAK,+KACLE,MAAO,CAAC,aAAc,YAAa,YAAa,WAAY,KAAM,OAAQ,OAAQ,QAAS,QAAS,UAAW,aAAc,aAAc,gBAC3IC,OAAQ,SAAUF,GAChB,IAAIiB,EAAM,qCAaV,OAXAA,GAAmB,MAAXjB,EAAEkB,MAAiB,qBAAuB,OAGlDD,GAAqB,MAAbjB,EAAEmB,QAAmB,cAAgB,KAEzB,MAAhBnB,EAAEoB,aACJH,GAAO,mBAGTA,GAA2B,MAAnBjB,EAAE,cAAyB,iBAAmB,OACzB,MAArBA,EAAE,gBAA2B,mBAAqB,QAI9D,CACEF,KAAM,kBACNC,IAAK,wBAEP,CACED,KAAM,mBACNC,IAAK,0BACLG,OAAQ,wBAEV,CACEJ,KAAM,aACNC,IAAK,qBACLG,OAAQ,kBAEV,CACE1K,KAAM,QACNuK,IAAK,iCACLE,MAAO,CAAC,KAAM,YAAa,SAC3BC,OAAQ,SAAUF,GAChB,IAAIiB,EAAM,UAOV,OANmB,MAAfjB,EAAEzF,YACJ0G,GAAO,MACQ,MAAXjB,EAAEvF,QACJwG,GAAO,QAGJA,IAGX,CAEEzL,KAAM,aAENuK,IAAK,mEACLE,MAAO,CAAC,YAAa,SACrBC,OAAQ,oBAEV,CACEJ,KAAM,eACNC,IAAK,gCACLE,MAAO,CAAC,WAAY,SACpBC,OAAQ,wBAEV,CACE1K,KAAM,SACNuK,IAAK,oBACLE,MAAO,CAAC,OAAQ,QAChBC,OAAQ,eAEV,CACEJ,KAAM,UACNC,IAAK,eAEP,CACED,KAAM,YACNC,IAAK,iBAEP,CACED,KAAM,UACNC,IAAK,uCACLE,MAAO,CAAC,gBAAiB,MAAO,kBAChCC,OAAQ,SAAUF,GAChB,OAA4B,MAApBA,EAAEqB,eACR,mBACA,kBAGN,CACEvB,KAAM,cACNC,IAAK,0BACLG,OAAQ,oBAEV,CACE1K,KAAM,OACNuK,IAAK,sCACLE,MAAO,CAAC,KAAM,YAAa,UAC3BC,OAAQ,SAAUF,GAChB,OAAQA,EAAQ,OAAI,eAAiB,cAGzC,CAGExK,KAAM,aACNuK,IAAK,IAAIuB,OAEP,wKAMFrB,MAAO,CAAC,KAAM,OAAQ,SAAU,OAAQ,UACxCC,OAAQ,SAAUF,GAChB,MAAO,sBAAwBA,EAAEuB,KAAO,SAAW,MAGvD,CAEEzB,KAAM,YACNC,IAAK,IAAIuB,OAEP,2FAQFrB,MAAO,CAAC,OAAQ,QAAS,OAAQ,SACjCC,OAAQ,SAAUF,GAChB,MAAO,mBAAqBA,EAAEuB,KAAO,SAAW,MAGpD,CAIEzB,KAAM,eACNC,IAAK,kCACLE,MAAO,CAAC,SACRC,OAAQ,iBAEV,CAGEJ,KAAM,YACNC,IAAK,8BACLG,OAAQ,gBAEV,CACE1K,KAAM,UACNyK,MAAO,CAAC,YAMdvM,OAAOC,KAAKiM,GAAS/L,SAAQ,SAAU2N,GAC1B5B,EAAQ4B,GACd3N,SAAQ,SAAU4N,GAChBA,EAAI1B,MACP0B,EAAI1B,IAAM,QAEP0B,EAAIvB,SACPuB,EAAIvB,OAAS,2BChVnB,IAAIwB,EAAS,EAAQ,KACjBC,EAAS,EAAQ,KAErB9O,EAAQ2M,MAAQmC,EAChB9O,EAAQqL,MAAQwD,EAAOxD,MACvBrL,EAAQ+O,gBAAkBF,EAAOE,gBACjC/O,EAAQgP,YAAcH,EAAOG,YAC7BhP,EAAQiP,cAAgBJ,EAAOI,cAC/BjP,EAAQkP,sBAAwBL,EAAOK,sBACvClP,EAAQmP,qBAAuBN,EAAOM,qBACtCnP,EAAQoP,yBAA2BP,EAAOO,wCCV1C,IAAIC,EAAa,SAAUrC,GACzB,OAAOsC,OAAOC,OAAOvC,MAAQA,EAAIuC,OAAOvC,GAAKA,GAgB3CwC,EAAW,SAAUZ,EAAKa,EAAUC,GACtC,IAAIC,EAAaf,EAAI3B,MAAQ2B,EAAIxB,MAC7BwB,EAAIjM,OAAS8M,EAASb,EAAIjM,MAC5B8M,EAASb,EAAIjM,MAAQ,GAEdgN,IAAeF,EAASb,EAAI3B,QACnCwC,EAASb,EAAI3B,MAAQ,IAEvB,IAAI2C,EAAchB,EAAIjM,KACpB,GACAgN,EAAaF,EAASb,EAAI3B,MAAQwC,GAvBf,SAAU5K,EAAO4K,EAAUrC,EAAOyC,GACvD,GAAIA,IAAYzC,EACdqC,EAASI,GAAWR,EAAWxK,EAAM,SAGrC,IAAK,IAAI5C,EAAI,EAAGA,EAAImL,EAAMjL,OAAQF,GAAK,EACnB,MAAd4C,EAAM5C,EAAE,KACVwN,EAASrC,EAAMnL,IAAMoN,EAAWxK,EAAM5C,EAAE,KAkB9C6N,CAAiBJ,EAAQ7K,MAAM+J,EAAI1B,KAAM0C,EAAahB,EAAIxB,MAAOwB,EAAI3B,MAEjE2B,EAAIjM,MACN8M,EAASb,EAAIjM,MAAMA,KAAKiN,IAIxB7C,EAAU,EAAQ,IAClBgD,EAAYtB,OAAO/M,UAAUsO,KAAK3O,KAAK,iBAE3CrB,EAAQqL,MAAQ,SAAU7C,GACxB,IAAIP,EAAU,GACVG,EAAQ,GACRqH,EAAWxH,EAoBf,OAjBAO,EAAI7D,MAAM,gBAAgB6C,OAAOuI,GAAW/O,SAAQ,SAAU0E,GAC5D,IAAI2C,EAAO3C,EAAE,GACTgK,EAAUhK,EAAEN,MAAM,GACT,MAATiD,IACFD,EAAMzF,KAAK,CAACsN,IAAK,GAAIC,KAAM,KAC3BT,EAAWrH,EAAMA,EAAMjG,OAAO,IAGhC,IAAK,IAAIsJ,EAAI,EAAGA,GAAKsB,EAAQ1E,IAAS,IAAIlG,OAAQsJ,GAAK,EAAG,CACxD,IAAImD,EAAM7B,EAAQ1E,GAAMoD,GACxB,GAAImD,EAAI1B,IAAI8C,KAAKN,GACf,OAAOF,EAASZ,EAAKa,EAAUC,OAKrCzH,EAAQG,MAAQA,EACTH,GAGT,IAAIkI,EAAe,SAAUC,EAAKC,GAChC,IAAI/C,EAAI+C,EAAK1L,MAAM,QAAS,GAI5B,OAHiB,IAAb2I,EAAEnL,SACJiO,EAAI9C,EAAE,IAAM+B,EAAW/B,EAAE,KAEpB8C,GAGTpQ,EAAQgP,YAAc,SAAUZ,GAC9B,OAAOA,EAAIzJ,MAAM,SAAS2L,OAAOH,EAAc,KAIjDnQ,EAAQ+O,gBAAkB/O,EAAQgP,YAElChP,EAAQiP,cAAgB,SAAUb,GAChC,OAAOA,EAAIzJ,MAAM,KAAKgD,IAAI4H,SAG5BvP,EAAQkP,sBAAwB,SAAUd,GAGxC,IAFA,IAAImC,EAAa,GACb5E,EAAQyC,EAAIzJ,MAAM,KAAKgD,IAAI0H,GACtBpN,EAAI,EAAGA,EAAI0J,EAAMxJ,OAAQF,GAAK,EACrCsO,EAAW5N,KAAK,CACd6N,UAAW7E,EAAM1J,GACjBwO,GAAI9E,EAAM1J,EAAI,GACdyO,KAAM/E,EAAM1J,EAAI,KAGpB,OAAOsO,GAGTvQ,EAAQmP,qBAAuB,SAAUf,GACvC,OAAOA,EAAIzJ,MAAM,KAAKgD,KAAI,SAAUgJ,GAClC,OAAOA,EAAKC,UAAU,EAAGD,EAAKxO,OAAO,GAAGwC,MAAM,KAAK2L,OAAOH,EAAc,QAI5EnQ,EAAQoP,yBAA2B,SAAUhB,GAC3C,OAAOA,EAAIzJ,MAAM,KAAKgD,KAAI,SAAUkJ,GAClC,OAAOA,EAAOlM,MAAM,KAAKgD,KAAI,SAAU0F,GACrC,IAAIyD,EAAMC,GAAS,EASnB,MAPkB,MAAd1D,EAAO,GACTyD,EAAOzB,EAAWhC,IAElByD,EAAOzB,EAAWhC,EAAOuD,UAAU,EAAGvD,EAAOlL,SAC7C4O,GAAS,GAGJ,CACLD,KAAMA,EACNC,OAAQA,yBCrHhB,IAAIhE,EAAU,EAAQ,IAGlBiE,EAAe,WACf3D,EAAS,SAAU4D,GACrB,IAAIhP,EAAI,EACJiD,EAAO9D,UACPc,EAAMgD,EAAK/C,OACf,OAAO8O,EAAUC,QAAQF,GAAc,SAAUG,GAC/C,GAAIlP,GAAKC,EACP,OAAOiP,EAET,IAAI/O,EAAM8C,EAAKjD,GAEf,OADAA,GAAK,EACGkP,GACR,IAAK,KACH,MAAO,IACT,IAAK,KACH,OAAO7B,OAAOlN,GAChB,IAAK,KACH,OAAOmN,OAAOnN,GAChB,IAAK,KACH,MAAO,QAMTgP,EAAW,SAAU/I,EAAMuG,EAAKa,GAClC,IAIIvK,EAAO,CAACmD,EAAO,KAJTuG,EAAIvB,kBAAkBgE,SAC7BzC,EAAIvB,OAAOuB,EAAIjM,KAAO8M,EAAWA,EAASb,EAAI3B,OAC/C2B,EAAIvB,SAGN,GAAIuB,EAAIxB,MACN,IAAK,IAAInL,EAAI,EAAGA,EAAI2M,EAAIxB,MAAMjL,OAAQF,GAAK,EAAG,CAC5C,IAAIqP,EAAI1C,EAAIxB,MAAMnL,GACd2M,EAAI3B,KACN/H,EAAKvC,KAAK8M,EAASb,EAAI3B,MAAMqE,IAG7BpM,EAAKvC,KAAK8M,EAASb,EAAIxB,MAAMnL,UAKjCiD,EAAKvC,KAAK8M,EAASb,EAAI3B,OAEzB,OAAOI,EAAOlM,MAAM,KAAM+D,IAKxBqM,EAAoB,CACtB,IAAK,IAAK,IAAK,IACf,IAAK,IAAK,IAAK,IACf,IAAK,IAAK,IAAK,IAAK,KAElBC,EAAoB,CAAC,IAAK,IAAK,IAAK,KAGxCvR,EAAOD,QAAU,SAAUiI,EAASwJ,GAClCA,EAAOA,GAAQ,GAEQ,MAAnBxJ,EAAQyJ,UACVzJ,EAAQyJ,QAAU,GAEA,MAAhBzJ,EAAQgF,OACVhF,EAAQgF,KAAO,KAEjBhF,EAAQG,MAAMpH,SAAQ,SAAUoG,GACR,MAAlBA,EAAMuK,WACRvK,EAAMuK,SAAW,OAIrB,IAAIC,EAAaH,EAAKG,YAAcL,EAChCM,EAAaJ,EAAKI,YAAcL,EAChChJ,EAAM,GAkCV,OA/BAoJ,EAAW5Q,SAAQ,SAAUqH,GAC3B0E,EAAQ1E,GAAMrH,SAAQ,SAAU4N,GAC1BA,EAAI3B,QAAQhF,GAAgC,MAArBA,EAAQ2G,EAAI3B,MACrCzE,EAAI7F,KAAKyO,EAAS/I,EAAMuG,EAAK3G,IAEtB2G,EAAIjM,QAAQsF,GAAgC,MAArBA,EAAQ2G,EAAIjM,OAC1CsF,EAAQ2G,EAAIjM,MAAM3B,SAAQ,SAAU8Q,GAClCtJ,EAAI7F,KAAKyO,EAAS/I,EAAMuG,EAAKkD,aAOrC7J,EAAQG,MAAMpH,SAAQ,SAAUoG,GAC9BoB,EAAI7F,KAAKyO,EAAS,IAAKrE,EAAQnI,EAAE,GAAIwC,IAErCyK,EAAW7Q,SAAQ,SAAUqH,GAC3B0E,EAAQ1E,GAAMrH,SAAQ,SAAU4N,GAC1BA,EAAI3B,QAAQ7F,GAA4B,MAAnBA,EAAMwH,EAAI3B,MACjCzE,EAAI7F,KAAKyO,EAAS/I,EAAMuG,EAAKxH,IAEtBwH,EAAIjM,QAAQyE,GAA4B,MAAnBA,EAAMwH,EAAIjM,OACtCyE,EAAMwH,EAAIjM,MAAM3B,SAAQ,SAAU8Q,GAChCtJ,EAAI7F,KAAKyO,EAAS/I,EAAMuG,EAAKkD,gBAOhCtJ,EAAIwB,KAAK,QAAU,kCC/F5B,SAAS+H,EAAOC,EAAQC,GAIvB,YAHWzF,IAAPyF,IACHA,EAAKpR,QAECoR,GAA2B,mBAAdA,EAAGF,OAAwBE,EAAGF,OAAOC,GAAUA,EAUpE,IAAIE,EAAYH,EAAO,CAUtBI,KAAM,YAYNC,OAAQ,SAAUxK,GACjB,OAAOA,IAAUsK,EAAUC,MAU5BE,gBAAiB,kBASjBC,SAAU,WAUVC,sBAAuB,wBASvBC,cAAe,kBAQZC,EAAYV,EAAO,CAMtBI,KAAM,+BASNC,OAAQ,SAAUM,GACjB,OAAOA,IAAQD,EAAUN,MAQ1BQ,IAAK,6BAOLC,IAAK,uCAOLC,MAAO,kCAGR7S,EAAQ+R,OAASA,EACjB/R,EAAQkS,UAAYA,EACpBlS,EAAQyS,UAAYA,qBC/IhBK,EAAc,EAAQ,KACtBC,EAAM,EAAQ,KACdC,EAAW,EAAQ,IACnBC,EAAM,EAAQ,KAEdC,EAAoBH,EAAIG,kBAExBT,EAAYK,EAAYL,UAExBU,EAAaF,EAAIE,WACjBC,EAAYH,EAAIG,UAEpB,SAASC,EAAU7S,GAClBC,KAAKD,QAAUA,GAAU,CAAC8S,QAAQ,IAgEnC,SAASC,IACL9S,KAAK+S,OAAQ,EAEjB,SAASC,EAASH,EAAQI,GACzBA,EAAKC,WAAaL,EAAQK,WAC1BD,EAAKE,aAAeN,EAAQM,aAkH7B,SAASC,EAASnO,GACjB,GAAGA,EACF,MAAO,OAAOA,EAAEoO,UAAW,IAAI,UAAUpO,EAAEiO,WAAW,QAAQjO,EAAEkO,aAAa,IAG/E,SAASG,EAAUC,EAAMnR,EAAMV,GAC9B,MAAmB,iBAAT6R,EACFA,EAAMlP,OAAOjC,EAAMV,GAEvB6R,EAAM7R,QAAUU,EAAMV,GAAUU,EAC3B,IAAIoR,KAAKC,KAAK5E,OAAO0E,EAAMnR,EAAMV,GAAQ,GAE1C6R,EAwCT,SAASG,EAAeC,EAAOV,GACtBU,EAAOC,eAGRD,EAAOC,eAAeC,YAAYZ,GAFlCU,EAAOG,IAAID,YAAYZ,GA1O/BL,EAAU3R,UAAU8S,gBAAkB,SAAS1H,EAAO2H,GACrD,IAAIjU,EAAUC,KAAKD,QACfyS,EAAO,IAAIG,EACXsB,EAAalU,EAAQkU,YAAc,IAAInB,EACvCoB,EAAenU,EAAQmU,aACvBrB,EAAU9S,EAAQ8S,QAClBsB,EAAepU,EAAQqU,OAAO,GAC9BzC,EAAS,aAAapC,KAAKyE,GACzBK,EAAY1C,EAASY,EAAS+B,cAAgB/B,EAASgC,aAgB7D,OAfG1B,GACFoB,EAAWO,mBAAmB3B,GAG/BL,EAAI0B,aAaL,SAA2BO,EAAUR,EAAWpB,GAC/C,IAAI4B,EAAU,CACb,GAAGR,aAAsBnB,EACxB,OAAOmB,EAERQ,EAAYR,EAEb,IAAIC,EAAe,GACfQ,EAAaD,aAAqB7D,SAEtC,SAAS+D,EAAMzG,GACd,IAAI0G,EAAKH,EAAUvG,IACf0G,GAAMF,IACTE,EAAyB,GAApBH,EAAU/S,OAAY,SAASH,GAAKkT,EAAUvG,EAAI3M,IAAMkT,GAE9DP,EAAahG,GAAO0G,GAAM,SAASrT,GAClCqT,EAAG,WAAW1G,EAAI,MAAM3M,EAAI6R,EAASP,MACnC,aAKJ,OAbAA,EAAUA,GAAS,GAUnB8B,EAAM,WACNA,EAAM,SACNA,EAAM,cACCT,EAnCYW,CAAkBX,EAAaD,EAAWpB,GAC7DL,EAAIyB,WAAalU,EAAQkU,YAAcA,EACpCtC,IACFwC,EAAa,IAAMnC,EAAUN,MAE9ByC,EAAaW,IAAMX,EAAaW,KAAO9C,EAAUG,IAC9C9F,GAA4B,iBAAXA,EACnBmG,EAAI5H,MAAMyB,EAAO8H,EAAaE,GAE9B7B,EAAI0B,aAAa7S,MAAM,sBAEjB4S,EAAWH,KAgDnBhB,EAAW7R,UAAY,CACtB8T,cAAgB,WACZ/U,KAAK8T,KAAM,IAAIrB,GAAoBuC,eAAe,KAAM,KAAM,MAC1DhV,KAAK6S,UACL7S,KAAK8T,IAAImB,YAAcjV,KAAK6S,QAAQQ,WAG5C6B,aAAa,SAASC,EAAcC,EAAWC,EAAOC,GACrD,IAAIxB,EAAM9T,KAAK8T,IACRzC,EAAKyC,EAAIyB,gBAAgBJ,EAAcE,GAAOD,GAC9C3T,EAAM6T,EAAM5T,OAChBgS,EAAc1T,KAAMqR,GACpBrR,KAAK4T,eAAiBvC,EAEzBrR,KAAK6S,SAAWG,EAAShT,KAAK6S,QAAQxB,GACnC,IAAK,IAAI7P,EAAI,EAAIA,EAAIC,EAAKD,IAAK,CACvB2T,EAAeG,EAAME,OAAOhU,GAAhC,IACI2F,EAAQmO,EAAMG,SAASjU,GAE7BkU,GADML,EAAQC,EAAMK,SAASnU,GACtBsS,EAAI8B,kBAAkBT,EAAcE,IAC/CrV,KAAK6S,SAAUG,EAASsC,EAAMO,WAAWrU,GAAGkU,GAC5CA,EAAKvO,MAAQuO,EAAKI,UAAY3O,EAC9BkK,EAAG0E,iBAAiBL,KAGtBM,WAAW,SAASb,EAAcC,EAAWC,GAC5C,IAAIY,EAAUjW,KAAK4T,eACLqC,EAAQC,QACtBlW,KAAK4T,eAAiBqC,EAAQE,YAE/BC,mBAAmB,SAASC,EAAQpE,KAEpCqE,iBAAiB,SAASD,KAE1BE,sBAAsB,SAASC,EAAQC,GACnC,IAAIC,EAAM1W,KAAK8T,IAAI6C,4BAA4BH,EAAQC,GACvDzW,KAAK6S,SAAWG,EAAShT,KAAK6S,QAAQ6D,GACtChD,EAAc1T,KAAM0W,IAExBE,oBAAoB,SAASC,EAAIzU,EAAOV,KAExCoV,WAAW,SAASvD,EAAOnR,EAAOV,GAGjC,GAFA6R,EAAQD,EAAU5S,MAAMV,KAAKW,WAEpB,CACR,GAAIX,KAAK+S,MACR,IAAIgE,EAAW/W,KAAK8T,IAAIkD,mBAAmBzD,QAEvCwD,EAAW/W,KAAK8T,IAAImD,eAAe1D,GAErCvT,KAAK4T,eACP5T,KAAK4T,eAAeC,YAAYkD,GACxB,QAAQxH,KAAKgE,IACrBvT,KAAK8T,IAAID,YAAYkD,GAGtB/W,KAAK6S,SAAWG,EAAShT,KAAK6S,QAAQkE,KAGxCG,cAAc,SAAS1K,KAEvB2K,YAAY,WACXnX,KAAK8T,IAAIsD,aAEV5C,mBAAmB,SAAU3B,IACtB7S,KAAK6S,QAAUA,KACjBA,EAAQK,WAAa,IAI1BmE,QAAQ,SAAS9D,EAAOnR,EAAOV,GAC9B6R,EAAQD,EAAU5S,MAAMV,KAAKW,WAC1B,IAAI2W,EAAOtX,KAAK8T,IAAIyD,cAAchE,GAClCvT,KAAK6S,SAAWG,EAAShT,KAAK6S,QAAQyE,GACtC5D,EAAc1T,KAAMsX,IAGxBE,WAAW,WAEPxX,KAAK+S,OAAQ,GAEjB0E,SAAS,WACLzX,KAAK+S,OAAQ,GAGjB2E,SAAS,SAASlL,EAAMmL,EAAUtE,GACjC,IAAIuE,EAAO5X,KAAK8T,IAAI+D,eACjB,GAAID,GAAQA,EAAKE,mBAAoB,CACjC,IAAIC,EAAKH,EAAKE,mBAAmBtL,EAAMmL,EAAUtE,GACjDrT,KAAK6S,SAAWG,EAAShT,KAAK6S,QAAQkF,GACtCrE,EAAc1T,KAAM+X,GACxB/X,KAAK8T,IAAIkE,QAAUD,IAOvBE,QAAQ,SAAS5W,GAChB4B,QAAQiV,KAAK,qBAAqB7W,EAAM+R,EAASpT,KAAK6S,WAEvDxR,MAAM,SAASA,GACd4B,QAAQ5B,MAAM,mBAAmBA,EAAM+R,EAASpT,KAAK6S,WAEtDsF,WAAW,SAAS9W,GACnB,MAAM,IAAIqR,EAAWrR,EAAOrB,KAAK6S,WAkDnC,+JAA+JpC,QAAQ,QAAO,SAASvC,GACtL4E,EAAW7R,UAAUiN,GAAO,WAAW,OAAO,SAa/C3O,EAAQqT,UAAYA,EAKQN,EAAIG,kBAKRH,EAAI8F,6BC3Q5B,IAEIpG,EAFc,EAAQ,KAEEA,UAO5B,SAASqG,EAAgBC,GACxB,MAAiB,KAAVA,EAqBR,SAASC,EAAmBtC,EAASuC,GAIpC,OAHKvC,EAAQwC,eAAeD,KAC3BvC,EAAQuC,IAAW,GAEbvC,EAQR,SAASyC,EAAaJ,GACrB,IAAKA,EAAO,MAAO,GACnB,IAAIK,EA1BL,SAAgCL,GAE/B,OAAOA,EAAQA,EAAMpU,MAAM,gBAAgB6C,OAAOsR,GAAkB,GAwBzDO,CAAuBN,GAClC,OAAOlY,OAAOC,KAAKsY,EAAK9I,OAAO0I,EAAmB,KAgBnD,SAASM,EAAKC,EAAIC,GACjB,IAAI,IAAI/L,KAAK8L,EACZC,EAAK/L,GAAK8L,EAAI9L,GAQhB,SAASgM,EAASC,EAAMC,GACvB,IAAIC,EAAKF,EAAMhY,UACf,KAAKkY,aAAcD,GAAO,CACzB,SAASlU,KACTA,EAAE/D,UAAYiY,EAAMjY,UAEpB4X,EAAKM,EADLnU,EAAI,IAAIA,GAERiU,EAAMhY,UAAYkY,EAAKnU,EAErBmU,EAAGC,aAAeH,IACD,mBAATA,GACThW,QAAQ5B,MAAM,iBAAiB4X,GAEhCE,EAAGC,YAAcH,GAKnB,IAAII,EAAW,GACXC,EAA8BD,EAASC,aAA8B,EACrEC,EAA8BF,EAASE,eAA8B,EACrEC,EAA8BH,EAASG,UAA8B,EACrEC,EAA8BJ,EAASI,mBAA8B,EACrEC,EAA8BL,EAASK,sBAA8B,EACrEC,EAA8BN,EAASM,YAA8B,EACrEC,EAA8BP,EAASO,4BAA8B,EACrEC,EAA8BR,EAASQ,aAA8B,EACrEC,EAA8BT,EAASS,cAA8B,EACrEC,EAA8BV,EAASU,mBAA8B,GACrEC,EAA8BX,EAASW,uBAA8B,GACrEC,EAA8BZ,EAASY,cAA8B,GAGrEC,EAAgB,GAChBC,EAAmB,GAGnBC,GAF8BF,EAAcG,gBAAgCF,EAAiB,GAAG,mBAAoB,GACtFD,EAAcI,oBAAgCH,EAAiB,GAAG,uBAAwB,GAC1FD,EAAcE,uBAAgCD,EAAiB,GAAG,0BAA2B,IAK3HI,GAJ8BL,EAAcM,oBAAgCL,EAAiB,GAAG,iBAAkB,GACpFD,EAAcO,uBAAgCN,EAAiB,GAAG,oBAAqB,GACvFD,EAAcQ,qBAAgCP,EAAiB,GAAG,kBAAmB,GACrFD,EAAcS,6BAAgCR,EAAiB,GAAG,0BAA2B,GAC7FD,EAAcK,eAAgCJ,EAAiB,GAAG,YAAa,IAE7GS,GAD8BV,EAAcW,mBAAgCV,EAAiB,GAAG,gBAAiB,GACnFD,EAAcU,qBAAgCT,EAAiB,IAAI,mBAAoB,KAczH,SAASW,EAAaC,EAAMC,GAC3B,GAAGA,aAAmBhX,MACrB,IAAI3C,EAAQ2Z,OAEZ3Z,EAAQrB,KACRgE,MAAMY,KAAK5E,KAAMma,EAAiBY,IAClC/a,KAAKgb,QAAUb,EAAiBY,GAC7B/W,MAAMiX,mBAAmBjX,MAAMiX,kBAAkBjb,KAAM8a,GAI3D,OAFAzZ,EAAM0Z,KAAOA,EACVC,IAAShb,KAAKgb,QAAUhb,KAAKgb,QAAU,KAAOA,GAC1C3Z,EAUR,SAAS6Z,KA2BT,SAASC,EAAalI,EAAKmI,GAC1Bpb,KAAKqb,MAAQpI,EACbjT,KAAKsb,SAAWF,EAChBG,EAAgBvb,MAEjB,SAASub,EAAgB5C,GACxB,IAAI6C,EAAM7C,EAAK0C,MAAMI,MAAQ9C,EAAK0C,MAAMK,cAAcD,KACtD,GAAG9C,EAAK8C,MAAQD,EAAI,CACnB,IAAIG,EAAKhD,EAAK2C,SAAS3C,EAAK0C,OAE5BO,GAAQjD,EAAK,SAASgD,EAAGja,QACzBmX,EAAK8C,EAAGhD,GACRA,EAAK8C,KAAOD,GAqBd,SAASK,KAGT,SAASC,EAAenD,EAAK1F,GAE5B,IADA,IAAIzR,EAAImX,EAAKjX,OACPF,KACL,GAAGmX,EAAKnX,KAAOyR,EAAM,OAAOzR,EAI9B,SAASua,EAAc1K,EAAGsH,EAAKqD,EAAQC,GAMtC,GALGA,EACFtD,EAAKmD,EAAenD,EAAKsD,IAAYD,EAErCrD,EAAKA,EAAKjX,UAAYsa,EAEpB3K,EAAG,CACL2K,EAAQE,aAAe7K,EACvB,IAAIyC,EAAMzC,EAAGqK,cACV5H,IACFmI,GAAWE,EAAmBrI,EAAIzC,EAAG4K,GAwVxC,SAAyBnI,EAAIzC,EAAG2K,GAC/BlI,GAAOA,EAAI2H,OACFO,EAAQ7G,eACPnD,EAAUI,QAEnBf,EAAG+K,OAAOJ,EAAQ3F,OAAO2F,EAAQ5G,UAAU,IAAM4G,EAAQ7U,OA5VxDkV,CAAgBvI,EAAIzC,EAAG2K,KAI1B,SAASM,EAAiBjL,EAAGsH,EAAKjD,GAEjC,IAAIlU,EAAIsa,EAAenD,EAAKjD,GAC5B,KAAGlU,GAAG,GAcL,MAAMsZ,EAAaP,EAAc,IAAIvW,MAAMqN,EAAG6E,QAAQ,IAAIR,IAZ1D,IADA,IAAI6G,EAAY5D,EAAKjX,OAAO,EACtBF,EAAE+a,GACP5D,EAAKnX,GAAKmX,IAAOnX,GAGlB,GADAmX,EAAKjX,OAAS6a,EACXlL,EAAG,CACL,IAAIyC,EAAMzC,EAAGqK,cACV5H,IACFqI,EAAmBrI,EAAIzC,EAAGqE,GAC1BA,EAAKwG,aAAe,OAsFxB,SAASzJ,KA+FT,SAAS+J,KAiHT,SAASC,EAAYtP,GACpB,OAAY,KAALA,EAAY,OACN,KAALA,GAAY,SACP,KAALA,GAAY,SACP,KAALA,GAAY,UACZ,KAAKA,EAAEuP,aAAa,IAW7B,SAASC,EAAW1J,EAAK2J,GACxB,GAAGA,EAAS3J,GACX,OAAO,EAER,GAAGA,EAAOA,EAAK4J,WACd,GACC,GAAGF,EAAW1J,EAAK2J,GAAW,OAAO,QACzB3J,EAAKA,EAAK6J,aAMzB,SAASC,KAYT,SAASZ,EAAmBrI,EAAIzC,EAAG2K,EAAQgB,GAC1ClJ,GAAOA,EAAI2H,OACFO,EAAQ7G,eACPnD,EAAUI,cAEZf,EAAG+K,OAAOJ,EAAQ3F,OAAO2F,EAAQ5G,UAAU,IAIpD,SAAS6H,EAAenJ,EAAIzC,EAAG6L,GAC9B,GAAGpJ,GAAOA,EAAI2H,KAAK,CAClB3H,EAAI2H,OAEJ,IAAI0B,EAAK9L,EAAG+L,WACZ,GAAGF,EACFC,EAAGA,EAAGzb,UAAYwb,MACd,CAIJ,IAFA,IAAIG,EAAQhM,EAAGwL,WACXrb,EAAI,EACF6b,GACLF,EAAG3b,KAAO6b,EACVA,EAAOA,EAAMP,YAEdK,EAAGzb,OAASF,IAaf,SAAS8b,EAAanH,EAAWkH,GAChC,IAAIE,EAAWF,EAAMG,gBACjBC,EAAOJ,EAAMP,YAYjB,OAXGS,EACFA,EAAST,YAAcW,EAEvBtH,EAAW0G,WAAaY,EAEtBA,EACFA,EAAKD,gBAAkBD,EAEvBpH,EAAWuH,UAAYH,EAExBN,EAAe9G,EAAWuF,cAAcvF,GACjCkH,EAKR,SAASM,EAAcxH,EAAW+G,EAASU,GAC1C,IAAIC,EAAKX,EAAS/G,WAIlB,GAHG0H,GACFA,EAAGC,YAAYZ,GAEbA,EAASa,WAAa/D,EAAuB,CAC/C,IAAIgE,EAAWd,EAASL,WACxB,GAAgB,MAAZmB,EACH,OAAOd,EAER,IAAIe,EAAUf,EAASQ,eAEvBM,EAAWC,EAAUf,EAEtB,IAAIgB,EAAMN,EAAYA,EAAUJ,gBAAkBrH,EAAWuH,UAE7DM,EAASR,gBAAkBU,EAC3BD,EAAQnB,YAAcc,EAGnBM,EACFA,EAAIpB,YAAckB,EAElB7H,EAAW0G,WAAamB,EAET,MAAbJ,EACFzH,EAAWuH,UAAYO,EAEvBL,EAAUJ,gBAAkBS,EAE7B,GACCD,EAAS7H,WAAaA,QAChB6H,IAAaC,IAAYD,EAAUA,EAASlB,cAMnD,OALAG,EAAe9G,EAAWuF,eAAevF,EAAWA,GAEhD+G,EAASa,UAAY/D,IACxBkD,EAASL,WAAaK,EAASQ,UAAY,MAErCR,EA6NR,SAASiB,IACRne,KAAKoc,OAAS,GA6Ff,SAASgC,KAMT,SAASC,KA+BT,SAASC,KAmBT,SAASC,KAQT,SAASC,KAST,SAASC,KAKT,SAASC,KAKT,SAASC,KAKT,SAASC,KAKT,SAASC,MAOT,SAASC,MAIT,SAAS1G,MAKT,SAAS2G,GAAsBC,EAAOC,GACrC,IAAIC,EAAM,GACNC,EAA2B,GAAjBnf,KAAK+d,UAAiB/d,KAAKof,iBAAmBpf,KACxDqW,EAAS8I,EAAQ9I,OACjBpE,EAAMkN,EAAQhK,aAElB,GAAGlD,GAAiB,MAAVoE,GAGI,OADTA,EAAS8I,EAAQE,aAAapN,IAGjC,IAAIqN,EAAkB,CACtB,CAACC,UAAUtN,EAAIoE,OAAO,OAOxB,OAFAmJ,GAAkBxf,KAAKkf,EAAIF,EAAOC,EAAWK,GAEtCJ,EAAI3V,KAAK,IAGjB,SAASkW,GAAoBxM,EAAMtB,EAAQ2N,GAC1C,IAAIjJ,EAASpD,EAAKoD,QAAU,GACxBpE,EAAMgB,EAAKkC,aAQf,IAAKlD,EACJ,OAAO,EAER,GAAe,QAAXoE,GAAoBpE,IAAQD,EAAUG,KAAOF,IAAQD,EAAUI,MAClE,OAAO,EAIR,IADA,IAAI5Q,EAAI8d,EAAkB5d,OACnBF,KAAK,CACX,IAAIke,EAAKJ,EAAkB9d,GAE3B,GAAIke,EAAGrJ,SAAWA,EACjB,OAAOqJ,EAAGH,YAActN,EAG1B,OAAO,EAQR,SAAS0N,GAAuBT,EAAKU,EAAezY,GACnD+X,EAAIhd,KAAK,IAAK0d,EAAe,KAAMzY,EAAMsJ,QAAQ,SAASgM,GAAc,KAGzE,SAAS+C,GAAkBvM,EAAKiM,EAAIvN,EAAOsN,EAAWK,GAKrD,GAJKA,IACJA,EAAoB,IAGlBL,EAAW,CAEb,KADAhM,EAAOgM,EAAWhM,IAOjB,OALA,GAAkB,iBAARA,EAET,YADAiM,EAAIhd,KAAK+Q,GASZ,OAAOA,EAAK8K,UACZ,KAAKzE,EACJ,IAAIhE,EAAQrC,EAAK4M,WACbpe,EAAM6T,EAAM5T,OACZ2b,EAAQpK,EAAK4J,WACbiD,EAAW7M,EAAKiD,QAIhB6J,EAAmBD,EACvB,KAHAnO,EAASK,EAAUL,OAAOsB,EAAKkC,eAAiBxD,KAGhCsB,EAAKoD,QAAUpD,EAAKkC,aAAc,CAGjD,IAFA,IAAI6K,EAEKC,EAAK,EAAGA,EAAK3K,EAAM5T,OAAQue,IACnC,GAA4B,UAAxB3K,EAAMpF,KAAK+P,GAAIzT,KAAkB,CACpCwT,EAAY1K,EAAMpF,KAAK+P,GAAI9Y,MAC3B,MAGF,IAAK6Y,EAEJ,IAAK,IAAIE,EAAMZ,EAAkB5d,OAAS,EAAGwe,GAAO,EAAGA,IAEtD,GAAyB,MADrBX,EAAYD,EAAkBY,IACpB7J,QAAiBkJ,EAAUA,YAActM,EAAKkC,aAAc,CACzE6K,EAAYT,EAAUA,UACtB,MAIH,GAAIS,IAAc/M,EAAKkC,aACtB,IAAS+K,EAAMZ,EAAkB5d,OAAS,EAAGwe,GAAO,EAAGA,IAAO,CAC7D,IAAIX,EACJ,IADIA,EAAYD,EAAkBY,IACpBX,YAActM,EAAKkC,aAAc,CAC1CoK,EAAUlJ,SACb0J,EAAmBR,EAAUlJ,OAAS,IAAMyJ,GAE7C,QAMJZ,EAAIhd,KAAK,IAAK6d,GAEd,IAAI,IAAIve,EAAE,EAAEA,EAAEC,EAAID,IAGE,UADfkU,EAAOJ,EAAMpF,KAAK1O,IACb6U,OACRiJ,EAAkBpd,KAAK,CAAEmU,OAAQX,EAAKN,UAAWmK,UAAW7J,EAAKvO,QACxC,SAAjBuO,EAAKoK,UACbR,EAAkBpd,KAAK,CAAEmU,OAAQ,GAAIkJ,UAAW7J,EAAKvO,QAIvD,IAAQ3F,EAAE,EAAEA,EAAEC,EAAID,IAAI,CACrB,IAAIkU,EAECW,EACApE,EAFDwN,GADA/J,EAAOJ,EAAMpF,KAAK1O,GACOmQ,EAAQ2N,KAGpCK,GAAuBT,GAFnB7I,EAASX,EAAKW,QAAQ,IAEW,SAAWA,EAAS,QADrDpE,EAAMyD,EAAKP,cAEfmK,EAAkBpd,KAAK,CAAEmU,OAAQA,EAAQkJ,UAAUtN,KAEpDuN,GAAkB9J,EAAKwJ,EAAIvN,EAAOsN,EAAWK,GAW9C,GAPIQ,IAAaC,GAAoBN,GAAoBxM,EAAMtB,EAAQ2N,KAGtEK,GAAuBT,GAFnB7I,EAASpD,EAAKoD,QAAQ,IAEW,SAAWA,EAAS,QADrDpE,EAAMgB,EAAKkC,cAEfmK,EAAkBpd,KAAK,CAAEmU,OAAQA,EAAQkJ,UAAUtN,KAGjDoL,GAAS1L,IAAW,mCAAmCpC,KAAKuQ,GAAU,CAGxE,GAFAZ,EAAIhd,KAAK,KAENyP,GAAU,YAAYpC,KAAKuQ,GAC7B,KAAMzC,GACFA,EAAM5G,KACRyI,EAAIhd,KAAKmb,EAAM5G,MAEf+I,GAAkBnC,EAAO6B,EAAKvN,EAAQsN,EAAYK,EAAkB3a,SAErE0Y,EAAQA,EAAMP,iBAIf,KAAMO,GACLmC,GAAkBnC,EAAO6B,EAAKvN,EAAQsN,EAAYK,EAAkB3a,SACpE0Y,EAAQA,EAAMP,YAGhBoC,EAAIhd,KAAK,KAAK6d,EAAiB,UAE/Bb,EAAIhd,KAAK,MAIV,OACD,KAAK4X,EACL,KAAKE,EAEJ,IADIqD,EAAQpK,EAAK4J,WACXQ,GACLmC,GAAkBnC,EAAO6B,EAAKvN,EAAQsN,EAAYK,EAAkB3a,SACpE0Y,EAAQA,EAAMP,YAEf,OACD,KAAKvD,EACJ,OAAOoG,GAAuBT,EAAKjM,EAAKzG,KAAMyG,EAAK9L,OACpD,KAAKqS,EAgBJ,OAAO0F,EAAIhd,KAAK+Q,EAAKwD,KACnBhG,QAAQ,QAAQgM,GAChBhM,QAAQ,OAAQ,WAEnB,KAAKgJ,EACJ,OAAOyF,EAAIhd,KAAM,YAAY+Q,EAAKwD,KAAK,OACxC,KAAKoD,EACJ,OAAOqF,EAAIhd,KAAM,UAAO+Q,EAAKwD,KAAK,UACnC,KAAKsD,EACJ,IAAIoG,EAAQlN,EAAK0E,SACbyI,EAAQnN,EAAKI,SAEjB,GADA6L,EAAIhd,KAAK,aAAa+Q,EAAKzG,MACxB2T,EACFjB,EAAIhd,KAAK,WAAYie,GACjBC,GAAgB,KAAPA,GACZlB,EAAIhd,KAAK,IAAKke,GAEflB,EAAIhd,KAAK,UACJ,GAAGke,GAAgB,KAAPA,EACjBlB,EAAIhd,KAAK,WAAYke,EAAO,SACxB,CACJ,IAAIC,EAAMpN,EAAKqN,eACZD,GACFnB,EAAIhd,KAAK,KAAKme,EAAI,KAEnBnB,EAAIhd,KAAK,KAEV,OACD,KAAK0X,EACJ,OAAOsF,EAAIhd,KAAM,KAAK+Q,EAAKuD,OAAO,IAAIvD,EAAKwD,KAAK,MACjD,KAAKiD,EACJ,OAAOwF,EAAIhd,KAAM,IAAI+Q,EAAK6M,SAAS,KAGpC,QACCZ,EAAIhd,KAAK,KAAK+Q,EAAK6M,WAGrB,SAASS,GAAWzM,EAAIb,EAAKuN,GAC5B,IAAIC,EACJ,OAAQxN,EAAK8K,UACb,KAAKzE,GACJmH,EAAQxN,EAAKyN,WAAU,IACjBhF,cAAgB5H,EAMvB,KAAKkG,EACJ,MACD,KAAKT,EACJiH,GAAO,EAsBR,GALIC,IACHA,EAAQxN,EAAKyN,WAAU,IAExBD,EAAM/E,cAAgB5H,EACtB2M,EAAMtK,WAAa,KAChBqK,EAEF,IADA,IAAInD,EAAQpK,EAAK4J,WACXQ,GACLoD,EAAM5M,YAAY0M,GAAWzM,EAAIuJ,EAAMmD,IACvCnD,EAAQA,EAAMP,YAGhB,OAAO2D,EAKR,SAASC,GAAU5M,EAAIb,EAAKuN,GAC3B,IAAIC,EAAQ,IAAIxN,EAAKmG,YACrB,IAAI,IAAIvI,KAAKoC,EAAK,CACjB,IAAI1G,EAAI0G,EAAKpC,GACE,iBAALtE,GACNA,GAAKkU,EAAM5P,KACb4P,EAAM5P,GAAKtE,GAQd,OAJG0G,EAAKmK,aACPqD,EAAMrD,WAAa,IAAIlC,GAExBuF,EAAM/E,cAAgB5H,EACd2M,EAAM1C,UACd,KAAKzE,EACJ,IAAIhE,EAAQrC,EAAK4M,WACbc,EAASF,EAAMZ,WAAa,IAAIhE,EAChCpa,EAAM6T,EAAM5T,OAChBif,EAAOC,cAAgBH,EACvB,IAAI,IAAIjf,EAAE,EAAEA,EAAEC,EAAID,IACjBif,EAAM1K,iBAAiB2K,GAAU5M,EAAIwB,EAAMpF,KAAK1O,IAAG,IAEpD,MACD,KAAK+X,EACJiH,GAAO,EAER,GAAGA,EAEF,IADA,IAAInD,EAAQpK,EAAK4J,WACXQ,GACLoD,EAAM5M,YAAY6M,GAAU5M,EAAIuJ,EAAMmD,IACtCnD,EAAQA,EAAMP,YAGhB,OAAO2D,EAGR,SAAS7E,GAAQrK,EAAOrD,EAAI/G,GAC3BoK,EAAOrD,GAAO/G,EA9xCiB+S,EAAc2G,mBAA8B1G,EAAiB,IAAI,gBAAiB,IAClFD,EAAc4G,YAA8B3G,EAAiB,IAAI,eAAgB,IACjFD,EAAc6G,0BAA8B5G,EAAiB,IAAI,uBAAwB,IACzFD,EAAc8G,eAA6B7G,EAAiB,IAAI,oBAAqB,IACrFD,EAAc+G,oBAA6B9G,EAAiB,IAAI,iBAAkB,IAqBlHW,EAAa7Z,UAAY+C,MAAM/C,UAC/B4X,EAAKqB,EAAcY,GASnBI,EAASja,UAAY,CAKpBS,OAAO,EASPwO,KAAM,SAAS5F,GACd,OAAOtK,KAAKsK,IAAU,MAEvB4W,SAAS,SAASvP,EAAOsN,GACxB,IAAI,IAAIC,EAAM,GAAI1d,EAAI,EAAEA,EAAExB,KAAK0B,OAAOF,IACrCge,GAAkBxf,KAAKwB,GAAG0d,EAAIvN,EAAOsN,GAEtC,OAAOC,EAAI3V,KAAK,MAmBlB4R,EAAala,UAAUiP,KAAO,SAAS1O,GAEtC,OADA+Z,EAAgBvb,MACTA,KAAKwB,IAGbwX,EAASmC,EAAaD,GA0DtBW,EAAa5a,UAAY,CACxBS,OAAO,EACPwO,KAAKgL,EAASja,UAAUiP,KACxBiR,aAAc,SAASjT,GAMtB,IADA,IAAI1M,EAAIxB,KAAK0B,OACPF,KAAI,CACT,IAAIkU,EAAO1V,KAAKwB,GAEhB,GAAGkU,EAAKoK,UAAY5R,EACnB,OAAOwH,IAIV0L,aAAc,SAAS1L,GACtB,IAAIrE,EAAKqE,EAAKwG,aACd,GAAG7K,GAAMA,GAAIrR,KAAK4gB,cACjB,MAAM,IAAI9F,EAAaF,GAExB,IAAIqB,EAAUjc,KAAKmhB,aAAazL,EAAKoK,UAErC,OADA/D,EAAc/b,KAAK4gB,cAAc5gB,KAAK0V,EAAKuG,GACpCA,GAGRoF,eAAgB,SAAS3L,GACxB,IAA4BuG,EAAxB5K,EAAKqE,EAAKwG,aACd,GAAG7K,GAAMA,GAAIrR,KAAK4gB,cACjB,MAAM,IAAI9F,EAAaF,GAIxB,OAFAqB,EAAUjc,KAAKshB,eAAe5L,EAAKP,aAAaO,EAAKN,WACrD2G,EAAc/b,KAAK4gB,cAAc5gB,KAAK0V,EAAKuG,GACpCA,GAIRsF,gBAAiB,SAASrT,GACzB,IAAIwH,EAAO1V,KAAKmhB,aAAajT,GAE7B,OADAoO,EAAiBtc,KAAK4gB,cAAc5gB,KAAK0V,GAClCA,GAMR8L,kBAAkB,SAASrM,EAAaC,GACvC,IAAIM,EAAO1V,KAAKshB,eAAenM,EAAaC,GAE5C,OADAkH,EAAiBtc,KAAK4gB,cAAc5gB,KAAK0V,GAClCA,GAER4L,eAAgB,SAASnM,EAAcC,GAEtC,IADA,IAAI5T,EAAIxB,KAAK0B,OACPF,KAAI,CACT,IAAIyR,EAAOjT,KAAKwB,GAChB,GAAGyR,EAAKmC,WAAaA,GAAanC,EAAKkC,cAAgBA,EACtD,OAAOlC,EAGT,OAAO,OAsBTR,EAAkBxR,UAAY,CAgB7BwgB,WAAY,SAASC,EAASzQ,GAC5B,OAAO,GAwBT+D,eAAgB,SAASG,EAAeyK,EAAe5H,GACtD,IAAIlE,EAAM,IAAIiJ,EAOd,GANAjJ,EAAI+D,eAAiB7X,KACrB8T,EAAIsJ,WAAa,IAAIlC,EACrBpH,EAAIkE,QAAUA,GAAW,KACrBA,GACHlE,EAAID,YAAYmE,GAEb4H,EAAc,CACjB,IAAIvgB,EAAOyU,EAAIyB,gBAAgBJ,EAAcyK,GAC7C9L,EAAID,YAAYxU,GAEjB,OAAOyU,GAuBRgE,mBAAoB,SAAS8H,EAAejI,EAAUtE,GACrD,IAAIJ,EAAO,IAAIwL,EAMf,OALAxL,EAAKzG,KAAOoT,EACZ3M,EAAK6M,SAAWF,EAChB3M,EAAK0E,SAAWA,GAAY,GAC5B1E,EAAKI,SAAWA,GAAY,GAErBJ,IAYTuJ,EAAKvb,UAAY,CAChB4b,WAAa,KACba,UAAY,KACZF,gBAAkB,KAClBV,YAAc,KACd+C,WAAa,KACb1J,WAAa,KACbiH,WAAa,KACb1B,cAAgB,KAChB5F,UAAY,KACZX,aAAe,KACfkB,OAAS,KACTjB,UAAY,KAEZuM,aAAa,SAASzE,EAAU0E,GAC/B,OAAOjE,EAAc3d,KAAKkd,EAAS0E,IAEpCC,aAAa,SAAS3E,EAAU4E,GAC/B9hB,KAAK2hB,aAAazE,EAAS4E,GACxBA,GACF9hB,KAAK8d,YAAYgE,IAGnBhE,YAAY,SAASgE,GACpB,OAAOxE,EAAatd,KAAK8hB,IAE1BjO,YAAY,SAASqJ,GACpB,OAAOld,KAAK2hB,aAAazE,EAAS,OAEnC6E,cAAc,WACb,OAA0B,MAAnB/hB,KAAK6c,YAEb6D,UAAU,SAASF,GAClB,OAAOE,GAAU1gB,KAAK0b,eAAe1b,KAAKA,KAAKwgB,IAGhDpJ,UAAU,WAET,IADA,IAAIiG,EAAQrd,KAAK6c,WACXQ,GAAM,CACX,IAAII,EAAOJ,EAAMP,YACdW,GAAQA,EAAKM,UAAYvE,GAAa6D,EAAMU,UAAYvE,GAC1DxZ,KAAK8d,YAAYL,GACjBJ,EAAM2E,WAAWvE,EAAKhH,QAEtB4G,EAAMjG,YACNiG,EAAQI,KAKXwE,YAAY,SAASP,EAASzQ,GAC7B,OAAOjR,KAAK0b,cAAc7D,eAAe4J,WAAWC,EAAQzQ,IAG1DiR,cAAc,WACb,OAAOliB,KAAK6f,WAAWne,OAAO,GAgB/B2d,aAAa,SAASlK,GAErB,IADA,IAAI9D,EAAKrR,KACHqR,GAAG,CACR,IAAInK,EAAMmK,EAAG+K,OAEb,GAAGlV,EACF,IAAI,IAAI2J,KAAK3J,EACZ,GAAGA,EAAI2J,IAAMsE,EACZ,OAAOtE,EAIVQ,EAAKA,EAAG0M,UAAYxE,EAAelI,EAAGqK,cAAgBrK,EAAG8E,WAE1D,OAAO,MAGRgM,mBAAmB,SAAS9L,GAE3B,IADA,IAAIhF,EAAKrR,KACHqR,GAAG,CACR,IAAInK,EAAMmK,EAAG+K,OAEb,GAAGlV,GACCmP,KAAUnP,EACZ,OAAOA,EAAImP,GAGbhF,EAAKA,EAAG0M,UAAYxE,EAAelI,EAAGqK,cAAgBrK,EAAG8E,WAE1D,OAAO,MAGRiM,mBAAmB,SAASjN,GAE3B,OAAiB,MADJnV,KAAKqf,aAAalK,KAepC0D,EAAKQ,EAASmD,GACd3D,EAAKQ,EAASmD,EAAKvb,WAoJnB8b,EAAS9b,UAAY,CAEpB6e,SAAY,YACZ/B,SAAYjE,EAOZ9B,QAAW,KACXoH,gBAAmB,KACnB3D,KAAO,EAEPkG,aAAgB,SAASzE,EAAU0E,GAClC,GAAG1E,EAASa,UAAY/D,EAAuB,CAE9C,IADA,IAAIqD,EAAQH,EAASL,WACfQ,GAAM,CACX,IAAII,EAAOJ,EAAMP,YACjB9c,KAAK2hB,aAAatE,EAAMuE,GACxBvE,EAAQI,EAET,OAAOP,EAMR,OAJ2B,MAAxBld,KAAKof,iBAA2BlC,EAASa,UAAYzE,IACvDtZ,KAAKof,gBAAkBlC,GAGjBS,EAAc3d,KAAKkd,EAAS0E,GAAW1E,EAASxB,cAAgB1b,KAAMkd,GAE9EY,YAAe,SAASgE,GAIvB,OAHG9hB,KAAKof,iBAAmB0C,IAC1B9hB,KAAKof,gBAAkB,MAEjB9B,EAAatd,KAAK8hB,IAG1BvB,WAAa,SAAS8B,EAAa7B,GAClC,OAAOD,GAAWvgB,KAAKqiB,EAAa7B,IAGrC8B,eAAiB,SAASjd,GACzB,IAAIkd,EAAM,KASV,OARA5F,EAAW3c,KAAKof,iBAAgB,SAASnM,GACxC,GAAGA,EAAK8K,UAAYzE,GAChBrG,EAAKuP,aAAa,OAASnd,EAE7B,OADAkd,EAAMtP,GACC,KAIHsP,GAoBRE,uBAAwB,SAASC,GAChC,IAAIC,EAAgBjK,EAAagK,GACjC,OAAO,IAAIvH,EAAanb,MAAM,SAAS4iB,GACtC,IAAIjH,EAAK,GAoBT,OAnBIgH,EAAcjhB,OAAS,GAC1Bib,EAAWiG,EAAKxD,iBAAiB,SAASnM,GACzC,GAAGA,IAAS2P,GAAQ3P,EAAK8K,WAAazE,EAAc,CACnD,IAAIuJ,EAAiB5P,EAAKuP,aAAa,SAEvC,GAAIK,EAAgB,CAEnB,IAAIC,EAAUJ,IAAeG,EAC7B,IAAKC,EAAS,CACb,IAAIC,EAAoBrK,EAAamK,GACrCC,EAAUH,EAAcK,OA1tBRrK,EA0tB4BoK,EAztB5C,SAASvK,GACf,OAAOG,IAAmC,IAA3BA,EAAKtV,QAAQmV,MA0tBpBsK,GACFnH,EAAGzZ,KAAK+Q,IA7tBhB,IAAwB0F,KAmuBdgD,MAKTsH,cAAgB,SAAS/M,GACxB,IAAIjD,EAAO,IAAIkL,EAQf,OAPAlL,EAAKyI,cAAgB1b,KACrBiT,EAAK6M,SAAW5J,EAChBjD,EAAKiD,QAAUA,EACfjD,EAAKmC,UAAYc,EACjBjD,EAAKmK,WAAa,IAAIlC,GACVjI,EAAK4M,WAAa,IAAIhE,GAC5B+E,cAAgB3N,EACfA,GAERiQ,uBAAyB,WACxB,IAAIjQ,EAAO,IAAI4L,GAGf,OAFA5L,EAAKyI,cAAgB1b,KACrBiT,EAAKmK,WAAa,IAAIlC,EACfjI,GAERgE,eAAiB,SAASR,GACzB,IAAIxD,EAAO,IAAIqL,EAGf,OAFArL,EAAKyI,cAAgB1b,KACrBiT,EAAK+O,WAAWvL,GACTxD,GAERsE,cAAgB,SAASd,GACxB,IAAIxD,EAAO,IAAIsL,EAGf,OAFAtL,EAAKyI,cAAgB1b,KACrBiT,EAAK+O,WAAWvL,GACTxD,GAER+D,mBAAqB,SAASP,GAC7B,IAAIxD,EAAO,IAAIuL,EAGf,OAFAvL,EAAKyI,cAAgB1b,KACrBiT,EAAK+O,WAAWvL,GACTxD,GAER0D,4BAA8B,SAASH,EAAOC,GAC7C,IAAIxD,EAAO,IAAI6L,GAIf,OAHA7L,EAAKyI,cAAgB1b,KACrBiT,EAAKiD,QAAUjD,EAAKuD,OAASA,EAC7BvD,EAAK6C,UAAW7C,EAAKwD,KAAOA,EACrBxD,GAERkQ,gBAAkB,SAAS3W,GAC1B,IAAIyG,EAAO,IAAImL,EAMf,OALAnL,EAAKyI,cAAgB1b,KACrBiT,EAAKzG,KAAOA,EACZyG,EAAK6M,SAAWtT,EAChByG,EAAKmC,UAAY5I,EACjByG,EAAKmQ,WAAY,EACVnQ,GAERoQ,sBAAwB,SAAS7W,GAChC,IAAIyG,EAAO,IAAI2L,EAGf,OAFA3L,EAAKyI,cAAgB1b,KACrBiT,EAAK6M,SAAWtT,EACTyG,GAGRsC,gBAAkB,SAASJ,EAAayK,GACvC,IAAI3M,EAAO,IAAIkL,EACXmF,EAAK1D,EAAc1b,MAAM,KACzBoR,EAAQrC,EAAK4M,WAAa,IAAIhE,EAclC,OAbA5I,EAAKmK,WAAa,IAAIlC,EACtBjI,EAAKyI,cAAgB1b,KACrBiT,EAAK6M,SAAWF,EAChB3M,EAAKiD,QAAU0J,EACf3M,EAAKkC,aAAeA,EACJ,GAAbmO,EAAG5hB,QACLuR,EAAKoD,OAASiN,EAAG,GACjBrQ,EAAKmC,UAAYkO,EAAG,IAGpBrQ,EAAKmC,UAAYwK,EAElBtK,EAAMsL,cAAgB3N,EACfA,GAGR2C,kBAAoB,SAAST,EAAayK,GACzC,IAAI3M,EAAO,IAAImL,EACXkF,EAAK1D,EAAc1b,MAAM,KAa7B,OAZA+O,EAAKyI,cAAgB1b,KACrBiT,EAAK6M,SAAWF,EAChB3M,EAAKzG,KAAOoT,EACZ3M,EAAKkC,aAAeA,EACpBlC,EAAKmQ,WAAY,EACD,GAAbE,EAAG5hB,QACLuR,EAAKoD,OAASiN,EAAG,GACjBrQ,EAAKmC,UAAYkO,EAAG,IAGpBrQ,EAAKmC,UAAYwK,EAEX3M,IAGT+F,EAAS+D,EAASP,GAMlB2B,EAAQld,UAAY,CACnB8c,SAAWzE,EACXiK,aAAe,SAAS/W,GACvB,OAAoC,MAA7BxM,KAAKwjB,iBAAiBhX,IAE9BgW,aAAe,SAAShW,GACvB,IAAIkJ,EAAO1V,KAAKwjB,iBAAiBhX,GACjC,OAAOkJ,GAAQA,EAAKvO,OAAS,IAE9Bqc,iBAAmB,SAAShX,GAC3B,OAAOxM,KAAK6f,WAAWsB,aAAa3U,IAErCiX,aAAe,SAASjX,EAAMrF,GAC7B,IAAIuO,EAAO1V,KAAK0b,cAAcyH,gBAAgB3W,GAC9CkJ,EAAKvO,MAAQuO,EAAKI,UAAY,GAAK3O,EACnCnH,KAAK+V,iBAAiBL,IAEvBgO,gBAAkB,SAASlX,GAC1B,IAAIkJ,EAAO1V,KAAKwjB,iBAAiBhX,GACjCkJ,GAAQ1V,KAAK2jB,oBAAoBjO,IAIlC7B,YAAY,SAASqJ,GACpB,OAAGA,EAASa,WAAa/D,EACjBha,KAAK2hB,aAAazE,EAAS,MAvPrC,SAA4B/G,EAAW+G,GACtC,IAAIW,EAAKX,EAAS/G,WAClB,GAAG0H,EAAG,CACL,IAAIK,EAAM/H,EAAWuH,UACrBG,EAAGC,YAAYZ,GACXgB,EAAM/H,EAAWuH,UAatB,OAXIQ,EAAM/H,EAAWuH,UACrBR,EAAS/G,WAAaA,EACtB+G,EAASM,gBAAkBU,EAC3BhB,EAASJ,YAAc,KACpBoB,EACFA,EAAIpB,YAAcI,EAElB/G,EAAW0G,WAAaK,EAEzB/G,EAAWuH,UAAYR,EACvBD,EAAe9G,EAAWuF,cAAcvF,EAAW+G,GAC5CA,EAuOE0G,CAAmB5jB,KAAKkd,IAGjCnH,iBAAmB,SAASiG,GAC3B,OAAOhc,KAAK6f,WAAWuB,aAAapF,IAErC6H,mBAAqB,SAAS7H,GAC7B,OAAOhc,KAAK6f,WAAWwB,eAAerF,IAEvC2H,oBAAsB,SAAS1H,GAE9B,OAAOjc,KAAK6f,WAAW0B,gBAAgBtF,EAAQ6D,WAGhDgE,kBAAoB,SAAS3O,EAAcC,GAC1C,IAAI2O,EAAM/jB,KAAKgkB,mBAAmB7O,EAAcC,GAChD2O,GAAO/jB,KAAK2jB,oBAAoBI,IAGjCE,eAAiB,SAAS9O,EAAcC,GACvC,OAAyD,MAAlDpV,KAAKgkB,mBAAmB7O,EAAcC,IAE9C8O,eAAiB,SAAS/O,EAAcC,GACvC,IAAIM,EAAO1V,KAAKgkB,mBAAmB7O,EAAcC,GACjD,OAAOM,GAAQA,EAAKvO,OAAS,IAE9Bgd,eAAiB,SAAShP,EAAcyK,EAAezY,GACtD,IAAIuO,EAAO1V,KAAK0b,cAAc9F,kBAAkBT,EAAcyK,GAC9DlK,EAAKvO,MAAQuO,EAAKI,UAAY,GAAK3O,EACnCnH,KAAK+V,iBAAiBL,IAEvBsO,mBAAqB,SAAS7O,EAAcC,GAC3C,OAAOpV,KAAK6f,WAAWyB,eAAenM,EAAcC,IAGrDgP,qBAAuB,SAASlO,GAC/B,OAAO,IAAIiF,EAAanb,MAAK,SAAS4iB,GACrC,IAAIjH,EAAK,GAMT,OALAgB,EAAWiG,GAAK,SAAS3P,GACrBA,IAAS2P,GAAQ3P,EAAK8K,UAAYzE,GAA6B,MAAZpD,GAAmBjD,EAAKiD,SAAWA,GACxFyF,EAAGzZ,KAAK+Q,MAGH0I,MAGT0I,uBAAyB,SAASlP,EAAcC,GAC/C,OAAO,IAAI+F,EAAanb,MAAK,SAAS4iB,GACrC,IAAIjH,EAAK,GAMT,OALAgB,EAAWiG,GAAK,SAAS3P,GACrBA,IAAS2P,GAAQ3P,EAAK8K,WAAazE,GAAkC,MAAjBnE,GAAwBlC,EAAKkC,eAAiBA,GAAgC,MAAdC,GAAqBnC,EAAKmC,WAAaA,GAC7JuG,EAAGzZ,KAAK+Q,MAGH0I,OAKVoB,EAAS9b,UAAUmjB,qBAAuBjG,EAAQld,UAAUmjB,qBAC5DrH,EAAS9b,UAAUojB,uBAAyBlG,EAAQld,UAAUojB,uBAG9DrL,EAASmF,EAAQ3B,GAGjB4B,EAAKnd,UAAU8c,SAAWxE,EAC1BP,EAASoF,EAAK5B,GAKd6B,EAAcpd,UAAY,CACzBwV,KAAO,GACP6N,cAAgB,SAASC,EAAQtiB,GAChC,OAAOjC,KAAKyW,KAAKtG,UAAUoU,EAAQA,EAAOtiB,IAE3C+f,WAAY,SAAShgB,GACpBA,EAAOhC,KAAKyW,KAAKzU,EACjBhC,KAAK8V,UAAY9V,KAAKyW,KAAOzU,EAC7BhC,KAAK0B,OAASM,EAAKN,QAEpB8iB,WAAY,SAASD,EAAOviB,GAC3BhC,KAAKykB,YAAYF,EAAO,EAAEviB,IAG3B6R,YAAY,SAASqJ,GACpB,MAAM,IAAIlZ,MAAMmW,EAAiBC,KAElCsK,WAAY,SAASH,EAAQtiB,GAC5BjC,KAAKykB,YAAYF,EAAOtiB,EAAM,KAE/BwiB,YAAa,SAASF,EAAQtiB,EAAOD,GAGpCA,EAFYhC,KAAKyW,KAAKtG,UAAU,EAAEoU,GAEnBviB,EADLhC,KAAKyW,KAAKtG,UAAUoU,EAAOtiB,GAErCjC,KAAK8V,UAAY9V,KAAKyW,KAAOzU,EAC7BhC,KAAK0B,OAASM,EAAKN,SAGrBsX,EAASqF,EAAc7B,GAGvB8B,EAAKrd,UAAY,CAChB6e,SAAW,QACX/B,SAAWvE,EACXmL,UAAY,SAASJ,GACpB,IAAIviB,EAAOhC,KAAKyW,KACZmO,EAAU5iB,EAAKmO,UAAUoU,GAC7BviB,EAAOA,EAAKmO,UAAU,EAAGoU,GACzBvkB,KAAKyW,KAAOzW,KAAK8V,UAAY9T,EAC7BhC,KAAK0B,OAASM,EAAKN,OACnB,IAAImjB,EAAU7kB,KAAK0b,cAAczE,eAAe2N,GAIhD,OAHG5kB,KAAKmW,YACPnW,KAAKmW,WAAWwL,aAAakD,EAAS7kB,KAAK8c,aAErC+H,IAGT7L,EAASsF,EAAKD,GAGdE,EAAQtd,UAAY,CACnB6e,SAAW,WACX/B,SAAWlE,GAEZb,EAASuF,EAAQF,GAIjBG,EAAavd,UAAY,CACxB6e,SAAW,iBACX/B,SAAWtE,GAEZT,EAASwF,EAAaH,GAKtBI,EAAaxd,UAAU8c,SAAWhE,EAClCf,EAASyF,EAAajC,GAItBkC,EAASzd,UAAU8c,SAAW9D,EAC9BjB,EAAS0F,EAASlC,GAIlBmC,EAAO1d,UAAU8c,SAAWpE,EAC5BX,EAAS2F,EAAOnC,GAIhBoC,EAAgB3d,UAAU8c,SAAWrE,EACrCV,EAAS4F,EAAgBpC,GAIzBqC,GAAiB5d,UAAU6e,SAAW,qBACtCjB,GAAiB5d,UAAU8c,SAAW/D,EACtChB,EAAS6F,GAAiBrC,GAK1BsC,GAAsB7d,UAAU8c,SAAWnE,EAC3CZ,EAAS8F,GAAsBtC,GAE/BpE,GAAcnX,UAAUue,kBAAoB,SAASvM,EAAK+L,EAAOC,GAChE,OAAOF,GAAsBna,KAAKqO,EAAK+L,EAAOC,IAE/CzC,EAAKvb,UAAUigB,SAAWnC,GA0U1B,IACC,GAAG3e,OAAO0kB,eAAe,CAiCxB,SAASC,GAAe9R,GACvB,OAAOA,EAAK8K,UACZ,KAAKzE,EACL,KAAKU,EACJ,IAAIkF,EAAM,GAEV,IADAjM,EAAOA,EAAK4J,WACN5J,GACc,IAAhBA,EAAK8K,UAAiC,IAAjB9K,EAAK8K,UAC5BmB,EAAIhd,KAAK6iB,GAAe9R,IAEzBA,EAAOA,EAAK6J,YAEb,OAAOoC,EAAI3V,KAAK,IACjB,QACC,OAAO0J,EAAK6C,WA9Cd1V,OAAO0kB,eAAe3J,EAAala,UAAU,SAAS,CACrD+jB,IAAI,WAEH,OADAzJ,EAAgBvb,MACTA,KAAKilB,YAId7kB,OAAO0kB,eAAetI,EAAKvb,UAAU,cAAc,CAClD+jB,IAAI,WACH,OAAOD,GAAe/kB,OAGvBklB,IAAI,SAASzO,GACZ,OAAOzW,KAAK+d,UACZ,KAAKzE,EACL,KAAKU,EACJ,KAAMha,KAAK6c,YACV7c,KAAK8d,YAAY9d,KAAK6c,aAEpBpG,GAAQ5H,OAAO4H,KACjBzW,KAAK6T,YAAY7T,KAAK0b,cAAczE,eAAeR,IAEpD,MAED,QACCzW,KAAKyW,KAAOA,EACZzW,KAAKmH,MAAQsP,EACbzW,KAAK8V,UAAYW,MAuBpBmF,GAAU,SAASrK,EAAOrD,EAAI/G,GAE7BoK,EAAO,KAAKrD,GAAO/G,IAGrB,MAAM4F,IAINxN,EAAQkf,aAAeA,EACvBlf,EAAQub,aAAeA,EACvBvb,EAAQkT,kBAAoBA,EAC5BlT,EAAQ4e,QAAUA,EAClB5e,EAAQid,KAAOA,EACfjd,EAAQ2b,SAAWA,EACnB3b,EAAQ6Y,cAAgBA,iBC19CzB,IAAI9G,EAAS,cASb/R,EAAQgV,aAAejD,EAAO,CAAC6T,IAAI,IAAKC,KAAK,IAAKC,GAAG,IAAKC,GAAG,IAAKC,KAAK,MAevEhmB,EAAQ+U,cAAgBhD,EAAO,CACxBgU,GAAI,IACJD,GAAI,IACJF,IAAK,IACLI,KAAM,IACNH,KAAM,IACNI,OAAQ,IACRC,OAAQ,IACRC,MAAO,IACPC,OAAQ,IACRC,KAAM,IACNC,MAAO,IACPC,MAAO,IACPC,OAAQ,IACRC,OAAQ,IACRC,OAAQ,IACRC,MAAO,IACPC,KAAM,IACNC,OAAQ,IACRC,OAAQ,IACRC,MAAO,IACPC,KAAM,IACNC,IAAK,IACLC,OAAQ,IACRC,OAAQ,IACRC,OAAQ,IACRC,MAAO,IACPC,OAAQ,IACRC,KAAM,IACNC,OAAQ,IACRC,OAAQ,IACRC,OAAQ,IACRC,MAAO,IACPC,KAAM,IACNC,OAAQ,IACRC,MAAO,IACPC,MAAO,IACPC,OAAQ,IACRC,OAAQ,IACRC,MAAO,IACPC,OAAQ,IACRC,KAAM,IACNC,MAAO,IACPC,MAAO,IACPC,OAAQ,IACRC,OAAQ,IACRC,OAAQ,IACRC,MAAO,IACPC,KAAM,IACNC,OAAQ,IACRC,OAAQ,IACRC,MAAO,IACPC,KAAM,IACNC,IAAK,IACLC,OAAQ,IACRC,OAAQ,IACRC,OAAQ,IACRC,MAAO,IACPC,OAAQ,IACRC,KAAM,IACNC,OAAQ,IACRC,OAAQ,IACRC,OAAQ,IACRC,MAAO,IACPC,KAAM,IACNC,OAAQ,IACRC,MAAO,IACPC,KAAM,IACNC,KAAM,IACNC,MAAO,IACPC,KAAM,IACNC,MAAO,IACPC,OAAQ,IACRC,IAAK,IACLC,OAAQ,IACRC,KAAM,IACNC,IAAK,IACLjR,KAAM,IACNkR,KAAM,IACNC,MAAO,IACPC,IAAK,IACLC,IAAK,KACLzd,IAAK,IACL0d,KAAM,IACNC,IAAK,IACLC,OAAQ,IACRC,KAAM,IACNC,KAAM,IACNC,MAAO,IACPC,MAAO,IACPC,KAAM,IACNC,OAAQ,IACRC,MAAO,IACPC,KAAM,IACNC,KAAM,IACNC,MAAO,IACPC,OAAQ,IACRC,OAAQ,IACRC,OAAQ,IACRC,OAAQ,IACRC,MAAO,IACPC,OAAQ,IACRC,OAAQ,IACRC,KAAM,IACNC,MAAO,IACPC,MAAO,IACPC,MAAO,IACPC,KAAM,IACNC,MAAO,IACPC,GAAI,IACJC,KAAM,IACNC,IAAK,IACLC,MAAO,IACPC,OAAQ,IACRC,MAAO,IACPC,KAAM,IACNC,MAAO,IACPC,IAAK,IACLC,IAAK,IACLC,GAAI,IACJC,IAAK,IACLC,IAAK,IACL,IAAO,IACPC,OAAQ,IACRC,IAAK,IACLC,KAAM,IACNC,MAAO,IACPC,GAAI,IACJC,MAAO,IACPC,GAAI,IACJC,GAAI,IACJ5M,IAAK,IACL6M,IAAK,IACLC,KAAM,IACNC,KAAM,IACNC,KAAM,IACNC,MAAO,IACPC,OAAQ,IACRC,KAAM,IACNC,KAAM,IACNC,MAAO,IACPC,KAAM,IACNC,MAAO,IACPC,MAAO,IACPC,QAAS,IACTC,KAAM,IACNC,IAAK,IACLC,MAAO,IACPC,KAAM,IACNC,MAAO,IACPC,OAAQ,IACRC,GAAI,IACJC,GAAI,IACJC,GAAI,IACJC,QAAS,IACTC,GAAI,IACJC,IAAK,IACLC,MAAO,IACPC,IAAK,IACLC,QAAS,IACTC,IAAK,IACLC,IAAK,IACLC,IAAK,IACLC,MAAO,IACPC,MAAO,IACPC,KAAM,IACNC,MAAO,IACPC,MAAO,IACPC,QAAS,IACTC,KAAM,IACNC,IAAK,IACLC,MAAO,IACPC,KAAM,IACNC,MAAO,IACPC,OAAQ,IACRC,GAAI,IACJC,GAAI,IACJC,GAAI,IACJC,QAAS,IACTC,GAAI,IACJC,IAAK,IACLC,OAAQ,IACRC,MAAO,IACPC,IAAK,IACLC,QAAS,IACTC,IAAK,IACLC,IAAK,IACLC,IAAK,IACLC,MAAO,IACPC,SAAU,IACVC,MAAO,IACPC,IAAK,IACLC,MAAO,IACPC,MAAO,IACPC,OAAQ,IACRC,OAAQ,IACRC,KAAM,IACNC,KAAM,IACNC,KAAM,IACNC,MAAO,IACPC,KAAM,IACNC,KAAM,IACNC,OAAQ,IACRC,KAAM,IACNC,IAAK,IACLC,IAAK,IACLC,IAAK,IACLC,MAAO,IACPC,MAAO,IACPC,MAAO,IACPC,MAAO,IACPC,MAAO,IACPC,MAAO,IACPC,MAAO,IACPC,MAAO,IACPC,OAAQ,IACRC,OAAQ,IACRC,KAAM,IACNC,OAAQ,IACRC,OAAQ,IACRC,MAAO,IACPC,MAAO,IACPC,OAAQ,IACRC,OAAQ,IACRC,MAAO,IACPC,KAAM,IACNC,MAAO,IACPC,KAAM,IACNC,KAAM,IACNC,KAAM,IACNC,KAAM,IACNC,KAAM,IACNC,MAAO,IACPC,MAAO,IACPC,MAAO,IACPC,OAAQ,IACRC,OAAQ,IACRC,IAAK,IACLC,OAAQ,IACRC,MAAO,IACPC,OAAQ,IACRC,MAAO,MAOdx0B,EAAQ8U,UAAY9U,EAAQ+U,iCChRxBhC,EAAM,EAAQ,KAClB/S,EAAQ,EAAoB+S,EAAIG,kBACRH,EAAI8F,cAC5B7Y,EAAQqT,UAAY,EAApB,8BCHA,IAAIZ,EAAY,iBAKZgiB,EAAgB,mJAChBC,EAAW,IAAIjmB,OAAO,aAAagmB,EAAc3nB,OAAO1H,MAAM,GAAG,GAAG,0CACpEuvB,EAAiB,IAAIlmB,OAAO,IAAIgmB,EAAc3nB,OAAO4nB,EAAS5nB,OAAO,QAAS2nB,EAAc3nB,OAAO4nB,EAAS5nB,OAAO,QAsBvH,SAASqG,EAAWsI,EAASnI,GAC5B7S,KAAKgb,QAAUA,EACfhb,KAAK6S,QAAUA,EACZ7O,MAAMiX,mBAAmBjX,MAAMiX,kBAAkBjb,KAAM0S,GAK3D,SAASC,KAiLT,SAASwhB,EAAYC,EAAEpvB,GAGtB,OAFAA,EAAEkO,WAAakhB,EAAElhB,WACjBlO,EAAEmO,aAAeihB,EAAEjhB,aACZnO,EAOR,SAASqvB,EAAsBhoB,EAAOjK,EAAMiP,EAAGijB,EAAaC,EAAergB,GAO1E,SAASsgB,EAAaC,EAAOttB,EAAOutB,GAC/BrjB,EAAGsjB,eAAelc,eAAegc,IACpCvgB,EAAaiE,WAAW,aAAesc,EAAQ,cAEhDpjB,EAAGujB,SAASH,EAAOttB,EAAOutB,GAM3B,IAJA,IAAIG,EAEA7nB,IAAM5K,EACNyK,EAnOO,IAoOA,CACV,IAAIM,EAAId,EAAOyoB,OAAO9nB,GACtB,OAAOG,GACP,IAAK,IACJ,GAvOU,IAuOPN,EACFgoB,EAAWxoB,EAAO1H,MAAMvC,EAAM4K,GAC9BH,EAvOO,MAwOF,IAzOQ,IAyOLA,EAIR,MAAM,IAAI7I,MAAM,uCAHhB6I,EAzOO,EA8OR,MACD,IAAK,IACL,IAAK,IACJ,GAjPQ,IAiPLA,GAnPO,IAmPOA,EACf,CAOD,GA3PS,IAqPNA,IACFqH,EAAa+D,QAAQ,kCACrB4c,EAAWxoB,EAAO1H,MAAMvC,EAAM4K,IAE/B5K,EAAQ4K,EAAE,KACVA,EAAIX,EAAOhJ,QAAQ8J,EAAE/K,IAChB,GAMJ,MAAM,IAAI4B,MAAM,2BAA4BmJ,EAAE,WAJ9CqnB,EAAaK,EADb1tB,EAAQkF,EAAO1H,MAAMvC,EAAM4K,GAAGyD,QAAQ,WAAW8jB,GACnBnyB,EAAM,GACpCyK,EA1PY,MA+PR,IAhQiB,GAgQdA,EAUR,MAAM,IAAI7I,MAAM,kCAPhBwwB,EAAaK,EAFb1tB,EAAQkF,EAAO1H,MAAMvC,EAAM4K,GAAGyD,QAAQ,WAAW8jB,GAEnBnyB,GAE9B8R,EAAa+D,QAAQ,cAAc4c,EAAS,uBAAuB1nB,EAAE,OACrE/K,EAAQ4K,EAAE,EACVH,EAtQa,EA2Qd,MACD,IAAK,IACJ,OAAOA,GACP,KAnRS,EAoRRwE,EAAG0jB,WAAW1oB,EAAO1H,MAAMvC,EAAM4K,IAClC,KAhRc,EAiRd,KAhRe,EAiRf,KAhRe,EAiRdH,EAjRc,EAkRdwE,EAAG2jB,QAAS,EACb,KAtRuB,EAuRvB,KA1RU,EA2RV,KA1Rc,EA2Rb,MAED,QACC,MAAM,IAAIhxB,MAAM,qCAEjB,MACD,IAAK,GAKJ,OAJAkQ,EAAa7S,MAAM,2BApSV,GAqSNwL,GACFwE,EAAG0jB,WAAW1oB,EAAO1H,MAAMvC,EAAM4K,IAE3BA,EACR,IAAK,IACJ,OAAOH,GACP,KA3SS,EA4SRwE,EAAG0jB,WAAW1oB,EAAO1H,MAAMvC,EAAM4K,IAClC,KAxSc,EAySd,KAxSe,EAySf,KAxSe,EAySd,MACD,KA7SuB,EA8SvB,KAjTU,EAmTc,OADvB7F,EAAQkF,EAAO1H,MAAMvC,EAAM4K,IAClBrI,OAAO,KACf0M,EAAG2jB,QAAU,EACb7tB,EAAQA,EAAMxC,MAAM,GAAG,IAEzB,KAtTc,MAuTVkI,IACF1F,EAAQ0tB,GAtTa,GAwTnBhoB,GACFqH,EAAa+D,QAAQ,cAAc9Q,EAAM,qBACzCqtB,EAAaK,EAAU1tB,EAAMsJ,QAAQ,WAAW8jB,GAAiBnyB,KAE7D4P,EAAUL,OAAO2iB,EAAa,MAASntB,EAAM/C,MAAM,qCACtD8P,EAAa+D,QAAQ,cAAc9Q,EAAM,qBAAqBA,EAAM,eAErEqtB,EAAartB,EAAOA,EAAO/E,IAE5B,MACD,KAnUQ,EAoUP,MAAM,IAAI4B,MAAM,4BAGjB,OAAOgJ,EAER,IAAK,IACJG,EAAI,IACL,QACC,GAAGA,GAAI,IACN,OAAON,GACP,KAjVQ,EAkVPwE,EAAG0jB,WAAW1oB,EAAO1H,MAAMvC,EAAM4K,IACjCH,EA7Ua,EA8Ub,MACD,KApVS,EAqVRgoB,EAAWxoB,EAAO1H,MAAMvC,EAAM4K,GAC9BH,EArVY,EAsVZ,MACD,KArVsB,EAsVrB,IAAI1F,EAAQkF,EAAO1H,MAAMvC,EAAM4K,GAAGyD,QAAQ,WAAW8jB,GACrDrgB,EAAa+D,QAAQ,cAAc9Q,EAAM,sBACzCqtB,EAAaK,EAAU1tB,EAAO/E,GAC/B,KAxVa,EAyVZyK,EAxVa,OAoWd,OAAOA,GAIP,KA5Wa,EA6WGwE,EAAG6E,QACblE,EAAUL,OAAO2iB,EAAa,MAASO,EAASzwB,MAAM,qCAC1D8P,EAAa+D,QAAQ,cAAc4c,EAAS,qBAAqBA,EAAS,gBAE3EL,EAAaK,EAAUA,EAAUzyB,GACjCA,EAAQ4K,EACRH,EApXQ,EAqXR,MACD,KAlXa,EAmXZqH,EAAa+D,QAAQ,+BAA+B4c,EAAS,OAC9D,KAnXc,EAoXbhoB,EAzXQ,EA0XRzK,EAAQ4K,EACR,MACD,KA1XO,EA2XNH,EA1XqB,EA2XrBzK,EAAQ4K,EACR,MACD,KA1Xc,EA2Xb,MAAM,IAAIhJ,MAAM,+DAKnBgJ,KAMF,SAAS0G,EAAcrC,EAAG4C,EAAWqgB,GAKpC,IAJA,IAAIpe,EAAU7E,EAAG6E,QACb+e,EAAa,KAEbzzB,EAAI6P,EAAG3P,OACLF,KAAI,CACT,IAAI6L,EAAIgE,EAAG7P,GACP6T,EAAQhI,EAAEgI,MACVlO,EAAQkG,EAAElG,MAEd,IADI+tB,EAAM7f,EAAMhS,QAAQ,MACjB,EACN,IAAIgT,EAAShJ,EAAEgJ,OAAShB,EAAM1Q,MAAM,EAAEuwB,GAClC9f,EAAYC,EAAM1Q,MAAMuwB,EAAI,GAC5BC,EAAsB,UAAX9e,GAAsBjB,OAErCA,EAAYC,EACZgB,EAAS,KACT8e,EAAqB,UAAV9f,GAAqB,GAGjChI,EAAE+H,UAAYA,GAEE,IAAb+f,IACe,MAAdF,IACFA,EAAa,GAEbG,EAAMd,EAAaA,EAAa,KAGjCA,EAAaa,GAAYF,EAAWE,GAAYhuB,EAChDkG,EAAE4E,IAAMD,EAAUI,MAClB6B,EAAWmC,mBAAmB+e,EAAUhuB,IAI1C,IADI3F,EAAI6P,EAAG3P,OACLF,MAED6U,GADJhJ,EAAIgE,EAAG7P,IACQ6U,UAEA,QAAXA,IACFhJ,EAAE4E,IAAMD,EAAUG,KACJ,UAAXkE,IACHhJ,EAAE4E,IAAMqiB,EAAaje,GAAU,MAMlC,IAAI6e,GAAAA,EAAMhf,EAAQ7S,QAAQ,MACnB,GACNgT,EAAShF,EAAGgF,OAASH,EAAQvR,MAAM,EAAEuwB,GACrC9f,EAAY/D,EAAG+D,UAAYc,EAAQvR,MAAMuwB,EAAI,KAE7C7e,EAAS,KACTjB,EAAY/D,EAAG+D,UAAYc,GAG5B,IAAIwJ,EAAKrO,EAAGY,IAAMqiB,EAAaje,GAAU,IAIzC,GAHApC,EAAWiB,aAAawK,EAAGtK,EAAUc,EAAQ7E,IAG1CA,EAAG2jB,OAWL,OAHA3jB,EAAGijB,aAAeA,EAClBjjB,EAAG4jB,WAAaA,GAET,EATP,GADAhhB,EAAW+B,WAAW0J,EAAGtK,EAAUc,GAChC+e,EACF,IAAI5e,KAAU4e,EACbhhB,EAAWqC,iBAAiBD,GAUhC,SAASgf,EAAwBhpB,EAAOipB,EAAWpf,EAAQqe,EAAetgB,GACzE,GAAG,yBAAyB1E,KAAK2G,GAAS,CACzC,IAAIqf,EAAclpB,EAAOhJ,QAAQ,KAAK6S,EAAQ,IAAIof,GAC9CtzB,EAAOqK,EAAO8D,UAAUmlB,EAAW,EAAEC,GACzC,GAAG,OAAOhmB,KAAKvN,GACd,MAAG,YAAYuN,KAAK2G,IAGlBjC,EAAW6C,WAAW9U,EAAK,EAAEA,EAAKN,QAE3B6zB,IAGRvzB,EAAOA,EAAKyO,QAAQ,WAAW8jB,GAC/BtgB,EAAW6C,WAAW9U,EAAK,EAAEA,EAAKN,QAC3B6zB,GAKV,OAAOD,EAAW,EAEnB,SAASE,EAAcnpB,EAAOipB,EAAWpf,EAAQuf,GAEhD,IAAIC,EAAMD,EAASvf,GASnB,OARU,MAAPwf,KAEFA,EAAOrpB,EAAOspB,YAAY,KAAKzf,EAAQ,MAChCof,IACNI,EAAMrpB,EAAOspB,YAAY,KAAKzf,IAE/Buf,EAASvf,GAAUwf,GAEbA,EAAIJ,EAGZ,SAASF,EAAM/oB,EAAOmK,GACrB,IAAI,IAAI3F,KAAKxE,EAAQmK,EAAO3F,GAAKxE,EAAOwE,GAEzC,SAAS+kB,EAASvpB,EAAOjK,EAAM6R,EAAWC,GAEzC,GACK,MAFK7H,EAAOyoB,OAAO1yB,EAAM,GAG7B,MAAgC,MAA7BiK,EAAOyoB,OAAO1yB,EAAQ,IACpByzB,EAAMxpB,EAAOhJ,QAAQ,SAAMjB,EAAM,IAE9BA,GACN6R,EAAWoD,QAAQhL,EAAOjK,EAAM,EAAEyzB,EAAIzzB,EAAM,GACrCyzB,EAAI,IAEX3hB,EAAa7S,MAAM,qBACX,IAID,EAGT,GAA+B,UAA5BgL,EAAOhI,OAAOjC,EAAM,EAAE,GAAe,CACvC,IAAIyzB,EAAMxpB,EAAOhJ,QAAQ,MAAMjB,EAAM,GAIrC,OAHA6R,EAAWuD,aACXvD,EAAW6C,WAAWzK,EAAOjK,EAAM,EAAEyzB,EAAIzzB,EAAM,GAC/C6R,EAAWwD,WACJoe,EAAI,EAIZ,IAAIC,EA8EN,SAAezpB,EAAOjK,GACrB,IAAIgC,EACA8a,EAAM,GACNzS,EAAM,6CAGV,IAFAA,EAAI8P,UAAYna,EAChBqK,EAAIspB,KAAK1pB,GACHjI,EAAQqI,EAAIspB,KAAK1pB,IAEtB,GADA6S,EAAIhd,KAAKkC,GACNA,EAAM,GAAG,OAAO8a,EAtFNhb,CAAMmI,EAAOjK,GACtBX,EAAMq0B,EAAOp0B,OACjB,GAAGD,EAAI,GAAK,YAAY8N,KAAKumB,EAAO,GAAG,IAAI,CAC1C,IAAItpB,EAAOspB,EAAO,GAAG,GACjB3V,GAAQ,EACRC,GAAQ,EACT3e,EAAI,IACH,YAAY8N,KAAKumB,EAAO,GAAG,KAC7B3V,EAAQ2V,EAAO,GAAG,GAClB1V,EAAQ3e,EAAI,GAAKq0B,EAAO,GAAG,IACnB,YAAYvmB,KAAKumB,EAAO,GAAG,MACnC1V,EAAQ0V,EAAO,GAAG,KAGpB,IAAIE,EAAYF,EAAOr0B,EAAI,GAI3B,OAHAwS,EAAWyD,SAASlL,EAAM2T,EAAOC,GACjCnM,EAAWgiB,SAEJD,EAAU1rB,MAAM0rB,EAAU,GAAGt0B,OAGtC,OAAQ,EAKT,SAASw0B,EAAiB7pB,EAAOjK,EAAM6R,GACtC,IAAI4hB,EAAMxpB,EAAOhJ,QAAQ,KAAKjB,GAC9B,GAAGyzB,EAAI,CACN,IAAIzxB,EAAQiI,EAAO8D,UAAU/N,EAAMyzB,GAAKzxB,MAAM,8BAC9C,OAAGA,GACQA,EAAM,GAAG1C,OACnBuS,EAAWsC,sBAAsBnS,EAAM,GAAIA,EAAM,IAC1CyxB,EAAI,IAEH,EAGV,OAAQ,EAGT,SAASM,IACRn2B,KAAK20B,eAAiB,GAhjBvBjiB,EAAWzR,UAAY,IAAI+C,MAC3B0O,EAAWzR,UAAUuL,KAAOkG,EAAWlG,KAMvCmG,EAAU1R,UAAY,CACrB2J,MAAM,SAASyB,EAAO8H,EAAaE,GAClC,IAAIJ,EAAajU,KAAKiU,WACtBA,EAAWc,gBACXqgB,EAAMjhB,EAAcA,EAAe,IAMrC,SAAe9H,EAAO+pB,EAAiB/hB,EAAUJ,EAAWC,GAc3D,SAASqgB,EAAelnB,GACvB,IAAIgpB,EAAIhpB,EAAE1I,MAAM,GAAG,GACnB,OAAG0xB,KAAKhiB,EACAA,EAAUgiB,GACO,MAAhBA,EAAEvB,OAAO,GAjBnB,SAA2B/Z,GAG1B,GAAIA,EAAO,MAAQ,CAElB,IAAIub,EAAa,QADjBvb,GAAQ,QAC2B,IAChCwb,EAAa,OAAiB,KAAPxb,GAE1B,OAAOlM,OAAO2nB,aAAaF,EAAYC,GAEvC,OAAO1nB,OAAO2nB,aAAazb,GAQpB0b,CAAkBhuB,SAAS4tB,EAAEhyB,OAAO,GAAGoM,QAAQ,IAAI,SAE1DyD,EAAa7S,MAAM,oBAAoBgM,GAChCA,GAGT,SAASqpB,EAAWb,GACnB,GAAGA,EAAIzzB,EAAM,CACZ,IAAIu0B,EAAKtqB,EAAO8D,UAAU/N,EAAMyzB,GAAKplB,QAAQ,WAAW8jB,GACxD1hB,GAASG,EAAS5Q,GAClB6R,EAAW6C,WAAW6f,EAAG,EAAEd,EAAIzzB,GAC/BA,EAAQyzB,GAGV,SAAS7iB,EAAShG,EAAE7I,GACnB,KAAM6I,GAAG4pB,IAAYzyB,EAAI0yB,EAAYd,KAAK1pB,KACzCyqB,EAAY3yB,EAAEmG,MACdssB,EAAUE,EAAY3yB,EAAE,GAAGzC,OAC3BmR,EAAQK,aAGTL,EAAQM,aAAenG,EAAE8pB,EAAU,EAUpC,IARA,IAAIA,EAAY,EACZF,EAAU,EACVC,EAAc,sBACdhkB,EAAUoB,EAAWpB,QAErBkkB,EAAa,CAAC,CAACzC,aAAa8B,IAC5BX,EAAW,GACXrzB,EAAQ,IACD,CACV,IACC,IAAI40B,EAAW3qB,EAAOhJ,QAAQ,IAAIjB,GAClC,GAAG40B,EAAS,EAAE,CACb,IAAI3qB,EAAOhI,OAAOjC,GAAOgC,MAAM,SAAS,CACvC,IAAI0P,EAAMG,EAAWH,IACd9R,EAAO8R,EAAImD,eAAe5K,EAAOhI,OAAOjC,IAC5C0R,EAAID,YAAY7R,GAChBiS,EAAWL,eAAiB5R,EAEhC,OAKD,OAHGg1B,EAAS50B,GACXs0B,EAAWM,GAEL3qB,EAAOyoB,OAAOkC,EAAS,IAC9B,IAAK,IACJ,IAAInB,EAAMxpB,EAAOhJ,QAAQ,IAAI2zB,EAAS,GAClC9gB,EAAU7J,EAAO8D,UAAU6mB,EAAW,EAAGnB,GAAKplB,QAAQ,eAAgB,IACtEhD,EAASspB,EAAWE,MACrBpB,EAAI,GAEA3f,EAAU7J,EAAO8D,UAAU6mB,EAAS,GAAGvmB,QAAQ,UAAU,IACzDyD,EAAa7S,MAAM,iBAAiB6U,EAAQ,oBAAoBzI,EAAOyI,SACvE2f,EAAMmB,EAAS,EAAE9gB,EAAQxU,QACjBwU,EAAQ9R,MAAM,SACtB8R,EAAUA,EAAQzF,QAAQ,UAAU,IACpCyD,EAAa7S,MAAM,iBAAiB6U,EAAQ,uBAC5C2f,EAAMmB,EAAS,EAAE9gB,EAAQxU,QAEhC,IAAIuzB,EAAaxnB,EAAOwnB,WACpBiC,EAAWzpB,EAAOyI,SAAWA,EAE3B,GADkBghB,GAAYzpB,EAAOyI,SAASzI,EAAOyI,QAAQihB,eAAiBjhB,EAAQihB,cACjE,CAE1B,GADMljB,EAAW+B,WAAWvI,EAAOwE,IAAIxE,EAAO2H,UAAUc,GACrD+e,EACF,IAAI,IAAI5e,KAAU4e,EACjBhhB,EAAWqC,iBAAiBD,GAG1B6gB,GACMhjB,EAAaiE,WAAW,iBAAiBjC,EAAQ,2CAA2CzI,EAAOyI,cAGvG6gB,EAAW70B,KAAKuL,GAGvBooB,IACA,MAED,IAAK,IACJhjB,GAASG,EAASgkB,GAClBnB,EAAMK,EAAiB7pB,EAAO2qB,EAAS/iB,GACvC,MACD,IAAK,IACJpB,GAASG,EAASgkB,GAClBnB,EAAMD,EAASvpB,EAAO2qB,EAAS/iB,EAAWC,GAC1C,MACD,QACCrB,GAASG,EAASgkB,GAClB,IAAI3lB,EAAK,IAAI8kB,EACT7B,EAAeyC,EAAWA,EAAWr1B,OAAO,GAAG4yB,aAG/C7yB,GADAo0B,EAAMxB,EAAsBhoB,EAAO2qB,EAAS3lB,EAAGijB,EAAaC,EAAergB,GACrE7C,EAAG3P,QASb,IANI2P,EAAG2jB,QAAUQ,EAAcnpB,EAAOwpB,EAAIxkB,EAAG6E,QAAQuf,KACpDpkB,EAAG2jB,QAAS,EACR3gB,EAAUiV,MACbpV,EAAa+D,QAAQ,2BAGpBpF,GAAWpR,EAAI,CAGjB,IAFA,IAAI21B,EAAWjD,EAAYthB,EAAQ,IAE3BrR,EAAI,EAAEA,EAAEC,EAAID,IAAI,CACvB,IAAI6L,EAAIgE,EAAG7P,GACXwR,EAAS3F,EAAEkX,QACXlX,EAAEwF,QAAUshB,EAAYthB,EAAQ,IAEjCoB,EAAWpB,QAAUukB,EAClB1jB,EAAcrC,EAAG4C,EAAWqgB,IAC9ByC,EAAW70B,KAAKmP,GAEjB4C,EAAWpB,QAAUA,OAElBa,EAAcrC,EAAG4C,EAAWqgB,IAC9ByC,EAAW70B,KAAKmP,GAIdW,EAAUL,OAAON,EAAGY,OAASZ,EAAG2jB,OACnCa,EAAMR,EAAwBhpB,EAAOwpB,EAAIxkB,EAAG6E,QAAQqe,EAAetgB,GAEnE4hB,KAGF,MAAM9oB,GACN,GAAIA,aAAa2F,EAChB,MAAM3F,EAEPmH,EAAa7S,MAAM,wBAAwB0L,GAC3C8oB,GAAO,EAELA,EAAIzzB,EACNA,EAAQyzB,EAGRa,EAAWzsB,KAAKotB,IAAIL,EAAS50B,GAAO,IApKrCwI,CAAMyB,EAAO8H,EAAaE,EACxBJ,EAAWjU,KAAKkU,cAClBD,EAAWkD,gBAoiBbgf,EAAkBl1B,UAAY,CAC7B8zB,WAAW,SAAS7e,GACnB,IAAIge,EAAe3kB,KAAK2G,GACvB,MAAM,IAAIlS,MAAM,mBAAmBkS,GAEpClW,KAAKkW,QAAUA,GAEhB0e,SAAS,SAASvf,EAAOlO,EAAOod,GAC/B,IAAI2P,EAAe3kB,KAAK8F,GACvB,MAAM,IAAIrR,MAAM,qBAAqBqR,GAEtCrV,KAAK20B,eAAetf,GAASrV,KAAK0B,OAClC1B,KAAKA,KAAK0B,UAAY,CAAC2T,MAAMA,EAAMlO,MAAMA,EAAMod,OAAOA,IAEvD7iB,OAAO,EACP41B,aAAa,SAAS91B,GAAG,OAAOxB,KAAKwB,GAAG4T,WACxCS,WAAW,SAASrU,GAAG,OAAOxB,KAAKwB,GAAGqR,SACtC8C,SAAS,SAASnU,GAAG,OAAOxB,KAAKwB,GAAG6T,OACpCG,OAAO,SAAShU,GAAG,OAAOxB,KAAKwB,GAAGyQ,KAClCwD,SAAS,SAASjU,GAAG,OAAOxB,KAAKwB,GAAG2F,QA2BrC5H,EAAQoT,UAAYA,EACpBpT,EAAQmT,WAAaA,iBCjoBrBlT,EAAOD,QAAU,EAAjBC,KAAAA,iBCgCAA,EAAOD,QAlCU,CAsBbg4B,gBAAe,CAACC,EAAYC,EAAUC,IAGf,iBAFPF,EAGD,KAHCA,EAMD/mB,QAAQ,SAAUgnB,GACxBhnB,QAAQ,iBAAiC,IAAhBinB,aCvBtC,SAASC,EAAsB7e,EAAKC,GAChC,IAAKD,IAAQC,GAAmC,mBAApBD,EAAI8e,aACJ,mBAAd7e,EAAK8e,KACf,MAAM,IAAI7zB,MAAM,qDAEpBhE,KAAK8Y,IAAMA,EACX9Y,KAAK+Y,KAAOA,EAWhB4e,EAAsB12B,UAAU62B,QAAU,WAAkB,2BAANrzB,EAAM,yBAANA,EAAM,gBACxD,MAAMszB,EAAWtzB,EAAK,GAItBA,EAAK,GAAKzE,KAAK+Y,KAGf/Y,KAAK8Y,IAAI8e,YACLG,EACAnnB,SAAS3P,UAAUL,KAAKF,MAAMV,KAAK+Y,KAAK8e,KAAMpzB,KAGtDjF,EAAOD,QAAUo4B,UC1BjB,MAAMK,EAAW,GAGXC,EAAoB31B,OAAO41B,QAY3BC,EAA0B71B,OAAO81B,qBAYvC91B,OAAO41B,QAlBP,WAA0C,2BAANzzB,EAAM,yBAANA,EAAM,gBACtCuzB,EAASz3B,SAAQ83B,GAAWA,KAAW5zB,KACvCwzB,GAAqBA,KAAqBxzB,IAiB9CnC,OAAO81B,qBAPP,SAAuCE,GACnCN,EAASz3B,SAAQ83B,GAAWA,EAAQ,KAAM,KAAM,KAAM,KAAMC,EAAMC,UAClEJ,GAA2BA,EAAwBG,IAOvD,MAAME,EAAuB,CAKzBC,WAAWJ,GACPL,EAAS91B,KAAKm2B,IAOlBK,iBAAiBr3B,GACb,MAAMs3B,EAAar2B,OAAO41B,QAErBS,GAGLA,EAAW,KAAM,KAAM,KAAM,KAAMt3B,IAOvCu3B,8BAA8Bv3B,GAC1B,MAAMs3B,EAAar2B,OAAO81B,qBAErBO,GAGLA,EAAWt3B,KAKnB7B,EAAOD,QAAUi5B,WC5DjB,SAASK,EAAUC,EAAKzB,GACpB,OAAOptB,KAAKC,MAAMD,KAAKE,UAAYktB,EAAMyB,EAAM,IAAMA,EAQzD,SAASC,EAAcC,GACnB,OAAOA,EAAIH,EAAU,EAAGG,EAAIt3B,OAAS,IAqBzC,MAAMu3B,EAAa,CAKfC,eAAc,IACHH,EA7CI,oBAoDfI,gBAAgB13B,GACZ,IAAI23B,EAAM,GAEV,KAAO33B,KACH23B,GAAOp5B,KAAKk5B,iBAGhB,OAAOE,GAEXL,cAAAA,EACAM,kBApCJ,SAA2B33B,GACvB,IAAI43B,EAAS,GAEb,IAAK,IAAI93B,EAAI,EAAGA,EAAIE,EAAQF,GAAK,EAC7B83B,GAAUP,EApCZ,kEAuCF,OAAOO,GA8BPT,UAAAA,GAGJr5B,EAAOD,QAAU05B,iBC5EjB,MAAMM,EAAyBC,EAAQ,KAQjCC,EAAa,CAgBfC,WACQ5gB,EACA6gB,EACAC,EACAC,EACAC,EACAC,GACJ,MAAMC,EAAIC,SACJ/jB,EAAU,SACVgkB,EAASF,EAAE/W,cAAc/M,GACzBikB,EAAgBH,EAAE5V,qBAAqBlO,GAAS,GAItD,GAFAgkB,EAAOP,MAAQA,EAEXE,EAAa,CAGb,MAAMO,EAAWb,IAEjB,GAAIa,EAAU,CACV,MAAMC,EAAYD,EAASthB,IACrBwhB,EACAD,EAAUlqB,UAAU,EAAGkqB,EAAU1E,YAAY,KAAO,GAEtD0E,GAAaC,IAEbxhB,EAAMwhB,EAAgBxhB,IAK9BghB,IACAI,EAAOK,OAAST,GAEhBC,IACAG,EAAOhC,QAAU6B,GAGrBG,EAAOphB,IAAMA,EACT8gB,EACAO,EAAchkB,WAAWwL,aAAauY,EAAQC,GAE9CA,EAAchkB,WAAWtC,YAAYqmB,KAOjD16B,EAAOD,QAAUk6B,WClDjBj6B,EAAOD,QAAU,CAAEi7B,YAhBnB,SAAqBC,GACjB,IAAKA,EACD,OAAO,EAGX,IAAIC,EAAgBl5B,EAAVm5B,EAAO,EAEjB,IAAKn5B,EAAI,EAAGA,EAAIi5B,EAAO/4B,OAAQF,IAC3Bk5B,EAAOD,EAAO/d,WAAWlb,GACzBm5B,GAAQD,EAAOzwB,KAAK2wB,IAAI,GAAIH,EAAO/4B,OAAS,EAAIF,GAChDm5B,EAAO1wB,KAAK4wB,IAAW,EAAPF,GAGpB,OAAOA,mBCpBX,MAAM1B,EAAaO,EAAQ,KASrB7sB,EAAQ,CACV,UAAW,QAAS,UAAW,QAAS,QAAS,WAAY,OAC7D,SAAU,QAAS,WAAY,MAAO,OAAQ,WAAY,UAC1D,UAAW,WAAY,QAAS,UAAW,MAAO,OAAQ,YAC1D,UAAW,OAAQ,OAAQ,QAAS,UAAW,QAAS,WAAY,QACpE,SAAU,UAAW,QAAS,SAAU,SAAU,SAAU,QAC5D,SAAU,SAAU,WAAY,SAAU,SAAU,SAAU,UAC9D,WAAY,SAAU,SAAU,WAAY,QAAS,QAAS,QAC9D,UAAW,WAAY,QAAS,QAAS,OAAQ,QAAS,QAAS,SACnE,QAAS,SAAU,QAAS,KAAM,SAAU,OAAQ,QAAS,SAC7D,SAAU,SAAU,OAAQ,SAAU,UAAW,WAAY,UAC7D,QAAS,SAAU,OAAQ,QAAS,OAAQ,QAAS,YACrD,aAAc,OAAQ,QAAS,QAAS,aAAc,aACtD,UAAW,SAAU,OAAQ,QAAS,YAAa,YAAa,YAChE,aAAc,aAAc,cAAe,YAAa,UACxD,WAAY,SAAU,SAAU,SAAU,aAAc,MAAO,UAC/D,UAAW,SAAU,SAAU,UAAW,UAAW,MAAO,OAAQ,QACpE,SAAU,QAAS,SAAU,SAAU,SAAU,QAAS,SAAU,QACpE,QAAS,QAAS,QAAS,SAAU,QAAS,UAAW,OAAQ,WACjE,OAAQ,SAAU,OAAQ,QAAS,SAAU,SAAU,UAAW,SAClE,QAAS,QAAS,SAAU,QAAS,SAAU,SAAU,UACzD,SAAU,SAAU,QAAS,QAAS,QAAS,QAAS,QAAS,UACjE,SAAU,SAAU,QAAS,UAAW,UAAW,OAAQ,QAAS,OACpE,QAAS,QAAS,OAAQ,SAAU,MAAO,OAAQ,MAAO,SAC1D,WAAY,QAAS,QAAS,YAAa,YAAa,WAAY,QACpE,WAAY,YAAa,SAAU,SAAU,OAAQ,QAAS,SAC9D,WAAY,WAAY,WAAY,WAAY,SAAU,QAAS,QACnE,SAAU,QAAS,SAAU,QAAS,QAAS,SAAU,SAAU,OACnE,UAAW,WAAY,YAAa,WAAY,UAAW,YAC3D,OAAQ,UAAW,UAAW,QAAS,QAAS,SAAU,UAC1D,aAAc,SAAU,YAAa,YAAa,UAAW,aAC7D,WAAY,UAAW,SAAU,SAAU,OAAQ,QAAS,MAC5D,UAAW,UAAW,OAAQ,YAAa,UAAW,QAAS,SAC/D,QAAS,MAAO,SAAU,UAAW,OAAQ,QAAS,UAAW,QACjE,SAAU,QAAS,OAAQ,SAAU,UAAW,SAAU,UAAW,OACrE,OAAQ,SAAU,UAAW,UAAW,OAAQ,MAAO,SAAU,SACjE,QAAS,QAAS,UAAW,UAAW,MAAO,OAAQ,SAAU,WACjE,SAAU,QAAS,UAAW,SAAU,SAAU,OAAQ,UAC1D,SAAU,SAAU,SAAU,SAAU,QAAS,QAAS,YAC1D,SAAU,SAAU,UAAW,YAAa,WAAY,UACxD,UAAW,UAAW,SAAU,SAAU,SAAU,SAAU,SAC9D,MAAO,QAAS,OAAQ,OAAQ,QAAS,QAAS,OAAQ,QAAS,OACnE,SAAU,SAAU,UAAW,SAAU,QAAS,UAAW,QAC7D,OAAQ,aAAc,SAAU,SAAU,WAAY,OAAQ,UAC9D,OAAQ,QAAS,QAAS,MAAO,WAAY,WAAY,UACzD,SAAU,QAAS,SAAU,WAAY,aAAc,YACvD,UAAW,WAAY,WAAY,WAAY,UAAW,SAC1D,WAAY,UAAW,QAAS,OAAQ,QAAS,SAAU,UAC3D,WAAY,QAAS,SAAU,OAAQ,UAAW,SAAU,QAC5D,QAAS,SAAU,QAAS,SAAU,SAAU,UAAW,SAAU,OACrE,SAAU,QAAS,SAAU,QAAS,SAAU,QAAS,SACzD,UAAW,QAAS,KAAM,SAAU,QAAS,SAAU,SAAU,QACjE,OAAQ,OAAQ,SAAU,WAAY,UAAW,SAAU,QAC3D,UAAW,QAAS,SAAU,SAAU,UAAW,SAAU,SAC7D,UAAW,UAAW,UAAW,QAAS,UAAW,UAAW,SAChE,SAAU,UAAW,UAAW,SAAU,UAAW,UAAW,UAChE,SAAU,UAAW,UAAW,QAAS,OAAQ,QAAS,OAAQ,QAClE,SAAU,UAAW,QAAS,UAAW,YAAa,SAAU,UAChE,WAAY,UAAW,QAAS,UAAW,WAAY,QAAS,YAChE,QAAS,QAAS,SAAU,WAAY,SAAU,QAAS,QAC3D,SAAU,QAAS,SAAU,QAAS,OAAQ,MAAO,QAAS,SAC9D,QAAS,WAAY,SAAU,UAAW,SAAU,OAAQ,QAC5D,SAAU,UAAW,OAAQ,QAAS,UAAW,OAAQ,UACzD,SAAU,SAAU,UAAW,SAAU,UAAW,UAAW,SAC/D,SAAU,SAAU,UAAW,UAAW,aAAc,UACxD,UAAW,UAAW,OAAQ,QAAS,UAAW,SAAU,WAC5D,SAAU,QAAS,SAAU,QAAS,SAAU,WAAY,SAC5D,UAAW,WAAY,UAAW,SAAU,UAAW,QAAS,YAChE,SAAU,WAAY,WAAY,UAAW,WAAY,SACzD,UAAW,SAAU,SAAU,OAAQ,WAAY,QAAS,UAC5D,UAAW,SAAU,YAAa,YAAa,UAAW,SAC1D,WAAY,WAAY,YAAa,YAAa,WAAY,UAC9D,QAAS,QAAS,SAAU,UAAW,QAAS,SAAU,UAC1D,UAAW,YAAa,YAAa,QAAS,SAAU,QAAS,OACjE,QAAS,WAAY,QAAS,SAAU,WAAY,SAAU,WAC9D,UAAW,WAAY,UAAW,UAAW,UAAW,YACxD,QAAS,UAAW,WAAY,QAAS,OAAQ,UAAW,UAC5D,UAAW,UAAW,UAAW,OAAQ,WAAY,WAAY,QACjE,QAAS,SAAU,UAAW,aAAc,YAAa,aACzD,YAAa,YAAa,WAAY,aAAc,cACpD,UAAW,QAAS,QAAS,SAAU,QAAS,SAAU,QAC1D,WAAY,QAAS,SAAU,QAAS,aAAc,QAAS,WAC/D,QAAS,QAAS,SAAU,UAAW,UAAW,WAAY,OAC9D,UAAW,UAAW,aAAc,aAAc,UAAW,OAC7D,SAAU,QAAS,SAAU,QAAS,YAAa,WAAY,UAC/D,QAAS,UAAW,WAAY,SAAU,QAAS,QAAS,OAAQ,OACpE,QAAS,OAAQ,UAAW,QAAS,UAAW,SAAU,OAAQ,SAClE,SAAU,WAAY,aAAc,SAAU,SAAU,SAAU,QAClE,SAAU,YAAa,aAAc,WAAY,SAAU,OAC3D,UAAW,SAAU,WAAY,UAAW,SAAU,SAAU,SAChE,SAAU,YAAa,UAAW,UAAW,SAAU,UAAW,OAClE,OAAQ,WAAY,MAAO,QAAS,WAAY,SAAU,UAC1D,WAAY,WAAY,YAAa,aAAc,OAAQ,UAC3D,UAAW,SAAU,OAAQ,SAAU,SAAU,UAAW,QAC5D,QAAS,SAAU,SAAU,QAAS,SAAU,QAAS,SAAU,OACnE,SAAU,SAAU,SAAU,UAAW,SAAU,SAAU,SAC7D,SAAU,QAAS,MAAO,OAAQ,SAAU,OAAQ,WAAa,UACjE,SAAU,UAAW,WAAY,WAAY,SAAU,SAAU,QACjE,QAAS,SAAU,SAAU,UAAW,UAAW,QAAS,QAC5D,SAAU,UAAW,SAAU,QAAS,SAAU,SAAU,UAC5D,QAAS,SAAU,UAAW,SAAU,UAAW,SAAU,UAC7D,SAAU,SAAU,SAAU,QAAS,UAAW,QAAS,OAAQ,QACnE,QAAS,SAAU,QAAS,UAAW,OAAQ,SAAU,MAAO,SAChE,QAAS,QAAS,SAAU,OAAQ,WAAY,SAAU,UAC1D,SAAU,SAAU,UAAW,MAAO,QAAS,OAAQ,QAAS,QAChE,SAAU,UAAW,UAAW,UAAW,QAAS,UAAW,OAC/D,QAAS,SAAU,UAAW,SAAU,UAAW,WAAY,QAC/D,UAAW,WAAY,UAAW,WAAY,YAAa,SAAU,OACrE,QAAS,SAAU,OAAQ,UAAW,UAAW,SAAU,SAC3D,QAAS,SAAU,QAAS,UAAW,UAAW,UAAW,UAC7D,UAAW,SAAU,UAAW,SAAU,WAAY,WAAY,UAClE,UAAW,QAAS,UAAW,QAAS,QAAS,QAAS,UAC1D,QAAS,UAAW,SAAU,SAAU,UAAW,QAAS,SAC5D,QAAS,SAAU,SAAU,UAAW,OAAQ,OAAQ,OAAQ,QAChE,OAAQ,QAAS,UAAW,UAAW,WAAY,WAAY,WAC/D,UAAW,UAAW,YAAa,MAAO,SAAU,SAAU,UAC9D,QAAS,UAAW,SAAU,QAAS,OAAQ,SAAU,SAAU,QACnE,WAAY,UAAW,SAAU,SAAU,SAAU,OAAQ,UAC7D,QAAS,QAAS,QAAS,OAAQ,QAAS,SAAU,QAAS,SAC/D,UAAW,SAAU,QAAS,SAAU,QAAS,OAAQ,UACzD,UAAW,UAAW,aAAc,SAAU,SAAU,OAAQ,QAChE,KAAM,MAAO,MAAO,QAAS,OAAQ,QAAS,UAAW,SAAU,SACnE,SAAU,OAAQ,UAAW,SAAU,UAAW,QAAS,SAC3D,QAAS,SAAU,QAAS,SAAU,QAAS,SAAU,QAAS,OAClE,SAAU,SAAU,SAAU,OAAQ,QAAS,SAAU,SACzD,WAAY,WAAY,WAAY,UAAW,SAAU,QAAS,SAClE,UAAW,WAAY,WAAY,MAAO,QAAS,SAAU,QAC7D,UAAW,SAAU,SAAU,UAAW,QAAS,YAAa,QAChE,SAAU,SAAU,SAAU,QAAS,YAAa,OAAQ,QAC5D,QAAS,SAAU,UAAW,QAAS,YAAa,QAAS,SAC7D,OAAQ,SAAU,OAAQ,SAAU,QAAS,SAAU,SAAU,UACjE,OAAQ,QAAS,OAAQ,OAAQ,QAAS,OAAQ,QAAS,OAAQ,SACnE,QAAS,QAAS,QAAS,QAAS,QAAS,SAAU,OAAQ,UAC/D,SAAU,SAAU,QAAS,UAAW,UAAW,QAAS,OAAQ,OACpE,QAAS,SAAU,WAAY,SAAU,SAAU,QAAS,OAC5D,UAAW,WAAY,aAAc,QAAS,SAAU,QAAS,SACjE,OAAQ,QAAS,MAAO,OAAQ,QAAS,QAAS,OAAQ,SAC1D,UAAW,UAAW,MAAO,WAAY,OAAQ,QAAS,QAAS,QACnE,SAAU,OAAQ,QAAS,OAAQ,SAAU,OAAQ,SAAU,YAC/D,YAAa,UAAW,QAAS,QAAS,QAAS,OAAQ,YAC3D,YAAa,OAAQ,UAAW,YAAa,QAAS,SAAU,UAChE,UAAW,UAAW,SAAU,WAAY,OAAQ,QAAS,QAC7D,UAAW,QAAS,QAAS,SAAU,SAAU,UAAW,OAAQ,QACpE,UAAW,OAAQ,SAAU,UAAW,MAAO,SAAU,OACzD,aAAc,QAAS,MAAO,UAAW,SAAU,WAAY,UAC/D,WAAY,QAAS,OAAQ,QAAS,QAAS,UAAW,WAC1D,OAAQ,SAAU,UAAW,MAAO,SAAU,QAAS,SAAU,WACjE,SAAU,SAAU,MAAO,OAAQ,WAAY,UAAW,WAC1D,WAAY,SAAU,SAAU,QAAS,SAAU,SAAU,OAC7D,WAAY,QAAS,QAAS,YAAa,WAAY,OAAQ,QAC/D,SAAU,SAAU,QAAS,WAAY,MAAO,WAAY,YAC5D,UAAW,UAAW,UAAW,UAAW,OAAQ,QAAS,OAC7D,SAAU,UAAW,SAAU,UAAW,YAAa,YACvD,UAAW,YAAa,YAAa,SAAU,QAAS,UAAW,QACnE,OAAQ,QAAS,UAAW,SAAU,WAAY,YAAa,WAC/D,aAAc,WAAY,QAAS,SAAU,UAAW,SAAU,QAClE,SAAU,YAAa,QAAS,SAAU,OAAQ,UAAW,YAC7D,YAAa,UAAW,OAAQ,OAAQ,UAAW,SAAU,WAC7D,UAAW,SAAU,UAAW,SAAU,UAAW,UAAW,WAChE,QAAS,QAAS,SAAU,QAAS,MAAO,QAAS,UAAW,OAChE,UAAW,UAAW,YAAa,UAAW,WAAY,MAAO,WACjE,SAAU,YAAa,YAAa,aAAc,WAAY,WAC9D,UAAW,SAAU,YAAa,SAAU,UAAW,QAAS,UAChE,WAAY,SAAU,QAAS,SAAU,WAAY,MAAO,SAC5D,SAAU,UAAW,WAAY,QAAS,QAAS,UAAW,OAC9D,OAAQ,UAAW,WAAY,WAAY,WAAY,WACvD,WAAY,UAAW,SAAU,OAAQ,SAAU,SAAU,UAC7D,SAAU,UAAW,QAAS,SAAU,UAAW,SAAU,QAC7D,SAAU,WAAY,QAAS,SAAU,QAAS,YAAa,SAC/D,UAAW,QAAS,OAAQ,QAAS,WAAY,WAAY,UAC7D,QAAS,WAAY,UAAW,UAAW,SAAU,YAAa,SAClE,QAAS,YAAa,WAAY,SAAU,SAAU,MAAO,SAC7D,OAAQ,UAAW,MAAO,OAAQ,YAAa,SAAU,SAAU,SACnE,SAAU,MAAO,UAAW,QAAS,QAAS,QAAS,SAAU,OACjE,QAAS,SAAU,OAAQ,QAAS,SAAU,SAAU,UAAW,SACnE,WAAY,QAAS,SAAU,UAAW,SAAU,SAAU,SAC9D,QAAS,SAAU,SAAU,SAAU,SAAU,QAAS,QAAS,QACnE,UAAW,SAAU,QAAS,SAAU,QAAS,QAAS,SAC1D,SAAU,QAAS,SAAU,SAAU,UAAW,YAAa,QAC/D,YAAa,QAAS,UAAW,SAAU,UAAW,UAAW,WACjE,WAAY,UAAW,QAAS,SAAU,SAAU,SAAU,UAC9D,UAAW,QAAS,YAAa,UAAW,UAAW,QAAS,SAChE,WAAY,QAAS,SAAU,SAAU,SAAU,SAAU,QAC7D,OAAQ,SAAU,UAAW,WAAY,QAAS,UAAW,SAC7D,SAAU,OAAQ,SAAU,SAAU,OAAQ,QAAS,WAAY,SACnE,QAAS,MAAO,UAAW,OAAQ,MAAO,QAAS,SAAU,UAC7D,WAAY,MAAO,MAAO,QAAS,SAAU,MAAO,QAAS,SAC7D,WAAY,UAAW,OAAQ,OAAQ,SAAU,QAAS,QAAS,SACnE,UAAW,WAAY,WAAY,OAAQ,UAAW,OAAQ,SAC9D,SAAU,SAAU,SAAU,SAAU,OAAQ,SAAU,QAAS,QACnE,MAAO,OAAQ,QAAS,MAAO,WAAY,SAAU,SAAU,OAC/D,QAAS,WAAY,UAAW,OAAQ,YAAa,SAAU,UAC/D,UAAW,QAAS,SAAU,YAAa,UAAW,WAAY,OAClE,OAAQ,QAAS,QAAS,QAAS,SAAU,QAAS,SAAU,SAChE,QAAS,QAAS,UAAW,OAAQ,QAAS,SAAU,QAAS,QACjE,QAAS,SAAU,QAAS,QAAS,WAAY,QAAS,UAC1D,QAAS,QAAS,QAAS,QAAS,UAAW,SAAU,MAAO,OAChE,QAAS,OAAQ,UAAW,UAAW,QAAS,SAAU,SAAU,QACpE,QAAS,SAAU,SAAU,OAAQ,SAAU,WAAY,YAC3D,QAAS,QAAS,QAAS,QAAS,SAAU,UAAW,SACzD,UAAW,SAAU,SAAU,QAAS,SAAU,QAAS,SAC3D,UAAW,SAAU,QAAS,UAAW,MAAO,QAAS,SAAU,QACnE,QAAS,SAAU,SAAU,SAAU,SAAU,SAAU,SAC3D,QAAS,QAAS,SAAU,SAAU,SAAU,SAAU,UAAW,OACrE,WAAY,SAAU,SAAU,MAAO,WAAY,WAAY,OAC/D,WAAY,UAAW,UAAW,SAAU,OAAQ,UAAW,SAC/D,WAAY,WAAY,WAAY,SAAU,QAAS,SAAU,UACjE,SAAU,QAAS,UAAW,SAAU,UAAW,WAAY,SAC/D,QAAS,SAAU,SAAU,UAAW,SAAU,UAAW,QAC7D,OAAQ,QAAS,UAAW,SAAU,UAAW,QAAS,UAC1D,QAAS,OAAQ,SAAU,QAAS,QAAS,SAAU,UAAW,SAClE,QAAS,KAAM,OAAQ,QAAS,SAAU,SAAU,UAAW,SAC/D,QAAS,UAAW,UAAW,QAAS,OAAQ,MAAO,OAAQ,SAC/D,SAAU,OAAQ,QAAS,SAAU,UAAW,WAAY,OAC5D,YAAa,YAAa,UAAW,SAAU,WAAY,UAC3D,QAAS,MAAO,QAAS,UAAW,WAAY,WAAY,SAC5D,UAAW,QAAS,SAAU,QAAS,SAAU,QAAS,OAAQ,SAClE,WAAY,SAAU,YAAa,OAAQ,SAAU,UAAW,SAChE,UAAW,WAAY,QAAS,QAAS,QAAS,SAAU,UAC5D,SAAU,MAAO,QAAS,QAAS,UAAW,QAAS,OAAQ,OAC/D,QAAS,SAAU,OAAQ,QAAS,QAAS,SAAU,UACvD,WAAY,QAAS,SAAU,SAAU,QAAS,SAAU,OAC5D,SAAU,SAAU,SAAU,UAAW,UAAW,UAAW,SAC/D,SAAU,SAAU,UAAW,QAAS,QAAS,OAAQ,QAAS,OAClE,QAAS,QAAS,QAAS,SAAU,OAAQ,SAAU,SAAU,SACjE,UAAW,UAAW,OAAQ,QAAS,UAAW,QAAS,OAAQ,SACnE,UAAW,UAAW,SAAU,SAAU,SAAU,OAAQ,OAC5D,SAAU,UAAW,QAAS,OAAQ,UAAW,WAAY,SAC7D,SAAU,OAAQ,SAAU,SAAU,QAAS,SAAU,WACzD,SAAU,WAAY,QAAS,YAAa,WAAY,UACxD,UAAW,WAAY,YAAa,YAAa,WAAY,WAC7D,UAAW,UAAW,WAAY,SAAU,UAAW,UAAW,UAClE,SAAU,QAAS,MAAO,OAAQ,SAAU,SAAU,QAAS,SAC/D,SAAU,WAAY,SAAU,QAAS,SAAU,SAAU,SAC7D,QAAS,QAAS,SAAU,SAAU,SAAU,QAAS,SAAU,QACnE,QAAS,SAAU,SAAU,QAAS,SAAU,QAAS,QAAS,SAClE,SAAU,SAAU,MAAO,UAAW,SAAU,WAAY,QAC5D,UAAW,UAAW,UAAW,UAAW,QAAS,SAAU,QAC/D,WAAY,SAAU,OAAQ,UAAW,UAAW,QAAS,QAC7D,QAAS,QAAS,WAAY,SAAU,SAAU,OAAQ,QAAS,SACnE,QAAS,SAAU,OAAQ,QAAS,SAAU,QAAS,MAAO,WAC9D,OAAQ,MAAO,OAAQ,OAAQ,UAAW,UAAW,QAAS,OAC9D,OAAQ,OAAQ,QAAS,OAAQ,SAAU,QAAS,OAAQ,QAAS,OACrE,SAAU,WAAY,UAAW,WAAY,YAAa,aAC1D,aAAc,SAAU,UAAW,UAAW,WAAY,OAAQ,SAClE,OAAQ,OAAQ,QAAS,UAAW,QAAS,QAAS,OAAQ,QAC9D,OAAQ,WAAY,YAAa,QAAS,SAAU,QAAS,UAC7D,SAAU,QAAS,SAAU,OAAQ,QAAS,UAAW,QAAS,QAClE,QAAS,QAAS,SAAU,SAAU,WAAY,WAAY,WAC9D,YAAa,SAAU,UAAW,QAAS,SAAU,SAAU,SAC/D,UAAW,UAAW,SAAU,UAAW,QAAS,UAAW,WAC/D,SAAU,QAAS,QAAS,SAAU,MAAO,QAAS,SAAU,SAChE,SAAU,OAAQ,MAAO,OAAQ,QAAS,UAAW,OAAQ,QAC7D,SAAU,QAAS,QAAS,SAAU,QAAS,SAAU,QAAS,SAClE,SAAU,MAAO,QAAS,OAAQ,UAAW,WAAY,QAAS,SAClE,SAAU,SAAU,UAAW,UAAW,WAAY,QAAS,OAC/D,SAAU,SAAU,QAAS,SAAU,SAAU,OAAQ,QAAS,UAClE,OAAQ,MAAO,QAAS,OAAQ,QAAS,QAAS,MAAO,OAAQ,QACjE,SAAU,QAAS,OAAQ,SAAU,UAAW,UAAW,QAC3D,UAAW,WAAY,SAAU,QAAS,OAAQ,SAAU,OAC5D,UAAW,QAAS,UAAW,UAAW,SAAU,SAAU,UAC9D,SAAU,OAAQ,WAAY,UAAW,QAAS,OAAQ,SAC1D,SAAU,YAAa,QAAS,QAAS,OAAQ,OAAQ,SAAU,OACnE,MAAO,SAAU,QAAS,SAAU,QAAS,QAAS,OAAQ,UAC9D,QAAS,SAAU,SAAU,UAAW,UAAW,OAAQ,SAC3D,QAAS,SAAU,MAAO,QAAS,SAAU,UAAW,WACxD,SAAU,MAAO,QAAS,QAAS,QAAS,UAAW,QAAS,WAChE,SAAU,UAAW,QAAS,UAAW,SAAU,OAAQ,QAC3D,SAAU,MAAO,SAAU,QAAS,OAAQ,QAAS,QAAS,OAC9D,OAAQ,OAAQ,OAAQ,OAAQ,UAAW,SAAU,MAAO,OAAQ,QACpE,OAAQ,OAAQ,QAAS,UAAW,QAAS,UAAW,QAAS,MACjE,QAAS,OAAQ,QAAS,OAAQ,YAAa,OAAQ,WACvD,UAAW,WAAY,WAAY,UAAW,WAAY,QAAS,QACnE,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,MAClE,SAAU,QAAS,UAAW,SAAU,WAAY,YAAa,SACjE,WAAY,SAAU,OAAQ,QAAS,QAAS,QAAS,UACzD,UAAW,WAAY,UAAW,UAAW,SAAU,UAAW,SAClE,UAAW,UAAW,QAAS,SAAU,SAAU,UAAW,OAC9D,OAAQ,SAAU,YAAa,YAAa,WAAY,WACxD,YAAa,UAAW,SAAU,QAAS,SAAU,SAAU,WAC/D,YAAa,YAAa,aAAc,aAAc,YAAa,QACnE,SAAU,SAAU,UAAW,aAAc,QAAS,SAAU,SAChE,SAAU,UAAW,UAAW,WAAY,WAAY,UACxD,UAAW,QAAS,UAAW,WAAY,WAAY,UAAW,UAClE,WAAY,SAAU,QAAS,SAAU,SAAU,UAAW,UAC9D,aAAc,WAAY,UAAW,OAAQ,SAAU,SAAU,SACjE,UAAW,SAAU,SAAU,SAAU,UAAW,UAAW,WAC/D,WAAY,QAAS,SAAU,UAAW,UAAW,QAAS,SAC9D,OAAQ,SAAU,WAAY,SAAU,QAAS,QAAS,SAC1D,UAAW,WAAY,UAAW,UAAW,OAAQ,SAAU,SAC/D,OAAQ,QAAS,SAAU,UAAW,UAAW,WAAY,UAC7D,WAAY,QAAS,MAAO,QAAS,SAAU,aAAc,aAC7D,cAAe,SAAU,UAAW,SAAU,UAAW,MAAO,OAChE,UAAW,WAAY,OAAQ,SAAU,UAAW,QAAS,QAC7D,UAAW,UAAW,WAAY,SAAU,UAAW,OAAQ,SAC/D,SAAU,SAAU,QAAS,SAAU,QAAS,SAAU,UAC1D,SAAU,SAAU,SAAU,UAAW,SAAU,UAAW,WAC9D,WAAY,OAAQ,QAAS,SAAU,UAAW,SAAU,SAC5D,OAAQ,MAAO,UAAW,QAAS,UAAW,WAAY,UAC1D,UAAW,SAAU,UAAW,WAAY,SAAU,UAAW,OACjE,QAAS,QAAS,QAAS,UAAW,SAAU,SAAU,OAAQ,SAClE,OAAQ,UAAW,SAAU,UAAW,WAAY,SAAU,SAC9D,WAAY,QAAS,UAAW,WAAY,SAAU,UAAW,UACjE,UAAW,WAAY,WAAY,SAAU,SAAU,QAAS,OAChE,SAAU,UAAW,SAAU,YAAa,aAAc,UAC1D,QAAS,QAAS,SAAU,SAAU,SAAU,WAAY,SAC5D,OAAQ,QAAS,QAAS,SAAU,SAAU,UAAW,WACzD,SAAU,OAAQ,SAAU,SAAU,UAAW,MAAO,OAAQ,SAChE,QAAS,OAAQ,SAAU,OAAQ,QAAS,QAAS,UAAW,SAChE,SAAU,SAAU,QAAS,QAAS,OAAQ,SAAU,QAAS,SACjE,WAAY,UAAW,OAAQ,QAAS,MAAO,UAAW,UAC1D,UAAW,SAAU,YAAa,YAAa,YAAa,SAC5D,SAAU,OAAQ,MAAO,QAAS,OAAQ,OAAQ,QAAS,QAAS,QACpE,SAAU,OAAQ,SAAU,QAAS,SAAU,SAAU,OAAQ,SACjE,SAAU,MAAO,WAAY,YAAa,UAAW,OAAQ,WAC7D,WAAY,OAAQ,SAAU,UAAW,SAAU,YAAa,QAChE,SAAU,QAAS,QAAS,OAAQ,UAAW,OAAQ,OAAQ,OAC/D,QAAS,MAAO,OAAQ,SAAU,QAAS,SAAU,QAAS,OAC9D,QAAS,OAAQ,OAAQ,UAAW,WAAY,SAAU,QAAS,SACnE,SAAU,UAAW,OAAQ,UAAW,MAAO,OAAQ,SAAU,OACjE,SAAU,OAAQ,UAAW,MAAO,QAAS,SAAU,OAAQ,SAC/D,OAAQ,MAAO,OAAQ,MAAO,OAAQ,QAAS,OAAQ,OAAQ,SAC/D,QAAS,MAAO,QAAS,OAAQ,MAAO,OAAQ,OAAQ,UAAW,MACnE,OAAQ,OAAQ,OAAQ,OAAQ,OAAQ,QAAS,SAAU,UAC3D,OAAQ,QAAS,QAAS,QAAS,UAAW,UAAW,UAAW,QACpE,UAAW,SAAU,UAAW,OAAQ,OAAQ,SAAU,OAAQ,UAClE,QAAS,OAAQ,MAAO,OAAQ,SAAU,QAAS,QAAS,QAC5D,SAAU,QAAS,QAAS,QAAS,SAAU,UAAW,WAAY,MACtE,WAAY,WAAY,UAAW,QAAS,SAAU,OAAQ,QAC9D,UAAW,SAAU,SAAU,QAAS,UAAW,WAAY,QAC/D,SAAU,WAAY,WAAY,QAAS,QAAS,OAAQ,QAC5D,QAAS,SAAU,SAAU,SAAU,UAAW,SAAU,SAC5D,SAAU,OAAQ,SAAU,QAAS,QAAS,SAAU,WACxD,UAAW,UAAW,QAAS,SAAU,WAAY,YACrD,aAAc,WAAY,QAAS,UAAW,UAAW,SAAU,QACnE,UAAW,UAAW,UAAW,SAAU,WAAY,MAAO,SAC9D,SAAU,UAAW,SAAU,UAAW,QAAS,QAAS,UAC5D,QAAS,SAAU,QAAS,SAAU,SAAU,UAAW,QAAS,QACpE,SAAU,QAAS,UAAW,YAAa,SAAU,SAAU,UAC/D,UAAW,OAAQ,QAAS,MAAO,UAAW,WAAY,SAC1D,SAAU,OAAQ,SAAU,UAAW,SAAU,UAAW,QAAS,OACrE,QAAS,QAAS,SAAU,WAAY,OAAQ,SAAU,QAC1D,WAAY,YAAa,OAAQ,QAAS,SAAU,OAAQ,QAC5D,QAAS,SAAU,OAAQ,MAAO,MAAO,QAAS,WAAY,QAC9D,UAAW,OAAQ,QAAS,UAAW,WAAY,QAAS,UAC5D,UAAW,SAAU,WAAY,OAAQ,SAAU,SAAU,QAC7D,OAAQ,YAAa,QAAS,OAAQ,QAAS,OAAQ,SAAU,SACjE,UAAW,UAAW,QAAS,QAAS,QAAS,QAAS,MAAO,WACjE,SAAU,UAAW,UAAW,UAAW,OAAQ,UAAW,QAC9D,SAAU,UAAW,SAAU,OAAQ,UAAW,QAAS,MAAO,UAClE,QAAS,YAAa,OAAQ,OAAQ,UAAW,UAAW,WAC5D,YAAa,UAAW,WAAY,UAAW,UAAW,SAAU,OACpE,UAAW,UAAW,YAAa,WAAY,UAAW,UAC1D,QAAS,SAAU,SAAU,OAAQ,SAAU,QAAS,SAAU,UAClE,SAAU,UAAW,MAAO,QAAS,QAAS,UAAW,QAAS,QAClE,OAAQ,QAAS,UAAW,OAAQ,SAAU,OAAQ,SAAU,UAChE,QAAS,OAAQ,QAAS,SAAU,OAAQ,QAAS,QAAS,QAC9D,QAAS,UAAW,QAAS,SAAU,UAAW,UAAW,QAC7D,QAAS,OAAQ,QAAS,SAAU,QAAS,QAAS,WACtD,YAAa,MAAO,UAAW,WAAY,SAAU,QAAS,SAC9D,QAAS,SAAU,SAAU,WAAY,QAAS,UAAW,QAC7D,WAAY,UAAW,UAAW,SAAU,QAAS,QAAS,SAC9D,QAAS,OAAQ,UAAW,UAAW,WAAY,SAAU,WAC7D,WAAY,OAAQ,UAAW,SAAU,SAAU,OAAQ,YAC3D,UAAW,SAAU,SAAU,SAAU,SAAU,WAAY,OAC/D,OAAQ,SAAU,UAAW,QAAS,QAAS,SAAU,WACzD,SAAU,SAAU,UAAW,SAAU,UAAW,SAAU,SAC9D,QAAS,SAAU,QAAS,QAAS,SAAU,UAAW,SAC1D,SAAU,OAAQ,SAAU,UAAW,SAAU,WAAY,UAC7D,WAAY,UAAW,SAAU,UAAW,QAAS,MAAO,SAC5D,SAAU,SAAU,UAAW,SAAU,SAAU,QAAS,MAAO,SACnE,SAAU,UAAW,SAAU,OAAQ,QAAS,SAAU,QAC1D,UAAW,QAAS,QAAS,QAAS,QAAS,SAAU,SACzD,UAAW,SAAU,QAAS,OAAQ,WAAY,UAAW,UAC7D,SAAU,WAAY,SAAU,UAAW,YAAa,YACxD,WAAY,UAAW,UAAW,WAAY,QAAS,SAAU,UACjE,QAAS,SAAU,SAAU,QAAS,QAAS,SAAU,UAAW,QACpE,UAAW,OAAQ,QAAS,SAAU,SAAU,QAAS,SAAU,SACnE,YAAa,SAAU,UAAW,MAAO,QAAS,QAAS,SAC3D,QAAS,QAAS,SAAU,QAAS,OAAQ,QAAS,OAAQ,QAC9D,UAAW,UAAW,UAAW,OAAQ,SAAU,SAAU,MAAO,QACpE,UAAW,SAAU,WAAY,UAAW,WAAY,UAAW,QACnE,OAAQ,SAAU,QAAS,OAAQ,WAAY,SAAU,OAAQ,SACjE,OAAQ,WAAY,WAAY,UAAW,UAAW,WAAY,SAClE,SAAU,QAAS,UAAW,MAAO,QAAS,SAAU,QAAS,SACjE,UAAW,UAAW,WAAY,QAAS,UAAW,OAAQ,OAC9D,QAAS,QAAS,OAAQ,MAAO,MAAO,QAAS,SAAU,SAC3D,QAAS,OAAQ,OAAQ,QAAS,WAAY,SAAU,MAAO,QAC/D,SAAU,QAAS,SAAU,SAAU,MAAO,WAAY,WAC1D,QAAS,UAAW,SAAU,UAAW,QAAS,SAAU,UAC5D,SAAU,OAAQ,UAAW,SAAU,WAAY,UAAW,UAC9D,OAAQ,SAAU,SAAU,UAAW,SAAU,QAAS,QAAS,OACnE,QAAS,SAAU,QAAS,SAAU,SAAU,UAAW,UAC3D,QAAS,SAAU,SAAU,SAAU,MAAO,SAAU,QAAS,QACjE,QAAS,SAAU,OAAQ,WAAY,YAAa,YAAa,UACjE,SAAU,MAAO,QAAS,UAAW,SAAU,OAAQ,QAAS,QAChE,QAAS,QAAS,OAAQ,QAAS,SAAU,SAAU,QAAS,SAChE,OAAQ,QAAS,SAAU,UAAW,SAAU,SAAU,SAC1D,WAAY,QAAS,UAAW,UAAW,SAAU,QAAS,SAC9D,WAAY,OAAQ,QAAS,QAAS,QAAS,UAAW,WAC1D,WAAY,SAAU,QAAS,SAAU,WAAY,SAAU,SAC/D,WAAY,WAAY,OAAQ,OAAQ,OAAQ,SAAU,UAC1D,WAAY,SAAU,WAAY,WAAY,OAAQ,QAAS,QAC/D,SAAU,UAAW,SAAU,SAAU,QAAS,OAAQ,SAC1D,SAAU,OAAQ,SAAU,QAAS,UAAW,SAAU,aAC1D,UAAW,QAAS,SAAU,UAAW,SAAU,UAAW,SAC9D,UAAW,UAAW,QAAS,UAAW,UAAW,WAAY,UACjE,UAAW,aAAc,OAAQ,QAAS,UAAW,UAAW,SAChE,SAAU,SAAU,QAAS,QAAS,SAAU,SAAU,SAC1D,WAAY,WAAY,YAAa,SAAU,UAAW,UAC1D,QAAS,QAAS,SAAU,SAAU,UAAW,SAAU,UAC3D,SAAU,UAAW,SAAU,UAAW,WAAY,UAAW,UACjE,SAAU,SAAU,YAAa,UAAW,UAAW,OAAQ,UAC/D,UAAW,SAAU,SAAU,OAAQ,QAAS,YAAa,QAC7D,QAAS,QAAS,OAAQ,QAAS,OAAQ,OAAQ,MAAO,OAAQ,OAClE,QAAS,OAAQ,OAAQ,QAc7BnN,EAAOD,QAAU,CACbu7B,iBARJ,WAII,MAAQ,GAHK7B,EAAWF,cAAcpsB,MACvBssB,EAAWI,kBAAkB,mCCjbzC,IAAK0B,21BAAAA,GAAAA,EAAAA,qBAAAA,2BAAAA,EAAAA,oBAAAA,0BAAAA,EAAAA,kBAAAA,wBAAAA,EAAAA,6BAAAA,mCAAAA,EAAAA,yBAAAA,+BAAAA,EAAAA,uBAAAA,6BAAAA,EAAAA,0BAAAA,gCAAAA,EAAAA,oBAAAA,0BAAAA,EAAAA,iCAAAA,uCAAAA,EAAAA,oBAAAA,0BAAAA,EAAAA,yBAAAA,+BAAAA,EAAAA,2CAAAA,iDAAAA,EAAAA,eAAAA,qBAAAA,EAAAA,mBAAAA,yBAAAA,EAAAA,kBAAAA,wBAAAA,EAAAA,qBAAAA,2BAAAA,EAAAA,oBAAAA,0BAAAA,EAAAA,6BAAAA,mCAAAA,EAAAA,8BAAAA,oCAAAA,EAAAA,4BAAAA,kCAAAA,EAAAA,oBAAAA,0BAAAA,EAAAA,wBAAAA,8BAAAA,EAAAA,sBAAAA,4BAAAA,EAAAA,0BAAAA,gCAAAA,EAAAA,wBAAAA,8BAAAA,EAAAA,oBAAAA,0BAAAA,EAAAA,qBAAAA,4BAAAA,IAAAA,EAAAA,KAmHL,MAAMC,EAAuBD,EAAUC,qBACjCC,EAAsBF,EAAUE,oBAChCC,EAAoBH,EAAUG,kBAC9BC,EAA+BJ,EAAUI,6BACzCC,EAA2BL,EAAUK,yBACrCC,EAAyBN,EAAUM,uBACnCC,EAA4BP,EAAUO,0BACtCC,EAAsBR,EAAUQ,oBAChCC,EAAmCT,EAAUS,iCAC7CC,EAAsBV,EAAUU,oBAChCC,EAA2BX,EAAUW,yBACrCC,EAA6CZ,EAAUY,2CACvDC,EAAiBb,EAAUa,eAC3BC,EAAqBd,EAAUc,mBAC/BC,EAAoBf,EAAUe,kBAC9BC,EAAuBhB,EAAUgB,qBACjCC,EAAsBjB,EAAUiB,oBAChCC,EAA+BlB,EAAUkB,6BACzCC,EAAgCnB,EAAUmB,8BAC1CC,EAA8BpB,EAAUoB,4BACxCC,EAAsBrB,EAAUqB,oBAChCC,EAA0BtB,EAAUsB,wBACpCC,EAAwBvB,EAAUuB,sBAClCC,EAA4BxB,EAAUwB,0BACtCC,EAA0BzB,EAAUyB,wBACpCC,EAAsB1B,EAAU0B,oBAChCC,EAAuB3B,EAAU2B,qBAK9C,gFClJO,MAAMC,EAAc,CACvB,KAAQ,CACJC,MAAO,KACPC,OAAQ,MAEZ,KAAM,CACFD,MAAO,KACPC,OAAQ,MAEZ,KAAQ,CACJD,MAAO,KACPC,OAAQ,MAEZ,OAAU,CACND,MAAO,KACPC,OAAQ,MAEZ,IAAO,CACHD,MAAO,KACPC,OAAQ,KAEZ,GAAM,CACFD,MAAO,KACPC,OAAQ,KAEZ,IAAO,CACHD,MAAO,IACPC,OAAQ,KAEZ,IAAO,CACHD,MAAO,IACPC,OAAQ,KAEZ,IAAO,CACHD,MAAO,IACPC,OAAQ,KAEZ,IAAO,CACHD,MAAO,IACPC,OAAQ,KAEZ,IAAO,CACHD,MAAO,IACPC,OAAQ,KAEZ,IAAO,CACHD,MAAO,IACPC,OAAQ,KAEZ,IAAO,CACHD,MAAO,IACPC,OAAQ,MAIhB,gCCpDO,IAAKC,2CAAAA,GAAAA,EAAAA,OAAAA,SAAAA,EAAAA,QAAAA,WAAAA,IAAAA,EAAAA,0FCHL,MAAMC,EAAuB,CAShCC,iBAAkB,mCAGtB,gDCZO,IAAKC,4CAAAA,GAAAA,EAAAA,yBAAAA,gCAAAA,EAAAA,qBAAAA,4BAAAA,EAAAA,qBAAAA,4BAAAA,EAAAA,wBAAAA,+BAAAA,EAAAA,YAAAA,mBAAAA,EAAAA,cAAAA,2BAAAA,EAAAA,cAAAA,2BAAAA,EAAAA,WAAAA,wBAAAA,EAAAA,oBAAAA,2BAAAA,EAAAA,wBAAAA,+BAAAA,EAAAA,8BAAAA,qCAAAA,EAAAA,uBAAAA,4BAAAA,EAAAA,kBAAAA,yBAAAA,EAAAA,uBAAAA,8BAAAA,EAAAA,oBAAAA,2BAAAA,EAAAA,sBAAAA,6BAAAA,EAAAA,qBAAAA,0BAAAA,EAAAA,0BAAAA,iCAAAA,EAAAA,qBAAAA,4BAAAA,EAAAA,gBAAAA,uBAAAA,EAAAA,kBAAAA,yBAAAA,EAAAA,SAAAA,gBAAAA,EAAAA,mBAAAA,0BAAAA,EAAAA,WAAAA,kBAAAA,EAAAA,kBAAAA,yBAAAA,EAAAA,eAAAA,qBAAAA,EAAAA,oBAAAA,0BAAAA,EAAAA,OAAAA,cAAAA,EAAAA,mBAAAA,yBAAAA,EAAAA,eAAAA,sBAAAA,EAAAA,iBAAAA,wBAAAA,EAAAA,wBAAAA,+BAAAA,EAAAA,yBAAAA,gCAAAA,EAAAA,4BAAAA,mCAAAA,EAAAA,cAAAA,qBAAAA,EAAAA,qBAAAA,4BAAAA,EAAAA,WAAAA,kBAAAA,EAAAA,kBAAAA,yBAAAA,EAAAA,gBAAAA,uBAAAA,EAAAA,wBAAAA,+BAAAA,EAAAA,yBAAAA,gCAAAA,EAAAA,sBAAAA,6BAAAA,EAAAA,kBAAAA,yBAAAA,EAAAA,SAAAA,gBAAAA,EAAAA,iBAAAA,wBAAAA,EAAAA,iBAAAA,wBAAAA,EAAAA,yBAAAA,gCAAAA,EAAAA,wBAAAA,mBAAAA,EAAAA,wBAAAA,mBAAAA,EAAAA,+BAAAA,kBAAAA,EAAAA,6BAAAA,oCAAAA,EAAAA,kBAAAA,yBAAAA,EAAAA,qBAAAA,gCAAAA,EAAAA,kBAAAA,yBAAAA,EAAAA,gBAAAA,uBAAAA,EAAAA,iBAAAA,wBAAAA,EAAAA,cAAAA,qBAAAA,EAAAA,uBAAAA,4BAAAA,EAAAA,aAAAA,oBAAAA,EAAAA,qBAAAA,4BAAAA,EAAAA,kBAAAA,8BAAAA,EAAAA,mBAAAA,0BAAAA,EAAAA,+BAAAA,sCAAAA,EAAAA,gBAAAA,uBAAAA,EAAAA,gCAAAA,uCAAAA,EAAAA,qBAAAA,4BAAAA,EAAAA,qBAAAA,4BAAAA,EAAAA,6BAAAA,oCAAAA,EAAAA,eAAAA,sBAAAA,EAAAA,qBAAAA,4BAAAA,EAAAA,uBAAAA,8BAAAA,EAAAA,WAAAA,kBAAAA,EAAAA,iBAAAA,wBAAAA,EAAAA,cAAAA,qBAAAA,EAAAA,oBAAAA,2BAAAA,EAAAA,uBAAAA,8BAAAA,EAAAA,8BAAAA,qCAAAA,EAAAA,uBAAAA,8BAAAA,EAAAA,uBAAAA,8BAAAA,EAAAA,uBAAAA,8BAAAA,EAAAA,sBAAAA,6BAAAA,EAAAA,mCAAAA,0CAAAA,EAAAA,mCAAAA,0CAAAA,EAAAA,4BAAAA,mCAAAA,EAAAA,qBAAAA,4BAAAA,EAAAA,uBAAAA,8BAAAA,EAAAA,uBAAAA,8BAAAA,EAAAA,gBAAAA,uBAAAA,EAAAA,iBAAAA,wBAAAA,EAAAA,6BAAAA,oCAAAA,EAAAA,eAAAA,4BAAAA,EAAAA,kCAAAA,qCAAAA,EAAAA,mCAAAA,qCAAAA,EAAAA,6BAAAA,oCAAAA,EAAAA,sBAAAA,8BAAAA,IAAAA,EAAAA,+BCEZ19B,EAAQ29B,WAuCR,SAAqBC,GACnB,IAAIC,EAAOC,EAAQF,GACfG,EAAWF,EAAK,GAChBG,EAAkBH,EAAK,GAC3B,OAAuC,GAA9BE,EAAWC,GAAuB,EAAKA,GA1ClDh+B,EAAQi+B,YAiDR,SAAsBL,GACpB,IAAIM,EAcAj8B,EAbA47B,EAAOC,EAAQF,GACfG,EAAWF,EAAK,GAChBG,EAAkBH,EAAK,GAEvBpE,EAAM,IAAI0E,EAVhB,SAAsBP,EAAKG,EAAUC,GACnC,OAAuC,GAA9BD,EAAWC,GAAuB,EAAKA,EAS9BI,CAAYR,EAAKG,EAAUC,IAEzCK,EAAU,EAGVn8B,EAAM87B,EAAkB,EACxBD,EAAW,EACXA,EAGJ,IAAK97B,EAAI,EAAGA,EAAIC,EAAKD,GAAK,EACxBi8B,EACGI,EAAUV,EAAIzgB,WAAWlb,KAAO,GAChCq8B,EAAUV,EAAIzgB,WAAWlb,EAAI,KAAO,GACpCq8B,EAAUV,EAAIzgB,WAAWlb,EAAI,KAAO,EACrCq8B,EAAUV,EAAIzgB,WAAWlb,EAAI,IAC/Bw3B,EAAI4E,KAAcH,GAAO,GAAM,IAC/BzE,EAAI4E,KAAcH,GAAO,EAAK,IAC9BzE,EAAI4E,KAAmB,IAANH,EAmBnB,OAhBwB,IAApBF,IACFE,EACGI,EAAUV,EAAIzgB,WAAWlb,KAAO,EAChCq8B,EAAUV,EAAIzgB,WAAWlb,EAAI,KAAO,EACvCw3B,EAAI4E,KAAmB,IAANH,GAGK,IAApBF,IACFE,EACGI,EAAUV,EAAIzgB,WAAWlb,KAAO,GAChCq8B,EAAUV,EAAIzgB,WAAWlb,EAAI,KAAO,EACpCq8B,EAAUV,EAAIzgB,WAAWlb,EAAI,KAAO,EACvCw3B,EAAI4E,KAAcH,GAAO,EAAK,IAC9BzE,EAAI4E,KAAmB,IAANH,GAGZzE,GA3FTz5B,EAAQu+B,cAkHR,SAAwBC,GAQtB,IAPA,IAAIN,EACAh8B,EAAMs8B,EAAMr8B,OACZs8B,EAAav8B,EAAM,EACnByJ,EAAQ,GACR+yB,EAAiB,MAGZz8B,EAAI,EAAG08B,EAAOz8B,EAAMu8B,EAAYx8B,EAAI08B,EAAM18B,GAAKy8B,EACtD/yB,EAAMhJ,KAAKi8B,EAAYJ,EAAOv8B,EAAIA,EAAIy8B,EAAkBC,EAAOA,EAAQ18B,EAAIy8B,IAqB7E,OAjBmB,IAAfD,GACFP,EAAMM,EAAMt8B,EAAM,GAClByJ,EAAMhJ,KACJk8B,EAAOX,GAAO,GACdW,EAAQX,GAAO,EAAK,IACpB,OAEsB,IAAfO,IACTP,GAAOM,EAAMt8B,EAAM,IAAM,GAAKs8B,EAAMt8B,EAAM,GAC1CyJ,EAAMhJ,KACJk8B,EAAOX,GAAO,IACdW,EAAQX,GAAO,EAAK,IACpBW,EAAQX,GAAO,EAAK,IACpB,MAIGvyB,EAAM3B,KAAK,KAzIpB,IALA,IAAI60B,EAAS,GACTP,EAAY,GACZH,EAA4B,oBAAfW,WAA6BA,WAAa35B,MAEvDqW,EAAO,mEACFvZ,EAAI,EAAGC,EAAMsZ,EAAKrZ,OAAQF,EAAIC,IAAOD,EAC5C48B,EAAO58B,GAAKuZ,EAAKvZ,GACjBq8B,EAAU9iB,EAAK2B,WAAWlb,IAAMA,EAQlC,SAAS67B,EAASF,GAChB,IAAI17B,EAAM07B,EAAIz7B,OAEd,GAAID,EAAM,EAAI,EACZ,MAAM,IAAIuC,MAAM,kDAKlB,IAAIs5B,EAAWH,EAAI95B,QAAQ,KAO3B,OANkB,IAAdi6B,IAAiBA,EAAW77B,GAMzB,CAAC67B,EAJcA,IAAa77B,EAC/B,EACA,EAAK67B,EAAW,GAsEtB,SAASa,EAAaJ,EAAO37B,EAAOyzB,GAGlC,IAFA,IAAI4H,EARoBa,EASpBC,EAAS,GACJ/8B,EAAIY,EAAOZ,EAAIq0B,EAAKr0B,GAAK,EAChCi8B,GACIM,EAAMv8B,IAAM,GAAM,WAClBu8B,EAAMv8B,EAAI,IAAM,EAAK,QACP,IAAfu8B,EAAMv8B,EAAI,IACb+8B,EAAOr8B,KAdFk8B,GADiBE,EAeMb,IAdT,GAAK,IACxBW,EAAOE,GAAO,GAAK,IACnBF,EAAOE,GAAO,EAAI,IAClBF,EAAa,GAANE,IAaT,OAAOC,EAAOh1B,KAAK,IAjGrBs0B,EAAU,IAAInhB,WAAW,IAAM,GAC/BmhB,EAAU,IAAInhB,WAAW,IAAM,oBCnBkCld,EAAOD,QAAiJ,SAASwN,GAAG,IAAI/H,EAAE,GAAG,SAASkI,EAAE1L,GAAG,GAAGwD,EAAExD,GAAG,OAAOwD,EAAExD,GAAGjC,QAAQ,IAAIsR,EAAE7L,EAAExD,GAAG,CAACA,EAAIyD,GAAE,EAAG1F,QAAQ,IAAI,OAAOwN,EAAEvL,GAAGoD,KAAKiM,EAAEtR,QAAQsR,EAAEA,EAAEtR,QAAQ2N,GAAG2D,EAAE5L,GAAE,EAAG4L,EAAEtR,QAAQ,OAAO2N,EAAE/I,EAAE4I,EAAEG,EAAEC,EAAEnI,EAAEkI,EAAE8sB,EAAE,SAASjtB,EAAE/H,EAAExD,GAAG0L,EAAER,EAAEK,EAAE/H,IAAI5E,OAAO0kB,eAAe/X,EAAE/H,EAAE,CAACw5B,YAAW,EAAGxZ,IAAIxjB,KAAK0L,EAAEA,EAAE,SAASH,GAAG,oBAAoB0xB,QAAQA,OAAOC,aAAat+B,OAAO0kB,eAAe/X,EAAE0xB,OAAOC,YAAY,CAACv3B,MAAM,WAAW/G,OAAO0kB,eAAe/X,EAAE,aAAa,CAAC5F,OAAM,KAAM+F,EAAElI,EAAE,SAAS+H,EAAE/H,GAAG,GAAG,EAAEA,IAAI+H,EAAEG,EAAEH,IAAI,EAAE/H,EAAE,OAAO+H,EAAE,GAAG,EAAE/H,GAAG,iBAAiB+H,GAAGA,GAAGA,EAAE4xB,WAAW,OAAO5xB,EAAE,IAAIvL,EAAEpB,OAAOw+B,OAAO,MAAM,GAAG1xB,EAAEA,EAAE1L,GAAGpB,OAAO0kB,eAAetjB,EAAE,UAAU,CAACg9B,YAAW,EAAGr3B,MAAM4F,IAAI,EAAE/H,GAAG,iBAAiB+H,EAAE,IAAI,IAAI8D,KAAK9D,EAAEG,EAAE8sB,EAAEx4B,EAAEqP,EAAE,SAAS7L,GAAG,OAAO+H,EAAE/H,IAAIpE,KAAK,KAAKiQ,IAAI,OAAOrP,GAAG0L,EAAE2D,EAAE,SAAS9D,GAAG,IAAI/H,EAAE+H,GAAGA,EAAE4xB,WAAW,WAAW,OAAO5xB,EAAE8xB,SAAS,WAAW,OAAO9xB,GAAG,OAAOG,EAAE8sB,EAAEh1B,EAAE,IAAIA,GAAGA,GAAGkI,EAAER,EAAE,SAASK,EAAE/H,GAAG,OAAO5E,OAAOa,UAAUwX,eAAe7T,KAAKmI,EAAE/H,IAAIkI,EAAEF,EAAE,GAAGE,EAAEA,EAAEL,EAAE,IAAj5B,CAAs5B,CAAC,GAAG,SAASE,EAAE/H,EAAEkI,GAAG,aAAalI,EAAE25B,YAAW,EAAG35B,EAAE65B,aAAQ,EAAO,IAAIr9B,EAAE0L,EAAE,IAAI2D,EAAE,WAAW,SAAS9D,KAAK,OAAOA,EAAE+xB,cAAc,SAAS/xB,EAAE/H,GAAG,IAAIkI,EAAElI,EAAEZ,MAAM2I,GAAG,OAAOG,GAAGA,EAAExL,OAAO,GAAGwL,EAAE,IAAI,IAAIH,EAAEgyB,eAAe,SAAShyB,EAAE/H,GAAG,IAAIkI,EAAElI,EAAEZ,MAAM2I,GAAG,OAAOG,GAAGA,EAAExL,OAAO,GAAGwL,EAAE,IAAI,IAAIH,EAAEiyB,oBAAoB,SAASjyB,EAAE/H,EAAEkI,GAAG,GAAGH,EAAEwC,KAAKvK,GAAG,OAAOkI,GAAGH,EAAEkyB,sBAAsB,SAASlyB,GAAG,OAAOA,GAAG,IAAI,KAAK,MAAM,KAAK,IAAI,KAA0C,IAAI,SAAS,MAAM,KAA7C,IAAI,SAAS,MAAM,OAA+B,IAAI,SAAS,MAAM,OAAO,IAAI,SAAS,MAAM,QAAQ,IAAI,SAAS,MAAM,IAAI,IAAI,SAAS,MAAM,IAAI,IAAI,SAAS,MAAM,MAAM,IAAI,UAAU,MAAM,KAAK,QAAQ,SAASA,EAAEmyB,oBAAoB,SAASnyB,GAAG,IAAI/H,EAAE+H,EAAE7I,MAAM,KAAKV,OAAO,EAAE,GAAG0D,KAAI,SAAU6F,GAAG,OAAOtE,SAASsE,EAAE,KAAK,KAAK,GAAG/H,EAAE9C,KAAK,GAAG,KAAK8C,EAAE,GAAG,OAAOA,EAAE,IAAI,KAAK,EAAE,MAAM,UAAU,KAAK,EAAE,MAAM,eAAe,KAAK,EAAE,MAAM,OAAO,KAAK,EAAE,MAAM,gBAAgB,KAAK,EAAE,MAAM,YAAY,KAAK,GAAG,MAAM,WAAW,KAAK,GAAG,MAAM,aAAa,KAAK,GAAG,MAAM,SAAS,KAAK,GAAG,MAAM,cAAc,KAAK,GAAG,MAAM,SAAS,KAAK,GAAG,MAAM,WAAW,QAAQ,SAAS+H,EAAEoyB,sBAAsB,SAASpyB,GAAG,IAAI/H,EAAE+H,EAAE7I,MAAM,KAAKV,OAAO,EAAE,GAAG0D,KAAI,SAAU6F,GAAG,OAAOtE,SAASsE,EAAE,KAAK,KAAK,GAAG/H,EAAE9C,KAAK,KAAK,IAAI8C,EAAE,IAAIA,EAAE,GAAG,GAAG,OAAO,IAAIA,EAAE,IAAIA,EAAE,GAAG,EAAE,UAAU,IAAIA,EAAE,IAAIA,EAAE,IAAI,EAAE,QAAQ,IAAIA,EAAE,IAAIA,EAAE,GAAG,EAAE,SAAS,IAAIA,EAAE,IAAI,IAAIA,EAAE,GAAG,QAAQ,IAAIA,EAAE,IAAIA,EAAE,GAAG,EAAE,cAAc,IAAIA,EAAE,GAAG,YAAY,IAAIA,EAAE,IAAIA,EAAE,GAAG,EAAE,qBAAqB,IAAIA,EAAE,IAAIA,EAAE,GAAG,EAAE,aAAa,IAAIA,EAAE,IAAIA,EAAE,IAAI,EAAE,SAAS,IAAIA,EAAE,GAAG,WAAW,IAAIA,EAAE,GAAG,cAAc,IAAIA,EAAE,GAAG,SAAS,IAAIA,EAAE,GAAG,OAAO,IAAIA,EAAE,GAAG,WAAM,GAAQ+H,EAAEqyB,oBAAoB,SAASryB,GAAG,OAAOA,EAAE7I,MAAM,KAAKxC,QAAQqL,EAAEsyB,gBAAgB,SAASr6B,EAAEkI,EAAE1L,QAAG,IAASA,IAAIA,GAAE,GAAI,IAAIqP,EAAE9D,EAAEqyB,oBAAoBp6B,GAAG6H,EAAEE,EAAEqyB,oBAAoBlyB,GAAGR,EAAEzC,KAAKotB,IAAIxmB,EAAEhE,GAAGQ,EAAE,EAAEP,EAAEC,EAAE7F,IAAI,CAAClC,EAAEkI,IAAG,SAAUlI,GAAG,IAAIkI,EAAER,EAAEK,EAAEqyB,oBAAoBp6B,GAAGxD,EAAEwD,EAAE,IAAIN,MAAMwI,EAAE,GAAG3D,KAAK,MAAM,OAAOwD,EAAE7F,IAAI1F,EAAE0C,MAAM,MAAK,SAAU6I,GAAG,OAAO,IAAIrI,MAAM,GAAGqI,EAAErL,QAAQ6H,KAAK,KAAKwD,KAAKuyB,aAAa,IAAI99B,IAAI6L,EAAEX,EAAEzC,KAAK6uB,IAAIjoB,EAAEhE,IAAIH,GAAG,EAAEA,GAAGW,GAAG,CAAC,GAAGP,EAAE,GAAGJ,GAAGI,EAAE,GAAGJ,GAAG,OAAO,EAAE,GAAGI,EAAE,GAAGJ,KAAKI,EAAE,GAAGJ,GAAG,CAAC,GAAGA,IAAIW,EAAE,OAAO,EAAEX,GAAG,OAAO,GAAGI,EAAE,GAAGJ,GAAGI,EAAE,GAAGJ,GAAG,OAAO,IAAIK,EAAE7F,IAAI,SAAS6F,EAAE/H,GAAG,IAAIkI,EAAE1L,EAAE,GAAG,GAAGkD,MAAMzD,UAAUiG,IAAI,OAAOxC,MAAMzD,UAAUiG,IAAItC,KAAKmI,EAAE/H,GAAG,IAAIkI,EAAE,EAAEA,EAAEH,EAAErL,OAAOwL,GAAG,EAAE1L,EAAEU,KAAK8C,EAAE+H,EAAEG,KAAK,OAAO1L,GAAGuL,EAAEwyB,gBAAgB,SAASxyB,GAAG,OAAOvL,EAAEg+B,oBAAoBzyB,IAAIA,EAAE0yB,sBAAsB,SAAS1yB,GAAG,OAAOvL,EAAEk+B,YAAY3yB,IAAI,IAAIA,EAAtvE,GAA2vE/H,EAAE65B,QAAQhuB,EAAE9D,EAAExN,QAAQyF,EAAE65B,SAAS,GAAG,SAAS9xB,EAAE/H,EAAEkI,GAAG,aAAalI,EAAE25B,YAAW,EAAG35B,EAAE26B,WAAW36B,EAAE46B,OAAO56B,EAAE66B,cAAc76B,EAAE06B,YAAY16B,EAAEw6B,yBAAoB,EAAOx6B,EAAEw6B,oBAAoB,CAAC,cAAc,cAAc,kBAAkB,UAAUM,KAAK,OAAOC,WAAW,aAAaC,OAAO,SAASC,SAAS,WAAWC,SAAS,WAAWC,QAAQ,UAAUC,MAAM,QAAQC,QAAQ,UAAU,gBAAgB,gBAAgBC,UAAU,YAAY,oBAAoB,KAAK,WAAW,WAAWC,QAAQ,UAAU,iBAAiB,OAAO,aAAa,KAAK,sBAAsB,QAAQC,MAAM,QAAQ,cAAc,cAAcC,UAAU,YAAYC,OAAO,SAASC,SAAS,WAAWC,GAAG,KAAKC,OAAO,SAASC,OAAO,SAASC,SAAS,WAAW,+BAA+B,mBAAmBC,UAAU,YAAYC,SAAS,WAAWC,MAAM,QAAQC,MAAM,QAAQ,aAAa,KAAKC,QAAQ,UAAU,gBAAgB,QAAQC,OAAO,SAAS,iBAAiB,SAASC,KAAK,QAAQt8B,EAAE06B,YAAY,CAAC6B,YAAY,cAAcC,QAAQ,kBAAkBC,KAAK,OAAOC,WAAW,aAAaC,OAAO,SAASC,SAAS,WAAWC,SAAS,WAAWC,QAAQ,UAAUC,MAAM,QAAQC,QAAQ,UAAUC,UAAU,YAAYC,cAAc,gBAAgBC,GAAG,oBAAoBC,SAAS,WAAWC,QAAQ,UAAUC,KAAK,iBAAiBC,GAAG,aAAaC,MAAM,sBAAsBC,MAAM,QAAQC,YAAY,cAAcC,UAAU,YAAYC,OAAO,SAASC,SAAS,WAAWC,GAAG,aAAaC,OAAO,kBAAkBC,OAAO,SAASC,SAAS,WAAWC,iBAAiB,+BAA+BC,UAAU,YAAYC,SAAS,WAAWC,MAAM,QAAQC,MAAM,QAAQC,GAAG,aAAaC,QAAQ,UAAUC,MAAM,gBAAgBC,OAAO,SAASC,OAAO,kBAAkB3+B,EAAE66B,cAAc,CAAC+D,OAAO,SAASC,OAAO,SAASC,QAAQ,UAAUC,GAAG,MAAM/+B,EAAE46B,OAAO,CAACoE,aAAa,gBAAgBC,QAAQ,UAAUC,MAAM,QAAQC,IAAI,MAAMC,QAAQ,UAAUC,MAAM,QAAQtE,WAAW,aAAaD,KAAK,OAAOqB,MAAM,QAAQmD,MAAM,QAAQC,SAAS,YAAYC,aAAa,gBAAgBlD,KAAK,QAAQt8B,EAAE26B,WAAW,CAAC8E,SAAS,WAAWC,MAAM,QAAQC,QAAQ,UAAUC,OAAO,SAASC,MAAM,QAAQC,OAAO,WAAW,GAAG,SAAS/3B,EAAE/H,EAAEkI,GAAG,aAAalI,EAAE25B,YAAW,EAAG35B,EAAE65B,aAAQ,EAAO,IAAIr9B,EAAEqP,GAAGrP,EAAE0L,EAAE,MAAM1L,EAAEm9B,WAAWn9B,EAAE,CAACq9B,QAAQr9B,GAAGqL,EAAEK,EAAE,IAAI,SAASR,EAAEK,EAAE/H,GAAG,IAAI,IAAIkI,EAAE,EAAEA,EAAElI,EAAEtD,OAAOwL,IAAI,CAAC,IAAI1L,EAAEwD,EAAEkI,GAAG1L,EAAEg9B,WAAWh9B,EAAEg9B,aAAY,EAAGh9B,EAAEujC,cAAa,EAAG,UAAUvjC,IAAIA,EAAEwjC,UAAS,GAAI5kC,OAAO0kB,eAAe/X,EAAEvL,EAAE0M,IAAI1M,IAAI,IAAI6L,EAAE,WAAW,SAASN,KAAK,IAAI/H,EAAIxD,EAAE,OAAOuL,EAAEk4B,UAAU,SAASl4B,EAAE/H,GAAG,QAAG,IAASA,IAAIA,GAAE,GAAI,iBAAiB+H,EAAE,MAAM,IAAI/I,MAAM,gCAAgC,OAAO,IAAI6M,EAAEguB,QAAQ9xB,EAAE/H,IAAI+H,EAAEnC,MAAM,SAASmC,GAAG,OAAO,IAAI8D,EAAEguB,QAAQ9xB,GAAGm4B,aAAalgC,EAAE+H,EAAEvL,EAAE,CAAC,CAAC0M,IAAI,cAAc8W,IAAI,WAAW,OAAOnY,EAAE6yB,cAAc,CAACxxB,IAAI,aAAa8W,IAAI,WAAW,OAAOnY,EAAE8yB,aAAa,CAACzxB,IAAI,SAAS8W,IAAI,WAAW,OAAOnY,EAAE+yB,SAAS,CAAC1xB,IAAI,gBAAgB8W,IAAI,WAAW,OAAOnY,EAAEgzB,iBAAoB,MAAOnzB,EAAE1H,EAAE/D,UAAX,MAAwBO,GAAGkL,EAAE1H,EAAExD,GAAGuL,EAA1f,GAA+f/H,EAAE65B,QAAQxxB,EAAEN,EAAExN,QAAQyF,EAAE65B,SAAS,GAAG,SAAS9xB,EAAE/H,EAAEkI,GAAG,aAAalI,EAAE25B,YAAW,EAAG35B,EAAE65B,aAAQ,EAAO,IAAIr9B,EAAEsL,EAAEI,EAAE,KAAK2D,EAAE/D,EAAEI,EAAE,KAAKL,EAAEC,EAAEI,EAAE,KAAKR,EAAEI,EAAEI,EAAE,KAAKG,EAAEP,EAAEI,EAAE,KAAK,SAASJ,EAAEC,GAAG,OAAOA,GAAGA,EAAE4xB,WAAW5xB,EAAE,CAAC8xB,QAAQ9xB,GAAG,IAAIitB,EAAE,WAAW,SAASjtB,EAAEA,EAAE/H,GAAG,QAAG,IAASA,IAAIA,GAAE,GAAI,MAAM+H,GAAG,KAAKA,EAAE,MAAM,IAAI/I,MAAM,sCAAsChE,KAAKmlC,IAAIp4B,EAAE/M,KAAKolC,aAAa,IAAG,IAAKpgC,GAAGhF,KAAK4K,QAAQ,IAAI5F,EAAE+H,EAAE9L,UAAU,OAAO+D,EAAEqgC,MAAM,WAAW,OAAOrlC,KAAKmlC,KAAKngC,EAAEuK,KAAK,SAASxC,GAAG,OAAOA,EAAEwC,KAAKvP,KAAKmlC,MAAMngC,EAAEsgC,aAAa,WAAW,IAAIv4B,EAAE/M,KAAKA,KAAKolC,aAAaG,QAAQ,GAAG,IAAIvgC,EAAExD,EAAEq9B,QAAQx2B,MAAK,SAAUrD,GAAG,GAAG,mBAAmBA,EAAEuK,KAAK,OAAOvK,EAAEuK,KAAKxC,GAAG,GAAG/H,EAAEuK,gBAAgB7K,MAAM,OAAOM,EAAEuK,KAAK3D,MAAK,SAAU5G,GAAG,OAAO+H,EAAEwC,KAAKvK,MAAM,MAAM,IAAIhB,MAAM,2CAA2C,OAAOgB,IAAIhF,KAAKolC,aAAaG,QAAQvgC,EAAEwgC,SAASxlC,KAAKqlC,UAAUrlC,KAAKolC,aAAaG,SAASvgC,EAAEygC,WAAW,WAAW,OAAOzlC,KAAKolC,aAAaG,QAAQvlC,KAAKolC,aAAaG,QAAQvlC,KAAKslC,gBAAgBtgC,EAAE0gC,eAAe,SAAS34B,GAAG,OAAOA,EAAE8B,OAAO7O,KAAKylC,aAAaj5B,MAAM2qB,eAAe,GAAGn3B,KAAKylC,aAAaj5B,MAAM,IAAIxH,EAAE2gC,kBAAkB,WAAW,OAAO3lC,KAAKylC,aAAax0B,SAASjM,EAAE4gC,MAAM,WAAW,OAAO5lC,KAAKolC,aAAaS,GAAG7lC,KAAKolC,aAAaS,GAAG7lC,KAAK8lC,WAAW9gC,EAAE8gC,QAAQ,WAAW,IAAI/4B,EAAE/M,KAAKA,KAAKolC,aAAaS,GAAG,GAAG,IAAI7gC,EAAE6L,EAAEguB,QAAQx2B,MAAK,SAAUrD,GAAG,GAAG,mBAAmBA,EAAEuK,KAAK,OAAOvK,EAAEuK,KAAKxC,GAAG,GAAG/H,EAAEuK,gBAAgB7K,MAAM,OAAOM,EAAEuK,KAAK3D,MAAK,SAAU5G,GAAG,OAAO+H,EAAEwC,KAAKvK,MAAM,MAAM,IAAIhB,MAAM,2CAA2C,OAAOgB,IAAIhF,KAAKolC,aAAaS,GAAG7gC,EAAEwgC,SAASxlC,KAAKqlC,UAAUrlC,KAAKolC,aAAaS,IAAI7gC,EAAE+gC,UAAU,SAASh5B,GAAG,IAAI/H,EAAEhF,KAAK4lC,QAAQp5B,KAAK,OAAOO,EAAE8B,OAAO7J,GAAGmyB,eAAe,GAAGnyB,GAAG,IAAIA,EAAEghC,aAAa,WAAW,OAAOhmC,KAAK4lC,QAAQ30B,SAASjM,EAAEihC,YAAY,WAAW,OAAOjmC,KAAKolC,aAAac,SAASlmC,KAAKolC,aAAac,SAASlmC,KAAKmmC,iBAAiBnhC,EAAEohC,gBAAgB,SAASr5B,QAAG,IAASA,IAAIA,GAAE,GAAI,IAAI/H,EAAEhF,KAAKimC,cAAcr+B,KAAK,OAAOmF,EAAE8B,OAAO7J,GAAGmyB,eAAe,GAAGnyB,GAAG,IAAIA,EAAEmhC,cAAc,WAAW,IAAIp5B,EAAE/M,KAAKA,KAAKolC,aAAac,SAAS,GAAG,IAAIlhC,EAAE6H,EAAEgyB,QAAQx2B,MAAK,SAAUrD,GAAG,GAAG,mBAAmBA,EAAEuK,KAAK,OAAOvK,EAAEuK,KAAKxC,GAAG,GAAG/H,EAAEuK,gBAAgB7K,MAAM,OAAOM,EAAEuK,KAAK3D,MAAK,SAAU5G,GAAG,OAAO+H,EAAEwC,KAAKvK,MAAM,MAAM,IAAIhB,MAAM,2CAA2C,OAAOgB,IAAIhF,KAAKolC,aAAac,SAASlhC,EAAEwgC,SAASxlC,KAAKqlC,UAAUrlC,KAAKolC,aAAac,UAAUlhC,EAAEqhC,UAAU,WAAW,OAAOrmC,KAAKolC,aAAakB,OAAOtmC,KAAKolC,aAAakB,OAAOtmC,KAAKumC,eAAevhC,EAAEwhC,cAAc,SAASz5B,GAAG,OAAOA,EAAE8B,OAAO7O,KAAKqmC,YAAY75B,MAAM2qB,eAAe,GAAGn3B,KAAKqmC,YAAY75B,MAAM,IAAIxH,EAAEuhC,YAAY,WAAW,IAAIx5B,EAAE/M,KAAKA,KAAKolC,aAAakB,OAAO,GAAG,IAAIthC,EAAE0H,EAAEmyB,QAAQx2B,MAAK,SAAUrD,GAAG,GAAG,mBAAmBA,EAAEuK,KAAK,OAAOvK,EAAEuK,KAAKxC,GAAG,GAAG/H,EAAEuK,gBAAgB7K,MAAM,OAAOM,EAAEuK,KAAK3D,MAAK,SAAU5G,GAAG,OAAO+H,EAAEwC,KAAKvK,MAAM,MAAM,IAAIhB,MAAM,2CAA2C,OAAOgB,IAAIhF,KAAKolC,aAAakB,OAAOthC,EAAEwgC,SAASxlC,KAAKqlC,UAAUrlC,KAAKolC,aAAakB,QAAQthC,EAAE4F,MAAM,WAAW,OAAO5K,KAAKslC,eAAetlC,KAAK8lC,UAAU9lC,KAAKmmC,gBAAgBnmC,KAAKumC,cAAcvmC,MAAMgF,EAAEkgC,UAAU,WAAW,OAAO9kC,OAAOqmC,OAAO,GAAGzmC,KAAKolC,eAAepgC,EAAE0hC,UAAU,SAAS35B,GAAG,IAAI/H,EAAEhF,KAAKkN,EAAE,GAAG1L,EAAE,EAAEqP,EAAE,GAAGhE,EAAE,EAAE,GAAGzM,OAAOC,KAAK0M,GAAGxM,SAAQ,SAAUyE,GAAG,IAAI0H,EAAEK,EAAE/H,GAAG,iBAAiB0H,GAAGmE,EAAE7L,GAAG0H,EAAEG,GAAG,GAAG,iBAAiBH,IAAIQ,EAAElI,GAAG0H,EAAElL,GAAG,MAAMA,EAAE,EAAE,CAAC,IAAIkL,EAAEtM,OAAOC,KAAK6M,GAAGG,EAAEX,EAAErE,MAAK,SAAU0E,GAAG,OAAO/H,EAAE2hC,KAAK55B,MAAM,GAAGM,EAAE,CAAC,IAAIP,EAAE9M,KAAK0mC,UAAUx5B,EAAEG,IAAI,QAAG,IAASP,EAAE,OAAOA,EAAE,IAAIktB,EAAEttB,EAAErE,MAAK,SAAU0E,GAAG,OAAO/H,EAAE4hC,WAAW75B,MAAM,GAAGitB,EAAE,CAAC,IAAI7sB,EAAEnN,KAAK0mC,UAAUx5B,EAAE8sB,IAAI,QAAG,IAAS7sB,EAAE,OAAOA,GAAG,GAAGN,EAAE,EAAE,CAAC,IAAIunB,EAAEh0B,OAAOC,KAAKwQ,GAAGxI,MAAK,SAAU0E,GAAG,OAAO/H,EAAE6hC,UAAU95B,GAAE,MAAO,QAAG,IAASqnB,EAAE,OAAOp0B,KAAK8mC,eAAej2B,EAAEujB,MAAMpvB,EAAE6hC,UAAU,SAAS95B,EAAE/H,QAAG,IAASA,IAAIA,GAAE,GAAI,IAAIkI,EAAElN,KAAK0lC,iBAAiBvO,cAAc31B,EAAEuL,EAAEoqB,cAActmB,EAAExD,EAAEwxB,QAAQY,sBAAsBj+B,GAAG,OAAOwD,GAAG6L,IAAIrP,EAAEqP,EAAEsmB,eAAe31B,IAAI0L,GAAGlI,EAAE8hC,eAAe,SAAS/5B,GAAG,IAAI/H,EAAE,CAAC,GAAGkI,EAAEH,EAAEvL,GAAE,EAAGqP,EAAE7Q,KAAK2lC,oBAAoB,GAAG,iBAAiB90B,EAAE,MAAM,MAAM9D,EAAE,IAAI,MAAMA,EAAE,IAAIG,EAAEH,EAAE1I,OAAO,GAAG,MAAM0I,EAAE,IAAIvL,GAAE,EAAG0L,EAAEH,EAAE1I,OAAO,IAAIW,EAAE,GAAG,MAAM+H,EAAE,GAAG/H,EAAE9C,KAAK,GAAG8C,EAAE9C,MAAM,IAAI,MAAM6K,EAAE,GAAGG,EAAEH,EAAE1I,OAAO,GAAG,MAAM0I,EAAE,KAAKvL,GAAE,EAAG0L,EAAEH,EAAE1I,OAAO,IAAIW,EAAE3B,QAAQgK,EAAEwxB,QAAQQ,gBAAgBxuB,EAAE3D,EAAE1L,KAAK,GAAGwD,EAAE2hC,KAAK,SAAS55B,GAAG,OAAO/M,KAAK+lC,WAAU,KAAMl3B,OAAO9B,GAAGoqB,eAAenyB,EAAE4hC,WAAW,SAAS75B,GAAG,OAAO/M,KAAKomC,iBAAgB,KAAMv3B,OAAO9B,GAAGoqB,eAAenyB,EAAE+hC,SAAS,SAASh6B,GAAG,OAAO/M,KAAKwmC,eAAc,KAAM33B,OAAO9B,GAAGoqB,eAAenyB,EAAEgiC,GAAG,SAASj6B,GAAG,OAAO/M,KAAK6mC,UAAU95B,IAAI/M,KAAK2mC,KAAK55B,IAAI/M,KAAK4mC,WAAW75B,IAAI/H,EAAE4G,KAAK,SAASmB,GAAG,IAAI/H,EAAEhF,KAAK,YAAO,IAAS+M,IAAIA,EAAE,IAAIA,EAAEnB,MAAK,SAAUmB,GAAG,OAAO/H,EAAEgiC,GAAGj6B,OAAOA,EAAluI,GAAuuI/H,EAAE65B,QAAQ7E,EAAEjtB,EAAExN,QAAQyF,EAAE65B,SAAS,GAAG,SAAS9xB,EAAE/H,EAAEkI,GAAG,aAAalI,EAAE25B,YAAW,EAAG35B,EAAE65B,aAAQ,EAAO,IAAIr9B,EAAEqP,GAAGrP,EAAE0L,EAAE,MAAM1L,EAAEm9B,WAAWn9B,EAAE,CAACq9B,QAAQr9B,GAAOqL,EAAE,6BAA6BH,EAAE,CAAC,CAAC6C,KAAK,CAAC,cAAci2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,aAAaU,EAAE2D,EAAEguB,QAAQC,cAAc,2BAA2B/xB,IAAI8D,EAAEguB,QAAQC,cAAcjyB,EAAEE,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,UAAUi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,SAASU,EAAE2D,EAAEguB,QAAQC,cAAcjyB,EAAEE,IAAI8D,EAAEguB,QAAQC,cAAc,kCAAkC/xB,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,gBAAgBi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,SAASU,EAAE2D,EAAEguB,QAAQC,cAAc,2BAA2B/xB,IAAI8D,EAAEguB,QAAQC,cAAcjyB,EAAEE,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,mBAAmBi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,gCAAgCU,EAAE2D,EAAEguB,QAAQC,cAAcjyB,EAAEE,IAAI8D,EAAEguB,QAAQC,cAAc,2CAA2C/xB,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,UAAUi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,uBAAuBU,EAAE2D,EAAEguB,QAAQC,cAAcjyB,EAAEE,IAAI8D,EAAEguB,QAAQC,cAAc,iCAAiC/xB,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,cAAci2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,cAAcU,EAAE2D,EAAEguB,QAAQC,cAAc,qCAAqC/xB,IAAI8D,EAAEguB,QAAQC,cAAcjyB,EAAEE,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,UAAUi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,SAASU,EAAE2D,EAAEguB,QAAQC,cAAc,iCAAiC/xB,IAAI8D,EAAEguB,QAAQC,cAAcjyB,EAAEE,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,UAAUi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,SAASU,EAAE2D,EAAEguB,QAAQC,cAAc,iCAAiC/xB,IAAI8D,EAAEguB,QAAQC,cAAcjyB,EAAEE,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,UAAUi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,eAAeU,EAAE2D,EAAEguB,QAAQC,cAAcjyB,EAAEE,IAAI8D,EAAEguB,QAAQC,cAAc,kCAAkC/xB,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,cAAci2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,kBAAkBU,EAAE2D,EAAEguB,QAAQC,cAAc,sCAAsC/xB,IAAI8D,EAAEguB,QAAQC,cAAcjyB,EAAEE,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,cAAci2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,cAAcU,EAAE2D,EAAEguB,QAAQC,cAAcjyB,EAAEE,IAAI8D,EAAEguB,QAAQC,cAAc,sCAAsC/xB,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,kBAAkBi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,WAAWU,EAAE2D,EAAEguB,QAAQC,cAAcjyB,EAAEE,IAAI8D,EAAEguB,QAAQC,cAAc,0CAA0C/xB,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,aAAai2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,YAAYU,EAAE2D,EAAEguB,QAAQC,cAAcjyB,EAAEE,IAAI8D,EAAEguB,QAAQC,cAAc,qCAAqC/xB,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,WAAWi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,UAAUU,EAAE2D,EAAEguB,QAAQC,cAAcjyB,EAAEE,IAAI8D,EAAEguB,QAAQC,cAAc,mCAAmC/xB,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,aAAai2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,YAAYU,EAAE2D,EAAEguB,QAAQC,cAAcjyB,EAAEE,IAAI8D,EAAEguB,QAAQC,cAAc,qCAAqC/xB,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,aAAai2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,YAAYU,EAAE2D,EAAEguB,QAAQC,cAAcjyB,EAAEE,IAAI8D,EAAEguB,QAAQC,cAAc,qCAAqC/xB,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,mBAAmBi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,UAAUU,EAAE2D,EAAEguB,QAAQC,cAAc,2CAA2C/xB,IAAI8D,EAAEguB,QAAQC,cAAcjyB,EAAEE,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,cAAci2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,iBAAiB+C,KAAKxC,GAAG,kBAAkB,cAAcG,EAAE2D,EAAEguB,QAAQC,cAAc,kDAAkD/xB,IAAI8D,EAAEguB,QAAQC,cAAcjyB,EAAEE,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,iBAAiBi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,qBAAqBU,EAAE2D,EAAEguB,QAAQC,cAAc,iCAAiC/xB,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,YAAYi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,kBAAkBU,EAAE2D,EAAEguB,QAAQC,cAAc,2BAA2B/xB,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,kBAAkBi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,kBAAkBU,EAAE2D,EAAEguB,QAAQE,eAAe,mCAAmChyB,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,YAAYi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,WAAWU,EAAE2D,EAAEguB,QAAQC,cAAc,6BAA6B/xB,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,cAAci2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,aAAaU,EAAE2D,EAAEguB,QAAQC,cAAc,+BAA+B/xB,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,aAAai2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,YAAYU,EAAE2D,EAAEguB,QAAQC,cAAc,qCAAqC/xB,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,SAASi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,eAAeU,EAAE2D,EAAEguB,QAAQC,cAAc,0BAA0B/xB,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,YAAYi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,aAAaU,EAAE2D,EAAEguB,QAAQC,cAAc,+BAA+B/xB,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,aAAai2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,YAAYU,EAAE2D,EAAEguB,QAAQC,cAAc,8BAA8B/xB,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,sBAAsB,gBAAgBi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,cAAcU,EAAE2D,EAAEguB,QAAQC,cAAcjyB,EAAEE,IAAI8D,EAAEguB,QAAQC,cAAc,qCAAqC/xB,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,mBAAmBi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,iBAAiBU,EAAE2D,EAAEguB,QAAQC,cAAcjyB,EAAEE,IAAI8D,EAAEguB,QAAQC,cAAc,0CAA0C/xB,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,SAASi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,QAAQU,EAAE2D,EAAEguB,QAAQC,cAAc,4BAA4B/xB,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,UAAUi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,SAASU,EAAE2D,EAAEguB,QAAQC,cAAc,0CAA0C/xB,IAAI8D,EAAEguB,QAAQC,cAAcjyB,EAAEE,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,aAAai2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,YAAYU,EAAE2D,EAAEguB,QAAQC,cAAc,qCAAqC/xB,IAAI8D,EAAEguB,QAAQC,cAAcjyB,EAAEE,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,4BAA4Bi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,WAAWU,EAAE2D,EAAEguB,QAAQC,cAAc,oDAAoD/xB,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,aAAai2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,YAAYU,EAAE2D,EAAEguB,QAAQC,cAAc,qCAAqC/xB,IAAI8D,EAAEguB,QAAQC,cAAcjyB,EAAEE,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,sBAAsBi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,UAAUU,EAAE2D,EAAEguB,QAAQC,cAAc,2CAA2C/xB,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,QAAQi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,iBAAiBU,EAAE2D,EAAEguB,QAAQC,cAAc,6BAA6B/xB,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,SAASxC,GAAG,IAAI/H,GAAG+H,EAAEwC,KAAK,iBAAiBrC,EAAEH,EAAEwC,KAAK,YAAY,OAAOvK,GAAGkI,GAAGs4B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,mBAAmBU,EAAE2D,EAAEguB,QAAQC,cAAcjyB,EAAEE,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,kBAAkBi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,iBAAiBU,EAAE2D,EAAEguB,QAAQC,cAAcjyB,EAAEE,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,uBAAuBi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAK,UAAUU,EAAE2D,EAAEguB,QAAQC,cAAcjyB,EAAEE,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,OAAOi2B,SAAS,SAASz4B,GAAG,IAAI/H,GAAG,IAAI+H,EAAEk6B,OAAO,OAAO,yBAAyB,eAAe,MAAM,CAACz6B,KAAKqE,EAAEguB,QAAQC,cAAc95B,EAAE+H,GAAGkE,QAAQJ,EAAEguB,QAAQE,eAAe/5B,EAAE+H,OAAO/H,EAAE65B,QAAQnyB,EAAEK,EAAExN,QAAQyF,EAAE65B,SAAS,GAAG,SAAS9xB,EAAE/H,EAAEkI,GAAG,aAAalI,EAAE25B,YAAW,EAAG35B,EAAE65B,aAAQ,EAAO,IAAIr9B,EAAEqP,GAAGrP,EAAE0L,EAAE,MAAM1L,EAAEm9B,WAAWn9B,EAAE,CAACq9B,QAAQr9B,GAAGqL,EAAEK,EAAE,IAAQR,EAAE,CAAC,CAAC6C,KAAK,CAAC,aAAai2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE6L,EAAEguB,QAAQC,cAAc,wBAAwB/xB,GAAG,MAAM,CAACP,KAAKK,EAAE+yB,OAAO0B,KAAKrwB,QAAQjM,KAAK,CAACuK,KAAK,CAAC,kBAAkBi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE6L,EAAEguB,QAAQC,cAAc,yCAAyC/xB,GAAG,MAAM,CAACP,KAAKK,EAAE+yB,OAAOoE,aAAa/yB,QAAQjM,KAAK,CAACuK,KAAK,CAAC,YAAYi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE6L,EAAEguB,QAAQC,cAAc,iCAAiC/xB,GAAGG,EAAE2D,EAAEguB,QAAQI,sBAAsBj6B,GAAG,MAAM,CAACwH,KAAKK,EAAE+yB,OAAOqE,QAAQhzB,QAAQjM,EAAEkiC,YAAYh6B,KAAK,CAACqC,KAAK,CAAC,cAAci2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE6L,EAAEguB,QAAQC,cAAc,6BAA6B/xB,GAAG0D,QAAQ,SAAS,KAAKvD,EAAE2D,EAAEguB,QAAQK,oBAAoBl6B,GAAGxD,EAAE,CAACgL,KAAKK,EAAE+yB,OAAOsE,MAAMjzB,QAAQjM,GAAG,OAAOkI,IAAI1L,EAAE0lC,YAAYh6B,GAAG1L,IAAI,CAAC+N,KAAK,CAAC,uBAAuBi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE6L,EAAEguB,QAAQC,cAAc,qCAAqC/xB,GAAG0D,QAAQ,SAAS,KAAK,MAAM,CAACjE,KAAKK,EAAE+yB,OAAOuE,IAAIlzB,QAAQjM,KAAK,CAACuK,KAAK,SAASxC,GAAG,IAAI/H,GAAG+H,EAAEwC,KAAK,iBAAiBrC,EAAEH,EAAEwC,KAAK,YAAY,OAAOvK,GAAGkI,GAAGs4B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE6L,EAAEguB,QAAQC,cAAc,8BAA8B/xB,GAAGG,EAAE2D,EAAEguB,QAAQM,sBAAsBn6B,GAAGxD,EAAE,CAACgL,KAAKK,EAAE+yB,OAAOwE,QAAQnzB,QAAQjM,GAAG,OAAOkI,IAAI1L,EAAE0lC,YAAYh6B,GAAG1L,IAAI,CAAC+N,KAAK,CAAC,mBAAmBi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE6L,EAAEguB,QAAQC,cAAc,mCAAmC/xB,GAAGG,EAAE,CAACV,KAAKK,EAAE+yB,OAAOyE,OAAO,OAAOr/B,GAAGA,EAAEtD,SAASwL,EAAE+D,QAAQjM,GAAGkI,IAAI,CAACqC,KAAK,CAAC,sBAAsB,gBAAgBi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE6L,EAAEguB,QAAQC,cAAc,kCAAkC/xB,IAAI8D,EAAEguB,QAAQC,cAAc,mCAAmC/xB,IAAI8D,EAAEguB,QAAQC,cAAc,aAAa/xB,GAAG,MAAM,CAACP,KAAKK,EAAE+yB,OAAOG,WAAW9uB,QAAQjM,KAAK,CAACuK,KAAK,CAAC,SAASi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE6L,EAAEguB,QAAQC,cAAc,uBAAuB/xB,GAAG,MAAM,CAACP,KAAKK,EAAE+yB,OAAOE,KAAK7uB,QAAQjM,KAAK,CAACuK,KAAK,CAAC,UAAUi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE6L,EAAEguB,QAAQC,cAAc,2BAA2B/xB,GAAG,MAAM,CAACP,KAAKK,EAAE+yB,OAAOuB,MAAMlwB,QAAQjM,KAAK,CAACuK,KAAK,CAAC,UAAUi2B,SAAS,WAAW,MAAM,CAACh5B,KAAKK,EAAE+yB,OAAO0E,SAAS,CAAC/0B,KAAK,CAAC,QAAQi2B,SAAS,WAAW,MAAM,CAACh5B,KAAKK,EAAE+yB,OAAO2E,YAAY,CAACh1B,KAAK,CAAC,iBAAiBi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE6L,EAAEguB,QAAQC,cAAc,mCAAmC/xB,GAAG,MAAM,CAACP,KAAKK,EAAE+yB,OAAO4E,aAAavzB,QAAQjM,MAAMA,EAAE65B,QAAQnyB,EAAEK,EAAExN,QAAQyF,EAAE65B,SAAS,GAAG,SAAS9xB,EAAE/H,EAAEkI,GAAG,aAAalI,EAAE25B,YAAW,EAAG35B,EAAE65B,aAAQ,EAAO,IAAIr9B,EAAEqP,GAAGrP,EAAE0L,EAAE,MAAM1L,EAAEm9B,WAAWn9B,EAAE,CAACq9B,QAAQr9B,GAAGqL,EAAEK,EAAE,IAAQR,EAAE,CAAC,CAAC6C,KAAK,CAAC,cAAci2B,SAAS,WAAW,MAAM,CAAC59B,KAAK,MAAMu/B,OAAO,YAAY,CAAC53B,KAAK,CAAC,WAAWi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE6L,EAAEguB,QAAQC,cAAc,aAAa/xB,IAAI,OAAOG,EAAE,CAACtF,KAAKiF,EAAEgzB,cAAcgE,OAAOsD,OAAO,UAAU,OAAOniC,IAAIkI,EAAEk6B,MAAMpiC,GAAGkI,IAAI,CAACqC,KAAK,CAAC,2BAA2Bi2B,SAAS,WAAW,MAAM,CAAC59B,KAAKiF,EAAEgzB,cAAc+D,OAAOuD,OAAO,WAAW,CAAC53B,KAAK,CAAC,SAASi2B,SAAS,WAAW,MAAM,CAAC59B,KAAKiF,EAAEgzB,cAAc+D,OAAOuD,OAAO,QAAQC,MAAM,UAAU,CAAC73B,KAAK,CAAC,eAAei2B,SAAS,WAAW,MAAM,CAAC59B,KAAKiF,EAAEgzB,cAAc+D,OAAOuD,OAAO,SAASC,MAAM,sBAAsB,CAAC73B,KAAK,CAAC,SAASi2B,SAAS,WAAW,MAAM,CAAC59B,KAAKiF,EAAEgzB,cAAc+D,OAAOuD,OAAO,YAAY,CAAC53B,KAAK,CAAC,kBAAkBi2B,SAAS,WAAW,MAAM,CAAC59B,KAAKiF,EAAEgzB,cAAc+D,UAAU,CAACr0B,KAAK,SAASxC,GAAG,IAAI/H,EAAE+H,EAAEwC,KAAK,gBAAgBrC,EAAEH,EAAEwC,KAAK,uBAAuB,OAAOvK,IAAIkI,GAAGs4B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE6L,EAAEguB,QAAQC,cAAc,iBAAiB/xB,GAAG,MAAM,CAACnF,KAAKiF,EAAEgzB,cAAcgE,OAAOsD,OAAO,QAAQC,MAAMpiC,KAAK,CAACuK,KAAK,CAAC,mBAAmB,iBAAiBi2B,SAAS,WAAW,MAAM,CAAC59B,KAAKiF,EAAEgzB,cAAcgE,OAAOsD,OAAO,WAAW,CAAC53B,KAAK,CAAC,aAAai2B,SAAS,WAAW,MAAM,CAAC59B,KAAKiF,EAAEgzB,cAAcgE,UAAU,CAACt0B,KAAK,SAASxC,GAAG,MAAM,eAAeA,EAAE24B,gBAAe,IAAKF,SAAS,WAAW,MAAM,CAAC59B,KAAKiF,EAAEgzB,cAAcgE,OAAOsD,OAAO,gBAAgB,CAAC53B,KAAK,SAASxC,GAAG,MAAM,SAASA,EAAE24B,gBAAe,IAAKF,SAAS,WAAW,MAAM,CAAC59B,KAAKiF,EAAEgzB,cAAcgE,UAAU,CAACt0B,KAAK,SAASxC,GAAG,MAAM,kBAAkBA,EAAE24B,kBAAkBF,SAAS,WAAW,MAAM,CAAC59B,KAAKiF,EAAEgzB,cAAcgE,OAAOsD,OAAO,eAAe,CAAC53B,KAAK,SAASxC,GAAG,IAAI/H,EAAE8J,OAAOD,OAAO9B,EAAEi5B,gBAAgB9hC,MAAM,KAAK,IAAI,MAAM,YAAY6I,EAAEg5B,WAAU,IAAK/gC,GAAG,GAAGwgC,SAAS,WAAW,MAAM,CAAC59B,KAAKiF,EAAEgzB,cAAc+D,UAAU,CAACr0B,KAAK,SAASxC,GAAG,MAAM,YAAYA,EAAEg5B,WAAU,IAAKP,SAAS,WAAW,MAAM,CAAC59B,KAAKiF,EAAEgzB,cAAcgE,UAAU,CAACt0B,KAAK,SAASxC,GAAG,MAAM,UAAUA,EAAEg5B,WAAU,IAAKP,SAAS,WAAW,MAAM,CAAC59B,KAAKiF,EAAEgzB,cAAciE,QAAQqD,OAAO,WAAW,CAAC53B,KAAK,SAASxC,GAAG,MAAM,YAAYA,EAAEg5B,WAAU,IAAKP,SAAS,WAAW,MAAM,CAAC59B,KAAKiF,EAAEgzB,cAAciE,WAAW,CAACv0B,KAAK,SAASxC,GAAG,MAAM,UAAUA,EAAEg5B,WAAU,IAAKP,SAAS,WAAW,MAAM,CAAC59B,KAAKiF,EAAEgzB,cAAciE,WAAW,CAACv0B,KAAK,SAASxC,GAAG,MAAM,kBAAkBA,EAAEg5B,WAAU,IAAKP,SAAS,WAAW,MAAM,CAAC59B,KAAKiF,EAAEgzB,cAAckE,MAAM,CAACx0B,KAAK,SAASxC,GAAG,MAAM,SAASA,EAAEg5B,WAAU,IAAKP,SAAS,WAAW,MAAM,CAAC59B,KAAKiF,EAAEgzB,cAAckE,OAAO/+B,EAAE65B,QAAQnyB,EAAEK,EAAExN,QAAQyF,EAAE65B,SAAS,GAAG,SAAS9xB,EAAE/H,EAAEkI,GAAG,aAAalI,EAAE25B,YAAW,EAAG35B,EAAE65B,aAAQ,EAAO,IAAIr9B,EAAEqP,GAAGrP,EAAE0L,EAAE,MAAM1L,EAAEm9B,WAAWn9B,EAAE,CAACq9B,QAAQr9B,GAAGqL,EAAEK,EAAE,IAAQR,EAAE,CAAC,CAAC6C,KAAK,SAASxC,GAAG,MAAM,mBAAmBA,EAAE24B,gBAAe,IAAKF,SAAS,SAASz4B,GAAG,GAAG,WAAWwC,KAAKxC,GAAG,MAAM,CAACP,KAAKK,EAAE8yB,WAAW+E,OAAO,IAAI1/B,EAAE6L,EAAEguB,QAAQC,cAAc,0BAA0B/xB,GAAG,MAAM,CAACP,KAAKK,EAAE8yB,WAAW8E,SAASxzB,QAAQjM,KAAK,CAACuK,KAAK,CAAC,YAAYi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAKK,EAAE8yB,WAAWgF,SAASz3B,EAAE2D,EAAEguB,QAAQC,cAAc,6BAA6B/xB,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,SAASxC,GAAG,OAAOA,EAAEwC,KAAK,YAAYi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAKK,EAAE8yB,WAAWiF,QAAQ13B,EAAE2D,EAAEguB,QAAQC,cAAc,4BAA4B/xB,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,SAASxC,GAAG,IAAI/H,EAAE+H,EAAEwC,KAAK,UAAUrC,EAAEH,EAAEwC,KAAK,eAAe,OAAOvK,IAAIkI,GAAGs4B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAKK,EAAE8yB,WAAWkF,OAAO33B,EAAE2D,EAAEguB,QAAQC,cAAc,2BAA2B/xB,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,IAAI,CAACuK,KAAK,CAAC,4BAA4Bi2B,SAAS,WAAW,MAAM,CAACh5B,KAAKK,EAAE8yB,WAAW+E,SAAS,CAACn1B,KAAK,CAAC,mBAAmBi2B,SAAS,SAASz4B,GAAG,IAAI/H,EAAE,CAACwH,KAAKK,EAAE8yB,WAAWmF,QAAQ53B,EAAE2D,EAAEguB,QAAQC,cAAc,4BAA4B/xB,GAAG,OAAOG,IAAIlI,EAAEiM,QAAQ/D,GAAGlI,KAAKA,EAAE65B,QAAQnyB,EAAEK,EAAExN,QAAQyF,EAAE65B,8BCA3+vB,QAsBE7+B,MAAQsC,YAXY,0BAAP,EAcb,WAEF,IAAI+kC,EAAmB,kCAGnBC,EAAgBhlC,OAAO0M,SAAW1M,OAAO0M,SAASu4B,KAAO,KACzDC,EAAUF,GAAcA,EAAY72B,QAAQ,OAAQ,IAAIA,QAAQ,QAAS,KAAc,KAGvFg3B,EAAUxN,SAAS7V,qBAAqB,UAGxCsjB,EAA2B,eAAiBD,EAAQ,IAAMxN,SAAShX,cAAc,WAGjF0kB,GAAcrlC,OAAOmgC,OAAqC,mBAA5BngC,OAAOmgC,MAAMvhB,WAG3C0mB,EAAiC,kBAAmB3N,SAIpD,oBAAqBj2B,OAASA,MAAM6jC,kBAAoBC,EAAAA,IAC/B9jC,MAAM6jC,gBACjC7jC,MAAM6jC,gBAAkBC,EAAAA,GAO1B,IAAIC,GAAyB,EACzBC,GAAwB,EAoF5B,SAASC,EAAsBhkC,EAAOikC,GACpC,IAAIplB,EACAqlB,EAAM,KACNC,EAA0C,iBAAnBF,EA+B3B,OA9BAA,EAAiBE,EAAgBn+B,KAAKo+B,MAAMH,GAAkB,EACzC,iBAAVjkC,GAAsBA,IAC3BmkC,EACFtlB,EAAU7e,EAAMG,MAAM,+GAGtB0e,EAAU7e,EAAMG,MAAM,kNAEL0e,EAAQ,KACvBA,EAAU7e,EAAMG,MAAM,kHAItB0e,GAAWA,EAAQ,KAGnBqlB,EAFED,EAAiB,EAEbD,EADWhkC,EAAMU,MAAMV,EAAMZ,QAAQyf,EAAQ,IAAMA,EAAQ,GAAGphB,QACvBwmC,EAAiB,GAGxDplB,EAAQ,KAWbqlB,EAyHT,SAASG,IAIP,GAAuB,IAAnBb,EAAQ/lC,OACV,OAAO,KAGT,IAAIF,EAAGuL,EAAG9I,EAAOkkC,EAAKjO,EAClBqO,EAAkB,GAClBL,EAAiBI,EAAwBJ,gBAAkB,EAQ/D,IAAK1mC,EAAI,EAAGA,EAAIimC,EAAQ/lC,OAAQF,IAC1BmmC,GAAcD,EACZL,EAAiB93B,KAAKk4B,EAAQjmC,GAAGgnC,aACnCD,EAAgBrmC,KAAKulC,EAAQjmC,IAI/B+mC,EAAgBrmC,KAAKulC,EAAQjmC,IAQjC,GAJAuL,EAAI,IAAI/I,MACJ+jC,IACF9jC,EAAQ8I,EAAE9I,QAEPA,GAAS+jC,EACZ,IACE,MAAMj7B,EAER,MAAO07B,GAELxkC,EAAQwkC,EAAIxkC,MAiEhB,GA7DIA,KAEFi2B,EAzQJ,SAA0BiO,EAAKI,GAC7B,IAAI/mC,EACA04B,EAAS,KAIb,GAFAqO,EAAkBA,GAAmBd,EAElB,iBAARU,GAAoBA,EAC7B,IAAK3mC,EAAI+mC,EAAgB7mC,OAAQF,KAC/B,GAAI+mC,EAAgB/mC,GAAGsX,MAAQqvB,EAAK,CAGlCjO,EAASqO,EAAgB/mC,GACzB,MAIN,OAAO04B,EAyPIwO,CADTP,EAAMF,EAAsBhkC,EAAOikC,GACJK,KAEhBf,GAAWW,IAAQX,IAK9BtN,EAhOR,SAA6BqO,GAC3B,IAAI/mC,EAAGC,EACHy4B,EAAS,KAEb,IAAK14B,EAAI,EAAGC,GADZ8mC,EAAkBA,GAAmBd,GACH/lC,OAAQF,EAAIC,EAAKD,IACjD,IAAK+mC,EAAgB/mC,GAAG+hB,aAAa,OAAQ,CAC3C,GAAI2W,EAAQ,CACVA,EAAS,KACT,MAEFA,EAASqO,EAAgB/mC,GAG7B,OAAO04B,EA+NQyO,CAAoBJ,IAU9BrO,GAK4B,IAA3BqO,EAAgB7mC,SAClBw4B,EAASqO,EAAgB,IAIxBrO,GAeC0N,IACF1N,EAASD,SAAS2O,gBAIjB1O,GAeCyN,GAAcD,EAChB,IAAKlmC,EAAI+mC,EAAgB7mC,OAAQF,KAC/B,GAAsC,gBAAlC+mC,EAAgB/mC,GAAGgnC,WAA8B,CACnDtO,EAASqO,EAAgB/mC,GACzB,MAkCR,OA5BK04B,IAyBHA,EAASqO,EAAgBA,EAAgB7mC,OAAS,IAAM,MAGnDw4B,GA3YT,WACE,IACE,IAAIuO,EAAM,IAAIzkC,MAEd,MADA+jC,EAA8C,iBAAdU,EAAIxkC,SAAwBwkC,EAAIxkC,MAC1DwkC,EAER,MAAOI,GACLb,EAAmD,iBAApBa,EAAU5kC,SAAwB4kC,EAAU5kC,QAP/E,GA+YAqkC,EAAwBJ,eAAiB,EAOrC,IAAI3O,EAA4B+O,EAShC,OARA/O,EAAuBuP,KAASR,EAChC/O,EAAuBwP,IA1R3B,WAME,OAAO,MAqRLxP,EAAuByP,OArL3B,WAIE,OAAO,MAuLEzP,IA9cW,UAAX,IAAW,wCCYtB,IAOI0P,EAPAC,EAAuB,iBAAZC,QAAuBA,QAAU,KAC5CC,EAAeF,GAAwB,mBAAZA,EAAExoC,MAC7BwoC,EAAExoC,MACF,SAAsB8V,EAAQ6yB,EAAU5kC,GACxC,OAAOmM,SAAS3P,UAAUP,MAAMkE,KAAK4R,EAAQ6yB,EAAU5kC,IAKzDwkC,EADEC,GAA0B,mBAAdA,EAAEI,QACCJ,EAAEI,QACVlpC,OAAOmpC,sBACC,SAAwB/yB,GACvC,OAAOpW,OAAOopC,oBAAoBhzB,GAC/BzR,OAAO3E,OAAOmpC,sBAAsB/yB,KAGxB,SAAwBA,GACvC,OAAOpW,OAAOopC,oBAAoBhzB,IAQtC,IAAIizB,EAAc36B,OAAO46B,OAAS,SAAqBviC,GACrD,OAAOA,GAAUA,GAGnB,SAASwiC,IACPA,EAAaC,KAAKhlC,KAAK5E,MAEzBR,EAAOD,QAAUoqC,EACjBnqC,EAAOD,QAAQsqC,KAwYf,SAAcC,EAASt9B,GACrB,OAAO,IAAIu9B,SAAQ,SAAUC,EAASC,GACpC,SAASC,EAAczB,GACrBqB,EAAQK,eAAe39B,EAAM49B,GAC7BH,EAAOxB,GAGT,SAAS2B,IAC+B,mBAA3BN,EAAQK,gBACjBL,EAAQK,eAAe,QAASD,GAElCF,EAAQ,GAAGrlC,MAAMC,KAAKjE,YAGxB0pC,EAA+BP,EAASt9B,EAAM49B,EAAU,CAAEP,MAAM,IACnD,UAATr9B,GAMR,SAAuCs9B,EAASzR,EAASiS,GAC7B,mBAAfR,EAAQS,IACjBF,EAA+BP,EAAS,QAASzR,EAPO,CAAEwR,MAAM,IAA9DW,CAA8BV,EAASI,OArZ7CP,EAAaA,aAAeA,EAE5BA,EAAa1oC,UAAUwpC,aAAU1+B,EACjC49B,EAAa1oC,UAAUypC,aAAe,EACtCf,EAAa1oC,UAAU0pC,mBAAgB5+B,EAIvC,IAAI6+B,EAAsB,GAE1B,SAASC,EAAcC,GACrB,GAAwB,mBAAbA,EACT,MAAM,IAAIC,UAAU,0EAA4ED,GAsCpG,SAASE,EAAiBC,GACxB,YAA2Bl/B,IAAvBk/B,EAAKN,cACAhB,EAAaiB,oBACfK,EAAKN,cAmDd,SAASO,EAAa10B,EAAQ5O,EAAMkjC,EAAUlR,GAC5C,IAAIz1B,EACAgnC,EACAC,EA1HsBnzB,EAgJ1B,GApBA4yB,EAAcC,QAGC/+B,KADfo/B,EAAS30B,EAAOi0B,UAEdU,EAAS30B,EAAOi0B,QAAUrqC,OAAOw+B,OAAO,MACxCpoB,EAAOk0B,aAAe,SAIK3+B,IAAvBo/B,EAAOE,cACT70B,EAAOqhB,KAAK,cAAejwB,EACfkjC,EAASA,SAAWA,EAASA,SAAWA,GAIpDK,EAAS30B,EAAOi0B,SAElBW,EAAWD,EAAOvjC,SAGHmE,IAAbq/B,EAEFA,EAAWD,EAAOvjC,GAAQkjC,IACxBt0B,EAAOk0B,kBAeT,GAbwB,mBAAbU,EAETA,EAAWD,EAAOvjC,GAChBgyB,EAAU,CAACkR,EAAUM,GAAY,CAACA,EAAUN,GAErClR,EACTwR,EAASE,QAAQR,GAEjBM,EAASlpC,KAAK4oC,IAIhB3mC,EAAI6mC,EAAiBx0B,IACb,GAAK40B,EAAS1pC,OAASyC,IAAMinC,EAASG,OAAQ,CACpDH,EAASG,QAAS,EAGlB,IAAIC,EAAI,IAAIxnC,MAAM,+CACEonC,EAAS1pC,OAAS,IAAMmN,OAAOjH,GADjC,qEAIlB4jC,EAAEh/B,KAAO,8BACTg/B,EAAE1B,QAAUtzB,EACZg1B,EAAE5jC,KAAOA,EACT4jC,EAAEvpC,MAAQmpC,EAAS1pC,OA7KGuW,EA8KHuzB,EA7KnBvoC,SAAWA,QAAQiV,MAAMjV,QAAQiV,KAAKD,GAiL1C,OAAOzB,EAcT,SAASi1B,IACP,IAAKzrC,KAAK0rC,MAGR,OAFA1rC,KAAKwW,OAAO2zB,eAAenqC,KAAK4H,KAAM5H,KAAK2rC,QAC3C3rC,KAAK0rC,OAAQ,EACY,IAArB/qC,UAAUe,OACL1B,KAAK8qC,SAASlmC,KAAK5E,KAAKwW,QAC1BxW,KAAK8qC,SAASpqC,MAAMV,KAAKwW,OAAQ7V,WAI5C,SAASirC,EAAUp1B,EAAQ5O,EAAMkjC,GAC/B,IAAIe,EAAQ,CAAEH,OAAO,EAAOC,YAAQ5/B,EAAWyK,OAAQA,EAAQ5O,KAAMA,EAAMkjC,SAAUA,GACjFgB,EAAUL,EAAY7qC,KAAKirC,GAG/B,OAFAC,EAAQhB,SAAWA,EACnBe,EAAMF,OAASG,EACRA,EA0HT,SAASC,EAAWv1B,EAAQ5O,EAAMokC,GAChC,IAAIb,EAAS30B,EAAOi0B,QAEpB,QAAe1+B,IAAXo/B,EACF,MAAO,GAET,IAAIc,EAAad,EAAOvjC,GACxB,YAAmBmE,IAAfkgC,EACK,GAEiB,mBAAfA,EACFD,EAAS,CAACC,EAAWnB,UAAYmB,GAAc,CAACA,GAElDD,EAsDT,SAAyBhT,GAEvB,IADA,IAAII,EAAM,IAAI10B,MAAMs0B,EAAIt3B,QACfF,EAAI,EAAGA,EAAI43B,EAAI13B,SAAUF,EAChC43B,EAAI53B,GAAKw3B,EAAIx3B,GAAGspC,UAAY9R,EAAIx3B,GAElC,OAAO43B,EA1DL8S,CAAgBD,GAAcE,EAAWF,EAAYA,EAAWvqC,QAoBpE,SAAS0qC,EAAcxkC,GACrB,IAAIujC,EAASnrC,KAAKyqC,QAElB,QAAe1+B,IAAXo/B,EAAsB,CACxB,IAAIc,EAAad,EAAOvjC,GAExB,GAA0B,mBAAfqkC,EACT,OAAO,EACF,QAAmBlgC,IAAfkgC,EACT,OAAOA,EAAWvqC,OAItB,OAAO,EAOT,SAASyqC,EAAWnT,EAAKnoB,GAEvB,IADA,IAAIgI,EAAO,IAAInU,MAAMmM,GACZrP,EAAI,EAAGA,EAAIqP,IAAKrP,EACvBqX,EAAKrX,GAAKw3B,EAAIx3B,GAChB,OAAOqX,EA4CT,SAASwxB,EAA+BP,EAASt9B,EAAMs+B,EAAUR,GAC/D,GAA0B,mBAAfR,EAAQS,GACbD,EAAMT,KACRC,EAAQD,KAAKr9B,EAAMs+B,GAEnBhB,EAAQS,GAAG/9B,EAAMs+B,OAEd,IAAwC,mBAA7BhB,EAAQuC,iBAYxB,MAAM,IAAItB,UAAU,6EAA+EjB,GATnGA,EAAQuC,iBAAiB7/B,GAAM,SAAS8/B,EAAa3qC,GAG/C2oC,EAAMT,MACRC,EAAQyC,oBAAoB//B,EAAM8/B,GAEpCxB,EAASnpC,OAhafvB,OAAO0kB,eAAe6kB,EAAc,sBAAuB,CACzDnL,YAAY,EACZxZ,IAAK,WACH,OAAO4lB,GAET1lB,IAAK,SAASvjB,GACZ,GAAmB,iBAARA,GAAoBA,EAAM,GAAK8nC,EAAY9nC,GACpD,MAAM,IAAI6qC,WAAW,kGAAoG7qC,EAAM,KAEjIipC,EAAsBjpC,KAI1BgoC,EAAaC,KAAO,gBAEG79B,IAAjB/L,KAAKyqC,SACLzqC,KAAKyqC,UAAYrqC,OAAOqsC,eAAezsC,MAAMyqC,UAC/CzqC,KAAKyqC,QAAUrqC,OAAOw+B,OAAO,MAC7B5+B,KAAK0qC,aAAe,GAGtB1qC,KAAK2qC,cAAgB3qC,KAAK2qC,oBAAiB5+B,GAK7C49B,EAAa1oC,UAAUyrC,gBAAkB,SAAyB77B,GAChE,GAAiB,iBAANA,GAAkBA,EAAI,GAAK44B,EAAY54B,GAChD,MAAM,IAAI27B,WAAW,gFAAkF37B,EAAI,KAG7G,OADA7Q,KAAK2qC,cAAgB95B,EACd7Q,MAST2pC,EAAa1oC,UAAU0rC,gBAAkB,WACvC,OAAO3B,EAAiBhrC,OAG1B2pC,EAAa1oC,UAAU42B,KAAO,SAAcjwB,GAE1C,IADA,IAAInD,EAAO,GACFjD,EAAI,EAAGA,EAAIb,UAAUe,OAAQF,IAAKiD,EAAKvC,KAAKvB,UAAUa,IAC/D,IAAIorC,EAAoB,UAAThlC,EAEXujC,EAASnrC,KAAKyqC,QAClB,QAAe1+B,IAAXo/B,EACFyB,EAAWA,QAA4B7gC,IAAjBo/B,EAAO9pC,WAC1B,IAAKurC,EACR,OAAO,EAGT,GAAIA,EAAS,CACX,IAAIC,EAGJ,GAFIpoC,EAAK/C,OAAS,IAChBmrC,EAAKpoC,EAAK,IACRooC,aAAc7oC,MAGhB,MAAM6oC,EAGR,IAAIpE,EAAM,IAAIzkC,MAAM,oBAAsB6oC,EAAK,KAAOA,EAAG7xB,QAAU,IAAM,KAEzE,MADAytB,EAAIqE,QAAUD,EACRpE,EAGR,IAAIpQ,EAAU8S,EAAOvjC,GAErB,QAAgBmE,IAAZssB,EACF,OAAO,EAET,GAAuB,mBAAZA,EACT+Q,EAAa/Q,EAASr4B,KAAMyE,OAE5B,KAAIhD,EAAM42B,EAAQ32B,OACdqrC,EAAYZ,EAAW9T,EAAS52B,GACpC,IAASD,EAAI,EAAGA,EAAIC,IAAOD,EACzB4nC,EAAa2D,EAAUvrC,GAAIxB,KAAMyE,GAGrC,OAAO,GAiETklC,EAAa1oC,UAAU22B,YAAc,SAAqBhwB,EAAMkjC,GAC9D,OAAOI,EAAalrC,KAAM4H,EAAMkjC,GAAU,IAG5CnB,EAAa1oC,UAAUspC,GAAKZ,EAAa1oC,UAAU22B,YAEnD+R,EAAa1oC,UAAU+rC,gBACnB,SAAyBplC,EAAMkjC,GAC7B,OAAOI,EAAalrC,KAAM4H,EAAMkjC,GAAU,IAqBhDnB,EAAa1oC,UAAU4oC,KAAO,SAAcjiC,EAAMkjC,GAGhD,OAFAD,EAAcC,GACd9qC,KAAKuqC,GAAG3iC,EAAMgkC,EAAU5rC,KAAM4H,EAAMkjC,IAC7B9qC,MAGT2pC,EAAa1oC,UAAUgsC,oBACnB,SAA6BrlC,EAAMkjC,GAGjC,OAFAD,EAAcC,GACd9qC,KAAKgtC,gBAAgBplC,EAAMgkC,EAAU5rC,KAAM4H,EAAMkjC,IAC1C9qC,MAIb2pC,EAAa1oC,UAAUkpC,eACnB,SAAwBviC,EAAMkjC,GAC5B,IAAInyB,EAAMwyB,EAAQn4B,EAAUxR,EAAG0rC,EAK/B,GAHArC,EAAcC,QAGC/+B,KADfo/B,EAASnrC,KAAKyqC,SAEZ,OAAOzqC,KAGT,QAAa+L,KADb4M,EAAOwyB,EAAOvjC,IAEZ,OAAO5H,KAET,GAAI2Y,IAASmyB,GAAYnyB,EAAKmyB,WAAaA,EACb,KAAtB9qC,KAAK0qC,aACT1qC,KAAKyqC,QAAUrqC,OAAOw+B,OAAO,cAEtBuM,EAAOvjC,GACVujC,EAAOhB,gBACTnqC,KAAK63B,KAAK,iBAAkBjwB,EAAM+Q,EAAKmyB,UAAYA,SAElD,GAAoB,mBAATnyB,EAAqB,CAGrC,IAFA3F,GAAY,EAEPxR,EAAImX,EAAKjX,OAAS,EAAGF,GAAK,EAAGA,IAChC,GAAImX,EAAKnX,KAAOspC,GAAYnyB,EAAKnX,GAAGspC,WAAaA,EAAU,CACzDoC,EAAmBv0B,EAAKnX,GAAGspC,SAC3B93B,EAAWxR,EACX,MAIJ,GAAIwR,EAAW,EACb,OAAOhT,KAEQ,IAAbgT,EACF2F,EAAKw0B,QAiIf,SAAmBx0B,EAAMrO,GACvB,KAAOA,EAAQ,EAAIqO,EAAKjX,OAAQ4I,IAC9BqO,EAAKrO,GAASqO,EAAKrO,EAAQ,GAC7BqO,EAAKse,MAlIGmW,CAAUz0B,EAAM3F,GAGE,IAAhB2F,EAAKjX,SACPypC,EAAOvjC,GAAQ+Q,EAAK,SAEQ5M,IAA1Bo/B,EAAOhB,gBACTnqC,KAAK63B,KAAK,iBAAkBjwB,EAAMslC,GAAoBpC,GAG1D,OAAO9qC,MAGb2pC,EAAa1oC,UAAUosC,IAAM1D,EAAa1oC,UAAUkpC,eAEpDR,EAAa1oC,UAAUqsC,mBACnB,SAA4B1lC,GAC1B,IAAImlC,EAAW5B,EAAQ3pC,EAGvB,QAAeuK,KADfo/B,EAASnrC,KAAKyqC,SAEZ,OAAOzqC,KAGT,QAA8B+L,IAA1Bo/B,EAAOhB,eAUT,OATyB,IAArBxpC,UAAUe,QACZ1B,KAAKyqC,QAAUrqC,OAAOw+B,OAAO,MAC7B5+B,KAAK0qC,aAAe,QACM3+B,IAAjBo/B,EAAOvjC,KACY,KAAtB5H,KAAK0qC,aACT1qC,KAAKyqC,QAAUrqC,OAAOw+B,OAAO,aAEtBuM,EAAOvjC,IAEX5H,KAIT,GAAyB,IAArBW,UAAUe,OAAc,CAC1B,IACIwM,EADA7N,EAAOD,OAAOC,KAAK8qC,GAEvB,IAAK3pC,EAAI,EAAGA,EAAInB,EAAKqB,SAAUF,EAEjB,oBADZ0M,EAAM7N,EAAKmB,KAEXxB,KAAKstC,mBAAmBp/B,GAK1B,OAHAlO,KAAKstC,mBAAmB,kBACxBttC,KAAKyqC,QAAUrqC,OAAOw+B,OAAO,MAC7B5+B,KAAK0qC,aAAe,EACb1qC,KAKT,GAAyB,mBAFzB+sC,EAAY5B,EAAOvjC,IAGjB5H,KAAKmqC,eAAeviC,EAAMmlC,QACrB,QAAkBhhC,IAAdghC,EAET,IAAKvrC,EAAIurC,EAAUrrC,OAAS,EAAGF,GAAK,EAAGA,IACrCxB,KAAKmqC,eAAeviC,EAAMmlC,EAAUvrC,IAIxC,OAAOxB,MAoBb2pC,EAAa1oC,UAAU8rC,UAAY,SAAmBnlC,GACpD,OAAOmkC,EAAW/rC,KAAM4H,GAAM,IAGhC+hC,EAAa1oC,UAAUssC,aAAe,SAAsB3lC,GAC1D,OAAOmkC,EAAW/rC,KAAM4H,GAAM,IAGhC+hC,EAAayC,cAAgB,SAAStC,EAASliC,GAC7C,MAAqC,mBAA1BkiC,EAAQsC,cACVtC,EAAQsC,cAAcxkC,GAEtBwkC,EAAcxnC,KAAKklC,EAASliC,IAIvC+hC,EAAa1oC,UAAUmrC,cAAgBA,EAiBvCzC,EAAa1oC,UAAUusC,WAAa,WAClC,OAAOxtC,KAAK0qC,aAAe,EAAIzB,EAAejpC,KAAKyqC,SAAW,sBCxahE,OAaA,SAAYgD,EAAQnuC,GAEnB,aAE6D,iBAAnBE,EAAOD,QAShDC,EAAOD,QAAUkuC,EAAOxT,SACvB36B,EAASmuC,GAAQ,GACjB,SAAUjC,GACT,IAAMA,EAAEvR,SACP,MAAM,IAAIj2B,MAAO,4CAElB,OAAO1E,EAASksC,IAGlBlsC,EAASmuC,GAtBX,CA0BuB,oBAAXnrC,OAAyBA,OAAStC,MAAM,SAAUsC,EAAQorC,GAMtE,aAEA,IAAI1U,EAAM,GAEN2U,EAAWvtC,OAAOqsC,eAElB9nC,EAAQq0B,EAAIr0B,MAEZipC,EAAO5U,EAAI4U,KAAO,SAAUrjC,GAC/B,OAAOyuB,EAAI4U,KAAKhpC,KAAM2F,IACnB,SAAUA,GACb,OAAOyuB,EAAIj0B,OAAOrE,MAAO,GAAI6J,IAI1BrI,EAAO82B,EAAI92B,KAEXmB,EAAU21B,EAAI31B,QAEdwqC,EAAa,GAEb3sB,EAAW2sB,EAAW3sB,SAEtB4sB,EAASD,EAAWp1B,eAEpBs1B,EAAaD,EAAO5sB,SAEpB8sB,EAAuBD,EAAWnpC,KAAMxE,QAExC6tC,EAAU,GAEVC,EAAa,SAAqB//B,GASpC,MAAsB,mBAARA,GAA8C,iBAAjBA,EAAI4P,UAC1B,mBAAb5P,EAAI+B,MAIVi+B,EAAW,SAAmBhgC,GAChC,OAAc,MAAPA,GAAeA,IAAQA,EAAI7L,QAIhC23B,EAAW33B,EAAO23B,SAIjBmU,EAA4B,CAC/BxmC,MAAM,EACNkR,KAAK,EACLu1B,OAAO,EACPC,UAAU,GAGX,SAASC,EAASxzB,EAAM9H,EAAMa,GAG7B,IAAItS,EAAGgtC,EACNtU,GAHDpmB,EAAMA,GAAOmmB,GAGChX,cAAe,UAG7B,GADAiX,EAAOl4B,KAAO+Y,EACT9H,EACJ,IAAMzR,KAAK4sC,GAYVI,EAAMv7B,EAAMzR,IAAOyR,EAAKuP,cAAgBvP,EAAKuP,aAAchhB,KAE1D04B,EAAOzW,aAAcjiB,EAAGgtC,GAI3B16B,EAAI26B,KAAK56B,YAAaqmB,GAAS/jB,WAAW2H,YAAaoc,GAIzD,SAASwU,EAAQvgC,GAChB,OAAY,MAAPA,EACGA,EAAM,GAIQ,iBAARA,GAAmC,mBAARA,EACxC0/B,EAAY3sB,EAAStc,KAAMuJ,KAAW,gBAC/BA,EAQT,IACC8C,EAAU,sNAGV09B,EAAS,SAAUC,EAAU9B,GAI5B,OAAO,IAAI6B,EAAO/5B,GAAGg1B,KAAMgF,EAAU9B,IA0VvC,SAAS+B,EAAa1gC,GAMrB,IAAIzM,IAAWyM,GAAO,WAAYA,GAAOA,EAAIzM,OAC5CkG,EAAO8mC,EAAQvgC,GAEhB,OAAK+/B,EAAY//B,KAASggC,EAAUhgC,KAIpB,UAATvG,GAA+B,IAAXlG,GACR,iBAAXA,GAAuBA,EAAS,GAAOA,EAAS,KAAOyM,GArWhEwgC,EAAO/5B,GAAK+5B,EAAO1tC,UAAY,CAG9B6tC,OAAQ79B,EAERmI,YAAau1B,EAGbjtC,OAAQ,EAERqtC,QAAS,WACR,OAAOpqC,EAAMC,KAAM5E,OAKpBglB,IAAK,SAAUsZ,GAGd,OAAY,MAAPA,EACG35B,EAAMC,KAAM5E,MAIbs+B,EAAM,EAAIt+B,KAAMs+B,EAAMt+B,KAAK0B,QAAW1B,KAAMs+B,IAKpD0Q,UAAW,SAAUC,GAGpB,IAAI7V,EAAMuV,EAAOO,MAAOlvC,KAAKoZ,cAAe61B,GAM5C,OAHA7V,EAAI+V,WAAanvC,KAGVo5B,GAIRgW,KAAM,SAAUxyB,GACf,OAAO+xB,EAAOS,KAAMpvC,KAAM4c,IAG3B1V,IAAK,SAAU0V,GACd,OAAO5c,KAAKgvC,UAAWL,EAAOznC,IAAKlH,MAAM,SAAUqvC,EAAM7tC,GACxD,OAAOob,EAAShY,KAAMyqC,EAAM7tC,EAAG6tC,QAIjC1qC,MAAO,WACN,OAAO3E,KAAKgvC,UAAWrqC,EAAMjE,MAAOV,KAAMW,aAG3C2uC,MAAO,WACN,OAAOtvC,KAAKuvC,GAAI,IAGjBC,KAAM,WACL,OAAOxvC,KAAKuvC,IAAK,IAGlBE,KAAM,WACL,OAAOzvC,KAAKgvC,UAAWL,EAAOe,KAAM1vC,MAAM,SAAU2vC,EAAOnuC,GAC1D,OAASA,EAAI,GAAM,OAIrBouC,IAAK,WACJ,OAAO5vC,KAAKgvC,UAAWL,EAAOe,KAAM1vC,MAAM,SAAU2vC,EAAOnuC,GAC1D,OAAOA,EAAI,OAIb+tC,GAAI,SAAU/tC,GACb,IAAIC,EAAMzB,KAAK0B,OACdsJ,GAAKxJ,GAAMA,EAAI,EAAIC,EAAM,GAC1B,OAAOzB,KAAKgvC,UAAWhkC,GAAK,GAAKA,EAAIvJ,EAAM,CAAEzB,KAAMgL,IAAQ,KAG5D6qB,IAAK,WACJ,OAAO71B,KAAKmvC,YAAcnvC,KAAKoZ,eAKhClX,KAAMA,EACN2tC,KAAM7W,EAAI6W,KACVrsC,OAAQw1B,EAAIx1B,QAGbmrC,EAAOmB,OAASnB,EAAO/5B,GAAGk7B,OAAS,WAClC,IAAI/vC,EAASyM,EAAMsM,EAAKD,EAAMk3B,EAAaC,EAC1Cx5B,EAAS7V,UAAW,IAAO,GAC3Ba,EAAI,EACJE,EAASf,UAAUe,OACnB8e,GAAO,EAsBR,IAnBuB,kBAAXhK,IACXgK,EAAOhK,EAGPA,EAAS7V,UAAWa,IAAO,GAC3BA,KAIsB,iBAAXgV,GAAwB03B,EAAY13B,KAC/CA,EAAS,IAILhV,IAAME,IACV8U,EAASxW,KACTwB,KAGOA,EAAIE,EAAQF,IAGnB,GAAqC,OAA9BzB,EAAUY,UAAWa,IAG3B,IAAMgL,KAAQzM,EACb8Y,EAAO9Y,EAASyM,GAIF,cAATA,GAAwBgK,IAAWqC,IAKnC2H,GAAQ3H,IAAU81B,EAAOsB,cAAep3B,KAC1Ck3B,EAAcrrC,MAAMgD,QAASmR,MAC/BC,EAAMtC,EAAQhK,GAIbwjC,EADID,IAAgBrrC,MAAMgD,QAASoR,GAC3B,GACIi3B,GAAgBpB,EAAOsB,cAAen3B,GAG1CA,EAFA,GAITi3B,GAAc,EAGdv5B,EAAQhK,GAASmiC,EAAOmB,OAAQtvB,EAAMwvB,EAAOn3B,SAGzB9M,IAAT8M,IACXrC,EAAQhK,GAASqM,IAOrB,OAAOrC,GAGRm4B,EAAOmB,OAAQ,CAGdI,QAAS,UAAaj/B,EAAUhH,KAAKE,UAAWsG,QAAS,MAAO,IAGhE7N,SAAS,EAETvB,MAAO,SAAUE,GAChB,MAAM,IAAIyC,MAAOzC,IAGlB4uC,KAAM,aAENF,cAAe,SAAU9hC,GACxB,IAAIiiC,EAAOC,EAIX,SAAMliC,GAAgC,oBAAzB+S,EAAStc,KAAMuJ,KAI5BiiC,EAAQzC,EAAUx/B,MASK,mBADvBkiC,EAAOvC,EAAOlpC,KAAMwrC,EAAO,gBAAmBA,EAAMh3B,cACf20B,EAAWnpC,KAAMyrC,KAAWrC,KAGlEsC,cAAe,SAAUniC,GACxB,IAAI3B,EAEJ,IAAMA,KAAQ2B,EACb,OAAO,EAER,OAAO,GAKRoiC,WAAY,SAAUx1B,EAAMhb,EAAS+T,GACpCy6B,EAASxzB,EAAM,CAAEszB,MAAOtuC,GAAWA,EAAQsuC,OAASv6B,IAGrDs7B,KAAM,SAAUjhC,EAAKyO,GACpB,IAAIlb,EAAQF,EAAI,EAEhB,GAAKqtC,EAAa1gC,GAEjB,IADAzM,EAASyM,EAAIzM,OACLF,EAAIE,IACqC,IAA3Ckb,EAAShY,KAAMuJ,EAAK3M,GAAKA,EAAG2M,EAAK3M,IADnBA,UAMpB,IAAMA,KAAK2M,EACV,IAAgD,IAA3CyO,EAAShY,KAAMuJ,EAAK3M,GAAKA,EAAG2M,EAAK3M,IACrC,MAKH,OAAO2M,GAIRqiC,UAAW,SAAUxX,EAAKyX,GACzB,IAAIrX,EAAMqX,GAAW,GAarB,OAXY,MAAPzX,IACC6V,EAAazuC,OAAQ44B,IACzB2V,EAAOO,MAAO9V,EACE,iBAARJ,EACN,CAAEA,GAAQA,GAGZ92B,EAAK0C,KAAMw0B,EAAKJ,IAIXI,GAGRsX,QAAS,SAAUrB,EAAMrW,EAAKx3B,GAC7B,OAAc,MAAPw3B,GAAe,EAAI31B,EAAQuB,KAAMo0B,EAAKqW,EAAM7tC,IAKpD0tC,MAAO,SAAUI,EAAOqB,GAKvB,IAJA,IAAIlvC,GAAOkvC,EAAOjvC,OACjBsJ,EAAI,EACJxJ,EAAI8tC,EAAM5tC,OAEHsJ,EAAIvJ,EAAKuJ,IAChBskC,EAAO9tC,KAAQmvC,EAAQ3lC,GAKxB,OAFAskC,EAAM5tC,OAASF,EAER8tC,GAGRI,KAAM,SAAUT,EAAOryB,EAAUg0B,GAShC,IARA,IACC9tB,EAAU,GACVthB,EAAI,EACJE,EAASutC,EAAMvtC,OACfmvC,GAAkBD,EAIXpvC,EAAIE,EAAQF,KACAob,EAAUqyB,EAAOztC,GAAKA,KAChBqvC,GACxB/tB,EAAQ5gB,KAAM+sC,EAAOztC,IAIvB,OAAOshB,GAIR5b,IAAK,SAAU+nC,EAAOryB,EAAUjb,GAC/B,IAAID,EAAQyF,EACX3F,EAAI,EACJ43B,EAAM,GAGP,GAAKyV,EAAaI,GAEjB,IADAvtC,EAASutC,EAAMvtC,OACPF,EAAIE,EAAQF,IAGL,OAFd2F,EAAQyV,EAAUqyB,EAAOztC,GAAKA,EAAGG,KAGhCy3B,EAAIl3B,KAAMiF,QAMZ,IAAM3F,KAAKytC,EAGI,OAFd9nC,EAAQyV,EAAUqyB,EAAOztC,GAAKA,EAAGG,KAGhCy3B,EAAIl3B,KAAMiF,GAMb,OAAOymC,EAAMxU,IAId0X,KAAM,EAIN7C,QAASA,IAGa,mBAAXxP,SACXkQ,EAAO/5B,GAAI6pB,OAAOsS,UAAa/X,EAAKyF,OAAOsS,WAI5CpC,EAAOS,KAAM,uEAAuElrC,MAAO,MAC1F,SAAU8sC,EAAIxkC,GACbqhC,EAAY,WAAarhC,EAAO,KAAQA,EAAK2qB,iBAmB/C,IAAI8Z,EAWJ,SAAY3uC,GACZ,IAAId,EACHysC,EACAiD,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EAGAC,EACA1X,EACA2X,EACAC,EACAC,EACAC,EACAjvB,EACAkvB,EAGA9B,EAAU,SAAW,EAAI,IAAI/qC,KAC7B8sC,EAAe3vC,EAAO23B,SACtBiY,EAAU,EACVC,EAAO,EACPC,EAAaC,KACbC,EAAaD,KACbE,EAAgBF,KAChBG,EAAyBH,KACzBI,EAAY,SAAUplC,EAAGD,GAIxB,OAHKC,IAAMD,IACVskC,GAAe,GAET,GAIR5D,EAAS,GAAOr1B,eAChBugB,EAAM,GACN/B,EAAM+B,EAAI/B,IACVyb,EAAa1Z,EAAI92B,KACjBA,EAAO82B,EAAI92B,KACXyC,EAAQq0B,EAAIr0B,MAIZtB,EAAU,SAAUsV,EAAM02B,GAGzB,IAFA,IAAI7tC,EAAI,EACPC,EAAMkX,EAAKjX,OACJF,EAAIC,EAAKD,IAChB,GAAKmX,EAAMnX,KAAQ6tC,EAClB,OAAO7tC,EAGT,OAAQ,GAGTmxC,EAAW,6HAMXC,EAAa,sBAGbC,EAAa,oFAIbhzB,EAAa,2BAA4BgzB,EAAa,OAASD,EAG9D,gBAAkBA,EAIlB,2DAA6DC,EAAa,OAC1ED,EAAa,OAEdE,EAAU,KAAOD,EAAP,wFAOoBhzB,EAPpB,eAcVkzB,EAAc,IAAI/kC,OAAQ4kC,EAAa,IAAK,KAC5CI,EAAQ,IAAIhlC,OAAQ,uEACA,KAEpBilC,EAAS,IAAIjlC,OAAQ,8CACrBklC,EAAe,IAAIllC,OAAQ,wEAE3BmlC,EAAW,IAAInlC,OAAQ4kC,EAAa,MAEpCQ,EAAU,IAAIplC,OAAQ8kC,GACtBO,EAAc,IAAIrlC,OAAQ,IAAM6kC,EAAa,KAE7CS,EAAY,CACX,GAAM,IAAItlC,OAAQ,MAAQ6kC,EAAa,KACvC,MAAS,IAAI7kC,OAAQ,QAAU6kC,EAAa,KAC5C,IAAO,IAAI7kC,OAAQ,KAAO6kC,EAAa,SACvC,KAAQ,IAAI7kC,OAAQ,IAAM6R,GAC1B,OAAU,IAAI7R,OAAQ,IAAM8kC,GAC5B,MAAS,IAAI9kC,OAAQ,4LAE+B,KACpD,KAAQ,IAAIA,OAAQ,OAAS2kC,EAAW,KAAM,KAI9C,aAAgB,IAAI3kC,OAAQ,6IAE2B,MAGxDulC,EAAQ,SACRC,EAAU,sCACVC,EAAU,SAEVC,EAAU,yBAGVC,EAAa,mCAEbC,GAAW,OAIXC,GAAY,IAAI7lC,OAAQ,8DAA8D,KACtF8lC,GAAY,SAAUC,EAAQC,GAC7B,IAAIC,EAAO,KAAOF,EAAOpvC,MAAO,GAAM,MAEtC,OAAOqvC,IASNC,EAAO,EACNplC,OAAO2nB,aAAcyd,EAAO,OAC5BplC,OAAO2nB,aAAcyd,GAAQ,GAAK,MAAe,KAAPA,EAAe,SAK5DC,GAAa,sDACbC,GAAa,SAAUt9B,EAAIu9B,GAC1B,OAAKA,EAGQ,OAAPv9B,EACG,IAIDA,EAAGlS,MAAO,GAAI,GAAM,KAC1BkS,EAAG6F,WAAY7F,EAAGnV,OAAS,GAAIwf,SAAU,IAAO,IAI3C,KAAOrK,GAOfw9B,GAAgB,WACf1C,KAGD2C,GAAqBC,IACpB,SAAUlF,GACT,OAAyB,IAAlBA,EAAKmF,UAAqD,aAAhCnF,EAAKvvB,SAASqX,gBAEhD,CAAEsd,IAAK,aAAch3B,KAAM,WAI7B,IACCvb,EAAKxB,MACFs4B,EAAMr0B,EAAMC,KAAMqtC,EAAa70B,YACjC60B,EAAa70B,YAMd4b,EAAKiZ,EAAa70B,WAAW1b,QAASqc,SACrC,MAAQhR,GACT7K,EAAO,CAAExB,MAAOs4B,EAAIt3B,OAGnB,SAAU8U,EAAQk+B,GACjBhC,EAAWhyC,MAAO8V,EAAQ7R,EAAMC,KAAM8vC,KAKvC,SAAUl+B,EAAQk+B,GAKjB,IAJA,IAAI1pC,EAAIwL,EAAO9U,OACdF,EAAI,EAGKgV,EAAQxL,KAAQ0pC,EAAKlzC,OAC/BgV,EAAO9U,OAASsJ,EAAI,IAKvB,SAASimC,GAAQrC,EAAU9B,EAAS2D,EAASkE,GAC5C,IAAIxwC,EAAG3C,EAAG6tC,EAAMuF,EAAKxwC,EAAOywC,EAAQC,EACnCC,EAAajI,GAAWA,EAAQpxB,cAGhCqC,EAAW+uB,EAAUA,EAAQ/uB,SAAW,EAKzC,GAHA0yB,EAAUA,GAAW,GAGI,iBAAb7B,IAA0BA,GACxB,IAAb7wB,GAA+B,IAAbA,GAA+B,KAAbA,EAEpC,OAAO0yB,EAIR,IAAMkE,IACLhD,EAAa7E,GACbA,EAAUA,GAAW7S,EAEhB4X,GAAiB,CAIrB,GAAkB,KAAb9zB,IAAqB3Z,EAAQuvC,EAAW5d,KAAM6Y,IAGlD,GAAOzqC,EAAIC,EAAO,IAGjB,GAAkB,IAAb2Z,EAAiB,CACrB,KAAOsxB,EAAOvC,EAAQxqB,eAAgBne,IAUrC,OAAOssC,EALP,GAAKpB,EAAKhqC,KAAOlB,EAEhB,OADAssC,EAAQvuC,KAAMmtC,GACPoB,OAYT,GAAKsE,IAAgB1F,EAAO0F,EAAWzyB,eAAgBne,KACtD6tC,EAAUlF,EAASuC,IACnBA,EAAKhqC,KAAOlB,EAGZ,OADAssC,EAAQvuC,KAAMmtC,GACPoB,MAKH,IAAKrsC,EAAO,GAElB,OADAlC,EAAKxB,MAAO+vC,EAAS3D,EAAQ1oB,qBAAsBwqB,IAC5C6B,EAGD,IAAOtsC,EAAIC,EAAO,KAAS6pC,EAAQxrB,wBACzCqqB,EAAQrqB,uBAGR,OADAvgB,EAAKxB,MAAO+vC,EAAS3D,EAAQrqB,uBAAwBte,IAC9CssC,EAKT,GAAKxC,EAAQ+G,MACXxC,EAAwB5D,EAAW,QACjCkD,IAAcA,EAAUviC,KAAMq/B,MAIlB,IAAb7wB,GAAqD,WAAnC+uB,EAAQhtB,SAASqX,eAA+B,CAYpE,GAVA2d,EAAclG,EACdmG,EAAajI,EASK,IAAb/uB,IACFo1B,EAAS5jC,KAAMq/B,IAAcsE,EAAa3jC,KAAMq/B,IAAe,CAqBjE,KAlBAmG,EAAanB,GAASrkC,KAAMq/B,IAAcqG,GAAanI,EAAQ32B,aAC9D22B,KAImBA,GAAYmB,EAAQiH,SAGhCN,EAAM9H,EAAQtqB,aAAc,OAClCoyB,EAAMA,EAAInkC,QAASyjC,GAAYC,IAE/BrH,EAAQrpB,aAAc,KAAQmxB,EAAM1E,IAMtC1uC,GADAqzC,EAASxD,EAAUzC,IACRltC,OACHF,KACPqzC,EAAQrzC,IAAQozC,EAAM,IAAMA,EAAM,UAAa,IAC9CO,GAAYN,EAAQrzC,IAEtBszC,EAAcD,EAAOtrC,KAAM,KAG5B,IAIC,OAHArH,EAAKxB,MAAO+vC,EACXsE,EAAWK,iBAAkBN,IAEvBrE,EACN,MAAQ4E,GACT7C,EAAwB5D,GAAU,GACjC,QACIgG,IAAQ1E,GACZpD,EAAQppB,gBAAiB,QAQ9B,OAAO6tB,EAAQ3C,EAASn+B,QAASuiC,EAAO,MAAQlG,EAAS2D,EAASkE,GASnE,SAAStC,KACR,IAAIhyC,EAAO,GAYX,OAVA,SAASi1C,EAAOpnC,EAAK/G,GAQpB,OALK9G,EAAK6B,KAAMgM,EAAM,KAAQgjC,EAAKqE,oBAG3BD,EAAOj1C,EAAK8sC,SAEXmI,EAAOpnC,EAAM,KAAQ/G,GAShC,SAASquC,GAAc5gC,GAEtB,OADAA,EAAIs7B,IAAY,EACTt7B,EAOR,SAAS6gC,GAAQ7gC,GAChB,IAAIvD,EAAK4oB,EAAShX,cAAe,YAEjC,IACC,QAASrO,EAAIvD,GACZ,MAAQtE,GACT,OAAO,EACN,QAGIsE,EAAG8E,YACP9E,EAAG8E,WAAW2H,YAAazM,GAI5BA,EAAK,MASP,SAASqkC,GAAWpgC,EAAO+iB,GAI1B,IAHA,IAAIW,EAAM1jB,EAAMpR,MAAO,KACtB1C,EAAIw3B,EAAIt3B,OAEDF,KACP0vC,EAAKyE,WAAY3c,EAAKx3B,IAAQ62B,EAUhC,SAASud,GAAcvoC,EAAGD,GACzB,IAAIyoC,EAAMzoC,GAAKC,EACdyoC,EAAOD,GAAsB,IAAfxoC,EAAE0Q,UAAiC,IAAf3Q,EAAE2Q,UACnC1Q,EAAE0oC,YAAc3oC,EAAE2oC,YAGpB,GAAKD,EACJ,OAAOA,EAIR,GAAKD,EACJ,KAAUA,EAAMA,EAAI/4B,aACnB,GAAK+4B,IAAQzoC,EACZ,OAAQ,EAKX,OAAOC,EAAI,GAAK,EAOjB,SAAS2oC,GAAmBpuC,GAC3B,OAAO,SAAUynC,GAEhB,MAAgB,UADLA,EAAKvvB,SAASqX,eACEkY,EAAKznC,OAASA,GAQ3C,SAASquC,GAAoBruC,GAC5B,OAAO,SAAUynC,GAChB,IAAI7iC,EAAO6iC,EAAKvvB,SAASqX,cACzB,OAAkB,UAAT3qB,GAA6B,WAATA,IAAuB6iC,EAAKznC,OAASA,GAQpE,SAASsuC,GAAsB1B,GAG9B,OAAO,SAAUnF,GAKhB,MAAK,SAAUA,EASTA,EAAKl5B,aAAgC,IAAlBk5B,EAAKmF,SAGvB,UAAWnF,EACV,UAAWA,EAAKl5B,WACbk5B,EAAKl5B,WAAWq+B,WAAaA,EAE7BnF,EAAKmF,WAAaA,EAMpBnF,EAAK8G,aAAe3B,GAI1BnF,EAAK8G,cAAgB3B,GACrBF,GAAoBjF,KAAWmF,EAG1BnF,EAAKmF,WAAaA,EAKd,UAAWnF,GACfA,EAAKmF,WAAaA,GAY5B,SAAS4B,GAAwBxhC,GAChC,OAAO4gC,IAAc,SAAUa,GAE9B,OADAA,GAAYA,EACLb,IAAc,SAAUb,EAAM7xB,GAMpC,IALA,IAAI9X,EACHsrC,EAAe1hC,EAAI,GAAI+/B,EAAKjzC,OAAQ20C,GACpC70C,EAAI80C,EAAa50C,OAGVF,KACFmzC,EAAQ3pC,EAAIsrC,EAAc90C,MAC9BmzC,EAAM3pC,KAAS8X,EAAS9X,GAAM2pC,EAAM3pC,WAYzC,SAASiqC,GAAanI,GACrB,OAAOA,QAAmD,IAAjCA,EAAQ1oB,sBAAwC0oB,EAkrC1E,IAAMtrC,KA9qCNysC,EAAUgD,GAAOhD,QAAU,GAO3BmD,EAAQH,GAAOG,MAAQ,SAAU/B,GAChC,IAAI9vB,EAAY8vB,GAAQA,EAAKl6B,aAC5By8B,EAAUvC,IAAUA,EAAK3zB,eAAiB2zB,GAAOjwB,gBAKlD,OAAQm0B,EAAMhkC,KAAMgQ,GAAaqyB,GAAWA,EAAQ9xB,UAAY,SAQjE6xB,EAAcV,GAAOU,YAAc,SAAU1+B,GAC5C,IAAIsjC,EAAYC,EACf1iC,EAAMb,EAAOA,EAAKyI,eAAiBzI,EAAOg/B,EAO3C,OAAKn+B,GAAOmmB,GAA6B,IAAjBnmB,EAAIiK,UAAmBjK,EAAIsL,iBAMnDwyB,GADA3X,EAAWnmB,GACQsL,gBACnByyB,GAAkBT,EAAOnX,GAQpBgY,GAAgBhY,IAClBuc,EAAYvc,EAASwc,cAAiBD,EAAUE,MAAQF,IAGrDA,EAAUnK,iBACdmK,EAAUnK,iBAAkB,SAAUgI,IAAe,GAG1CmC,EAAUG,aACrBH,EAAUG,YAAa,WAAYtC,KASrCpG,EAAQiH,MAAQO,IAAQ,SAAUpkC,GAEjC,OADAugC,EAAQ/9B,YAAaxC,GAAKwC,YAAaomB,EAAShX,cAAe,aACzB,IAAxB5R,EAAG+jC,mBACf/jC,EAAG+jC,iBAAkB,uBAAwB1zC,UAShDusC,EAAQpuB,WAAa41B,IAAQ,SAAUpkC,GAEtC,OADAA,EAAGulC,UAAY,KACPvlC,EAAGmR,aAAc,gBAO1ByrB,EAAQ7pB,qBAAuBqxB,IAAQ,SAAUpkC,GAEhD,OADAA,EAAGwC,YAAaomB,EAAS1iB,cAAe,MAChClG,EAAG+S,qBAAsB,KAAM1iB,UAIxCusC,EAAQxrB,uBAAyBixB,EAAQnkC,KAAM0qB,EAASxX,wBAMxDwrB,EAAQ4I,QAAUpB,IAAQ,SAAUpkC,GAEnC,OADAugC,EAAQ/9B,YAAaxC,GAAKhM,GAAK6qC,GACvBjW,EAAS6c,oBAAsB7c,EAAS6c,kBAAmB5G,GAAUxuC,UAIzEusC,EAAQ4I,SACZ3F,EAAKnqC,OAAa,GAAI,SAAU1B,GAC/B,IAAI0xC,EAAS1xC,EAAGoL,QAASojC,GAAWC,IACpC,OAAO,SAAUzE,GAChB,OAAOA,EAAK7sB,aAAc,QAAWu0B,IAGvC7F,EAAK7oC,KAAW,GAAI,SAAUhD,EAAIynC,GACjC,QAAuC,IAA3BA,EAAQxqB,gBAAkCuvB,EAAiB,CACtE,IAAIxC,EAAOvC,EAAQxqB,eAAgBjd,GACnC,OAAOgqC,EAAO,CAAEA,GAAS,OAI3B6B,EAAKnqC,OAAa,GAAK,SAAU1B,GAChC,IAAI0xC,EAAS1xC,EAAGoL,QAASojC,GAAWC,IACpC,OAAO,SAAUzE,GAChB,IAAIp8B,OAAwC,IAA1Bo8B,EAAK7rB,kBACtB6rB,EAAK7rB,iBAAkB,MACxB,OAAOvQ,GAAQA,EAAK9L,QAAU4vC,IAMhC7F,EAAK7oC,KAAW,GAAI,SAAUhD,EAAIynC,GACjC,QAAuC,IAA3BA,EAAQxqB,gBAAkCuvB,EAAiB,CACtE,IAAI5+B,EAAMzR,EAAGytC,EACZI,EAAOvC,EAAQxqB,eAAgBjd,GAEhC,GAAKgqC,EAAO,CAIX,IADAp8B,EAAOo8B,EAAK7rB,iBAAkB,QACjBvQ,EAAK9L,QAAU9B,EAC3B,MAAO,CAAEgqC,GAMV,IAFAJ,EAAQnC,EAAQgK,kBAAmBzxC,GACnC7D,EAAI,EACM6tC,EAAOJ,EAAOztC,MAEvB,IADAyR,EAAOo8B,EAAK7rB,iBAAkB,QACjBvQ,EAAK9L,QAAU9B,EAC3B,MAAO,CAAEgqC,GAKZ,MAAO,MAMV6B,EAAK7oC,KAAY,IAAI4lC,EAAQ7pB,qBAC5B,SAAU4yB,EAAKlK,GACd,YAA6C,IAAjCA,EAAQ1oB,qBACZ0oB,EAAQ1oB,qBAAsB4yB,GAG1B/I,EAAQ+G,IACZlI,EAAQsI,iBAAkB4B,QAD3B,GAKR,SAAUA,EAAKlK,GACd,IAAIuC,EACH5R,EAAM,GACNj8B,EAAI,EAGJivC,EAAU3D,EAAQ1oB,qBAAsB4yB,GAGzC,GAAa,MAARA,EAAc,CAClB,KAAU3H,EAAOoB,EAASjvC,MACF,IAAlB6tC,EAAKtxB,UACT0f,EAAIv7B,KAAMmtC,GAIZ,OAAO5R,EAER,OAAOgT,GAITS,EAAK7oC,KAAc,MAAI4lC,EAAQxrB,wBAA0B,SAAUm0B,EAAW9J,GAC7E,QAA+C,IAAnCA,EAAQrqB,wBAA0CovB,EAC7D,OAAO/E,EAAQrqB,uBAAwBm0B,IAUzC7E,EAAgB,GAOhBD,EAAY,IAEL7D,EAAQ+G,IAAMtB,EAAQnkC,KAAM0qB,EAASmb,qBAI3CK,IAAQ,SAAUpkC,GAEjB,IAAIiH,EAOJs5B,EAAQ/9B,YAAaxC,GAAK4lC,UAAY,UAAY/G,EAAZ,qBACpBA,EADoB,kEAQjC7+B,EAAG+jC,iBAAkB,wBAAyB1zC,QAClDowC,EAAU5vC,KAAM,yCAKXmP,EAAG+jC,iBAAkB,cAAe1zC,QACzCowC,EAAU5vC,KAAM,mCAAoCywC,EAAW,KAI1DthC,EAAG+jC,iBAAkB,QAAUlF,EAAU,MAAOxuC,QACrDowC,EAAU5vC,KAAM,OAQjBoW,EAAQ2hB,EAAShX,cAAe,UAC1BQ,aAAc,OAAQ,IAC5BpS,EAAGwC,YAAayE,GACVjH,EAAG+jC,iBAAkB,aAAc1zC,QACxCowC,EAAU5vC,KAAM,mFAOXmP,EAAG+jC,iBAAkB,YAAa1zC,QACvCowC,EAAU5vC,KAAM,YAMXmP,EAAG+jC,iBAAkB,KAAOlF,EAAU,MAAOxuC,QAClDowC,EAAU5vC,KAAM,YAKjBmP,EAAG+jC,iBAAkB,QACrBtD,EAAU5vC,KAAM,kBAGjBuzC,IAAQ,SAAUpkC,GACjBA,EAAG4lC,UAAY,oFAKf,IAAI3+B,EAAQ2hB,EAAShX,cAAe,SACpC3K,EAAMmL,aAAc,OAAQ,UAC5BpS,EAAGwC,YAAayE,GAAQmL,aAAc,OAAQ,KAIzCpS,EAAG+jC,iBAAkB,YAAa1zC,QACtCowC,EAAU5vC,KAAM,sCAKiC,IAA7CmP,EAAG+jC,iBAAkB,YAAa1zC,QACtCowC,EAAU5vC,KAAM,WAAY,aAK7B0vC,EAAQ/9B,YAAaxC,GAAKmjC,UAAW,EACc,IAA9CnjC,EAAG+jC,iBAAkB,aAAc1zC,QACvCowC,EAAU5vC,KAAM,WAAY,aAK7BmP,EAAG+jC,iBAAkB,QACrBtD,EAAU5vC,KAAM,aAIX+rC,EAAQiJ,gBAAkBxD,EAAQnkC,KAAQuT,EAAU8uB,EAAQ9uB,SAClE8uB,EAAQuF,uBACRvF,EAAQwF,oBACRxF,EAAQyF,kBACRzF,EAAQ0F,qBAER7B,IAAQ,SAAUpkC,GAIjB48B,EAAQsJ,kBAAoBz0B,EAAQle,KAAMyM,EAAI,KAI9CyR,EAAQle,KAAMyM,EAAI,aAClB0gC,EAAc7vC,KAAM,KAAM4wC,MAI5BhB,EAAYA,EAAUpwC,QAAU,IAAIsM,OAAQ8jC,EAAUvoC,KAAM,MAC5DwoC,EAAgBA,EAAcrwC,QAAU,IAAIsM,OAAQ+jC,EAAcxoC,KAAM,MAIxEgtC,EAAa7C,EAAQnkC,KAAMqiC,EAAQ4F,yBAKnCxF,EAAWuE,GAAc7C,EAAQnkC,KAAMqiC,EAAQI,UAC9C,SAAU3kC,EAAGD,GACZ,IAAIqqC,EAAuB,IAAfpqC,EAAE0Q,SAAiB1Q,EAAE+R,gBAAkB/R,EAClDqqC,EAAMtqC,GAAKA,EAAE+I,WACd,OAAO9I,IAAMqqC,MAAWA,GAAwB,IAAjBA,EAAI35B,YAClC05B,EAAMzF,SACLyF,EAAMzF,SAAU0F,GAChBrqC,EAAEmqC,yBAA8D,GAAnCnqC,EAAEmqC,wBAAyBE,MAG3D,SAAUrqC,EAAGD,GACZ,GAAKA,EACJ,KAAUA,EAAIA,EAAE+I,YACf,GAAK/I,IAAMC,EACV,OAAO,EAIV,OAAO,GAOTolC,EAAY8D,EACZ,SAAUlpC,EAAGD,GAGZ,GAAKC,IAAMD,EAEV,OADAskC,GAAe,EACR,EAIR,IAAIiG,GAAWtqC,EAAEmqC,yBAA2BpqC,EAAEoqC,wBAC9C,OAAKG,IAgBU,GAPfA,GAAYtqC,EAAEqO,eAAiBrO,KAASD,EAAEsO,eAAiBtO,GAC1DC,EAAEmqC,wBAAyBpqC,GAG3B,KAIG6gC,EAAQ2J,cAAgBxqC,EAAEoqC,wBAAyBnqC,KAAQsqC,EAOzDtqC,GAAK4sB,GAAY5sB,EAAEqO,eAAiBu2B,GACxCD,EAAUC,EAAc5kC,IAChB,EAOJD,GAAK6sB,GAAY7sB,EAAEsO,eAAiBu2B,GACxCD,EAAUC,EAAc7kC,GACjB,EAIDqkC,EACJpuC,EAASouC,EAAWpkC,GAAMhK,EAASouC,EAAWrkC,GAChD,EAGe,EAAVuqC,GAAe,EAAI,IAE3B,SAAUtqC,EAAGD,GAGZ,GAAKC,IAAMD,EAEV,OADAskC,GAAe,EACR,EAGR,IAAImE,EACHr0C,EAAI,EACJq2C,EAAMxqC,EAAE8I,WACRuhC,EAAMtqC,EAAE+I,WACR2hC,EAAK,CAAEzqC,GACP0qC,EAAK,CAAE3qC,GAGR,IAAMyqC,IAAQH,EAMb,OAAOrqC,GAAK4sB,GAAY,EACvB7sB,GAAK6sB,EAAW,EAEhB4d,GAAO,EACPH,EAAM,EACNjG,EACEpuC,EAASouC,EAAWpkC,GAAMhK,EAASouC,EAAWrkC,GAChD,EAGK,GAAKyqC,IAAQH,EACnB,OAAO9B,GAAcvoC,EAAGD,GAKzB,IADAyoC,EAAMxoC,EACIwoC,EAAMA,EAAI1/B,YACnB2hC,EAAGxM,QAASuK,GAGb,IADAA,EAAMzoC,EACIyoC,EAAMA,EAAI1/B,YACnB4hC,EAAGzM,QAASuK,GAIb,KAAQiC,EAAIt2C,KAAQu2C,EAAIv2C,IACvBA,IAGD,OAAOA,EAGNo0C,GAAckC,EAAIt2C,GAAKu2C,EAAIv2C,IAO3Bs2C,EAAIt2C,IAAOywC,GAAgB,EAC3B8F,EAAIv2C,IAAOywC,EAAe,EAE1B,GAGKhY,GA/cCA,GAkdTgX,GAAOnuB,QAAU,SAAUlT,EAAMooC,GAChC,OAAO/G,GAAQrhC,EAAM,KAAM,KAAMooC,IAGlC/G,GAAOiG,gBAAkB,SAAU7H,EAAMz/B,GAGxC,GAFA+hC,EAAatC,GAERpB,EAAQiJ,iBAAmBrF,IAC9BW,EAAwB5iC,EAAO,QAC7BmiC,IAAkBA,EAAcxiC,KAAMK,OACtCkiC,IAAkBA,EAAUviC,KAAMK,IAErC,IACC,IAAIwpB,EAAMtW,EAAQle,KAAMyqC,EAAMz/B,GAG9B,GAAKwpB,GAAO6U,EAAQsJ,mBAInBlI,EAAKpV,UAAuC,KAA3BoV,EAAKpV,SAASlc,SAC/B,OAAOqb,EAEP,MAAQrsB,GACTylC,EAAwB5iC,GAAM,GAIhC,OAAOqhC,GAAQrhC,EAAMqqB,EAAU,KAAM,CAAEoV,IAAS3tC,OAAS,GAG1DuvC,GAAOe,SAAW,SAAUlF,EAASuC,GAUpC,OAHOvC,EAAQpxB,eAAiBoxB,IAAa7S,GAC5C0X,EAAa7E,GAEPkF,EAAUlF,EAASuC,IAG3B4B,GAAOv7B,KAAO,SAAU25B,EAAM7iC,IAOtB6iC,EAAK3zB,eAAiB2zB,IAAUpV,GACtC0X,EAAatC,GAGd,IAAIz6B,EAAKs8B,EAAKyE,WAAYnpC,EAAK2qB,eAG9BqX,EAAM55B,GAAMk5B,EAAOlpC,KAAMssC,EAAKyE,WAAYnpC,EAAK2qB,eAC9CviB,EAAIy6B,EAAM7iC,GAAOqlC,QACjB9lC,EAEF,YAAeA,IAARyiC,EACNA,EACAP,EAAQpuB,aAAegyB,EACtBxC,EAAK7sB,aAAchW,IACjBgiC,EAAMa,EAAK7rB,iBAAkBhX,KAAYgiC,EAAIprB,UAC9CorB,EAAIrnC,MACJ,MAGJ8pC,GAAO8C,OAAS,SAAUkE,GACzB,OAASA,EAAM,IAAKxnC,QAASyjC,GAAYC,KAG1ClD,GAAO5vC,MAAQ,SAAUE,GACxB,MAAM,IAAIyC,MAAO,0CAA4CzC,IAO9D0vC,GAAOiH,WAAa,SAAUzH,GAC7B,IAAIpB,EACH8I,EAAa,GACbntC,EAAI,EACJxJ,EAAI,EAOL,GAJAkwC,GAAgBzD,EAAQmK,iBACxB3G,GAAaxD,EAAQoK,YAAc5H,EAAQ9rC,MAAO,GAClD8rC,EAAQZ,KAAM4C,GAETf,EAAe,CACnB,KAAUrC,EAAOoB,EAASjvC,MACpB6tC,IAASoB,EAASjvC,KACtBwJ,EAAImtC,EAAWj2C,KAAMV,IAGvB,KAAQwJ,KACPylC,EAAQjtC,OAAQ20C,EAAYntC,GAAK,GAQnC,OAFAymC,EAAY,KAELhB,GAORU,EAAUF,GAAOE,QAAU,SAAU9B,GACpC,IAAIp8B,EACHmmB,EAAM,GACN53B,EAAI,EACJuc,EAAWsxB,EAAKtxB,SAEjB,GAAMA,GAQC,GAAkB,IAAbA,GAA+B,IAAbA,GAA+B,KAAbA,EAAkB,CAIjE,GAAiC,iBAArBsxB,EAAKiJ,YAChB,OAAOjJ,EAAKiJ,YAIZ,IAAMjJ,EAAOA,EAAKxyB,WAAYwyB,EAAMA,EAAOA,EAAKvyB,YAC/Csc,GAAO+X,EAAS9B,QAGZ,GAAkB,IAAbtxB,GAA+B,IAAbA,EAC7B,OAAOsxB,EAAKv5B,eAnBZ,KAAU7C,EAAOo8B,EAAM7tC,MAGtB43B,GAAO+X,EAASl+B,GAqBlB,OAAOmmB,GAGR8X,EAAOD,GAAOsH,UAAY,CAGzBhD,YAAa,GAEbiD,aAAchD,GAEdpxC,MAAOkvC,EAEPqC,WAAY,GAEZttC,KAAM,GAENowC,SAAU,CACT,IAAK,CAAEhE,IAAK,aAAcnF,OAAO,GACjC,IAAK,CAAEmF,IAAK,cACZ,IAAK,CAAEA,IAAK,kBAAmBnF,OAAO,GACtC,IAAK,CAAEmF,IAAK,oBAGbiE,UAAW,CACV,KAAQ,SAAUt0C,GAWjB,OAVAA,EAAO,GAAMA,EAAO,GAAIqM,QAASojC,GAAWC,IAG5C1vC,EAAO,IAAQA,EAAO,IAAOA,EAAO,IACnCA,EAAO,IAAO,IAAKqM,QAASojC,GAAWC,IAEpB,OAAf1vC,EAAO,KACXA,EAAO,GAAM,IAAMA,EAAO,GAAM,KAG1BA,EAAMO,MAAO,EAAG,IAGxB,MAAS,SAAUP,GAiClB,OArBAA,EAAO,GAAMA,EAAO,GAAI+yB,cAEU,QAA7B/yB,EAAO,GAAIO,MAAO,EAAG,IAGnBP,EAAO,IACZ6sC,GAAO5vC,MAAO+C,EAAO,IAKtBA,EAAO,KAASA,EAAO,GACtBA,EAAO,IAAQA,EAAO,IAAO,GAC7B,GAAqB,SAAfA,EAAO,IAAiC,QAAfA,EAAO,KACvCA,EAAO,KAAWA,EAAO,GAAMA,EAAO,IAAwB,QAAfA,EAAO,KAG3CA,EAAO,IAClB6sC,GAAO5vC,MAAO+C,EAAO,IAGfA,GAGR,OAAU,SAAUA,GACnB,IAAIu0C,EACHC,GAAYx0C,EAAO,IAAOA,EAAO,GAElC,OAAKkvC,EAAmB,MAAE/jC,KAAMnL,EAAO,IAC/B,MAIHA,EAAO,GACXA,EAAO,GAAMA,EAAO,IAAOA,EAAO,IAAO,GAG9Bw0C,GAAYxF,EAAQ7jC,KAAMqpC,KAGnCD,EAAStH,EAAUuH,GAAU,MAG7BD,EAASC,EAASv1C,QAAS,IAAKu1C,EAASl3C,OAASi3C,GAAWC,EAASl3C,UAGxE0C,EAAO,GAAMA,EAAO,GAAIO,MAAO,EAAGg0C,GAClCv0C,EAAO,GAAMw0C,EAASj0C,MAAO,EAAGg0C,IAI1Bv0C,EAAMO,MAAO,EAAG,MAIzBoC,OAAQ,CAEP,IAAO,SAAU8xC,GAChB,IAAI/4B,EAAW+4B,EAAiBpoC,QAASojC,GAAWC,IAAY3c,cAChE,MAA4B,MAArB0hB,EACN,WACC,OAAO,GAER,SAAUxJ,GACT,OAAOA,EAAKvvB,UAAYuvB,EAAKvvB,SAASqX,gBAAkBrX,IAI3D,MAAS,SAAU82B,GAClB,IAAIkC,EAAU1G,EAAYwE,EAAY,KAEtC,OAAOkC,IACJA,EAAU,IAAI9qC,OAAQ,0BACjB4oC,EAAY,IAAMhE,EAAa,SAAaR,EACjDwE,GAAW,SAAUvH,GACpB,OAAOyJ,EAAQvpC,KACY,iBAAnB8/B,EAAKuH,WAA0BvH,EAAKuH,gBACd,IAAtBvH,EAAK7sB,cACX6sB,EAAK7sB,aAAc,UACpB,QAKN,KAAQ,SAAUhW,EAAMusC,EAAUC,GACjC,OAAO,SAAU3J,GAChB,IAAI/V,EAAS2X,GAAOv7B,KAAM25B,EAAM7iC,GAEhC,OAAe,MAAV8sB,EACgB,OAAbyf,GAEFA,IAINzf,GAAU,GAIU,MAAbyf,EAAmBzf,IAAW0f,EACvB,OAAbD,EAAoBzf,IAAW0f,EAClB,OAAbD,EAAoBC,GAAqC,IAA5B1f,EAAOj2B,QAAS21C,GAChC,OAAbD,EAAoBC,GAAS1f,EAAOj2B,QAAS21C,IAAW,EAC3C,OAAbD,EAAoBC,GAAS1f,EAAO30B,OAAQq0C,EAAMt3C,UAAas3C,EAClD,OAAbD,GAAsB,IAAMzf,EAAO7oB,QAASsiC,EAAa,KAAQ,KAAM1vC,QAAS21C,IAAW,EAC9E,OAAbD,IAAoBzf,IAAW0f,GAAS1f,EAAO30B,MAAO,EAAGq0C,EAAMt3C,OAAS,KAAQs3C,EAAQ,QAO3F,MAAS,SAAUpxC,EAAMqxC,EAAMC,EAAW5J,EAAOE,GAChD,IAAI2J,EAAgC,QAAvBvxC,EAAKjD,MAAO,EAAG,GAC3BmzB,EAA+B,SAArBlwB,EAAKjD,OAAQ,GACvBy0C,EAAkB,YAATH,EAEV,OAAiB,IAAV3J,GAAwB,IAATE,EAGrB,SAAUH,GACT,QAASA,EAAKl5B,YAGf,SAAUk5B,EAAMgK,EAAUvkC,GACzB,IAAIwgC,EAAOgE,EAAaC,EAAYtmC,EAAMumC,EAAWp3C,EACpDqyC,EAAM0E,IAAWrhB,EAAU,cAAgB,kBAC3C2hB,EAASpK,EAAKl5B,WACd3J,EAAO4sC,GAAU/J,EAAKvvB,SAASqX,cAC/BuiB,GAAY5kC,IAAQskC,EACpBtD,GAAO,EAER,GAAK2D,EAAS,CAGb,GAAKN,EAAS,CACb,KAAQ1E,GAAM,CAEb,IADAxhC,EAAOo8B,EACGp8B,EAAOA,EAAMwhC,IACtB,GAAK2E,EACJnmC,EAAK6M,SAASqX,gBAAkB3qB,EACd,IAAlByG,EAAK8K,SAEL,OAAO,EAKT3b,EAAQqyC,EAAe,SAAT7sC,IAAoBxF,GAAS,cAE5C,OAAO,EAMR,GAHAA,EAAQ,CAAE01B,EAAU2hB,EAAO58B,WAAa48B,EAAO/7B,WAG1Coa,GAAW4hB,GAkBf,IAHA5D,GADA0D,GADAlE,GAHAgE,GAJAC,GADAtmC,EAAOwmC,GACYvJ,KAAej9B,EAAMi9B,GAAY,KAI1Bj9B,EAAK0mC,YAC5BJ,EAAYtmC,EAAK0mC,UAAa,KAEZ/xC,IAAU,IACZ,KAAQsqC,GAAWoD,EAAO,KACzBA,EAAO,GAC3BriC,EAAOumC,GAAaC,EAAOr8B,WAAYo8B,GAE7BvmC,IAASumC,GAAavmC,GAAQA,EAAMwhC,KAG3CqB,EAAO0D,EAAY,IAAOp3C,EAAM60B,OAGlC,GAAuB,IAAlBhkB,EAAK8K,YAAoB+3B,GAAQ7iC,IAASo8B,EAAO,CACrDiK,EAAa1xC,GAAS,CAAEsqC,EAASsH,EAAW1D,GAC5C,YAyBF,GAlBK4D,IAaJ5D,EADA0D,GADAlE,GAHAgE,GAJAC,GADAtmC,EAAOo8B,GACYa,KAAej9B,EAAMi9B,GAAY,KAI1Bj9B,EAAK0mC,YAC5BJ,EAAYtmC,EAAK0mC,UAAa,KAEZ/xC,IAAU,IACZ,KAAQsqC,GAAWoD,EAAO,KAMhC,IAATQ,EAGJ,MAAU7iC,IAASumC,GAAavmC,GAAQA,EAAMwhC,KAC3CqB,EAAO0D,EAAY,IAAOp3C,EAAM60B,UAE3BmiB,EACNnmC,EAAK6M,SAASqX,gBAAkB3qB,EACd,IAAlByG,EAAK8K,cACH+3B,IAGG4D,KAMJJ,GALAC,EAAatmC,EAAMi9B,KAChBj9B,EAAMi9B,GAAY,KAIKj9B,EAAK0mC,YAC5BJ,EAAYtmC,EAAK0mC,UAAa,KAEpB/xC,GAAS,CAAEsqC,EAAS4D,IAG7B7iC,IAASo8B,MAUlB,OADAyG,GAAQtG,KACQF,GAAWwG,EAAOxG,GAAU,GAAKwG,EAAOxG,GAAS,KAKrE,OAAU,SAAUsK,EAAQvD,GAM3B,IAAI5xC,EACHmQ,EAAKs8B,EAAK4B,QAAS8G,IAAY1I,EAAK2I,WAAYD,EAAOziB,gBACtD8Z,GAAO5vC,MAAO,uBAAyBu4C,GAKzC,OAAKhlC,EAAIs7B,GACDt7B,EAAIyhC,GAIPzhC,EAAGlT,OAAS,GAChB+C,EAAO,CAAEm1C,EAAQA,EAAQ,GAAIvD,GACtBnF,EAAK2I,WAAWphC,eAAgBmhC,EAAOziB,eAC7Cqe,IAAc,SAAUb,EAAM7xB,GAI7B,IAHA,IAAIg3B,EACHC,EAAUnlC,EAAI+/B,EAAM0B,GACpB70C,EAAIu4C,EAAQr4C,OACLF,KAEPmzC,EADAmF,EAAMz2C,EAASsxC,EAAMoF,EAASv4C,OACbshB,EAASg3B,GAAQC,EAASv4C,OAG7C,SAAU6tC,GACT,OAAOz6B,EAAIy6B,EAAM,EAAG5qC,KAIhBmQ,IAITk+B,QAAS,CAGR,IAAO0C,IAAc,SAAU5G,GAK9B,IAAIt2B,EAAQ,GACXm4B,EAAU,GACVuJ,EAAU1I,EAAS1C,EAASn+B,QAASuiC,EAAO,OAE7C,OAAOgH,EAAS9J,GACfsF,IAAc,SAAUb,EAAM7xB,EAASu2B,EAAUvkC,GAMhD,IALA,IAAIu6B,EACH4K,EAAYD,EAASrF,EAAM,KAAM7/B,EAAK,IACtCtT,EAAImzC,EAAKjzC,OAGFF,MACA6tC,EAAO4K,EAAWz4C,MACxBmzC,EAAMnzC,KAASshB,EAASthB,GAAM6tC,OAIjC,SAAUA,EAAMgK,EAAUvkC,GAMzB,OALAwD,EAAO,GAAM+2B,EACb2K,EAAS1hC,EAAO,KAAMxD,EAAK27B,GAG3Bn4B,EAAO,GAAM,MACLm4B,EAAQxZ,UAInB,IAAOue,IAAc,SAAU5G,GAC9B,OAAO,SAAUS,GAChB,OAAO4B,GAAQrC,EAAUS,GAAO3tC,OAAS,MAI3C,SAAY8zC,IAAc,SAAUxzC,GAEnC,OADAA,EAAOA,EAAKyO,QAASojC,GAAWC,IACzB,SAAUzE,GAChB,OAASA,EAAKiJ,aAAenH,EAAS9B,IAAShsC,QAASrB,IAAU,MAWpE,KAAQwzC,IAAc,SAAU/hC,GAO/B,OAJM4/B,EAAY9jC,KAAMkE,GAAQ,KAC/Bw9B,GAAO5vC,MAAO,qBAAuBoS,GAEtCA,EAAOA,EAAKhD,QAASojC,GAAWC,IAAY3c,cACrC,SAAUkY,GAChB,IAAI6K,EACJ,GACC,GAAOA,EAAWrI,EACjBxC,EAAK57B,KACL47B,EAAK7sB,aAAc,aAAgB6sB,EAAK7sB,aAAc,QAGtD,OADA03B,EAAWA,EAAS/iB,iBACA1jB,GAA2C,IAAnCymC,EAAS72C,QAASoQ,EAAO,YAE3C47B,EAAOA,EAAKl5B,aAAkC,IAAlBk5B,EAAKtxB,UAC7C,OAAO,MAKT,OAAU,SAAUsxB,GACnB,IAAI1U,EAAOr4B,EAAO0M,UAAY1M,EAAO0M,SAAS2rB,KAC9C,OAAOA,GAAQA,EAAKh2B,MAAO,KAAQ0qC,EAAKhqC,IAGzC,KAAQ,SAAUgqC,GACjB,OAAOA,IAASuC,GAGjB,MAAS,SAAUvC,GAClB,OAAOA,IAASpV,EAASkgB,iBACrBlgB,EAASmgB,UAAYngB,EAASmgB,gBAC7B/K,EAAKznC,MAAQynC,EAAK9H,OAAS8H,EAAKgL,WAItC,QAAWnE,IAAsB,GACjC,SAAYA,IAAsB,GAElC,QAAW,SAAU7G,GAIpB,IAAIvvB,EAAWuvB,EAAKvvB,SAASqX,cAC7B,MAAsB,UAAbrX,KAA0BuvB,EAAKiL,SACxB,WAAbx6B,KAA2BuvB,EAAKkL,UAGpC,SAAY,SAAUlL,GASrB,OALKA,EAAKl5B,YAETk5B,EAAKl5B,WAAWqkC,eAGQ,IAAlBnL,EAAKkL,UAIb,MAAS,SAAUlL,GAMlB,IAAMA,EAAOA,EAAKxyB,WAAYwyB,EAAMA,EAAOA,EAAKvyB,YAC/C,GAAKuyB,EAAKtxB,SAAW,EACpB,OAAO,EAGT,OAAO,GAGR,OAAU,SAAUsxB,GACnB,OAAQ6B,EAAK4B,QAAiB,MAAGzD,IAIlC,OAAU,SAAUA,GACnB,OAAOoE,EAAQlkC,KAAM8/B,EAAKvvB,WAG3B,MAAS,SAAUuvB,GAClB,OAAOmE,EAAQjkC,KAAM8/B,EAAKvvB,WAG3B,OAAU,SAAUuvB,GACnB,IAAI7iC,EAAO6iC,EAAKvvB,SAASqX,cACzB,MAAgB,UAAT3qB,GAAkC,WAAd6iC,EAAKznC,MAA8B,WAAT4E,GAGtD,KAAQ,SAAU6iC,GACjB,IAAI35B,EACJ,MAAuC,UAAhC25B,EAAKvvB,SAASqX,eACN,SAAdkY,EAAKznC,OAIuC,OAAxC8N,EAAO25B,EAAK7sB,aAAc,UACN,SAAvB9M,EAAKyhB,gBAIR,MAASif,IAAwB,WAChC,MAAO,CAAE,MAGV,KAAQA,IAAwB,SAAUqE,EAAe/4C,GACxD,MAAO,CAAEA,EAAS,MAGnB,GAAM00C,IAAwB,SAAUqE,EAAe/4C,EAAQ20C,GAC9D,MAAO,CAAEA,EAAW,EAAIA,EAAW30C,EAAS20C,MAG7C,KAAQD,IAAwB,SAAUE,EAAc50C,GAEvD,IADA,IAAIF,EAAI,EACAA,EAAIE,EAAQF,GAAK,EACxB80C,EAAap0C,KAAMV,GAEpB,OAAO80C,KAGR,IAAOF,IAAwB,SAAUE,EAAc50C,GAEtD,IADA,IAAIF,EAAI,EACAA,EAAIE,EAAQF,GAAK,EACxB80C,EAAap0C,KAAMV,GAEpB,OAAO80C,KAGR,GAAMF,IAAwB,SAAUE,EAAc50C,EAAQ20C,GAM7D,IALA,IAAI70C,EAAI60C,EAAW,EAClBA,EAAW30C,EACX20C,EAAW30C,EACVA,EACA20C,IACQ70C,GAAK,GACd80C,EAAap0C,KAAMV,GAEpB,OAAO80C,KAGR,GAAMF,IAAwB,SAAUE,EAAc50C,EAAQ20C,GAE7D,IADA,IAAI70C,EAAI60C,EAAW,EAAIA,EAAW30C,EAAS20C,IACjC70C,EAAIE,GACb40C,EAAap0C,KAAMV,GAEpB,OAAO80C,OAKVpF,EAAK4B,QAAe,IAAI5B,EAAK4B,QAAc,GAGhC,CAAE4H,OAAO,EAAMC,UAAU,EAAMC,MAAM,EAAMC,UAAU,EAAMC,OAAO,GAC5E5J,EAAK4B,QAAStxC,GAAMw0C,GAAmBx0C,GAExC,IAAMA,IAAK,CAAEu5C,QAAQ,EAAMC,OAAO,GACjC9J,EAAK4B,QAAStxC,GAAMy0C,GAAoBz0C,GAIzC,SAASq4C,MA0ET,SAAS1E,GAAY8F,GAIpB,IAHA,IAAIz5C,EAAI,EACPC,EAAMw5C,EAAOv5C,OACbktC,EAAW,GACJptC,EAAIC,EAAKD,IAChBotC,GAAYqM,EAAQz5C,GAAI2F,MAEzB,OAAOynC,EAGR,SAAS2F,GAAeyF,EAASkB,EAAYt4B,GAC5C,IAAI6xB,EAAMyG,EAAWzG,IACpB0G,EAAOD,EAAWz9B,KAClBvP,EAAMitC,GAAQ1G,EACd2G,EAAmBx4B,GAAgB,eAAR1U,EAC3BmtC,EAAWlJ,IAEZ,OAAO+I,EAAW5L,MAGjB,SAAUD,EAAMvC,EAASh4B,GACxB,KAAUu6B,EAAOA,EAAMoF,IACtB,GAAuB,IAAlBpF,EAAKtxB,UAAkBq9B,EAC3B,OAAOpB,EAAS3K,EAAMvC,EAASh4B,GAGjC,OAAO,GAIR,SAAUu6B,EAAMvC,EAASh4B,GACxB,IAAIwmC,EAAUhC,EAAaC,EAC1BgC,EAAW,CAAErJ,EAASmJ,GAGvB,GAAKvmC,GACJ,KAAUu6B,EAAOA,EAAMoF,IACtB,IAAuB,IAAlBpF,EAAKtxB,UAAkBq9B,IACtBpB,EAAS3K,EAAMvC,EAASh4B,GAC5B,OAAO,OAKV,KAAUu6B,EAAOA,EAAMoF,IACtB,GAAuB,IAAlBpF,EAAKtxB,UAAkBq9B,EAQ3B,GAHA9B,GAJAC,EAAalK,EAAMa,KAAeb,EAAMa,GAAY,KAI1Bb,EAAKsK,YAC5BJ,EAAYlK,EAAKsK,UAAa,IAE5BwB,GAAQA,IAAS9L,EAAKvvB,SAASqX,cACnCkY,EAAOA,EAAMoF,IAASpF,MAChB,KAAOiM,EAAWhC,EAAaprC,KACrCotC,EAAU,KAAQpJ,GAAWoJ,EAAU,KAAQD,EAG/C,OAASE,EAAU,GAAMD,EAAU,GAOnC,GAHAhC,EAAaprC,GAAQqtC,EAGdA,EAAU,GAAMvB,EAAS3K,EAAMvC,EAASh4B,GAC9C,OAAO,EAMZ,OAAO,GAIV,SAAS0mC,GAAgBC,GACxB,OAAOA,EAAS/5C,OAAS,EACxB,SAAU2tC,EAAMvC,EAASh4B,GAExB,IADA,IAAItT,EAAIi6C,EAAS/5C,OACTF,KACP,IAAMi6C,EAAUj6C,GAAK6tC,EAAMvC,EAASh4B,GACnC,OAAO,EAGT,OAAO,GAER2mC,EAAU,GAYZ,SAASC,GAAUzB,EAAW/yC,EAAKH,EAAQ+lC,EAASh4B,GAOnD,IANA,IAAIu6B,EACHsM,EAAe,GACfn6C,EAAI,EACJC,EAAMw4C,EAAUv4C,OAChBk6C,EAAgB,MAAP10C,EAEF1F,EAAIC,EAAKD,KACT6tC,EAAO4K,EAAWz4C,MAClBuF,IAAUA,EAAQsoC,EAAMvC,EAASh4B,KACtC6mC,EAAaz5C,KAAMmtC,GACduM,GACJ10C,EAAIhF,KAAMV,KAMd,OAAOm6C,EAGR,SAASE,GAAYnD,EAAW9J,EAAUoL,EAAS8B,EAAYC,EAAYC,GAO1E,OANKF,IAAeA,EAAY5L,KAC/B4L,EAAaD,GAAYC,IAErBC,IAAeA,EAAY7L,KAC/B6L,EAAaF,GAAYE,EAAYC,IAE/BxG,IAAc,SAAUb,EAAMlE,EAAS3D,EAASh4B,GACtD,IAAImnC,EAAMz6C,EAAG6tC,EACZ6M,EAAS,GACTC,EAAU,GACVC,EAAc3L,EAAQ/uC,OAGtButC,EAAQ0F,GA5CX,SAA2B/F,EAAUyN,EAAU5L,GAG9C,IAFA,IAAIjvC,EAAI,EACPC,EAAM46C,EAAS36C,OACRF,EAAIC,EAAKD,IAChByvC,GAAQrC,EAAUyN,EAAU76C,GAAKivC,GAElC,OAAOA,EAsCW6L,CACf1N,GAAY,IACZ9B,EAAQ/uB,SAAW,CAAE+uB,GAAYA,EACjC,IAIDyP,GAAY7D,IAAe/D,GAAS/F,EAEnCK,EADAyM,GAAUzM,EAAOiN,EAAQxD,EAAW5L,EAASh4B,GAG9C0nC,EAAaxC,EAGZ+B,IAAgBpH,EAAO+D,EAAY0D,GAAeN,GAGjD,GAGArL,EACD8L,EAQF,GALKvC,GACJA,EAASuC,EAAWC,EAAY1P,EAASh4B,GAIrCgnC,EAMJ,IALAG,EAAOP,GAAUc,EAAYL,GAC7BL,EAAYG,EAAM,GAAInP,EAASh4B,GAG/BtT,EAAIy6C,EAAKv6C,OACDF,MACA6tC,EAAO4M,EAAMz6C,MACnBg7C,EAAYL,EAAS36C,MAAW+6C,EAAWJ,EAAS36C,IAAQ6tC,IAK/D,GAAKsF,GACJ,GAAKoH,GAAcrD,EAAY,CAC9B,GAAKqD,EAAa,CAKjB,IAFAE,EAAO,GACPz6C,EAAIg7C,EAAW96C,OACPF,MACA6tC,EAAOmN,EAAYh7C,KAGzBy6C,EAAK/5C,KAAQq6C,EAAW/6C,GAAM6tC,GAGhC0M,EAAY,KAAQS,EAAa,GAAMP,EAAMnnC,GAK9C,IADAtT,EAAIg7C,EAAW96C,OACPF,MACA6tC,EAAOmN,EAAYh7C,MACvBy6C,EAAOF,EAAa14C,EAASsxC,EAAMtF,GAAS6M,EAAQ16C,KAAS,IAE/DmzC,EAAMsH,KAAYxL,EAASwL,GAAS5M,UAOvCmN,EAAad,GACZc,IAAe/L,EACd+L,EAAWh5C,OAAQ44C,EAAaI,EAAW96C,QAC3C86C,GAEGT,EACJA,EAAY,KAAMtL,EAAS+L,EAAY1nC,GAEvC5S,EAAKxB,MAAO+vC,EAAS+L,MAMzB,SAASC,GAAmBxB,GAyB3B,IAxBA,IAAIyB,EAAc1C,EAAShvC,EAC1BvJ,EAAMw5C,EAAOv5C,OACbi7C,EAAkBzL,EAAKuH,SAAUwC,EAAQ,GAAIrzC,MAC7Cg1C,EAAmBD,GAAmBzL,EAAKuH,SAAU,KACrDj3C,EAAIm7C,EAAkB,EAAI,EAG1BE,EAAetI,IAAe,SAAUlF,GACvC,OAAOA,IAASqN,IACdE,GAAkB,GACrBE,EAAkBvI,IAAe,SAAUlF,GAC1C,OAAOhsC,EAASq5C,EAAcrN,IAAU,IACtCuN,GAAkB,GACrBnB,EAAW,CAAE,SAAUpM,EAAMvC,EAASh4B,GACrC,IAAIskB,GAASujB,IAAqB7nC,GAAOg4B,IAAY0E,MAClDkL,EAAe5P,GAAU/uB,SAC1B8+B,EAAcxN,EAAMvC,EAASh4B,GAC7BgoC,EAAiBzN,EAAMvC,EAASh4B,IAIlC,OADA4nC,EAAe,KACRtjB,IAGD53B,EAAIC,EAAKD,IAChB,GAAOw4C,EAAU9I,EAAKuH,SAAUwC,EAAQz5C,GAAIoG,MAC3C6zC,EAAW,CAAElH,GAAeiH,GAAgBC,GAAYzB,QAClD,CAIN,IAHAA,EAAU9I,EAAKnqC,OAAQk0C,EAAQz5C,GAAIoG,MAAOlH,MAAO,KAAMu6C,EAAQz5C,GAAIshB,UAGrDotB,GAAY,CAIzB,IADAllC,IAAMxJ,EACEwJ,EAAIvJ,IACNyvC,EAAKuH,SAAUwC,EAAQjwC,GAAIpD,MADhBoD,KAKjB,OAAO6wC,GACNr6C,EAAI,GAAKg6C,GAAgBC,GACzBj6C,EAAI,GAAK2zC,GAGT8F,EACEt2C,MAAO,EAAGnD,EAAI,GACduD,OAAQ,CAAEoC,MAAgC,MAAzB8zC,EAAQz5C,EAAI,GAAIoG,KAAe,IAAM,MACtD6I,QAASuiC,EAAO,MAClBgH,EACAx4C,EAAIwJ,GAAKyxC,GAAmBxB,EAAOt2C,MAAOnD,EAAGwJ,IAC7CA,EAAIvJ,GAAOg7C,GAAqBxB,EAASA,EAAOt2C,MAAOqG,IACvDA,EAAIvJ,GAAO0zC,GAAY8F,IAGzBQ,EAASv5C,KAAM83C,GAIjB,OAAOwB,GAAgBC,GAoTxB,OAtpBA5B,GAAW54C,UAAYiwC,EAAK6L,QAAU7L,EAAK4B,QAC3C5B,EAAK2I,WAAa,IAAIA,GAEtBxI,EAAWJ,GAAOI,SAAW,SAAUzC,EAAUoO,GAChD,IAAIjD,EAAS31C,EAAO62C,EAAQrzC,EAC3Bq1C,EAAOpI,EAAQqI,EACfC,EAAS7K,EAAY1D,EAAW,KAEjC,GAAKuO,EACJ,OAAOH,EAAY,EAAIG,EAAOx4C,MAAO,GAOtC,IAJAs4C,EAAQrO,EACRiG,EAAS,GACTqI,EAAahM,EAAKwH,UAEVuE,GAAQ,CA2Bf,IAAMr1C,KAxBAmyC,KAAa31C,EAAQ6uC,EAAOld,KAAMknB,MAClC74C,IAGJ64C,EAAQA,EAAMt4C,MAAOP,EAAO,GAAI1C,SAAYu7C,GAE7CpI,EAAO3yC,KAAQ+4C,EAAS,KAGzBlB,GAAU,GAGH31C,EAAQ8uC,EAAand,KAAMknB,MACjClD,EAAU31C,EAAM+oC,QAChB8N,EAAO/4C,KAAM,CACZiF,MAAO4yC,EAGPnyC,KAAMxD,EAAO,GAAIqM,QAASuiC,EAAO,OAElCiK,EAAQA,EAAMt4C,MAAOo1C,EAAQr4C,SAIhBwvC,EAAKnqC,SACX3C,EAAQkvC,EAAW1rC,GAAOmuB,KAAMknB,KAAgBC,EAAYt1C,MAChExD,EAAQ84C,EAAYt1C,GAAQxD,MAC9B21C,EAAU31C,EAAM+oC,QAChB8N,EAAO/4C,KAAM,CACZiF,MAAO4yC,EACPnyC,KAAMA,EACNkb,QAAS1e,IAEV64C,EAAQA,EAAMt4C,MAAOo1C,EAAQr4C,SAI/B,IAAMq4C,EACL,MAOF,OAAOiD,EACNC,EAAMv7C,OACNu7C,EACChM,GAAO5vC,MAAOutC,GAGd0D,EAAY1D,EAAUiG,GAASlwC,MAAO,IA4ZzC2sC,EAAUL,GAAOK,QAAU,SAAU1C,EAAUxqC,GAC9C,IAAI5C,EACH47C,EAAc,GACdC,EAAkB,GAClBF,EAAS5K,EAAe3D,EAAW,KAEpC,IAAMuO,EAAS,CAOd,IAJM/4C,IACLA,EAAQitC,EAAUzC,IAEnBptC,EAAI4C,EAAM1C,OACFF,MACP27C,EAASV,GAAmBr4C,EAAO5C,KACtB0uC,GACZkN,EAAYl7C,KAAMi7C,GAElBE,EAAgBn7C,KAAMi7C,GAKxBA,EAAS5K,EACR3D,EArJH,SAAmCyO,EAAiBD,GACnD,IAAIE,EAAQF,EAAY17C,OAAS,EAChC67C,EAAYF,EAAgB37C,OAAS,EACrC87C,EAAe,SAAU7I,EAAM7H,EAASh4B,EAAK27B,EAASgN,GACrD,IAAIpO,EAAMrkC,EAAGgvC,EACZ0D,EAAe,EACfl8C,EAAI,IACJy4C,EAAYtF,GAAQ,GACpBgJ,EAAa,GACbC,EAAgBpM,EAGhBvC,EAAQ0F,GAAQ4I,GAAarM,EAAK7oC,KAAY,IAAG,IAAKo1C,GAGtDI,EAAkB3L,GAA4B,MAAjB0L,EAAwB,EAAI3zC,KAAKE,UAAY,GAC1E1I,EAAMwtC,EAAMvtC,OAcb,IAZK+7C,IAMJjM,EAAmB1E,GAAW7S,GAAY6S,GAAW2Q,GAM9Cj8C,IAAMC,GAAgC,OAAvB4tC,EAAOJ,EAAOztC,IAAeA,IAAM,CACzD,GAAK+7C,GAAalO,EAAO,CAWxB,IAVArkC,EAAI,EAME8hC,GAAWuC,EAAK3zB,eAAiBue,IACtC0X,EAAatC,GACbv6B,GAAO+8B,GAEEmI,EAAUqD,EAAiBryC,MACpC,GAAKgvC,EAAS3K,EAAMvC,GAAW7S,EAAUnlB,GAAQ,CAChD27B,EAAQvuC,KAAMmtC,GACd,MAGGoO,IACJvL,EAAU2L,GAKPP,KAGGjO,GAAQ2K,GAAW3K,IACzBqO,IAII/I,GACJsF,EAAU/3C,KAAMmtC,IAgBnB,GATAqO,GAAgBl8C,EASX87C,GAAS97C,IAAMk8C,EAAe,CAElC,IADA1yC,EAAI,EACMgvC,EAAUoD,EAAapyC,MAChCgvC,EAASC,EAAW0D,EAAY7Q,EAASh4B,GAG1C,GAAK6/B,EAAO,CAGX,GAAK+I,EAAe,EACnB,KAAQl8C,KACCy4C,EAAWz4C,IAAOm8C,EAAYn8C,KACrCm8C,EAAYn8C,GAAMy1B,EAAIryB,KAAM6rC,IAM/BkN,EAAajC,GAAUiC,GAIxBz7C,EAAKxB,MAAO+vC,EAASkN,GAGhBF,IAAc9I,GAAQgJ,EAAWj8C,OAAS,GAC5Cg8C,EAAeN,EAAY17C,OAAW,GAExCuvC,GAAOiH,WAAYzH,GAUrB,OALKgN,IACJvL,EAAU2L,EACVrM,EAAmBoM,GAGb3D,GAGT,OAAOqD,EACN9H,GAAcgI,GACdA,EA4BCM,CAA0BT,EAAiBD,IAI5CD,EAAOvO,SAAWA,EAEnB,OAAOuO,GAYR5L,EAASN,GAAOM,OAAS,SAAU3C,EAAU9B,EAAS2D,EAASkE,GAC9D,IAAInzC,EAAGy5C,EAAQ8C,EAAOn2C,EAAMS,EAC3B21C,EAA+B,mBAAbpP,GAA2BA,EAC7CxqC,GAASuwC,GAAQtD,EAAYzC,EAAWoP,EAASpP,UAAYA,GAM9D,GAJA6B,EAAUA,GAAW,GAIC,IAAjBrsC,EAAM1C,OAAe,CAIzB,IADAu5C,EAAS72C,EAAO,GAAMA,EAAO,GAAIO,MAAO,IAC5BjD,OAAS,GAAsC,QAA/Bq8C,EAAQ9C,EAAQ,IAAMrzC,MAC5B,IAArBklC,EAAQ/uB,UAAkB8zB,GAAkBX,EAAKuH,SAAUwC,EAAQ,GAAIrzC,MAAS,CAIhF,KAFAklC,GAAYoE,EAAK7oC,KAAW,GAAG01C,EAAMj7B,QAAS,GAC5CrS,QAASojC,GAAWC,IAAahH,IAAa,IAAM,IAErD,OAAO2D,EAGIuN,IACXlR,EAAUA,EAAQ32B,YAGnBy4B,EAAWA,EAASjqC,MAAOs2C,EAAO9N,QAAQhmC,MAAMzF,QAKjD,IADAF,EAAI8xC,EAA0B,aAAE/jC,KAAMq/B,GAAa,EAAIqM,EAAOv5C,OACtDF,MACPu8C,EAAQ9C,EAAQz5C,IAGX0vC,EAAKuH,SAAY7wC,EAAOm2C,EAAMn2C,QAGnC,IAAOS,EAAO6oC,EAAK7oC,KAAMT,MAGjB+sC,EAAOtsC,EACb01C,EAAMj7B,QAAS,GAAIrS,QAASojC,GAAWC,IACvCF,GAASrkC,KAAM0rC,EAAQ,GAAIrzC,OAAUqtC,GAAanI,EAAQ32B,aACzD22B,IACI,CAKL,GAFAmO,EAAOz3C,OAAQhC,EAAG,KAClBotC,EAAW+F,EAAKjzC,QAAUyzC,GAAY8F,IAGrC,OADA/4C,EAAKxB,MAAO+vC,EAASkE,GACdlE,EAGR,OAeJ,OAPEuN,GAAY1M,EAAS1C,EAAUxqC,IAChCuwC,EACA7H,GACC+E,EACDpB,GACC3D,GAAW8G,GAASrkC,KAAMq/B,IAAcqG,GAAanI,EAAQ32B,aAAgB22B,GAExE2D,GAMRxC,EAAQoK,WAAanI,EAAQhsC,MAAO,IAAK2rC,KAAM4C,GAAYlpC,KAAM,MAAS2mC,EAI1EjC,EAAQmK,mBAAqB1G,EAG7BC,IAIA1D,EAAQ2J,aAAenC,IAAQ,SAAUpkC,GAGxC,OAA4E,EAArEA,EAAGmmC,wBAAyBvd,EAAShX,cAAe,gBAMtDwyB,IAAQ,SAAUpkC,GAEvB,OADAA,EAAG4lC,UAAY,mBACiC,MAAzC5lC,EAAGwL,WAAW2F,aAAc,YAEnCkzB,GAAW,0BAA0B,SAAUrG,EAAM7iC,EAAM4kC,GAC1D,IAAMA,EACL,OAAO/B,EAAK7sB,aAAchW,EAA6B,SAAvBA,EAAK2qB,cAA2B,EAAI,MAOjE8W,EAAQpuB,YAAe41B,IAAQ,SAAUpkC,GAG9C,OAFAA,EAAG4lC,UAAY,WACf5lC,EAAGwL,WAAW4G,aAAc,QAAS,IACY,KAA1CpS,EAAGwL,WAAW2F,aAAc,aAEnCkzB,GAAW,SAAS,SAAUrG,EAAM4O,EAAO7M,GAC1C,IAAMA,GAAyC,UAAhC/B,EAAKvvB,SAASqX,cAC5B,OAAOkY,EAAK6O,gBAOTzI,IAAQ,SAAUpkC,GACvB,OAAwC,MAAjCA,EAAGmR,aAAc,gBAExBkzB,GAAW/C,GAAU,SAAUtD,EAAM7iC,EAAM4kC,GAC1C,IAAI5C,EACJ,IAAM4C,EACL,OAAwB,IAAjB/B,EAAM7iC,GAAkBA,EAAK2qB,eACjCqX,EAAMa,EAAK7rB,iBAAkBhX,KAAYgiC,EAAIprB,UAC9CorB,EAAIrnC,MACJ,QAKE8pC,GA14EP,CA44EK3uC,GAILqsC,EAAOtmC,KAAO4oC,EACdtC,EAAO/+B,KAAOqhC,EAAOsH,UAGrB5J,EAAO/+B,KAAM,KAAQ++B,EAAO/+B,KAAKkjC,QACjCnE,EAAOuJ,WAAavJ,EAAOwP,OAASlN,EAAOiH,WAC3CvJ,EAAO3sC,KAAOivC,EAAOE,QACrBxC,EAAOyP,SAAWnN,EAAOG,MACzBzC,EAAOqD,SAAWf,EAAOe,SACzBrD,EAAO0P,eAAiBpN,EAAO8C,OAK/B,IAAIU,EAAM,SAAUpF,EAAMoF,EAAK6J,GAI9B,IAHA,IAAIvE,EAAU,GACbwE,OAAqBxyC,IAAVuyC,GAEFjP,EAAOA,EAAMoF,KAA6B,IAAlBpF,EAAKtxB,UACtC,GAAuB,IAAlBsxB,EAAKtxB,SAAiB,CAC1B,GAAKwgC,GAAY5P,EAAQU,GAAOrI,GAAIsX,GACnC,MAEDvE,EAAQ73C,KAAMmtC,GAGhB,OAAO0K,GAIJyE,EAAW,SAAU3tC,EAAGw+B,GAG3B,IAFA,IAAI0K,EAAU,GAENlpC,EAAGA,EAAIA,EAAEiM,YACI,IAAfjM,EAAEkN,UAAkBlN,IAAMw+B,GAC9B0K,EAAQ73C,KAAM2O,GAIhB,OAAOkpC,GAIJ0E,EAAgB9P,EAAO/+B,KAAKxL,MAAMs6C,aAItC,SAAS5+B,EAAUuvB,EAAM7iC,GAExB,OAAO6iC,EAAKvvB,UAAYuvB,EAAKvvB,SAASqX,gBAAkB3qB,EAAK2qB,cAG9D,IAAIwnB,EAAa,kEAKjB,SAASC,EAAQ5G,EAAU6G,EAAW50B,GACrC,OAAKikB,EAAY2Q,GACTlQ,EAAOe,KAAMsI,GAAU,SAAU3I,EAAM7tC,GAC7C,QAASq9C,EAAUj6C,KAAMyqC,EAAM7tC,EAAG6tC,KAAWplB,KAK1C40B,EAAU9gC,SACP4wB,EAAOe,KAAMsI,GAAU,SAAU3I,GACvC,OAASA,IAASwP,IAAgB50B,KAKV,iBAAd40B,EACJlQ,EAAOe,KAAMsI,GAAU,SAAU3I,GACvC,OAAShsC,EAAQuB,KAAMi6C,EAAWxP,IAAU,IAAQplB,KAK/C0kB,EAAO5nC,OAAQ83C,EAAW7G,EAAU/tB,GAG5C0kB,EAAO5nC,OAAS,SAAU6I,EAAMq/B,EAAOhlB,GACtC,IAAIolB,EAAOJ,EAAO,GAMlB,OAJKhlB,IACJra,EAAO,QAAUA,EAAO,KAGH,IAAjBq/B,EAAMvtC,QAAkC,IAAlB2tC,EAAKtxB,SACxB4wB,EAAOtmC,KAAK6uC,gBAAiB7H,EAAMz/B,GAAS,CAAEy/B,GAAS,GAGxDV,EAAOtmC,KAAKya,QAASlT,EAAM++B,EAAOe,KAAMT,GAAO,SAAUI,GAC/D,OAAyB,IAAlBA,EAAKtxB,cAId4wB,EAAO/5B,GAAGk7B,OAAQ,CACjBznC,KAAM,SAAUumC,GACf,IAAIptC,EAAG43B,EACN33B,EAAMzB,KAAK0B,OACX/B,EAAOK,KAER,GAAyB,iBAAb4uC,EACX,OAAO5uC,KAAKgvC,UAAWL,EAAQC,GAAW7nC,QAAQ,WACjD,IAAMvF,EAAI,EAAGA,EAAIC,EAAKD,IACrB,GAAKmtC,EAAOqD,SAAUryC,EAAM6B,GAAKxB,MAChC,OAAO,MAQX,IAFAo5B,EAAMp5B,KAAKgvC,UAAW,IAEhBxtC,EAAI,EAAGA,EAAIC,EAAKD,IACrBmtC,EAAOtmC,KAAMumC,EAAUjvC,EAAM6B,GAAK43B,GAGnC,OAAO33B,EAAM,EAAIktC,EAAOuJ,WAAY9e,GAAQA,GAE7CryB,OAAQ,SAAU6nC,GACjB,OAAO5uC,KAAKgvC,UAAW4P,EAAQ5+C,KAAM4uC,GAAY,IAAI,KAEtD3kB,IAAK,SAAU2kB,GACd,OAAO5uC,KAAKgvC,UAAW4P,EAAQ5+C,KAAM4uC,GAAY,IAAI,KAEtD5H,GAAI,SAAU4H,GACb,QAASgQ,EACR5+C,KAIoB,iBAAb4uC,GAAyB6P,EAAclvC,KAAMq/B,GACnDD,EAAQC,GACRA,GAAY,IACb,GACCltC,UASJ,IAAIo9C,EAMHnL,EAAa,uCAENhF,EAAO/5B,GAAGg1B,KAAO,SAAUgF,EAAU9B,EAASztC,GACpD,IAAI+E,EAAOirC,EAGX,IAAMT,EACL,OAAO5uC,KAQR,GAHAX,EAAOA,GAAQy/C,EAGU,iBAAblQ,EAAwB,CAanC,KAPCxqC,EALsB,MAAlBwqC,EAAU,IACsB,MAApCA,EAAUA,EAASltC,OAAS,IAC5BktC,EAASltC,QAAU,EAGX,CAAE,KAAMktC,EAAU,MAGlB+E,EAAW5d,KAAM6Y,MAIVxqC,EAAO,IAAQ0oC,EA6CxB,OAAMA,GAAWA,EAAQgC,QACtBhC,GAAWztC,GAAOgJ,KAAMumC,GAK1B5uC,KAAKoZ,YAAa0zB,GAAUzkC,KAAMumC,GAhDzC,GAAKxqC,EAAO,GAAM,CAYjB,GAXA0oC,EAAUA,aAAmB6B,EAAS7B,EAAS,GAAMA,EAIrD6B,EAAOO,MAAOlvC,KAAM2uC,EAAOoQ,UAC1B36C,EAAO,GACP0oC,GAAWA,EAAQ/uB,SAAW+uB,EAAQpxB,eAAiBoxB,EAAU7S,GACjE,IAII0kB,EAAWpvC,KAAMnL,EAAO,KAASuqC,EAAOsB,cAAenD,GAC3D,IAAM1oC,KAAS0oC,EAGToB,EAAYluC,KAAMoE,IACtBpE,KAAMoE,GAAS0oC,EAAS1oC,IAIxBpE,KAAK0V,KAAMtR,EAAO0oC,EAAS1oC,IAK9B,OAAOpE,KAYP,OARAqvC,EAAOpV,EAAS3X,eAAgBle,EAAO,OAKtCpE,KAAM,GAAMqvC,EACZrvC,KAAK0B,OAAS,GAER1B,KAcH,OAAK4uC,EAAS7wB,UACpB/d,KAAM,GAAM4uC,EACZ5uC,KAAK0B,OAAS,EACP1B,MAIIkuC,EAAYU,QACD7iC,IAAf1M,EAAK2/C,MACX3/C,EAAK2/C,MAAOpQ,GAGZA,EAAUD,GAGLA,EAAO6B,UAAW5B,EAAU5uC,QAIhCiB,UAAY0tC,EAAO/5B,GAGxBkqC,EAAanQ,EAAQ1U,GAGrB,IAAIglB,EAAe,iCAGlBC,EAAmB,CAClBC,UAAU,EACVC,UAAU,EACV3hC,MAAM,EACN4hC,MAAM,GAoFR,SAASC,EAASzJ,EAAKpB,GACtB,MAAUoB,EAAMA,EAAKpB,KAA4B,IAAjBoB,EAAI93B,WACpC,OAAO83B,EAnFRlH,EAAO/5B,GAAGk7B,OAAQ,CACjByP,IAAK,SAAU/oC,GACd,IAAIgpC,EAAU7Q,EAAQn4B,EAAQxW,MAC7BiF,EAAIu6C,EAAQ99C,OAEb,OAAO1B,KAAK+G,QAAQ,WAEnB,IADA,IAAIvF,EAAI,EACAA,EAAIyD,EAAGzD,IACd,GAAKmtC,EAAOqD,SAAUhyC,KAAMw/C,EAASh+C,IACpC,OAAO,MAMXi+C,QAAS,SAAUlH,EAAWzL,GAC7B,IAAI+I,EACHr0C,EAAI,EACJyD,EAAIjF,KAAK0B,OACTq4C,EAAU,GACVyF,EAA+B,iBAAdjH,GAA0B5J,EAAQ4J,GAGpD,IAAMkG,EAAclvC,KAAMgpC,GACzB,KAAQ/2C,EAAIyD,EAAGzD,IACd,IAAMq0C,EAAM71C,KAAMwB,GAAKq0C,GAAOA,IAAQ/I,EAAS+I,EAAMA,EAAI1/B,WAGxD,GAAK0/B,EAAI93B,SAAW,KAAQyhC,EAC3BA,EAAQl1C,MAAOurC,IAAS,EAGP,IAAjBA,EAAI93B,UACH4wB,EAAOtmC,KAAK6uC,gBAAiBrB,EAAK0C,IAAgB,CAEnDwB,EAAQ73C,KAAM2zC,GACd,MAMJ,OAAO71C,KAAKgvC,UAAW+K,EAAQr4C,OAAS,EAAIitC,EAAOuJ,WAAY6B,GAAYA,IAI5EzvC,MAAO,SAAU+kC,GAGhB,OAAMA,EAKe,iBAATA,EACJhsC,EAAQuB,KAAM+pC,EAAQU,GAAQrvC,KAAM,IAIrCqD,EAAQuB,KAAM5E,KAGpBqvC,EAAKP,OAASO,EAAM,GAAMA,GAZjBrvC,KAAM,IAAOA,KAAM,GAAImW,WAAenW,KAAKsvC,QAAQoQ,UAAUh+C,QAAU,GAgBlFi+C,IAAK,SAAU/Q,EAAU9B,GACxB,OAAO9sC,KAAKgvC,UACXL,EAAOuJ,WACNvJ,EAAOO,MAAOlvC,KAAKglB,MAAO2pB,EAAQC,EAAU9B,OAK/C8S,QAAS,SAAUhR,GAClB,OAAO5uC,KAAK2/C,IAAiB,MAAZ/Q,EAChB5uC,KAAKmvC,WAAanvC,KAAKmvC,WAAWpoC,OAAQ6nC,OAU7CD,EAAOS,KAAM,CACZqK,OAAQ,SAAUpK,GACjB,IAAIoK,EAASpK,EAAKl5B,WAClB,OAAOsjC,GAA8B,KAApBA,EAAO17B,SAAkB07B,EAAS,MAEpDoG,QAAS,SAAUxQ,GAClB,OAAOoF,EAAKpF,EAAM,eAEnByQ,aAAc,SAAUzQ,EAAM2B,EAAIsN,GACjC,OAAO7J,EAAKpF,EAAM,aAAciP,IAEjC7gC,KAAM,SAAU4xB,GACf,OAAOiQ,EAASjQ,EAAM,gBAEvBgQ,KAAM,SAAUhQ,GACf,OAAOiQ,EAASjQ,EAAM,oBAEvB0Q,QAAS,SAAU1Q,GAClB,OAAOoF,EAAKpF,EAAM,gBAEnBqQ,QAAS,SAAUrQ,GAClB,OAAOoF,EAAKpF,EAAM,oBAEnB2Q,UAAW,SAAU3Q,EAAM2B,EAAIsN,GAC9B,OAAO7J,EAAKpF,EAAM,cAAeiP,IAElC2B,UAAW,SAAU5Q,EAAM2B,EAAIsN,GAC9B,OAAO7J,EAAKpF,EAAM,kBAAmBiP,IAEtCE,SAAU,SAAUnP,GACnB,OAAOmP,GAAYnP,EAAKl5B,YAAc,IAAK0G,WAAYwyB,IAExD8P,SAAU,SAAU9P,GACnB,OAAOmP,EAAUnP,EAAKxyB,aAEvBuiC,SAAU,SAAU/P,GACnB,OAA6B,MAAxBA,EAAK6Q,iBAKTvS,EAAU0B,EAAK6Q,iBAER7Q,EAAK6Q,iBAMRpgC,EAAUuvB,EAAM,cACpBA,EAAOA,EAAKpgC,SAAWogC,GAGjBV,EAAOO,MAAO,GAAIG,EAAKjyB,gBAE7B,SAAU5Q,EAAMoI,GAClB+5B,EAAO/5B,GAAIpI,GAAS,SAAU8xC,EAAO1P,GACpC,IAAImL,EAAUpL,EAAOznC,IAAKlH,KAAM4U,EAAI0pC,GAuBpC,MArB0B,UAArB9xC,EAAK7H,OAAQ,KACjBiqC,EAAW0P,GAGP1P,GAAgC,iBAAbA,IACvBmL,EAAUpL,EAAO5nC,OAAQ6nC,EAAUmL,IAG/B/5C,KAAK0B,OAAS,IAGZw9C,EAAkB1yC,IACvBmiC,EAAOuJ,WAAY6B,GAIfkF,EAAa1vC,KAAM/C,IACvButC,EAAQza,WAIHt/B,KAAKgvC,UAAW+K,OAGzB,IAAIoG,EAAgB,oBAsOpB,SAASC,EAAU7zC,GAClB,OAAOA,EAER,SAAS8zC,EAASC,GACjB,MAAMA,EAGP,SAASC,EAAYp5C,EAAO6iC,EAASC,EAAQuW,GAC5C,IAAIC,EAEJ,IAGMt5C,GAAS+mC,EAAcuS,EAASt5C,EAAMu5C,SAC1CD,EAAO77C,KAAMuC,GAAQgrC,KAAMnI,GAAU2W,KAAM1W,GAGhC9iC,GAAS+mC,EAAcuS,EAASt5C,EAAMy5C,MACjDH,EAAO77C,KAAMuC,EAAO6iC,EAASC,GAQ7BD,EAAQtpC,WAAOqL,EAAW,CAAE5E,GAAQxC,MAAO67C,IAM3C,MAAQr5C,GAIT8iC,EAAOvpC,WAAOqL,EAAW,CAAE5E,KAvO7BwnC,EAAOkS,UAAY,SAAU9gD,GAI5BA,EAA6B,iBAAZA,EAlClB,SAAwBA,GACvB,IAAIwR,EAAS,GAIb,OAHAo9B,EAAOS,KAAMrvC,EAAQqE,MAAO+7C,IAAmB,IAAI,SAAUW,EAAGC,GAC/DxvC,EAAQwvC,IAAS,KAEXxvC,EA8BNyvC,CAAejhD,GACf4uC,EAAOmB,OAAQ,GAAI/vC,GAEpB,IACCkhD,EAGAC,EAGAxV,EAGAyV,EAGAxoC,EAAO,GAGP7X,EAAQ,GAGRsgD,GAAe,EAGfC,EAAO,WAQN,IALAF,EAASA,GAAUphD,EAAQ8pC,KAI3B6B,EAAQuV,GAAS,EACTngD,EAAMY,OAAQ0/C,GAAe,EAEpC,IADAF,EAASpgD,EAAMqsC,UACLiU,EAAczoC,EAAKjX,SAGmC,IAA1DiX,EAAMyoC,GAAc1gD,MAAOwgD,EAAQ,GAAKA,EAAQ,KACpDnhD,EAAQuhD,cAGRF,EAAczoC,EAAKjX,OACnBw/C,GAAS,GAMNnhD,EAAQmhD,SACbA,GAAS,GAGVD,GAAS,EAGJE,IAIHxoC,EADIuoC,EACG,GAIA,KAMVvhD,EAAO,CAGNggD,IAAK,WA2BJ,OA1BKhnC,IAGCuoC,IAAWD,IACfG,EAAczoC,EAAKjX,OAAS,EAC5BZ,EAAMoB,KAAMg/C,IAGb,SAAWvB,EAAKl7C,GACfkqC,EAAOS,KAAM3qC,GAAM,SAAUq8C,EAAGn/C,GAC1BusC,EAAYvsC,GACV5B,EAAQo+C,QAAWx+C,EAAK4/C,IAAK59C,IAClCgX,EAAKzW,KAAMP,GAEDA,GAAOA,EAAID,QAA4B,WAAlBgtC,EAAQ/sC,IAGxCg+C,EAAKh+C,MATR,CAYKhB,WAEAugD,IAAWD,GACfI,KAGKrhD,MAIRgd,OAAQ,WAYP,OAXA2xB,EAAOS,KAAMzuC,WAAW,SAAUmgD,EAAGn/C,GAEpC,IADA,IAAI2I,GACMA,EAAQqkC,EAAO+B,QAAS/uC,EAAKgX,EAAMrO,KAAa,GACzDqO,EAAKnV,OAAQ8G,EAAO,GAGfA,GAAS82C,GACbA,OAIIphD,MAKRu/C,IAAK,SAAU3qC,GACd,OAAOA,EACN+5B,EAAO+B,QAAS97B,EAAI+D,IAAU,EAC9BA,EAAKjX,OAAS,GAIhB+pB,MAAO,WAIN,OAHK9S,IACJA,EAAO,IAED3Y,MAMRuhD,QAAS,WAGR,OAFAJ,EAASrgD,EAAQ,GACjB6X,EAAOuoC,EAAS,GACTlhD,MAERw0C,SAAU,WACT,OAAQ77B,GAMT6oC,KAAM,WAKL,OAJAL,EAASrgD,EAAQ,GACXogD,GAAWD,IAChBtoC,EAAOuoC,EAAS,IAEVlhD,MAERmhD,OAAQ,WACP,QAASA,GAIVM,SAAU,SAAU3U,EAASroC,GAS5B,OARM08C,IAEL18C,EAAO,CAAEqoC,GADTroC,EAAOA,GAAQ,IACQE,MAAQF,EAAKE,QAAUF,GAC9C3D,EAAMoB,KAAMuC,GACNw8C,GACLI,KAGKrhD,MAIRqhD,KAAM,WAEL,OADA1hD,EAAK8hD,SAAUzhD,KAAMW,WACdX,MAIR0rC,MAAO,WACN,QAASA,IAIZ,OAAO/rC,GA4CRgvC,EAAOmB,OAAQ,CAEd4R,SAAU,SAAUC,GACnB,IAAIC,EAAS,CAIX,CAAE,SAAU,WAAYjT,EAAOkS,UAAW,UACzClS,EAAOkS,UAAW,UAAY,GAC/B,CAAE,UAAW,OAAQlS,EAAOkS,UAAW,eACtClS,EAAOkS,UAAW,eAAiB,EAAG,YACvC,CAAE,SAAU,OAAQlS,EAAOkS,UAAW,eACrClS,EAAOkS,UAAW,eAAiB,EAAG,aAExChV,EAAQ,UACR6U,EAAU,CACT7U,MAAO,WACN,OAAOA,GAERgW,OAAQ,WAEP,OADAC,EAAS3P,KAAMxxC,WAAYggD,KAAMhgD,WAC1BX,MAER,MAAS,SAAU4U,GAClB,OAAO8rC,EAAQE,KAAM,KAAMhsC,IAI5BmtC,KAAM,WACL,IAAIC,EAAMrhD,UAEV,OAAOguC,EAAO+S,UAAU,SAAUO,GACjCtT,EAAOS,KAAMwS,GAAQ,SAAU5Q,EAAIkR,GAGlC,IAAIttC,EAAKs5B,EAAY8T,EAAKE,EAAO,MAAWF,EAAKE,EAAO,IAKxDJ,EAAUI,EAAO,KAAO,WACvB,IAAIC,EAAWvtC,GAAMA,EAAGlU,MAAOV,KAAMW,WAChCwhD,GAAYjU,EAAYiU,EAASzB,SACrCyB,EAASzB,UACP0B,SAAUH,EAASI,QACnBlQ,KAAM8P,EAASjY,SACf2W,KAAMsB,EAAShY,QAEjBgY,EAAUC,EAAO,GAAM,QACtBliD,KACA4U,EAAK,CAAEutC,GAAaxhD,iBAKxBqhD,EAAM,QACHtB,WAELE,KAAM,SAAU0B,EAAaC,EAAYC,GACxC,IAAIC,EAAW,EACf,SAASzY,EAAS0Y,EAAOZ,EAAUzpB,EAASsqB,GAC3C,OAAO,WACN,IAAI1X,EAAOjrC,KACVyE,EAAO9D,UACPiiD,EAAa,WACZ,IAAIT,EAAUvB,EAKd,KAAK8B,EAAQD,GAAb,CAQA,IAJAN,EAAW9pB,EAAQ33B,MAAOuqC,EAAMxmC,MAIdq9C,EAASpB,UAC1B,MAAM,IAAI3V,UAAW,4BAOtB6V,EAAOuB,IAKgB,iBAAbA,GACY,mBAAbA,IACRA,EAASvB,KAGL1S,EAAY0S,GAGX+B,EACJ/B,EAAKh8C,KACJu9C,EACAnY,EAASyY,EAAUX,EAAU1B,EAAUuC,GACvC3Y,EAASyY,EAAUX,EAAUzB,EAASsC,KAOvCF,IAEA7B,EAAKh8C,KACJu9C,EACAnY,EAASyY,EAAUX,EAAU1B,EAAUuC,GACvC3Y,EAASyY,EAAUX,EAAUzB,EAASsC,GACtC3Y,EAASyY,EAAUX,EAAU1B,EAC5B0B,EAASe,eASPxqB,IAAY+nB,IAChBnV,OAAOl/B,EACPtH,EAAO,CAAE09C,KAKRQ,GAAWb,EAASgB,aAAe7X,EAAMxmC,MAK7Cs+C,EAAUJ,EACTC,EACA,WACC,IACCA,IACC,MAAQ71C,GAEJ4hC,EAAO+S,SAASsB,eACpBrU,EAAO+S,SAASsB,cAAej2C,EAC9Bg2C,EAAQE,YAMLP,EAAQ,GAAKD,IAIZpqB,IAAYgoB,IAChBpV,OAAOl/B,EACPtH,EAAO,CAAEsI,IAGV+0C,EAASoB,WAAYjY,EAAMxmC,MAS3Bi+C,EACJK,KAKKpU,EAAO+S,SAASyB,eACpBJ,EAAQE,WAAatU,EAAO+S,SAASyB,gBAEtC7gD,EAAOE,WAAYugD,KAKtB,OAAOpU,EAAO+S,UAAU,SAAUO,GAGjCL,EAAQ,GAAK,GAAIjC,IAChB3V,EACC,EACAiY,EACA/T,EAAYsU,GACXA,EACApC,EACD6B,EAASY,aAKXjB,EAAQ,GAAK,GAAIjC,IAChB3V,EACC,EACAiY,EACA/T,EAAYoU,GACXA,EACAlC,IAKHwB,EAAQ,GAAK,GAAIjC,IAChB3V,EACC,EACAiY,EACA/T,EAAYqU,GACXA,EACAlC,OAGAK,WAKLA,QAAS,SAAUvyC,GAClB,OAAc,MAAPA,EAAcwgC,EAAOmB,OAAQ3hC,EAAKuyC,GAAYA,IAGvDoB,EAAW,GAkEZ,OA/DAnT,EAAOS,KAAMwS,GAAQ,SAAUpgD,EAAG0gD,GACjC,IAAIvpC,EAAOupC,EAAO,GACjBkB,EAAclB,EAAO,GAKtBxB,EAASwB,EAAO,IAAQvpC,EAAKgnC,IAGxByD,GACJzqC,EAAKgnC,KACJ,WAIC9T,EAAQuX,IAKTxB,EAAQ,EAAIpgD,GAAK,GAAI+/C,QAIrBK,EAAQ,EAAIpgD,GAAK,GAAI+/C,QAGrBK,EAAQ,GAAK,GAAIJ,KAGjBI,EAAQ,GAAK,GAAIJ,MAOnB7oC,EAAKgnC,IAAKuC,EAAO,GAAIb,MAKrBS,EAAUI,EAAO,IAAQ,WAExB,OADAJ,EAAUI,EAAO,GAAM,QAAUliD,OAAS8hD,OAAW/1C,EAAY/L,KAAMW,WAChEX,MAMR8hD,EAAUI,EAAO,GAAM,QAAWvpC,EAAK8oC,YAIxCf,EAAQA,QAASoB,GAGZH,GACJA,EAAK/8C,KAAMk9C,EAAUA,GAIfA,GAIRuB,KAAM,SAAUC,GACf,IAGCC,EAAY5iD,UAAUe,OAGtBF,EAAI+hD,EAGJC,EAAkB9+C,MAAOlD,GACzBiiD,EAAgB9+C,EAAMC,KAAMjE,WAG5B+iD,EAAU/U,EAAO+S,WAGjBiC,EAAa,SAAUniD,GACtB,OAAO,SAAU2F,GAChBq8C,EAAiBhiD,GAAMxB,KACvByjD,EAAejiD,GAAMb,UAAUe,OAAS,EAAIiD,EAAMC,KAAMjE,WAAcwG,IAC5Do8C,GACTG,EAAQZ,YAAaU,EAAiBC,KAM1C,GAAKF,GAAa,IACjBhD,EAAY+C,EAAaI,EAAQvR,KAAMwR,EAAYniD,IAAMwoC,QAAS0Z,EAAQzZ,QACxEsZ,GAGuB,YAApBG,EAAQ7X,SACZqC,EAAYuV,EAAejiD,IAAOiiD,EAAejiD,GAAIo/C,OAErD,OAAO8C,EAAQ9C,OAKjB,KAAQp/C,KACP++C,EAAYkD,EAAejiD,GAAKmiD,EAAYniD,GAAKkiD,EAAQzZ,QAG1D,OAAOyZ,EAAQhD,aAOjB,IAAIkD,EAAc,yDAElBjV,EAAO+S,SAASsB,cAAgB,SAAU3hD,EAAO4C,GAI3C3B,EAAOW,SAAWX,EAAOW,QAAQiV,MAAQ7W,GAASuiD,EAAYr0C,KAAMlO,EAAMmL,OAC9ElK,EAAOW,QAAQiV,KAAM,8BAAgC7W,EAAM2Z,QAAS3Z,EAAM4C,MAAOA,IAOnF0qC,EAAOkV,eAAiB,SAAUxiD,GACjCiB,EAAOE,YAAY,WAClB,MAAMnB,MAQR,IAAIyiD,EAAYnV,EAAO+S,WAkDvB,SAASqC,IACR9pB,EAASsS,oBAAqB,mBAAoBwX,GAClDzhD,EAAOiqC,oBAAqB,OAAQwX,GACpCpV,EAAOqQ,QAnDRrQ,EAAO/5B,GAAGoqC,MAAQ,SAAUpqC,GAY3B,OAVAkvC,EACElD,KAAMhsC,GAKNovC,OAAO,SAAU3iD,GACjBstC,EAAOkV,eAAgBxiD,MAGlBrB,MAGR2uC,EAAOmB,OAAQ,CAGdltC,SAAS,EAITqhD,UAAW,EAGXjF,MAAO,SAAUkF,KAGF,IAATA,IAAkBvV,EAAOsV,UAAYtV,EAAO/rC,WAKjD+rC,EAAO/rC,SAAU,GAGH,IAATshD,KAAmBvV,EAAOsV,UAAY,GAK3CH,EAAUhB,YAAa7oB,EAAU,CAAE0U,QAIrCA,EAAOqQ,MAAM4B,KAAOkD,EAAUlD,KAaD,aAAxB3mB,EAASuO,YACa,YAAxBvO,EAASuO,aAA6BvO,EAAS7a,gBAAgB+kC,SAGjE7hD,EAAOE,WAAYmsC,EAAOqQ,QAK1B/kB,EAASoS,iBAAkB,mBAAoB0X,GAG/CzhD,EAAO+pC,iBAAkB,OAAQ0X,IAQlC,IAAIK,EAAS,SAAUnV,EAAOr6B,EAAI1G,EAAK/G,EAAOk9C,EAAWC,EAAUC,GAClE,IAAI/iD,EAAI,EACPC,EAAMwtC,EAAMvtC,OACZ8iD,EAAc,MAAPt2C,EAGR,GAAuB,WAAlBwgC,EAAQxgC,GAEZ,IAAM1M,KADN6iD,GAAY,EACDn2C,EACVk2C,EAAQnV,EAAOr6B,EAAIpT,EAAG0M,EAAK1M,IAAK,EAAM8iD,EAAUC,QAI3C,QAAex4C,IAAV5E,IACXk9C,GAAY,EAENnW,EAAY/mC,KACjBo9C,GAAM,GAGFC,IAGCD,GACJ3vC,EAAGhQ,KAAMqqC,EAAO9nC,GAChByN,EAAK,OAIL4vC,EAAO5vC,EACPA,EAAK,SAAUy6B,EAAMoV,EAAMt9C,GAC1B,OAAOq9C,EAAK5/C,KAAM+pC,EAAQU,GAAQloC,MAKhCyN,GACJ,KAAQpT,EAAIC,EAAKD,IAChBoT,EACCq6B,EAAOztC,GAAK0M,EAAKq2C,EAChBp9C,EACAA,EAAMvC,KAAMqqC,EAAOztC,GAAKA,EAAGoT,EAAIq6B,EAAOztC,GAAK0M,KAMhD,OAAKm2C,EACGpV,EAIHuV,EACG5vC,EAAGhQ,KAAMqqC,GAGVxtC,EAAMmT,EAAIq6B,EAAO,GAAK/gC,GAAQo2C,GAKlCI,EAAY,QACfC,EAAa,YAGd,SAASC,EAAYC,EAAMC,GAC1B,OAAOA,EAAOC,cAMf,SAASC,EAAWvqB,GACnB,OAAOA,EAAOhqB,QAASi0C,EAAW,OAAQj0C,QAASk0C,EAAYC,GAEhE,IAAIK,EAAa,SAAUC,GAQ1B,OAA0B,IAAnBA,EAAMnnC,UAAqC,IAAnBmnC,EAAMnnC,YAAsBmnC,EAAMnnC,UAMlE,SAASonC,IACRnlD,KAAKkwC,QAAUvB,EAAOuB,QAAUiV,EAAKC,MAGtCD,EAAKC,IAAM,EAEXD,EAAKlkD,UAAY,CAEhBq0C,MAAO,SAAU4P,GAGhB,IAAI/9C,EAAQ+9C,EAAOllD,KAAKkwC,SA4BxB,OAzBM/oC,IACLA,EAAQ,GAKH89C,EAAYC,KAIXA,EAAMnnC,SACVmnC,EAAOllD,KAAKkwC,SAAY/oC,EAMxB/G,OAAO0kB,eAAgBogC,EAAOllD,KAAKkwC,QAAS,CAC3C/oC,MAAOA,EACP49B,cAAc,MAMX59B,GAER+d,IAAK,SAAUggC,EAAOzuC,EAAMtP,GAC3B,IAAIglB,EACHmpB,EAAQt1C,KAAKs1C,MAAO4P,GAIrB,GAAqB,iBAATzuC,EACX6+B,EAAO0P,EAAWvuC,IAAWtP,OAM7B,IAAMglB,KAAQ1V,EACb6+B,EAAO0P,EAAW74B,IAAW1V,EAAM0V,GAGrC,OAAOmpB,GAERtwB,IAAK,SAAUkgC,EAAOh3C,GACrB,YAAenC,IAARmC,EACNlO,KAAKs1C,MAAO4P,GAGZA,EAAOllD,KAAKkwC,UAAagV,EAAOllD,KAAKkwC,SAAW8U,EAAW92C,KAE7Dk2C,OAAQ,SAAUc,EAAOh3C,EAAK/G,GAa7B,YAAa4E,IAARmC,GACCA,GAAsB,iBAARA,QAAgCnC,IAAV5E,EAElCnH,KAAKglB,IAAKkgC,EAAOh3C,IASzBlO,KAAKklB,IAAKggC,EAAOh3C,EAAK/G,QAIL4E,IAAV5E,EAAsBA,EAAQ+G,IAEtC8O,OAAQ,SAAUkoC,EAAOh3C,GACxB,IAAI1M,EACH8zC,EAAQ4P,EAAOllD,KAAKkwC,SAErB,QAAenkC,IAAVupC,EAAL,CAIA,QAAavpC,IAARmC,EAAoB,CAkBxB1M,GAXC0M,EAJIxJ,MAAMgD,QAASwG,GAIbA,EAAIhH,IAAK89C,IAEf92C,EAAM82C,EAAW92C,MAIJonC,EACZ,CAAEpnC,GACAA,EAAI9J,MAAO+7C,IAAmB,IAG1Bz+C,OAER,KAAQF,YACA8zC,EAAOpnC,EAAK1M,UAKRuK,IAARmC,GAAqBygC,EAAO2B,cAAegF,MAM1C4P,EAAMnnC,SACVmnC,EAAOllD,KAAKkwC,cAAYnkC,SAEjBm5C,EAAOllD,KAAKkwC,YAItBmV,QAAS,SAAUH,GAClB,IAAI5P,EAAQ4P,EAAOllD,KAAKkwC,SACxB,YAAiBnkC,IAAVupC,IAAwB3G,EAAO2B,cAAegF,KAGvD,IAAIgQ,EAAW,IAAIH,EAEfI,EAAW,IAAIJ,EAcfK,GAAS,gCACZC,GAAa,SA2Bd,SAASC,GAAUrW,EAAMnhC,EAAKuI,GAC7B,IAAIjK,EAIJ,QAAcT,IAAT0K,GAAwC,IAAlB44B,EAAKtxB,SAI/B,GAHAvR,EAAO,QAAU0B,EAAIuC,QAASg1C,GAAY,OAAQtuB,cAG7B,iBAFrB1gB,EAAO44B,EAAK7sB,aAAchW,IAEM,CAC/B,IACCiK,EApCJ,SAAkBA,GACjB,MAAc,SAATA,GAIS,UAATA,IAIS,SAATA,EACG,KAIHA,KAAUA,EAAO,IACbA,EAGJ+uC,GAAOj2C,KAAMkH,GACVrV,KAAKwJ,MAAO6L,GAGbA,GAcGkvC,CAASlvC,GACf,MAAQ1J,IAGVw4C,EAASrgC,IAAKmqB,EAAMnhC,EAAKuI,QAEzBA,OAAO1K,EAGT,OAAO0K,EAGRk4B,EAAOmB,OAAQ,CACduV,QAAS,SAAUhW,GAClB,OAAOkW,EAASF,QAAShW,IAAUiW,EAASD,QAAShW,IAGtD54B,KAAM,SAAU44B,EAAM7iC,EAAMiK,GAC3B,OAAO8uC,EAASnB,OAAQ/U,EAAM7iC,EAAMiK,IAGrCmvC,WAAY,SAAUvW,EAAM7iC,GAC3B+4C,EAASvoC,OAAQqyB,EAAM7iC,IAKxBq5C,MAAO,SAAUxW,EAAM7iC,EAAMiK,GAC5B,OAAO6uC,EAASlB,OAAQ/U,EAAM7iC,EAAMiK,IAGrCqvC,YAAa,SAAUzW,EAAM7iC,GAC5B84C,EAAStoC,OAAQqyB,EAAM7iC,MAIzBmiC,EAAO/5B,GAAGk7B,OAAQ,CACjBr5B,KAAM,SAAUvI,EAAK/G,GACpB,IAAI3F,EAAGgL,EAAMiK,EACZ44B,EAAOrvC,KAAM,GACbsV,EAAQ+5B,GAAQA,EAAKxvB,WAGtB,QAAa9T,IAARmC,EAAoB,CACxB,GAAKlO,KAAK0B,SACT+U,EAAO8uC,EAASvgC,IAAKqqB,GAEE,IAAlBA,EAAKtxB,WAAmBunC,EAAStgC,IAAKqqB,EAAM,iBAAmB,CAEnE,IADA7tC,EAAI8T,EAAM5T,OACFF,KAIF8T,EAAO9T,IAEsB,KADjCgL,EAAO8I,EAAO9T,GAAIgL,MACRnJ,QAAS,WAClBmJ,EAAOw4C,EAAWx4C,EAAK7H,MAAO,IAC9B+gD,GAAUrW,EAAM7iC,EAAMiK,EAAMjK,KAI/B84C,EAASpgC,IAAKmqB,EAAM,gBAAgB,GAItC,OAAO54B,EAIR,MAAoB,iBAARvI,EACJlO,KAAKovC,MAAM,WACjBmW,EAASrgC,IAAKllB,KAAMkO,MAIfk2C,EAAQpkD,MAAM,SAAUmH,GAC9B,IAAIsP,EAOJ,GAAK44B,QAAkBtjC,IAAV5E,EAKZ,YAAc4E,KADd0K,EAAO8uC,EAASvgC,IAAKqqB,EAAMnhC,UAQbnC,KADd0K,EAAOivC,GAAUrW,EAAMnhC,IALfuI,OAWR,EAIDzW,KAAKovC,MAAM,WAGVmW,EAASrgC,IAAKllB,KAAMkO,EAAK/G,QAExB,KAAMA,EAAOxG,UAAUe,OAAS,EAAG,MAAM,IAG7CkkD,WAAY,SAAU13C,GACrB,OAAOlO,KAAKovC,MAAM,WACjBmW,EAASvoC,OAAQhd,KAAMkO,SAM1BygC,EAAOmB,OAAQ,CACdhvC,MAAO,SAAUuuC,EAAMznC,EAAM6O,GAC5B,IAAI3V,EAEJ,GAAKuuC,EAYJ,OAXAznC,GAASA,GAAQ,MAAS,QAC1B9G,EAAQwkD,EAAStgC,IAAKqqB,EAAMznC,GAGvB6O,KACE3V,GAAS4D,MAAMgD,QAAS+O,GAC7B3V,EAAQwkD,EAASlB,OAAQ/U,EAAMznC,EAAM+mC,EAAO6B,UAAW/5B,IAEvD3V,EAAMoB,KAAMuU,IAGP3V,GAAS,IAIlBilD,QAAS,SAAU1W,EAAMznC,GACxBA,EAAOA,GAAQ,KAEf,IAAI9G,EAAQ6tC,EAAO7tC,MAAOuuC,EAAMznC,GAC/Bo+C,EAAcllD,EAAMY,OACpBkT,EAAK9T,EAAMqsC,QACX8Y,EAAQtX,EAAOuX,YAAa7W,EAAMznC,GAMvB,eAAPgN,IACJA,EAAK9T,EAAMqsC,QACX6Y,KAGIpxC,IAIU,OAAThN,GACJ9G,EAAMwqC,QAAS,qBAIT2a,EAAMljD,KACb6R,EAAGhQ,KAAMyqC,GApBF,WACNV,EAAOoX,QAAS1W,EAAMznC,KAmBFq+C,KAGhBD,GAAeC,GACpBA,EAAMx6B,MAAM41B,QAKd6E,YAAa,SAAU7W,EAAMznC,GAC5B,IAAIsG,EAAMtG,EAAO,aACjB,OAAO09C,EAAStgC,IAAKqqB,EAAMnhC,IAASo3C,EAASlB,OAAQ/U,EAAMnhC,EAAK,CAC/Dud,MAAOkjB,EAAOkS,UAAW,eAAgBlB,KAAK,WAC7C2F,EAAStoC,OAAQqyB,EAAM,CAAEznC,EAAO,QAASsG,YAM7CygC,EAAO/5B,GAAGk7B,OAAQ,CACjBhvC,MAAO,SAAU8G,EAAM6O,GACtB,IAAI0vC,EAAS,EAQb,MANqB,iBAATv+C,IACX6O,EAAO7O,EACPA,EAAO,KACPu+C,KAGIxlD,UAAUe,OAASykD,EAChBxX,EAAO7tC,MAAOd,KAAM,GAAK4H,QAGjBmE,IAAT0K,EACNzW,KACAA,KAAKovC,MAAM,WACV,IAAItuC,EAAQ6tC,EAAO7tC,MAAOd,KAAM4H,EAAM6O,GAGtCk4B,EAAOuX,YAAalmD,KAAM4H,GAEZ,OAATA,GAAgC,eAAf9G,EAAO,IAC5B6tC,EAAOoX,QAAS/lD,KAAM4H,OAI1Bm+C,QAAS,SAAUn+C,GAClB,OAAO5H,KAAKovC,MAAM,WACjBT,EAAOoX,QAAS/lD,KAAM4H,OAGxBw+C,WAAY,SAAUx+C,GACrB,OAAO5H,KAAKc,MAAO8G,GAAQ,KAAM,KAKlC84C,QAAS,SAAU94C,EAAMuG,GACxB,IAAIsvB,EACHx7B,EAAQ,EACRokD,EAAQ1X,EAAO+S,WACf1J,EAAWh4C,KACXwB,EAAIxB,KAAK0B,OACTsoC,EAAU,aACC/nC,GACTokD,EAAMvD,YAAa9K,EAAU,CAAEA,KAUlC,IANqB,iBAATpwC,IACXuG,EAAMvG,EACNA,OAAOmE,GAERnE,EAAOA,GAAQ,KAEPpG,MACPi8B,EAAM6nB,EAAStgC,IAAKgzB,EAAUx2C,GAAKoG,EAAO,gBAC9B61B,EAAIhS,QACfxpB,IACAw7B,EAAIhS,MAAMk0B,IAAK3V,IAIjB,OADAA,IACOqc,EAAM3F,QAASvyC,MAGxB,IAAIm4C,GAAO,sCAA0Cj6C,OAEjDk6C,GAAU,IAAIv4C,OAAQ,iBAAmBs4C,GAAO,cAAe,KAG/DE,GAAY,CAAE,MAAO,QAAS,SAAU,QAExCpnC,GAAkB6a,EAAS7a,gBAI1BqnC,GAAa,SAAUpX,GACzB,OAAOV,EAAOqD,SAAU3C,EAAK3zB,cAAe2zB,IAE7CqX,GAAW,CAAEA,UAAU,GAOnBtnC,GAAgBunC,cACpBF,GAAa,SAAUpX,GACtB,OAAOV,EAAOqD,SAAU3C,EAAK3zB,cAAe2zB,IAC3CA,EAAKsX,YAAaD,MAAerX,EAAK3zB,gBAG1C,IAAIkrC,GAAqB,SAAUvX,EAAMh+B,GAOvC,MAA8B,UAH9Bg+B,EAAOh+B,GAAMg+B,GAGDwX,MAAMC,SACM,KAAvBzX,EAAKwX,MAAMC,SAMXL,GAAYpX,IAEsB,SAAlCV,EAAOoY,IAAK1X,EAAM,YAuEjB2X,GAAoB,GAExB,SAASC,GAAmB5X,GAC3B,IAAI4M,EACHnoC,EAAMu7B,EAAK3zB,cACXoE,EAAWuvB,EAAKvvB,SAChBgnC,EAAUE,GAAmBlnC,GAE9B,OAAKgnC,IAIL7K,EAAOnoC,EAAIozC,KAAKrzC,YAAaC,EAAImP,cAAenD,IAChDgnC,EAAUnY,EAAOoY,IAAK9K,EAAM,WAE5BA,EAAK9lC,WAAW2H,YAAam+B,GAEZ,SAAZ6K,IACJA,EAAU,SAEXE,GAAmBlnC,GAAagnC,EAEzBA,GAGR,SAASK,GAAUnP,EAAUoP,GAO5B,IANA,IAAIN,EAASzX,EACZ/lC,EAAS,GACTgB,EAAQ,EACR5I,EAASs2C,EAASt2C,OAGX4I,EAAQ5I,EAAQ4I,KACvB+kC,EAAO2I,EAAU1tC,IACNu8C,QAIXC,EAAUzX,EAAKwX,MAAMC,QAChBM,GAKa,SAAZN,IACJx9C,EAAQgB,GAAUg7C,EAAStgC,IAAKqqB,EAAM,YAAe,KAC/C/lC,EAAQgB,KACb+kC,EAAKwX,MAAMC,QAAU,KAGK,KAAvBzX,EAAKwX,MAAMC,SAAkBF,GAAoBvX,KACrD/lC,EAAQgB,GAAU28C,GAAmB5X,KAGrB,SAAZyX,IACJx9C,EAAQgB,GAAU,OAGlBg7C,EAASpgC,IAAKmqB,EAAM,UAAWyX,KAMlC,IAAMx8C,EAAQ,EAAGA,EAAQ5I,EAAQ4I,IACR,MAAnBhB,EAAQgB,KACZ0tC,EAAU1tC,GAAQu8C,MAAMC,QAAUx9C,EAAQgB,IAI5C,OAAO0tC,EAGRrJ,EAAO/5B,GAAGk7B,OAAQ,CACjBsX,KAAM,WACL,OAAOD,GAAUnnD,MAAM,IAExBqnD,KAAM,WACL,OAAOF,GAAUnnD,OAElBsnD,OAAQ,SAAUzb,GACjB,MAAsB,kBAAVA,EACJA,EAAQ7rC,KAAKonD,OAASpnD,KAAKqnD,OAG5BrnD,KAAKovC,MAAM,WACZwX,GAAoB5mD,MACxB2uC,EAAQ3uC,MAAOonD,OAEfzY,EAAQ3uC,MAAOqnD,aAKnB,IAUEE,GACAjvC,GAXEkvC,GAAiB,wBAEjBC,GAAW,iCAEXC,GAAc,qCAMhBH,GADcttB,EAAS/W,yBACRrP,YAAaomB,EAAShX,cAAe,SACpD3K,GAAQ2hB,EAAShX,cAAe,UAM3BQ,aAAc,OAAQ,SAC5BnL,GAAMmL,aAAc,UAAW,WAC/BnL,GAAMmL,aAAc,OAAQ,KAE5B8jC,GAAI1zC,YAAayE,IAIjB21B,EAAQ0Z,WAAaJ,GAAI7mC,WAAW,GAAOA,WAAW,GAAOhD,UAAU48B,QAIvEiN,GAAItQ,UAAY,yBAChBhJ,EAAQ2Z,iBAAmBL,GAAI7mC,WAAW,GAAOhD,UAAUwgC,aAK3DqJ,GAAItQ,UAAY,oBAChBhJ,EAAQ4Z,SAAWN,GAAI7pC,UAKxB,IAAIoqC,GAAU,CAKbC,MAAO,CAAE,EAAG,UAAW,YACvBC,IAAK,CAAE,EAAG,oBAAqB,uBAC/BC,GAAI,CAAE,EAAG,iBAAkB,oBAC3BC,GAAI,CAAE,EAAG,qBAAsB,yBAE/BC,SAAU,CAAE,EAAG,GAAI,KAYpB,SAASC,GAAQtb,EAASkK,GAIzB,IAAI5d,EAYJ,OATCA,OAD4C,IAAjC0T,EAAQ1oB,qBACb0oB,EAAQ1oB,qBAAsB4yB,GAAO,UAEI,IAA7BlK,EAAQsI,iBACpBtI,EAAQsI,iBAAkB4B,GAAO,KAGjC,QAGMjrC,IAARirC,GAAqBA,GAAOl3B,EAAUgtB,EAASkK,GAC5CrI,EAAOO,MAAO,CAAEpC,GAAW1T,GAG5BA,EAKR,SAASivB,GAAepZ,EAAOqZ,GAI9B,IAHA,IAAI9mD,EAAI,EACPyD,EAAIgqC,EAAMvtC,OAEHF,EAAIyD,EAAGzD,IACd8jD,EAASpgC,IACR+pB,EAAOztC,GACP,cACC8mD,GAAehD,EAAStgC,IAAKsjC,EAAa9mD,GAAK,eA1CnDsmD,GAAQS,MAAQT,GAAQU,MAAQV,GAAQW,SAAWX,GAAQY,QAAUZ,GAAQC,MAC7ED,GAAQa,GAAKb,GAAQI,GAGfja,EAAQ4Z,SACbC,GAAQc,SAAWd,GAAQD,OAAS,CAAE,EAAG,+BAAgC,cA2C1E,IAAItU,GAAQ,YAEZ,SAASsV,GAAe5Z,EAAOnC,EAASrF,EAASqhB,EAAWC,GAO3D,IANA,IAAI1Z,EAAM5R,EAAKuZ,EAAKgS,EAAMC,EAAUj+C,EACnCk+C,EAAWpc,EAAQ5pB,yBACnBimC,EAAQ,GACR3nD,EAAI,EACJyD,EAAIgqC,EAAMvtC,OAEHF,EAAIyD,EAAGzD,IAGd,IAFA6tC,EAAOJ,EAAOztC,KAEQ,IAAT6tC,EAGZ,GAAwB,WAAnBX,EAAQW,GAIZV,EAAOO,MAAOia,EAAO9Z,EAAKtxB,SAAW,CAAEsxB,GAASA,QAG1C,GAAMkE,GAAMhkC,KAAM8/B,GAIlB,CAUN,IATA5R,EAAMA,GAAOyrB,EAASr1C,YAAai5B,EAAQ7pB,cAAe,QAG1D+zB,GAAQyQ,GAAS1xB,KAAMsZ,IAAU,CAAE,GAAI,KAAQ,GAAIlY,cACnD6xB,EAAOlB,GAAS9Q,IAAS8Q,GAAQK,SACjC1qB,EAAIwZ,UAAY+R,EAAM,GAAMra,EAAOya,cAAe/Z,GAAS2Z,EAAM,GAGjEh+C,EAAIg+C,EAAM,GACFh+C,KACPyyB,EAAMA,EAAI/f,UAKXixB,EAAOO,MAAOia,EAAO1rB,EAAIrgB,aAGzBqgB,EAAMyrB,EAASrsC,YAGXy7B,YAAc,QAzBlB6Q,EAAMjnD,KAAM4qC,EAAQ71B,eAAgBo4B,IAkCvC,IAHA6Z,EAAS5Q,YAAc,GAEvB92C,EAAI,EACM6tC,EAAO8Z,EAAO3nD,MAGvB,GAAKsnD,GAAana,EAAO+B,QAASrB,EAAMyZ,IAAe,EACjDC,GACJA,EAAQ7mD,KAAMmtC,QAgBhB,GAXA4Z,EAAWxC,GAAYpX,GAGvB5R,EAAM2qB,GAAQc,EAASr1C,YAAaw7B,GAAQ,UAGvC4Z,GACJZ,GAAe5qB,GAIXgK,EAEJ,IADAz8B,EAAI,EACMqkC,EAAO5R,EAAKzyB,MAChB08C,GAAYn4C,KAAM8/B,EAAKznC,MAAQ,KACnC6/B,EAAQvlC,KAAMmtC,GAMlB,OAAO6Z,EAIR,IAAIG,GAAiB,sBAErB,SAASC,KACR,OAAO,EAGR,SAASC,KACR,OAAO,EASR,SAASC,GAAYna,EAAMznC,GAC1B,OAASynC,IAMV,WACC,IACC,OAAOpV,EAASkgB,cACf,MAAQ1R,KATQghB,KAAqC,UAAT7hD,GAY/C,SAAS2iC,GAAI8E,EAAMqa,EAAO9a,EAAUn4B,EAAM7B,EAAI+0C,GAC7C,IAAIC,EAAQhiD,EAGZ,GAAsB,iBAAV8hD,EAAqB,CAShC,IAAM9hD,IANmB,iBAAbgnC,IAGXn4B,EAAOA,GAAQm4B,EACfA,OAAW7iC,GAEE29C,EACbnf,GAAI8E,EAAMznC,EAAMgnC,EAAUn4B,EAAMizC,EAAO9hD,GAAQ+hD,GAEhD,OAAOta,EAsBR,GAnBa,MAAR54B,GAAsB,MAAN7B,GAGpBA,EAAKg6B,EACLn4B,EAAOm4B,OAAW7iC,GACD,MAAN6I,IACc,iBAAbg6B,GAGXh6B,EAAK6B,EACLA,OAAO1K,IAIP6I,EAAK6B,EACLA,EAAOm4B,EACPA,OAAW7iC,KAGD,IAAP6I,EACJA,EAAK20C,QACC,IAAM30C,EACZ,OAAOy6B,EAeR,OAZa,IAARsa,IACJC,EAASh1C,EACTA,EAAK,SAAU0jB,GAId,OADAqW,IAAStB,IAAK/U,GACPsxB,EAAOlpD,MAAOV,KAAMW,YAI5BiU,EAAGk8B,KAAO8Y,EAAO9Y,OAAU8Y,EAAO9Y,KAAOnC,EAAOmC,SAE1CzB,EAAKD,MAAM,WACjBT,EAAOrW,MAAMqnB,IAAK3/C,KAAM0pD,EAAO90C,EAAI6B,EAAMm4B,MA+a3C,SAASib,GAAgBx4C,EAAIzJ,EAAM4hD,GAG5BA,GAQNlE,EAASpgC,IAAK7T,EAAIzJ,GAAM,GACxB+mC,EAAOrW,MAAMqnB,IAAKtuC,EAAIzJ,EAAM,CAC3B2X,WAAW,EACX8Y,QAAS,SAAUC,GAClB,IAAIwxB,EAAUxwB,EACbywB,EAAQzE,EAAStgC,IAAKhlB,KAAM4H,GAE7B,GAAyB,EAAlB0wB,EAAM0xB,WAAmBhqD,KAAM4H,IAKrC,GAAMmiD,EAAMroD,QAuCEitC,EAAOrW,MAAMqqB,QAAS/6C,IAAU,IAAKqiD,cAClD3xB,EAAM4xB,uBArBN,GAdAH,EAAQplD,EAAMC,KAAMjE,WACpB2kD,EAASpgC,IAAKllB,KAAM4H,EAAMmiD,GAK1BD,EAAWN,EAAYxpD,KAAM4H,GAC7B5H,KAAM4H,KAEDmiD,KADLzwB,EAASgsB,EAAStgC,IAAKhlB,KAAM4H,KACJkiD,EACxBxE,EAASpgC,IAAKllB,KAAM4H,GAAM,GAE1B0xB,EAAS,GAELywB,IAAUzwB,EAWd,OARAhB,EAAM6xB,2BACN7xB,EAAM8xB,iBAOC9wB,GAAUA,EAAOnyB,WAef4iD,EAAMroD,SAGjB4jD,EAASpgC,IAAKllB,KAAM4H,EAAM,CACzBT,MAAOwnC,EAAOrW,MAAM+xB,QAInB1b,EAAOmB,OAAQia,EAAO,GAAKpb,EAAO2b,MAAMrpD,WACxC8oD,EAAMplD,MAAO,GACb3E,QAKFs4B,EAAM6xB,qCA/E0Bp+C,IAA7Bu5C,EAAStgC,IAAK3T,EAAIzJ,IACtB+mC,EAAOrW,MAAMqnB,IAAKtuC,EAAIzJ,EAAM0hD,IA5a/B3a,EAAOrW,MAAQ,CAEdmV,OAAQ,GAERkS,IAAK,SAAUtQ,EAAMqa,EAAOrxB,EAAS5hB,EAAMm4B,GAE1C,IAAI2b,EAAaC,EAAa/sB,EAC7B0N,EAAQnmC,EAAGylD,EACX9H,EAAS3qB,EAAUpwB,EAAM8iD,EAAYC,EACrCC,EAAWtF,EAAStgC,IAAKqqB,GAG1B,GAAM4V,EAAY5V,GAuClB,IAlCKhX,EAAQA,UAEZA,GADAkyB,EAAclyB,GACQA,QACtBuW,EAAW2b,EAAY3b,UAKnBA,GACJD,EAAOtmC,KAAK6uC,gBAAiB93B,GAAiBwvB,GAIzCvW,EAAQyY,OACbzY,EAAQyY,KAAOnC,EAAOmC,SAIf3F,EAASyf,EAASzf,UACzBA,EAASyf,EAASzf,OAAS/qC,OAAOw+B,OAAQ,QAEnC4rB,EAAcI,EAASC,UAC9BL,EAAcI,EAASC,OAAS,SAAU99C,GAIzC,YAAyB,IAAX4hC,GAA0BA,EAAOrW,MAAMwyB,YAAc/9C,EAAEnF,KACpE+mC,EAAOrW,MAAMyyB,SAASrqD,MAAO2uC,EAAM1uC,gBAAcoL,IAMpD/G,GADA0kD,GAAUA,GAAS,IAAKtlD,MAAO+7C,IAAmB,CAAE,KAC1Cz+C,OACFsD,KAEP4C,EAAO+iD,GADPltB,EAAM4rB,GAAetzB,KAAM2zB,EAAO1kD,KAAS,IACpB,GACvB0lD,GAAejtB,EAAK,IAAO,IAAKv5B,MAAO,KAAM2rC,OAGvCjoC,IAKN+6C,EAAUhU,EAAOrW,MAAMqqB,QAAS/6C,IAAU,GAG1CA,GAASgnC,EAAW+T,EAAQsH,aAAetH,EAAQqI,WAAcpjD,EAGjE+6C,EAAUhU,EAAOrW,MAAMqqB,QAAS/6C,IAAU,GAG1C6iD,EAAY9b,EAAOmB,OAAQ,CAC1BloC,KAAMA,EACN+iD,SAAUA,EACVl0C,KAAMA,EACN4hB,QAASA,EACTyY,KAAMzY,EAAQyY,KACdlC,SAAUA,EACV8P,aAAc9P,GAAYD,EAAO/+B,KAAKxL,MAAMs6C,aAAanvC,KAAMq/B,GAC/DrvB,UAAWmrC,EAAWnhD,KAAM,MAC1BghD,IAGKvyB,EAAWmT,EAAQvjC,OAC1BowB,EAAWmT,EAAQvjC,GAAS,IACnBqjD,cAAgB,EAGnBtI,EAAQuI,QACiD,IAA9DvI,EAAQuI,MAAMtmD,KAAMyqC,EAAM54B,EAAMi0C,EAAYF,IAEvCnb,EAAKhD,kBACTgD,EAAKhD,iBAAkBzkC,EAAM4iD,IAK3B7H,EAAQhD,MACZgD,EAAQhD,IAAI/6C,KAAMyqC,EAAMob,GAElBA,EAAUpyB,QAAQyY,OACvB2Z,EAAUpyB,QAAQyY,KAAOzY,EAAQyY,OAK9BlC,EACJ5W,EAASx0B,OAAQw0B,EAASizB,gBAAiB,EAAGR,GAE9CzyB,EAAS91B,KAAMuoD,GAIhB9b,EAAOrW,MAAMmV,OAAQ7lC,IAAS,IAMhCoV,OAAQ,SAAUqyB,EAAMqa,EAAOrxB,EAASuW,EAAUuc,GAEjD,IAAIngD,EAAGogD,EAAW3tB,EACjB0N,EAAQnmC,EAAGylD,EACX9H,EAAS3qB,EAAUpwB,EAAM8iD,EAAYC,EACrCC,EAAWtF,EAASD,QAAShW,IAAUiW,EAAStgC,IAAKqqB,GAEtD,GAAMub,IAAezf,EAASyf,EAASzf,QAAvC,CAOA,IADAnmC,GADA0kD,GAAUA,GAAS,IAAKtlD,MAAO+7C,IAAmB,CAAE,KAC1Cz+C,OACFsD,KAMP,GAJA4C,EAAO+iD,GADPltB,EAAM4rB,GAAetzB,KAAM2zB,EAAO1kD,KAAS,IACpB,GACvB0lD,GAAejtB,EAAK,IAAO,IAAKv5B,MAAO,KAAM2rC,OAGvCjoC,EAAN,CAeA,IARA+6C,EAAUhU,EAAOrW,MAAMqqB,QAAS/6C,IAAU,GAE1CowB,EAAWmT,EADXvjC,GAASgnC,EAAW+T,EAAQsH,aAAetH,EAAQqI,WAAcpjD,IACpC,GAC7B61B,EAAMA,EAAK,IACV,IAAIzvB,OAAQ,UAAY08C,EAAWnhD,KAAM,iBAAoB,WAG9D6hD,EAAYpgD,EAAIgtB,EAASt2B,OACjBsJ,KACPy/C,EAAYzyB,EAAUhtB,IAEfmgD,GAAeR,IAAaF,EAAUE,UACzCtyB,GAAWA,EAAQyY,OAAS2Z,EAAU3Z,MACtCrT,IAAOA,EAAIluB,KAAMk7C,EAAUlrC,YAC3BqvB,GAAYA,IAAa6b,EAAU7b,WACxB,OAAbA,IAAqB6b,EAAU7b,YAChC5W,EAASx0B,OAAQwH,EAAG,GAEfy/C,EAAU7b,UACd5W,EAASizB,gBAELtI,EAAQ3lC,QACZ2lC,EAAQ3lC,OAAOpY,KAAMyqC,EAAMob,IAOzBW,IAAcpzB,EAASt2B,SACrBihD,EAAQ0I,WACkD,IAA/D1I,EAAQ0I,SAASzmD,KAAMyqC,EAAMqb,EAAYE,EAASC,SAElDlc,EAAO2c,YAAajc,EAAMznC,EAAMgjD,EAASC,eAGnC1f,EAAQvjC,SA1Cf,IAAMA,KAAQujC,EACbwD,EAAOrW,MAAMtb,OAAQqyB,EAAMznC,EAAO8hD,EAAO1kD,GAAKqzB,EAASuW,GAAU,GA8C/DD,EAAO2B,cAAenF,IAC1Bma,EAAStoC,OAAQqyB,EAAM,mBAIzB0b,SAAU,SAAUQ,GAEnB,IAAI/pD,EAAGwJ,EAAGouB,EAAK2gB,EAAS0Q,EAAWe,EAClC/mD,EAAO,IAAIC,MAAO/D,UAAUe,QAG5B42B,EAAQqW,EAAOrW,MAAMmzB,IAAKF,GAE1BvzB,GACCstB,EAAStgC,IAAKhlB,KAAM,WAAcI,OAAOw+B,OAAQ,OAC/CtG,EAAM1wB,OAAU,GACnB+6C,EAAUhU,EAAOrW,MAAMqqB,QAASrqB,EAAM1wB,OAAU,GAKjD,IAFAnD,EAAM,GAAM6zB,EAEN92B,EAAI,EAAGA,EAAIb,UAAUe,OAAQF,IAClCiD,EAAMjD,GAAMb,UAAWa,GAMxB,GAHA82B,EAAMozB,eAAiB1rD,MAGlB2iD,EAAQgJ,cAA2D,IAA5ChJ,EAAQgJ,YAAY/mD,KAAM5E,KAAMs4B,GAA5D,CASA,IAJAkzB,EAAe7c,EAAOrW,MAAMN,SAASpzB,KAAM5E,KAAMs4B,EAAON,GAGxDx2B,EAAI,GACMu4C,EAAUyR,EAAchqD,QAAY82B,EAAMszB,wBAInD,IAHAtzB,EAAMuzB,cAAgB9R,EAAQ1K,KAE9BrkC,EAAI,GACMy/C,EAAY1Q,EAAQ/hB,SAAUhtB,QACtCstB,EAAMwzB,iCAIDxzB,EAAMyzB,aAAsC,IAAxBtB,EAAUlrC,YACnC+Y,EAAMyzB,WAAWx8C,KAAMk7C,EAAUlrC,aAEjC+Y,EAAMmyB,UAAYA,EAClBnyB,EAAM7hB,KAAOg0C,EAAUh0C,UAKV1K,KAHbqtB,IAAUuV,EAAOrW,MAAMqqB,QAAS8H,EAAUE,WAAc,IAAKE,QAC5DJ,EAAUpyB,SAAU33B,MAAOq5C,EAAQ1K,KAAM5qC,MAGT,KAAzB6zB,EAAMgB,OAASF,KACrBd,EAAM8xB,iBACN9xB,EAAM4xB,oBAYX,OAJKvH,EAAQqJ,cACZrJ,EAAQqJ,aAAapnD,KAAM5E,KAAMs4B,GAG3BA,EAAMgB,SAGdtB,SAAU,SAAUM,EAAON,GAC1B,IAAIx2B,EAAGipD,EAAWxS,EAAKgU,EAAiBC,EACvCV,EAAe,GACfP,EAAgBjzB,EAASizB,cACzBpV,EAAMvd,EAAM9hB,OAGb,GAAKy0C,GAIJpV,EAAI93B,YAOc,UAAfua,EAAM1wB,MAAoB0wB,EAAM6zB,QAAU,GAE7C,KAAQtW,IAAQ71C,KAAM61C,EAAMA,EAAI1/B,YAAcnW,KAI7C,GAAsB,IAAjB61C,EAAI93B,WAAoC,UAAfua,EAAM1wB,OAAqC,IAAjBiuC,EAAIrB,UAAsB,CAGjF,IAFAyX,EAAkB,GAClBC,EAAmB,GACb1qD,EAAI,EAAGA,EAAIypD,EAAezpD,SAMEuK,IAA5BmgD,EAFLjU,GAHAwS,EAAYzyB,EAAUx2B,IAGNotC,SAAW,OAG1Bsd,EAAkBjU,GAAQwS,EAAU/L,aACnC/P,EAAQsJ,EAAKj4C,MAAOsK,MAAOurC,IAAS,EACpClH,EAAOtmC,KAAM4vC,EAAKj4C,KAAM,KAAM,CAAE61C,IAAQn0C,QAErCwqD,EAAkBjU,IACtBgU,EAAgB/pD,KAAMuoD,GAGnBwB,EAAgBvqD,QACpB8pD,EAAatpD,KAAM,CAAEmtC,KAAMwG,EAAK7d,SAAUi0B,IAY9C,OALApW,EAAM71C,KACDirD,EAAgBjzB,EAASt2B,QAC7B8pD,EAAatpD,KAAM,CAAEmtC,KAAMwG,EAAK7d,SAAUA,EAASrzB,MAAOsmD,KAGpDO,GAGRY,QAAS,SAAU5/C,EAAM6/C,GACxBjsD,OAAO0kB,eAAgB6pB,EAAO2b,MAAMrpD,UAAWuL,EAAM,CACpDgyB,YAAY,EACZuG,cAAc,EAEd/f,IAAKkpB,EAAYme,GAChB,WACC,GAAKrsD,KAAKssD,cACT,OAAOD,EAAMrsD,KAAKssD,gBAGpB,WACC,GAAKtsD,KAAKssD,cACT,OAAOtsD,KAAKssD,cAAe9/C,IAI9B0Y,IAAK,SAAU/d,GACd/G,OAAO0kB,eAAgB9kB,KAAMwM,EAAM,CAClCgyB,YAAY,EACZuG,cAAc,EACdC,UAAU,EACV79B,MAAOA,QAMXskD,IAAK,SAAUa,GACd,OAAOA,EAAe3d,EAAOuB,SAC5Boc,EACA,IAAI3d,EAAO2b,MAAOgC,IAGpB3J,QAAS,CACR4J,KAAM,CAGLC,UAAU,GAEXC,MAAO,CAGNvB,MAAO,SAAUz0C,GAIhB,IAAIpF,EAAKrR,MAAQyW,EAWjB,OARK+wC,GAAej4C,KAAM8B,EAAGzJ,OAC5ByJ,EAAGo7C,OAAS3sC,EAAUzO,EAAI,UAG1Bw4C,GAAgBx4C,EAAI,QAASi4C,KAIvB,GAERe,QAAS,SAAU5zC,GAIlB,IAAIpF,EAAKrR,MAAQyW,EAUjB,OAPK+wC,GAAej4C,KAAM8B,EAAGzJ,OAC5ByJ,EAAGo7C,OAAS3sC,EAAUzO,EAAI,UAE1Bw4C,GAAgBx4C,EAAI,UAId,GAKR82C,SAAU,SAAU7vB,GACnB,IAAI9hB,EAAS8hB,EAAM9hB,OACnB,OAAOgxC,GAAej4C,KAAMiH,EAAO5O,OAClC4O,EAAOi2C,OAAS3sC,EAAUtJ,EAAQ,UAClC8uC,EAAStgC,IAAKxO,EAAQ,UACtBsJ,EAAUtJ,EAAQ,OAIrBk2C,aAAc,CACbV,aAAc,SAAU1zB,QAIDvsB,IAAjBusB,EAAMgB,QAAwBhB,EAAMg0B,gBACxCh0B,EAAMg0B,cAAcK,YAAcr0B,EAAMgB,YAoG7CqV,EAAO2c,YAAc,SAAUjc,EAAMznC,EAAMijD,GAGrCxb,EAAK9C,qBACT8C,EAAK9C,oBAAqB3kC,EAAMijD,IAIlClc,EAAO2b,MAAQ,SAAUxxC,EAAK8zC,GAG7B,KAAQ5sD,gBAAgB2uC,EAAO2b,OAC9B,OAAO,IAAI3b,EAAO2b,MAAOxxC,EAAK8zC,GAI1B9zC,GAAOA,EAAIlR,MACf5H,KAAKssD,cAAgBxzC,EACrB9Y,KAAK4H,KAAOkR,EAAIlR,KAIhB5H,KAAK6sD,mBAAqB/zC,EAAIg0C,uBACH/gD,IAAzB+M,EAAIg0C,mBAGgB,IAApBh0C,EAAI6zC,YACLrD,GACAC,GAKDvpD,KAAKwW,OAAWsC,EAAItC,QAAkC,IAAxBsC,EAAItC,OAAOuH,SACxCjF,EAAItC,OAAOL,WACX2C,EAAItC,OAELxW,KAAK6rD,cAAgB/yC,EAAI+yC,cACzB7rD,KAAK+sD,cAAgBj0C,EAAIi0C,eAIzB/sD,KAAK4H,KAAOkR,EAIR8zC,GACJje,EAAOmB,OAAQ9vC,KAAM4sD,GAItB5sD,KAAKgtD,UAAYl0C,GAAOA,EAAIk0C,WAAa7nD,KAAK8nD,MAG9CjtD,KAAM2uC,EAAOuB,UAAY,GAK1BvB,EAAO2b,MAAMrpD,UAAY,CACxBmY,YAAau1B,EAAO2b,MACpBuC,mBAAoBtD,GACpBqC,qBAAsBrC,GACtBuC,8BAA+BvC,GAC/B2D,aAAa,EAEb9C,eAAgB,WACf,IAAIr9C,EAAI/M,KAAKssD,cAEbtsD,KAAK6sD,mBAAqBvD,GAErBv8C,IAAM/M,KAAKktD,aACfngD,EAAEq9C,kBAGJF,gBAAiB,WAChB,IAAIn9C,EAAI/M,KAAKssD,cAEbtsD,KAAK4rD,qBAAuBtC,GAEvBv8C,IAAM/M,KAAKktD,aACfngD,EAAEm9C,mBAGJC,yBAA0B,WACzB,IAAIp9C,EAAI/M,KAAKssD,cAEbtsD,KAAK8rD,8BAAgCxC,GAEhCv8C,IAAM/M,KAAKktD,aACfngD,EAAEo9C,2BAGHnqD,KAAKkqD,oBAKPvb,EAAOS,KAAM,CACZ+d,QAAQ,EACRC,SAAS,EACTC,YAAY,EACZC,gBAAgB,EAChBC,SAAS,EACTC,QAAQ,EACRC,YAAY,EACZC,SAAS,EACTC,OAAO,EACPC,OAAO,EACPC,UAAU,EACVC,MAAM,EACN,MAAQ,EACR/yC,MAAM,EACNgzC,UAAU,EACV7/C,KAAK,EACL8/C,SAAS,EACT7B,QAAQ,EACR8B,SAAS,EACTC,SAAS,EACTC,SAAS,EACTC,SAAS,EACTC,SAAS,EACTC,WAAW,EACXC,aAAa,EACbC,SAAS,EACTC,SAAS,EACTC,eAAe,EACfC,WAAW,EACXC,SAAS,EACTC,OAAO,GACLlgB,EAAOrW,MAAM8zB,SAEhBzd,EAAOS,KAAM,CAAErN,MAAO,UAAW+sB,KAAM,aAAc,SAAUlnD,EAAMqiD,GACpEtb,EAAOrW,MAAMqqB,QAAS/6C,GAAS,CAG9BsjD,MAAO,WAQN,OAHArB,GAAgB7pD,KAAM4H,EAAM4hD,KAGrB,GAERa,QAAS,WAMR,OAHAR,GAAgB7pD,KAAM4H,IAGf,GAKRugD,SAAU,WACT,OAAO,GAGR8B,aAAcA,MAYhBtb,EAAOS,KAAM,CACZ2f,WAAY,YACZC,WAAY,WACZC,aAAc,cACdC,aAAc,eACZ,SAAUC,EAAM1D,GAClB9c,EAAOrW,MAAMqqB,QAASwM,GAAS,CAC9BlF,aAAcwB,EACdT,SAAUS,EAEVZ,OAAQ,SAAUvyB,GACjB,IAAIc,EACH5iB,EAASxW,KACTovD,EAAU92B,EAAMy0B,cAChBtC,EAAYnyB,EAAMmyB,UASnB,OALM2E,IAAaA,IAAY54C,GAAWm4B,EAAOqD,SAAUx7B,EAAQ44C,MAClE92B,EAAM1wB,KAAO6iD,EAAUE,SACvBvxB,EAAMqxB,EAAUpyB,QAAQ33B,MAAOV,KAAMW,WACrC23B,EAAM1wB,KAAO6jD,GAEPryB,OAKVuV,EAAO/5B,GAAGk7B,OAAQ,CAEjBvF,GAAI,SAAUmf,EAAO9a,EAAUn4B,EAAM7B,GACpC,OAAO21B,GAAIvqC,KAAM0pD,EAAO9a,EAAUn4B,EAAM7B,IAEzC+0C,IAAK,SAAUD,EAAO9a,EAAUn4B,EAAM7B,GACrC,OAAO21B,GAAIvqC,KAAM0pD,EAAO9a,EAAUn4B,EAAM7B,EAAI,IAE7Cy4B,IAAK,SAAUqc,EAAO9a,EAAUh6B,GAC/B,IAAI61C,EAAW7iD,EACf,GAAK8hD,GAASA,EAAMU,gBAAkBV,EAAMe,UAW3C,OARAA,EAAYf,EAAMe,UAClB9b,EAAQ+a,EAAMgC,gBAAiBre,IAC9Bod,EAAUlrC,UACTkrC,EAAUE,SAAW,IAAMF,EAAUlrC,UACrCkrC,EAAUE,SACXF,EAAU7b,SACV6b,EAAUpyB,SAEJr4B,KAER,GAAsB,iBAAV0pD,EAAqB,CAGhC,IAAM9hD,KAAQ8hD,EACb1pD,KAAKqtC,IAAKzlC,EAAMgnC,EAAU8a,EAAO9hD,IAElC,OAAO5H,KAWR,OATkB,IAAb4uC,GAA0C,mBAAbA,IAGjCh6B,EAAKg6B,EACLA,OAAW7iC,IAEA,IAAP6I,IACJA,EAAK20C,IAECvpD,KAAKovC,MAAM,WACjBT,EAAOrW,MAAMtb,OAAQhd,KAAM0pD,EAAO90C,EAAIg6B,SAMzC,IAKCygB,GAAe,wBAGfC,GAAW,oCACXC,GAAe,2CAGhB,SAASC,GAAoBngB,EAAMpgC,GAClC,OAAK6Q,EAAUuvB,EAAM,UACpBvvB,EAA+B,KAArB7Q,EAAQ8O,SAAkB9O,EAAUA,EAAQ4N,WAAY,OAE3D8xB,EAAQU,GAAO8P,SAAU,SAAW,IAGrC9P,EAIR,SAASogB,GAAepgB,GAEvB,OADAA,EAAKznC,MAAyC,OAAhCynC,EAAK7sB,aAAc,SAAsB,IAAM6sB,EAAKznC,KAC3DynC,EAER,SAASqgB,GAAergB,GAOvB,MAN2C,WAApCA,EAAKznC,MAAQ,IAAKjD,MAAO,EAAG,GAClC0qC,EAAKznC,KAAOynC,EAAKznC,KAAKjD,MAAO,GAE7B0qC,EAAK3rB,gBAAiB,QAGhB2rB,EAGR,SAASsgB,GAAgB72C,EAAKC,GAC7B,IAAIvX,EAAGyD,EAAG2C,EAAgBgoD,EAAUC,EAAU1kB,EAE9C,GAAuB,IAAlBpyB,EAAKgF,SAAV,CAKA,GAAKunC,EAASD,QAASvsC,KAEtBqyB,EADWma,EAAStgC,IAAKlM,GACPqyB,QAKjB,IAAMvjC,KAFN09C,EAAStoC,OAAQjE,EAAM,iBAEToyB,EACb,IAAM3pC,EAAI,EAAGyD,EAAIkmC,EAAQvjC,GAAOlG,OAAQF,EAAIyD,EAAGzD,IAC9CmtC,EAAOrW,MAAMqnB,IAAK5mC,EAAMnR,EAAMujC,EAAQvjC,GAAQpG,IAO7C+jD,EAASF,QAASvsC,KACtB82C,EAAWrK,EAASnB,OAAQtrC,GAC5B+2C,EAAWlhB,EAAOmB,OAAQ,GAAI8f,GAE9BrK,EAASrgC,IAAKnM,EAAM82C,KAKtB,SAASC,GAAUh3C,EAAKC,GACvB,IAAI+G,EAAW/G,EAAK+G,SAASqX,cAGX,UAAbrX,GAAwB0nC,GAAej4C,KAAMuJ,EAAIlR,MACrDmR,EAAKuhC,QAAUxhC,EAAIwhC,QAGK,UAAbx6B,GAAqC,aAAbA,IACnC/G,EAAKmlC,aAAeplC,EAAIolC,cAI1B,SAAS6R,GAAUC,EAAYvrD,EAAMmY,EAAUmsC,GAG9CtkD,EAAOmpC,EAAMnpC,GAEb,IAAIykD,EAAU5Z,EAAO7H,EAASwoB,EAAYh9C,EAAMa,EAC/CtS,EAAI,EACJyD,EAAI+qD,EAAWtuD,OACfwuD,EAAWjrD,EAAI,EACfkC,EAAQ1C,EAAM,GACd0rD,EAAkBjiB,EAAY/mC,GAG/B,GAAKgpD,GACDlrD,EAAI,GAAsB,iBAAVkC,IAChB8mC,EAAQ0Z,YAAc2H,GAAS//C,KAAMpI,GACxC,OAAO6oD,EAAW5gB,MAAM,SAAU9kC,GACjC,IAAI3K,EAAOqwD,EAAWzgB,GAAIjlC,GACrB6lD,IACJ1rD,EAAM,GAAM0C,EAAMvC,KAAM5E,KAAMsK,EAAO3K,EAAKywD,SAE3CL,GAAUpwD,EAAM8E,EAAMmY,EAAUmsC,MAIlC,GAAK9jD,IAEJqqC,GADA4Z,EAAWL,GAAepkD,EAAMurD,EAAY,GAAIt0C,eAAe,EAAOs0C,EAAYjH,IACjElsC,WAEmB,IAA/BqsC,EAAS9rC,WAAW1b,SACxBwnD,EAAW5Z,GAIPA,GAASyZ,GAAU,CAOvB,IALAkH,GADAxoB,EAAUkH,EAAOznC,IAAKkhD,GAAQc,EAAU,UAAYuG,KAC/B/tD,OAKbF,EAAIyD,EAAGzD,IACdyR,EAAOi2C,EAEF1nD,IAAM0uD,IACVj9C,EAAO07B,EAAOqB,MAAO/8B,GAAM,GAAM,GAG5Bg9C,GAIJthB,EAAOO,MAAOzH,EAAS2gB,GAAQn1C,EAAM,YAIvC2J,EAAShY,KAAMorD,EAAYxuD,GAAKyR,EAAMzR,GAGvC,GAAKyuD,EAOJ,IANAn8C,EAAM2zB,EAASA,EAAQ/lC,OAAS,GAAIga,cAGpCizB,EAAOznC,IAAKugC,EAASioB,IAGfluD,EAAI,EAAGA,EAAIyuD,EAAYzuD,IAC5ByR,EAAOw0B,EAASjmC,GACXkmD,GAAYn4C,KAAM0D,EAAKrL,MAAQ,MAClC09C,EAASlB,OAAQnxC,EAAM,eACxB07B,EAAOqD,SAAUl+B,EAAKb,KAEjBA,EAAK6F,KAA8C,YAArC7F,EAAKrL,MAAQ,IAAKuvB,cAG/BwX,EAAO0hB,WAAap9C,EAAKq7B,UAC7BK,EAAO0hB,SAAUp9C,EAAK6F,IAAK,CAC1Bu1B,MAAOp7B,EAAKo7B,OAASp7B,EAAKuP,aAAc,UACtC1O,GAGJy6B,EAASt7B,EAAKqlC,YAAY7nC,QAAS8+C,GAAc,IAAMt8C,EAAMa,IAQnE,OAAOk8C,EAGR,SAAShzC,GAAQqyB,EAAMT,EAAU0hB,GAKhC,IAJA,IAAIr9C,EACHk2C,EAAQva,EAAWD,EAAO5nC,OAAQ6nC,EAAUS,GAASA,EACrD7tC,EAAI,EAE4B,OAAvByR,EAAOk2C,EAAO3nD,IAAeA,IAChC8uD,GAA8B,IAAlBr9C,EAAK8K,UACtB4wB,EAAO4hB,UAAWnI,GAAQn1C,IAGtBA,EAAKkD,aACJm6C,GAAY7J,GAAYxzC,IAC5Bo1C,GAAeD,GAAQn1C,EAAM,WAE9BA,EAAKkD,WAAW2H,YAAa7K,IAI/B,OAAOo8B,EAGRV,EAAOmB,OAAQ,CACdsZ,cAAe,SAAUgH,GACxB,OAAOA,GAGRpgB,MAAO,SAAUX,EAAMmhB,EAAeC,GACrC,IAAIjvD,EAAGyD,EAAGyrD,EAAaC,EACtB3gB,EAAQX,EAAK3uB,WAAW,GACxBkwC,EAASnK,GAAYpX,GAGtB,KAAMpB,EAAQ2Z,gBAAsC,IAAlBvY,EAAKtxB,UAAoC,KAAlBsxB,EAAKtxB,UAC3D4wB,EAAOyP,SAAU/O,IAMnB,IAHAshB,EAAevI,GAAQpY,GAGjBxuC,EAAI,EAAGyD,GAFbyrD,EAActI,GAAQ/Y,IAEO3tC,OAAQF,EAAIyD,EAAGzD,IAC3CsuD,GAAUY,EAAalvD,GAAKmvD,EAAcnvD,IAK5C,GAAKgvD,EACJ,GAAKC,EAIJ,IAHAC,EAAcA,GAAetI,GAAQ/Y,GACrCshB,EAAeA,GAAgBvI,GAAQpY,GAEjCxuC,EAAI,EAAGyD,EAAIyrD,EAAYhvD,OAAQF,EAAIyD,EAAGzD,IAC3CmuD,GAAgBe,EAAalvD,GAAKmvD,EAAcnvD,SAGjDmuD,GAAgBtgB,EAAMW,GAWxB,OANA2gB,EAAevI,GAAQpY,EAAO,WACZtuC,OAAS,GAC1B2mD,GAAesI,GAAeC,GAAUxI,GAAQ/Y,EAAM,WAIhDW,GAGRugB,UAAW,SAAUthB,GAKpB,IAJA,IAAIx4B,EAAM44B,EAAMznC,EACf+6C,EAAUhU,EAAOrW,MAAMqqB,QACvBnhD,EAAI,OAE6BuK,KAAxBsjC,EAAOJ,EAAOztC,IAAqBA,IAC5C,GAAKyjD,EAAY5V,GAAS,CACzB,GAAO54B,EAAO44B,EAAMiW,EAASpV,SAAc,CAC1C,GAAKz5B,EAAK00B,OACT,IAAMvjC,KAAQ6O,EAAK00B,OACbwX,EAAS/6C,GACb+mC,EAAOrW,MAAMtb,OAAQqyB,EAAMznC,GAI3B+mC,EAAO2c,YAAajc,EAAMznC,EAAM6O,EAAKo0C,QAOxCxb,EAAMiW,EAASpV,cAAYnkC,EAEvBsjC,EAAMkW,EAASrV,WAInBb,EAAMkW,EAASrV,cAAYnkC,OAOhC4iC,EAAO/5B,GAAGk7B,OAAQ,CACjB+gB,OAAQ,SAAUjiB,GACjB,OAAO5xB,GAAQhd,KAAM4uC,GAAU,IAGhC5xB,OAAQ,SAAU4xB,GACjB,OAAO5xB,GAAQhd,KAAM4uC,IAGtB5sC,KAAM,SAAUmF,GACf,OAAOi9C,EAAQpkD,MAAM,SAAUmH,GAC9B,YAAiB4E,IAAV5E,EACNwnC,EAAO3sC,KAAMhC,MACbA,KAAKyrB,QAAQ2jB,MAAM,WACK,IAAlBpvC,KAAK+d,UAAoC,KAAlB/d,KAAK+d,UAAqC,IAAlB/d,KAAK+d,WACxD/d,KAAKs4C,YAAcnxC,QAGpB,KAAMA,EAAOxG,UAAUe,SAG3BovD,OAAQ,WACP,OAAOf,GAAU/vD,KAAMW,WAAW,SAAU0uC,GACpB,IAAlBrvC,KAAK+d,UAAoC,KAAlB/d,KAAK+d,UAAqC,IAAlB/d,KAAK+d,UAC3CyxC,GAAoBxvD,KAAMqvC,GAChCx7B,YAAaw7B,OAKvBzV,QAAS,WACR,OAAOm2B,GAAU/vD,KAAMW,WAAW,SAAU0uC,GAC3C,GAAuB,IAAlBrvC,KAAK+d,UAAoC,KAAlB/d,KAAK+d,UAAqC,IAAlB/d,KAAK+d,SAAiB,CACzE,IAAIvH,EAASg5C,GAAoBxvD,KAAMqvC,GACvC74B,EAAOmL,aAAc0tB,EAAM74B,EAAOqG,iBAKrCk0C,OAAQ,WACP,OAAOhB,GAAU/vD,KAAMW,WAAW,SAAU0uC,GACtCrvC,KAAKmW,YACTnW,KAAKmW,WAAWwL,aAAc0tB,EAAMrvC,UAKvCgxD,MAAO,WACN,OAAOjB,GAAU/vD,KAAMW,WAAW,SAAU0uC,GACtCrvC,KAAKmW,YACTnW,KAAKmW,WAAWwL,aAAc0tB,EAAMrvC,KAAK8c,iBAK5C2O,MAAO,WAIN,IAHA,IAAI4jB,EACH7tC,EAAI,EAE2B,OAAtB6tC,EAAOrvC,KAAMwB,IAAeA,IACd,IAAlB6tC,EAAKtxB,WAGT4wB,EAAO4hB,UAAWnI,GAAQ/Y,GAAM,IAGhCA,EAAKiJ,YAAc,IAIrB,OAAOt4C,MAGRgwC,MAAO,SAAUwgB,EAAeC,GAI/B,OAHAD,EAAiC,MAAjBA,GAAgCA,EAChDC,EAAyC,MAArBA,EAA4BD,EAAgBC,EAEzDzwD,KAAKkH,KAAK,WAChB,OAAOynC,EAAOqB,MAAOhwC,KAAMwwD,EAAeC,OAI5CL,KAAM,SAAUjpD,GACf,OAAOi9C,EAAQpkD,MAAM,SAAUmH,GAC9B,IAAIkoC,EAAOrvC,KAAM,IAAO,GACvBwB,EAAI,EACJyD,EAAIjF,KAAK0B,OAEV,QAAeqK,IAAV5E,GAAyC,IAAlBkoC,EAAKtxB,SAChC,OAAOsxB,EAAK4H,UAIb,GAAsB,iBAAV9vC,IAAuBkoD,GAAa9/C,KAAMpI,KACpD2gD,IAAWL,GAAS1xB,KAAM5uB,IAAW,CAAE,GAAI,KAAQ,GAAIgwB,eAAkB,CAE1EhwB,EAAQwnC,EAAOya,cAAejiD,GAE9B,IACC,KAAQ3F,EAAIyD,EAAGzD,IAIS,KAHvB6tC,EAAOrvC,KAAMwB,IAAO,IAGVuc,WACT4wB,EAAO4hB,UAAWnI,GAAQ/Y,GAAM,IAChCA,EAAK4H,UAAY9vC,GAInBkoC,EAAO,EAGN,MAAQtiC,KAGNsiC,GACJrvC,KAAKyrB,QAAQqlC,OAAQ3pD,KAEpB,KAAMA,EAAOxG,UAAUe,SAG3BuvD,YAAa,WACZ,IAAIlI,EAAU,GAGd,OAAOgH,GAAU/vD,KAAMW,WAAW,SAAU0uC,GAC3C,IAAIoK,EAASz5C,KAAKmW,WAEbw4B,EAAO+B,QAAS1wC,KAAM+oD,GAAY,IACtCpa,EAAO4hB,UAAWnI,GAAQpoD,OACrBy5C,GACJA,EAAO53B,aAAcwtB,EAAMrvC,SAK3B+oD,MAILpa,EAAOS,KAAM,CACZ8hB,SAAU,SACVC,UAAW,UACXxvC,aAAc,SACdyvC,YAAa,QACbC,WAAY,gBACV,SAAU7kD,EAAM8kD,GAClB3iB,EAAO/5B,GAAIpI,GAAS,SAAUoiC,GAO7B,IANA,IAAIK,EACH7V,EAAM,GACNm4B,EAAS5iB,EAAQC,GACjBY,EAAO+hB,EAAO7vD,OAAS,EACvBF,EAAI,EAEGA,GAAKguC,EAAMhuC,IAClBytC,EAAQztC,IAAMguC,EAAOxvC,KAAOA,KAAKgwC,OAAO,GACxCrB,EAAQ4iB,EAAQ/vD,IAAO8vD,GAAYriB,GAInC/sC,EAAKxB,MAAO04B,EAAK6V,EAAMjqB,OAGxB,OAAOhlB,KAAKgvC,UAAW5V,OAGzB,IAAIo4B,GAAY,IAAIxjD,OAAQ,KAAOs4C,GAAO,kBAAmB,KAEzDmL,GAAY,SAAUpiB,GAKxB,IAAIye,EAAOze,EAAK3zB,cAAc+6B,YAM9B,OAJMqX,GAASA,EAAK4D,SACnB5D,EAAOxrD,GAGDwrD,EAAK6D,iBAAkBtiB,IAG5BuiB,GAAO,SAAUviB,EAAMtvC,EAAS6c,GACnC,IAAIwc,EAAK5sB,EACRuX,EAAM,GAGP,IAAMvX,KAAQzM,EACbgkB,EAAKvX,GAAS6iC,EAAKwX,MAAOr6C,GAC1B6iC,EAAKwX,MAAOr6C,GAASzM,EAASyM,GAM/B,IAAMA,KAHN4sB,EAAMxc,EAAShY,KAAMyqC,GAGPtvC,EACbsvC,EAAKwX,MAAOr6C,GAASuX,EAAKvX,GAG3B,OAAO4sB,GAIJy4B,GAAY,IAAI7jD,OAAQw4C,GAAUj9C,KAAM,KAAO,KAiJnD,SAASuoD,GAAQziB,EAAM7iC,EAAMulD,GAC5B,IAAIn1B,EAAOo1B,EAAUC,EAAU74B,EAM9BytB,EAAQxX,EAAKwX,MAqCd,OAnCAkL,EAAWA,GAAYN,GAAWpiB,MAQpB,MAFbjW,EAAM24B,EAASG,iBAAkB1lD,IAAUulD,EAAUvlD,KAEjCi6C,GAAYpX,KAC/BjW,EAAMuV,EAAOkY,MAAOxX,EAAM7iC,KAQrByhC,EAAQkkB,kBAAoBX,GAAUjiD,KAAM6pB,IAASy4B,GAAUtiD,KAAM/C,KAG1EowB,EAAQiqB,EAAMjqB,MACdo1B,EAAWnL,EAAMmL,SACjBC,EAAWpL,EAAMoL,SAGjBpL,EAAMmL,SAAWnL,EAAMoL,SAAWpL,EAAMjqB,MAAQxD,EAChDA,EAAM24B,EAASn1B,MAGfiqB,EAAMjqB,MAAQA,EACdiqB,EAAMmL,SAAWA,EACjBnL,EAAMoL,SAAWA,SAIJlmD,IAARqtB,EAINA,EAAM,GACNA,EAIF,SAASg5B,GAAcC,EAAaC,GAGnC,MAAO,CACNttC,IAAK,WACJ,IAAKqtC,IASL,OAASryD,KAAKglB,IAAMstC,GAAS5xD,MAAOV,KAAMW,kBALlCX,KAAKglB,OA3MhB,WAIC,SAASutC,IAGR,GAAMhL,EAAN,CAIAiL,EAAU3L,MAAM4L,QAAU,+EAE1BlL,EAAIV,MAAM4L,QACT,4HAGDrzC,GAAgBvL,YAAa2+C,GAAY3+C,YAAa0zC,GAEtD,IAAImL,EAAWpwD,EAAOqvD,iBAAkBpK,GACxCoL,EAAoC,OAAjBD,EAAShc,IAG5Bkc,EAAsE,KAA9CC,EAAoBH,EAASI,YAIrDvL,EAAIV,MAAMkM,MAAQ,MAClBC,EAA6D,KAAzCH,EAAoBH,EAASK,OAIjDE,EAAgE,KAAzCJ,EAAoBH,EAAS91B,OAMpD2qB,EAAIV,MAAM7zC,SAAW,WACrBkgD,EAAiE,KAA9CL,EAAoBtL,EAAI4L,YAAc,GAEzD/zC,GAAgBtB,YAAa00C,GAI7BjL,EAAM,MAGP,SAASsL,EAAoBO,GAC5B,OAAOnpD,KAAKo+B,MAAOgrB,WAAYD,IAGhC,IAAIT,EAAkBM,EAAsBC,EAAkBF,EAC7DM,EAAyBV,EACzBJ,EAAYv4B,EAAShX,cAAe,OACpCskC,EAAMttB,EAAShX,cAAe,OAGzBskC,EAAIV,QAMVU,EAAIV,MAAM0M,eAAiB,cAC3BhM,EAAI7mC,WAAW,GAAOmmC,MAAM0M,eAAiB,GAC7CtlB,EAAQulB,gBAA+C,gBAA7BjM,EAAIV,MAAM0M,eAEpC5kB,EAAOmB,OAAQ7B,EAAS,CACvBwlB,kBAAmB,WAElB,OADAlB,IACOU,GAERd,eAAgB,WAEf,OADAI,IACOS,GAERU,cAAe,WAEd,OADAnB,IACOI,GAERgB,mBAAoB,WAEnB,OADApB,IACOK,GAERgB,cAAe,WAEd,OADArB,IACOW,GAYRW,qBAAsB,WACrB,IAAIC,EAAO7L,EAAI8L,EAASC,EAmCxB,OAlCgC,MAA3BV,IACJQ,EAAQ75B,EAAShX,cAAe,SAChCglC,EAAKhuB,EAAShX,cAAe,MAC7B8wC,EAAU95B,EAAShX,cAAe,OAElC6wC,EAAMjN,MAAM4L,QAAU,2DACtBxK,EAAGpB,MAAM4L,QAAU,mBAKnBxK,EAAGpB,MAAMhqB,OAAS,MAClBk3B,EAAQlN,MAAMhqB,OAAS,MAQvBk3B,EAAQlN,MAAMC,QAAU,QAExB1nC,GACEvL,YAAaigD,GACbjgD,YAAao0C,GACbp0C,YAAakgD,GAEfC,EAAU1xD,EAAOqvD,iBAAkB1J,GACnCqL,EAA4B7qD,SAAUurD,EAAQn3B,OAAQ,IACrDp0B,SAAUurD,EAAQC,eAAgB,IAClCxrD,SAAUurD,EAAQE,kBAAmB,MAAWjM,EAAGkM,aAEpD/0C,GAAgBtB,YAAag2C,IAEvBR,MAvIV,GAsNA,IAAIc,GAAc,CAAE,SAAU,MAAO,MACpCC,GAAap6B,EAAShX,cAAe,OAAQ4jC,MAC7CyN,GAAc,GAkBf,SAASC,GAAe/nD,GAGvB,OAFYmiC,EAAO6lB,SAAUhoD,IAAU8nD,GAAa9nD,KAK/CA,KAAQ6nD,GACL7nD,EAED8nD,GAAa9nD,GAxBrB,SAAyBA,GAMxB,IAHA,IAAIioD,EAAUjoD,EAAM,GAAIu4C,cAAgBv4C,EAAK7H,MAAO,GACnDnD,EAAI4yD,GAAY1yD,OAETF,KAEP,IADAgL,EAAO4nD,GAAa5yD,GAAMizD,KACbJ,GACZ,OAAO7nD,EAeoBkoD,CAAgBloD,IAAUA,GAIxD,IAKCmoD,GAAe,4BACfC,GAAc,MACdC,GAAU,CAAE7hD,SAAU,WAAY8hD,WAAY,SAAUhO,QAAS,SACjEiO,GAAqB,CACpBC,cAAe,IACfC,WAAY,OAGd,SAASC,GAAmBvlB,EAAOxoC,EAAOguD,GAIzC,IAAIryC,EAAUyjC,GAAQxwB,KAAM5uB,GAC5B,OAAO2b,EAGN7Y,KAAKotB,IAAK,EAAGvU,EAAS,IAAQqyC,GAAY,KAAUryC,EAAS,IAAO,MACpE3b,EAGF,SAASiuD,GAAoB/lB,EAAMgmB,EAAWC,EAAKC,EAAaC,EAAQC,GACvE,IAAIj0D,EAAkB,UAAd6zD,EAAwB,EAAI,EACnCK,EAAQ,EACRrmC,EAAQ,EAGT,GAAKimC,KAAUC,EAAc,SAAW,WACvC,OAAO,EAGR,KAAQ/zD,EAAI,EAAGA,GAAK,EAGN,WAAR8zD,IACJjmC,GAASsf,EAAOoY,IAAK1X,EAAMimB,EAAM9O,GAAWhlD,IAAK,EAAMg0D,IAIlDD,GAmBQ,YAARD,IACJjmC,GAASsf,EAAOoY,IAAK1X,EAAM,UAAYmX,GAAWhlD,IAAK,EAAMg0D,IAIjD,WAARF,IACJjmC,GAASsf,EAAOoY,IAAK1X,EAAM,SAAWmX,GAAWhlD,GAAM,SAAS,EAAMg0D,MAtBvEnmC,GAASsf,EAAOoY,IAAK1X,EAAM,UAAYmX,GAAWhlD,IAAK,EAAMg0D,GAGhD,YAARF,EACJjmC,GAASsf,EAAOoY,IAAK1X,EAAM,SAAWmX,GAAWhlD,GAAM,SAAS,EAAMg0D,GAItEE,GAAS/mB,EAAOoY,IAAK1X,EAAM,SAAWmX,GAAWhlD,GAAM,SAAS,EAAMg0D,IAoCzE,OAhBMD,GAAeE,GAAe,IAInCpmC,GAASplB,KAAKotB,IAAK,EAAGptB,KAAK0rD,KAC1BtmB,EAAM,SAAWgmB,EAAW,GAAItQ,cAAgBsQ,EAAU1wD,MAAO,IACjE8wD,EACApmC,EACAqmC,EACA,MAIM,GAGDrmC,EAGR,SAASumC,GAAkBvmB,EAAMgmB,EAAWK,GAG3C,IAAIF,EAAS/D,GAAWpiB,GAKvBkmB,IADmBtnB,EAAQwlB,qBAAuBiC,IAEE,eAAnD/mB,EAAOoY,IAAK1X,EAAM,aAAa,EAAOmmB,GACvCK,EAAmBN,EAEnB/mB,EAAMsjB,GAAQziB,EAAMgmB,EAAWG,GAC/BM,EAAa,SAAWT,EAAW,GAAItQ,cAAgBsQ,EAAU1wD,MAAO,GAIzE,GAAK6sD,GAAUjiD,KAAMi/B,GAAQ,CAC5B,IAAMknB,EACL,OAAOlnB,EAERA,EAAM,OAyCP,QAlCQP,EAAQwlB,qBAAuB8B,IAMrCtnB,EAAQ4lB,wBAA0B/zC,EAAUuvB,EAAM,OAI3C,SAARb,IAIC6kB,WAAY7kB,IAA0D,WAAjDG,EAAOoY,IAAK1X,EAAM,WAAW,EAAOmmB,KAG1DnmB,EAAK0mB,iBAAiBr0D,SAEtB6zD,EAAiE,eAAnD5mB,EAAOoY,IAAK1X,EAAM,aAAa,EAAOmmB,IAKpDK,EAAmBC,KAAczmB,KAEhCb,EAAMa,EAAMymB,MAKdtnB,EAAM6kB,WAAY7kB,IAAS,GAI1B4mB,GACC/lB,EACAgmB,EACAK,IAAWH,EAAc,SAAW,WACpCM,EACAL,EAGAhnB,GAEE,KAGLG,EAAOmB,OAAQ,CAIdkmB,SAAU,CACTC,QAAS,CACRjxC,IAAK,SAAUqqB,EAAM0iB,GACpB,GAAKA,EAAW,CAGf,IAAI34B,EAAM04B,GAAQziB,EAAM,WACxB,MAAe,KAARjW,EAAa,IAAMA,MAO9B88B,UAAW,CACV,yBAA2B,EAC3B,aAAe,EACf,aAAe,EACf,UAAY,EACZ,YAAc,EACd,YAAc,EACd,UAAY,EACZ,YAAc,EACd,eAAiB,EACjB,iBAAmB,EACnB,SAAW,EACX,YAAc,EACd,cAAgB,EAChB,YAAc,EACd,SAAW,EACX,OAAS,EACT,SAAW,EACX,QAAU,EACV,QAAU,EACV,MAAQ,GAKT1B,SAAU,GAGV3N,MAAO,SAAUxX,EAAM7iC,EAAMrF,EAAOuuD,GAGnC,GAAMrmB,GAA0B,IAAlBA,EAAKtxB,UAAoC,IAAlBsxB,EAAKtxB,UAAmBsxB,EAAKwX,MAAlE,CAKA,IAAIztB,EAAKxxB,EAAMq+C,EACdkQ,EAAWnR,EAAWx4C,GACtB4pD,EAAexB,GAAYrlD,KAAM/C,GACjCq6C,EAAQxX,EAAKwX,MAad,GARMuP,IACL5pD,EAAO+nD,GAAe4B,IAIvBlQ,EAAQtX,EAAOqnB,SAAUxpD,IAAUmiC,EAAOqnB,SAAUG,QAGrCpqD,IAAV5E,EA0CJ,OAAK8+C,GAAS,QAASA,QACwBl6C,KAA5CqtB,EAAM6sB,EAAMjhC,IAAKqqB,GAAM,EAAOqmB,IAEzBt8B,EAIDytB,EAAOr6C,GA7CA,WAHd5E,SAAcT,KAGciyB,EAAMmtB,GAAQxwB,KAAM5uB,KAAaiyB,EAAK,KACjEjyB,EAxoEJ,SAAoBkoC,EAAMljB,EAAMkqC,EAAYC,GAC3C,IAAIC,EAAUC,EACbC,EAAgB,GAChBC,EAIC,WACC,OAAO/nB,EAAOoY,IAAK1X,EAAMljB,EAAM,KAEjCwqC,EAAUD,IACVE,EAAOP,GAAcA,EAAY,KAAS1nB,EAAOunB,UAAW/pC,GAAS,GAAK,MAG1E0qC,EAAgBxnB,EAAKtxB,WAClB4wB,EAAOunB,UAAW/pC,IAAmB,OAATyqC,IAAkBD,IAChDpQ,GAAQxwB,KAAM4Y,EAAOoY,IAAK1X,EAAMljB,IAElC,GAAK0qC,GAAiBA,EAAe,KAAQD,EAAO,CAYnD,IARAD,GAAoB,EAGpBC,EAAOA,GAAQC,EAAe,GAG9BA,GAAiBF,GAAW,EAEpBF,KAIP9nB,EAAOkY,MAAOxX,EAAMljB,EAAM0qC,EAAgBD,IACnC,EAAIJ,IAAY,GAAMA,EAAQE,IAAiBC,GAAW,MAAW,IAC3EF,EAAgB,GAEjBI,GAAgCL,EAIjCK,GAAgC,EAChCloB,EAAOkY,MAAOxX,EAAMljB,EAAM0qC,EAAgBD,GAG1CP,EAAaA,GAAc,GAgB5B,OAbKA,IACJQ,GAAiBA,IAAkBF,GAAW,EAG9CJ,EAAWF,EAAY,GACtBQ,GAAkBR,EAAY,GAAM,GAAMA,EAAY,IACrDA,EAAY,IAORE,EA0kEIO,CAAWznB,EAAM7iC,EAAM4sB,GAG/BxxB,EAAO,UAIM,MAATT,GAAiBA,GAAUA,IAOlB,WAATS,GAAsBwuD,IAC1BjvD,GAASiyB,GAAOA,EAAK,KAASuV,EAAOunB,UAAWC,GAAa,GAAK,OAI7DloB,EAAQulB,iBAA6B,KAAVrsD,GAAiD,IAAjCqF,EAAKnJ,QAAS,gBAC9DwjD,EAAOr6C,GAAS,WAIXy5C,GAAY,QAASA,QACsBl6C,KAA9C5E,EAAQ8+C,EAAM/gC,IAAKmqB,EAAMloC,EAAOuuD,MAE7BU,EACJvP,EAAMkQ,YAAavqD,EAAMrF,GAEzB0/C,EAAOr6C,GAASrF,MAkBpB4/C,IAAK,SAAU1X,EAAM7iC,EAAMkpD,EAAOF,GACjC,IAAIhnB,EAAKlQ,EAAK2nB,EACbkQ,EAAWnR,EAAWx4C,GA6BvB,OA5BgBooD,GAAYrlD,KAAM/C,KAMjCA,EAAO+nD,GAAe4B,KAIvBlQ,EAAQtX,EAAOqnB,SAAUxpD,IAAUmiC,EAAOqnB,SAAUG,KAGtC,QAASlQ,IACtBzX,EAAMyX,EAAMjhC,IAAKqqB,GAAM,EAAMqmB,SAIjB3pD,IAARyiC,IACJA,EAAMsjB,GAAQziB,EAAM7iC,EAAMgpD,IAId,WAARhnB,GAAoBhiC,KAAQuoD,KAChCvmB,EAAMumB,GAAoBvoD,IAIZ,KAAVkpD,GAAgBA,GACpBp3B,EAAM+0B,WAAY7kB,IACD,IAAVknB,GAAkBsB,SAAU14B,GAAQA,GAAO,EAAIkQ,GAGhDA,KAITG,EAAOS,KAAM,CAAE,SAAU,UAAW,SAAU4B,EAAIqkB,GACjD1mB,EAAOqnB,SAAUX,GAAc,CAC9BrwC,IAAK,SAAUqqB,EAAM0iB,EAAU2D,GAC9B,GAAK3D,EAIJ,OAAO4C,GAAaplD,KAAMo/B,EAAOoY,IAAK1X,EAAM,aAQxCA,EAAK0mB,iBAAiBr0D,QAAW2tC,EAAK4nB,wBAAwBr6B,MAIjEg5B,GAAkBvmB,EAAMgmB,EAAWK,GAHnC9D,GAAMviB,EAAMwlB,IAAS,WACpB,OAAOe,GAAkBvmB,EAAMgmB,EAAWK,OAM9CxwC,IAAK,SAAUmqB,EAAMloC,EAAOuuD,GAC3B,IAAI5yC,EACH0yC,EAAS/D,GAAWpiB,GAIpB6nB,GAAsBjpB,EAAQ2lB,iBACT,aAApB4B,EAAOxiD,SAIRuiD,GADkB2B,GAAsBxB,IAEY,eAAnD/mB,EAAOoY,IAAK1X,EAAM,aAAa,EAAOmmB,GACvCL,EAAWO,EACVN,GACC/lB,EACAgmB,EACAK,EACAH,EACAC,GAED,EAqBF,OAjBKD,GAAe2B,IACnB/B,GAAYlrD,KAAK0rD,KAChBtmB,EAAM,SAAWgmB,EAAW,GAAItQ,cAAgBsQ,EAAU1wD,MAAO,IACjE0uD,WAAYmC,EAAQH,IACpBD,GAAoB/lB,EAAMgmB,EAAW,UAAU,EAAOG,GACtD,KAKGL,IAAcryC,EAAUyjC,GAAQxwB,KAAM5uB,KACb,QAA3B2b,EAAS,IAAO,QAElBusB,EAAKwX,MAAOwO,GAAcluD,EAC1BA,EAAQwnC,EAAOoY,IAAK1X,EAAMgmB,IAGpBH,GAAmB7lB,EAAMloC,EAAOguD,QAK1CxmB,EAAOqnB,SAASlD,WAAaV,GAAcnkB,EAAQ0lB,oBAClD,SAAUtkB,EAAM0iB,GACf,GAAKA,EACJ,OAASsB,WAAYvB,GAAQziB,EAAM,gBAClCA,EAAK4nB,wBAAwBE,KAC5BvF,GAAMviB,EAAM,CAAEyjB,WAAY,IAAK,WAC9B,OAAOzjB,EAAK4nB,wBAAwBE,SAEnC,QAMPxoB,EAAOS,KAAM,CACZgoB,OAAQ,GACRC,QAAS,GACTC,OAAQ,UACN,SAAUjhD,EAAQkhD,GACpB5oB,EAAOqnB,SAAU3/C,EAASkhD,GAAW,CACpCC,OAAQ,SAAUrwD,GAOjB,IANA,IAAI3F,EAAI,EACPi2D,EAAW,GAGXvsD,EAAyB,iBAAV/D,EAAqBA,EAAMjD,MAAO,KAAQ,CAAEiD,GAEpD3F,EAAI,EAAGA,IACdi2D,EAAUphD,EAASmwC,GAAWhlD,GAAM+1D,GACnCrsD,EAAO1J,IAAO0J,EAAO1J,EAAI,IAAO0J,EAAO,GAGzC,OAAOusD,IAIO,WAAXphD,IACJs4B,EAAOqnB,SAAU3/C,EAASkhD,GAASryC,IAAMgwC,OAI3CvmB,EAAO/5B,GAAGk7B,OAAQ,CACjBiX,IAAK,SAAUv6C,EAAMrF,GACpB,OAAOi9C,EAAQpkD,MAAM,SAAUqvC,EAAM7iC,EAAMrF,GAC1C,IAAIquD,EAAQ/zD,EACXyF,EAAM,GACN1F,EAAI,EAEL,GAAKkD,MAAMgD,QAAS8E,GAAS,CAI5B,IAHAgpD,EAAS/D,GAAWpiB,GACpB5tC,EAAM+K,EAAK9K,OAEHF,EAAIC,EAAKD,IAChB0F,EAAKsF,EAAMhL,IAAQmtC,EAAOoY,IAAK1X,EAAM7iC,EAAMhL,IAAK,EAAOg0D,GAGxD,OAAOtuD,EAGR,YAAiB6E,IAAV5E,EACNwnC,EAAOkY,MAAOxX,EAAM7iC,EAAMrF,GAC1BwnC,EAAOoY,IAAK1X,EAAM7iC,KACjBA,EAAMrF,EAAOxG,UAAUe,OAAS,MAOrCitC,EAAO/5B,GAAG8iD,MAAQ,SAAUC,EAAM/vD,GAIjC,OAHA+vD,EAAOhpB,EAAOipB,IAAKjpB,EAAOipB,GAAGC,OAAQF,IAAiBA,EACtD/vD,EAAOA,GAAQ,KAER5H,KAAKc,MAAO8G,GAAM,SAAU6V,EAAMwoC,GACxC,IAAI6R,EAAUx1D,EAAOE,WAAYib,EAAMk6C,GACvC1R,EAAMljD,KAAO,WACZT,EAAOC,aAAcu1D,QAMxB,WACC,IAAIx/C,EAAQ2hB,EAAShX,cAAe,SAEnC80C,EADS99B,EAAShX,cAAe,UACpBpP,YAAaomB,EAAShX,cAAe,WAEnD3K,EAAM1Q,KAAO,WAIbqmC,EAAQ+pB,QAA0B,KAAhB1/C,EAAMnR,MAIxB8mC,EAAQgqB,YAAcF,EAAIxd,UAI1BjiC,EAAQ2hB,EAAShX,cAAe,UAC1B9b,MAAQ,IACdmR,EAAM1Q,KAAO,QACbqmC,EAAQiqB,WAA6B,MAAhB5/C,EAAMnR,MApB5B,GAwBA,IAAIgxD,GACHxiB,GAAahH,EAAO/+B,KAAK+lC,WAE1BhH,EAAO/5B,GAAGk7B,OAAQ,CACjBp6B,KAAM,SAAUlJ,EAAMrF,GACrB,OAAOi9C,EAAQpkD,KAAM2uC,EAAOj5B,KAAMlJ,EAAMrF,EAAOxG,UAAUe,OAAS,IAGnE02D,WAAY,SAAU5rD,GACrB,OAAOxM,KAAKovC,MAAM,WACjBT,EAAOypB,WAAYp4D,KAAMwM,SAK5BmiC,EAAOmB,OAAQ,CACdp6B,KAAM,SAAU25B,EAAM7iC,EAAMrF,GAC3B,IAAIiyB,EAAK6sB,EACRoS,EAAQhpB,EAAKtxB,SAGd,GAAe,IAAVs6C,GAAyB,IAAVA,GAAyB,IAAVA,EAKnC,YAAkC,IAAtBhpB,EAAK7sB,aACTmsB,EAAOxiB,KAAMkjB,EAAM7iC,EAAMrF,IAKlB,IAAVkxD,GAAgB1pB,EAAOyP,SAAU/O,KACrC4W,EAAQtX,EAAO2pB,UAAW9rD,EAAK2qB,iBAC5BwX,EAAO/+B,KAAKxL,MAAMm0D,KAAKhpD,KAAM/C,GAAS2rD,QAAWpsD,SAGtCA,IAAV5E,EACW,OAAVA,OACJwnC,EAAOypB,WAAY/oB,EAAM7iC,GAIrBy5C,GAAS,QAASA,QACuBl6C,KAA3CqtB,EAAM6sB,EAAM/gC,IAAKmqB,EAAMloC,EAAOqF,IACzB4sB,GAGRiW,EAAK5rB,aAAcjX,EAAMrF,EAAQ,IAC1BA,GAGH8+C,GAAS,QAASA,GAA+C,QAApC7sB,EAAM6sB,EAAMjhC,IAAKqqB,EAAM7iC,IACjD4sB,EAMM,OAHdA,EAAMuV,EAAOtmC,KAAKqN,KAAM25B,EAAM7iC,SAGTT,EAAYqtB,IAGlCk/B,UAAW,CACV1wD,KAAM,CACLsd,IAAK,SAAUmqB,EAAMloC,GACpB,IAAM8mC,EAAQiqB,YAAwB,UAAV/wD,GAC3B2Y,EAAUuvB,EAAM,SAAY,CAC5B,IAAIb,EAAMa,EAAKloC,MAKf,OAJAkoC,EAAK5rB,aAAc,OAAQtc,GACtBqnC,IACJa,EAAKloC,MAAQqnC,GAEPrnC,MAMXixD,WAAY,SAAU/oB,EAAMloC,GAC3B,IAAIqF,EACHhL,EAAI,EAIJg3D,EAAYrxD,GAASA,EAAM/C,MAAO+7C,GAEnC,GAAKqY,GAA+B,IAAlBnpB,EAAKtxB,SACtB,KAAUvR,EAAOgsD,EAAWh3D,MAC3B6tC,EAAK3rB,gBAAiBlX,MAO1B2rD,GAAW,CACVjzC,IAAK,SAAUmqB,EAAMloC,EAAOqF,GAQ3B,OAPe,IAAVrF,EAGJwnC,EAAOypB,WAAY/oB,EAAM7iC,GAEzB6iC,EAAK5rB,aAAcjX,EAAMA,GAEnBA,IAITmiC,EAAOS,KAAMT,EAAO/+B,KAAKxL,MAAMm0D,KAAKlsD,OAAOjI,MAAO,SAAU,SAAU4sC,EAAIxkC,GACzE,IAAIisD,EAAS9iB,GAAYnpC,IAAUmiC,EAAOtmC,KAAKqN,KAE/CigC,GAAYnpC,GAAS,SAAU6iC,EAAM7iC,EAAM4kC,GAC1C,IAAIhY,EAAKyxB,EACR6N,EAAgBlsD,EAAK2qB,cAYtB,OAVMia,IAGLyZ,EAASlV,GAAY+iB,GACrB/iB,GAAY+iB,GAAkBt/B,EAC9BA,EAAqC,MAA/Bq/B,EAAQppB,EAAM7iC,EAAM4kC,GACzBsnB,EACA,KACD/iB,GAAY+iB,GAAkB7N,GAExBzxB,MAOT,IAAIu/B,GAAa,sCAChBC,GAAa,gBAyIb,SAASC,GAAkB1xD,GAE1B,OADaA,EAAM/C,MAAO+7C,IAAmB,IAC/B52C,KAAM,KAItB,SAASuvD,GAAUzpB,GAClB,OAAOA,EAAK7sB,cAAgB6sB,EAAK7sB,aAAc,UAAa,GAG7D,SAASu2C,GAAgB5xD,GACxB,OAAKzC,MAAMgD,QAASP,GACZA,EAEc,iBAAVA,GACJA,EAAM/C,MAAO+7C,IAEd,GAxJRxR,EAAO/5B,GAAGk7B,OAAQ,CACjB3jB,KAAM,SAAU3f,EAAMrF,GACrB,OAAOi9C,EAAQpkD,KAAM2uC,EAAOxiB,KAAM3f,EAAMrF,EAAOxG,UAAUe,OAAS,IAGnEs3D,WAAY,SAAUxsD,GACrB,OAAOxM,KAAKovC,MAAM,kBACVpvC,KAAM2uC,EAAOsqB,QAASzsD,IAAUA,SAK1CmiC,EAAOmB,OAAQ,CACd3jB,KAAM,SAAUkjB,EAAM7iC,EAAMrF,GAC3B,IAAIiyB,EAAK6sB,EACRoS,EAAQhpB,EAAKtxB,SAGd,GAAe,IAAVs6C,GAAyB,IAAVA,GAAyB,IAAVA,EAWnC,OAPe,IAAVA,GAAgB1pB,EAAOyP,SAAU/O,KAGrC7iC,EAAOmiC,EAAOsqB,QAASzsD,IAAUA,EACjCy5C,EAAQtX,EAAOuqB,UAAW1sD,SAGZT,IAAV5E,EACC8+C,GAAS,QAASA,QACuBl6C,KAA3CqtB,EAAM6sB,EAAM/gC,IAAKmqB,EAAMloC,EAAOqF,IACzB4sB,EAGCiW,EAAM7iC,GAASrF,EAGpB8+C,GAAS,QAASA,GAA+C,QAApC7sB,EAAM6sB,EAAMjhC,IAAKqqB,EAAM7iC,IACjD4sB,EAGDiW,EAAM7iC,IAGd0sD,UAAW,CACV7e,SAAU,CACTr1B,IAAK,SAAUqqB,GAOd,IAAI8pB,EAAWxqB,EAAOtmC,KAAKqN,KAAM25B,EAAM,YAEvC,OAAK8pB,EACG1wD,SAAU0wD,EAAU,IAI3BR,GAAWppD,KAAM8/B,EAAKvvB,WACtB84C,GAAWrpD,KAAM8/B,EAAKvvB,WACtBuvB,EAAK9H,KAEE,GAGA,KAKX0xB,QAAS,CACR,IAAO,UACP,MAAS,eAYLhrB,EAAQgqB,cACbtpB,EAAOuqB,UAAU3e,SAAW,CAC3Bv1B,IAAK,SAAUqqB,GAId,IAAIoK,EAASpK,EAAKl5B,WAIlB,OAHKsjC,GAAUA,EAAOtjC,YACrBsjC,EAAOtjC,WAAWqkC,cAEZ,MAERt1B,IAAK,SAAUmqB,GAId,IAAIoK,EAASpK,EAAKl5B,WACbsjC,IACJA,EAAOe,cAEFf,EAAOtjC,YACXsjC,EAAOtjC,WAAWqkC,kBAOvB7L,EAAOS,KAAM,CACZ,WACA,WACA,YACA,cACA,cACA,UACA,UACA,SACA,cACA,oBACE,WACFT,EAAOsqB,QAASj5D,KAAKm3B,eAAkBn3B,QA4BxC2uC,EAAO/5B,GAAGk7B,OAAQ,CACjBspB,SAAU,SAAUjyD,GACnB,IAAIkyD,EAAShqB,EAAMwG,EAAKyjB,EAAUC,EAAOvuD,EAAGwuD,EAC3Ch4D,EAAI,EAEL,GAAK0sC,EAAY/mC,GAChB,OAAOnH,KAAKovC,MAAM,SAAUpkC,GAC3B2jC,EAAQ3uC,MAAOo5D,SAAUjyD,EAAMvC,KAAM5E,KAAMgL,EAAG8tD,GAAU94D,WAM1D,IAFAq5D,EAAUN,GAAgB5xD,IAEbzF,OACZ,KAAU2tC,EAAOrvC,KAAMwB,MAItB,GAHA83D,EAAWR,GAAUzpB,GACrBwG,EAAwB,IAAlBxG,EAAKtxB,UAAoB,IAAM86C,GAAkBS,GAAa,IAEzD,CAEV,IADAtuD,EAAI,EACMuuD,EAAQF,EAASruD,MACrB6qC,EAAIxyC,QAAS,IAAMk2D,EAAQ,KAAQ,IACvC1jB,GAAO0jB,EAAQ,KAMZD,KADLE,EAAaX,GAAkBhjB,KAE9BxG,EAAK5rB,aAAc,QAAS+1C,GAMhC,OAAOx5D,MAGRy5D,YAAa,SAAUtyD,GACtB,IAAIkyD,EAAShqB,EAAMwG,EAAKyjB,EAAUC,EAAOvuD,EAAGwuD,EAC3Ch4D,EAAI,EAEL,GAAK0sC,EAAY/mC,GAChB,OAAOnH,KAAKovC,MAAM,SAAUpkC,GAC3B2jC,EAAQ3uC,MAAOy5D,YAAatyD,EAAMvC,KAAM5E,KAAMgL,EAAG8tD,GAAU94D,WAI7D,IAAMW,UAAUe,OACf,OAAO1B,KAAK0V,KAAM,QAAS,IAK5B,IAFA2jD,EAAUN,GAAgB5xD,IAEbzF,OACZ,KAAU2tC,EAAOrvC,KAAMwB,MAMtB,GALA83D,EAAWR,GAAUzpB,GAGrBwG,EAAwB,IAAlBxG,EAAKtxB,UAAoB,IAAM86C,GAAkBS,GAAa,IAEzD,CAEV,IADAtuD,EAAI,EACMuuD,EAAQF,EAASruD,MAG1B,KAAQ6qC,EAAIxyC,QAAS,IAAMk2D,EAAQ,MAAS,GAC3C1jB,EAAMA,EAAIplC,QAAS,IAAM8oD,EAAQ,IAAK,KAMnCD,KADLE,EAAaX,GAAkBhjB,KAE9BxG,EAAK5rB,aAAc,QAAS+1C,GAMhC,OAAOx5D,MAGR05D,YAAa,SAAUvyD,EAAOwyD,GAC7B,IAAI/xD,SAAcT,EACjByyD,EAAwB,WAAThyD,GAAqBlD,MAAMgD,QAASP,GAEpD,MAAyB,kBAAbwyD,GAA0BC,EAC9BD,EAAW35D,KAAKo5D,SAAUjyD,GAAUnH,KAAKy5D,YAAatyD,GAGzD+mC,EAAY/mC,GACTnH,KAAKovC,MAAM,SAAU5tC,GAC3BmtC,EAAQ3uC,MAAO05D,YACdvyD,EAAMvC,KAAM5E,KAAMwB,EAAGs3D,GAAU94D,MAAQ25D,GACvCA,MAKI35D,KAAKovC,MAAM,WACjB,IAAIwH,EAAWp1C,EAAG7B,EAAM+iB,EAExB,GAAKk3C,EAOJ,IAJAp4D,EAAI,EACJ7B,EAAOgvC,EAAQ3uC,MACf0iB,EAAaq2C,GAAgB5xD,GAEnByvC,EAAYl0B,EAAYlhB,MAG5B7B,EAAKk6D,SAAUjjB,GACnBj3C,EAAK85D,YAAa7iB,GAElBj3C,EAAKy5D,SAAUxiB,aAKI7qC,IAAV5E,GAAgC,YAATS,KAClCgvC,EAAYkiB,GAAU94D,QAIrBslD,EAASpgC,IAAKllB,KAAM,gBAAiB42C,GAOjC52C,KAAKyjB,cACTzjB,KAAKyjB,aAAc,QAClBmzB,IAAuB,IAAVzvC,EACZ,GACAm+C,EAAStgC,IAAKhlB,KAAM,kBAAqB,SAO/C65D,SAAU,SAAUjrB,GACnB,IAAIgI,EAAWvH,EACd7tC,EAAI,EAGL,IADAo1C,EAAY,IAAMhI,EAAW,IACnBS,EAAOrvC,KAAMwB,MACtB,GAAuB,IAAlB6tC,EAAKtxB,WACP,IAAM86C,GAAkBC,GAAUzpB,IAAW,KAAMhsC,QAASuzC,IAAe,EAC7E,OAAO,EAIT,OAAO,KAOT,IAAIkjB,GAAU,MAEdnrB,EAAO/5B,GAAGk7B,OAAQ,CACjBtB,IAAK,SAAUrnC,GACd,IAAI8+C,EAAO7sB,EAAK+2B,EACf9gB,EAAOrvC,KAAM,GAEd,OAAMW,UAAUe,QA0BhByuD,EAAkBjiB,EAAY/mC,GAEvBnH,KAAKovC,MAAM,SAAU5tC,GAC3B,IAAIgtC,EAEmB,IAAlBxuC,KAAK+d,WAWE,OANXywB,EADI2hB,EACEhpD,EAAMvC,KAAM5E,KAAMwB,EAAGmtC,EAAQ3uC,MAAOwuC,OAEpCrnC,GAKNqnC,EAAM,GAEoB,iBAARA,EAClBA,GAAO,GAEI9pC,MAAMgD,QAAS8mC,KAC1BA,EAAMG,EAAOznC,IAAKsnC,GAAK,SAAUrnC,GAChC,OAAgB,MAATA,EAAgB,GAAKA,EAAQ,QAItC8+C,EAAQtX,EAAOorB,SAAU/5D,KAAK4H,OAAU+mC,EAAOorB,SAAU/5D,KAAK8f,SAASqX,iBAGrD,QAAS8uB,QAA+Cl6C,IAApCk6C,EAAM/gC,IAAKllB,KAAMwuC,EAAK,WAC3DxuC,KAAKmH,MAAQqnC,QAzDTa,GACJ4W,EAAQtX,EAAOorB,SAAU1qB,EAAKznC,OAC7B+mC,EAAOorB,SAAU1qB,EAAKvvB,SAASqX,iBAG/B,QAAS8uB,QACgCl6C,KAAvCqtB,EAAM6sB,EAAMjhC,IAAKqqB,EAAM,UAElBjW,EAMY,iBAHpBA,EAAMiW,EAAKloC,OAIHiyB,EAAI3oB,QAASqpD,GAAS,IAIhB,MAAP1gC,EAAc,GAAKA,OAG3B,KAyCHuV,EAAOmB,OAAQ,CACdiqB,SAAU,CACTlS,OAAQ,CACP7iC,IAAK,SAAUqqB,GAEd,IAAIb,EAAMG,EAAOtmC,KAAKqN,KAAM25B,EAAM,SAClC,OAAc,MAAPb,EACNA,EAMAqqB,GAAkBlqB,EAAO3sC,KAAMqtC,MAGlCkC,OAAQ,CACPvsB,IAAK,SAAUqqB,GACd,IAAIloC,EAAO0gD,EAAQrmD,EAClBzB,EAAUsvC,EAAKtvC,QACfuK,EAAQ+kC,EAAKmL,cACbmP,EAAoB,eAAdta,EAAKznC,KACX0B,EAASqgD,EAAM,KAAO,GACtBtyB,EAAMsyB,EAAMr/C,EAAQ,EAAIvK,EAAQ2B,OAUjC,IAPCF,EADI8I,EAAQ,EACR+sB,EAGAsyB,EAAMr/C,EAAQ,EAIX9I,EAAI61B,EAAK71B,IAKhB,KAJAqmD,EAAS9nD,EAASyB,IAIJ+4C,UAAY/4C,IAAM8I,KAG7Bu9C,EAAOrT,YACLqT,EAAO1xC,WAAWq+B,WACnB10B,EAAU+nC,EAAO1xC,WAAY,aAAiB,CAMjD,GAHAhP,EAAQwnC,EAAQkZ,GAASrZ,MAGpBmb,EACJ,OAAOxiD,EAIRmC,EAAOpH,KAAMiF,GAIf,OAAOmC,GAGR4b,IAAK,SAAUmqB,EAAMloC,GAMpB,IALA,IAAI6yD,EAAWnS,EACd9nD,EAAUsvC,EAAKtvC,QACfuJ,EAASqlC,EAAO6B,UAAWrpC,GAC3B3F,EAAIzB,EAAQ2B,OAELF,OACPqmD,EAAS9nD,EAASyB,IAIN+4C,SACX5L,EAAO+B,QAAS/B,EAAOorB,SAASlS,OAAO7iC,IAAK6iC,GAAUv+C,IAAY,KAElE0wD,GAAY,GAUd,OAHMA,IACL3qB,EAAKmL,eAAiB,GAEhBlxC,OAOXqlC,EAAOS,KAAM,CAAE,QAAS,aAAc,WACrCT,EAAOorB,SAAU/5D,MAAS,CACzBklB,IAAK,SAAUmqB,EAAMloC,GACpB,GAAKzC,MAAMgD,QAASP,GACnB,OAASkoC,EAAKiL,QAAU3L,EAAO+B,QAAS/B,EAAQU,GAAOb,MAAOrnC,IAAW,IAItE8mC,EAAQ+pB,UACbrpB,EAAOorB,SAAU/5D,MAAOglB,IAAM,SAAUqqB,GACvC,OAAwC,OAAjCA,EAAK7sB,aAAc,SAAqB,KAAO6sB,EAAKloC,WAW9D8mC,EAAQgsB,QAAU,cAAe33D,EAGjC,IAAI43D,GAAc,kCACjBC,GAA0B,SAAUptD,GACnCA,EAAEm9C,mBAGJvb,EAAOmB,OAAQnB,EAAOrW,MAAO,CAE5B+xB,QAAS,SAAU/xB,EAAO7hB,EAAM44B,EAAM+qB,GAErC,IAAI54D,EAAGq0C,EAAKpY,EAAK48B,EAAYC,EAAQzP,EAAQlI,EAAS4X,EACrDC,EAAY,CAAEnrB,GAAQpV,GACtBryB,EAAOkmC,EAAOlpC,KAAM0zB,EAAO,QAAWA,EAAM1wB,KAAO0wB,EACnDoyB,EAAa5c,EAAOlpC,KAAM0zB,EAAO,aAAgBA,EAAM/Y,UAAUrb,MAAO,KAAQ,GAKjF,GAHA2xC,EAAM0kB,EAAc98B,EAAM4R,EAAOA,GAAQpV,EAGlB,IAAlBoV,EAAKtxB,UAAoC,IAAlBsxB,EAAKtxB,WAK5Bm8C,GAAY3qD,KAAM3H,EAAO+mC,EAAOrW,MAAMwyB,aAItCljD,EAAKvE,QAAS,MAAS,IAG3BqnD,EAAa9iD,EAAK1D,MAAO,KACzB0D,EAAO8iD,EAAWvd,QAClBud,EAAW7a,QAEZyqB,EAAS1yD,EAAKvE,QAAS,KAAQ,GAAK,KAAOuE,GAG3C0wB,EAAQA,EAAOqW,EAAOuB,SACrB5X,EACA,IAAIqW,EAAO2b,MAAO1iD,EAAuB,iBAAV0wB,GAAsBA,IAGhD0xB,UAAYoQ,EAAe,EAAI,EACrC9hC,EAAM/Y,UAAYmrC,EAAWnhD,KAAM,KACnC+uB,EAAMyzB,WAAazzB,EAAM/Y,UACxB,IAAIvR,OAAQ,UAAY08C,EAAWnhD,KAAM,iBAAoB,WAC7D,KAGD+uB,EAAMgB,YAASvtB,EACTusB,EAAM9hB,SACX8hB,EAAM9hB,OAAS64B,GAIhB54B,EAAe,MAARA,EACN,CAAE6hB,GACFqW,EAAO6B,UAAW/5B,EAAM,CAAE6hB,IAG3BqqB,EAAUhU,EAAOrW,MAAMqqB,QAAS/6C,IAAU,GACpCwyD,IAAgBzX,EAAQ0H,UAAmD,IAAxC1H,EAAQ0H,QAAQ3pD,MAAO2uC,EAAM54B,IAAtE,CAMA,IAAM2jD,IAAiBzX,EAAQ6J,WAAare,EAAUkB,GAAS,CAM9D,IAJAgrB,EAAa1X,EAAQsH,cAAgBriD,EAC/BsyD,GAAY3qD,KAAM8qD,EAAazyD,KACpCiuC,EAAMA,EAAI1/B,YAEH0/B,EAAKA,EAAMA,EAAI1/B,WACtBqkD,EAAUt4D,KAAM2zC,GAChBpY,EAAMoY,EAIFpY,KAAU4R,EAAK3zB,eAAiBue,IACpCugC,EAAUt4D,KAAMu7B,EAAIgZ,aAAehZ,EAAIg9B,cAAgBn4D,GAMzD,IADAd,EAAI,GACMq0C,EAAM2kB,EAAWh5D,QAAY82B,EAAMszB,wBAC5C2O,EAAc1kB,EACdvd,EAAM1wB,KAAOpG,EAAI,EAChB64D,EACA1X,EAAQqI,UAAYpjD,GAGrBijD,GAAWvF,EAAStgC,IAAK6wB,EAAK,WAAcz1C,OAAOw+B,OAAQ,OAAUtG,EAAM1wB,OAC1E09C,EAAStgC,IAAK6wB,EAAK,YAEnBgV,EAAOnqD,MAAOm1C,EAAKp/B,IAIpBo0C,EAASyP,GAAUzkB,EAAKykB,KACTzP,EAAOnqD,OAASukD,EAAYpP,KAC1Cvd,EAAMgB,OAASuxB,EAAOnqD,MAAOm1C,EAAKp/B,IACZ,IAAjB6hB,EAAMgB,QACVhB,EAAM8xB,kBA8CT,OA1CA9xB,EAAM1wB,KAAOA,EAGPwyD,GAAiB9hC,EAAMu0B,sBAEpBlK,EAAQwF,WACqC,IAApDxF,EAAQwF,SAASznD,MAAO85D,EAAUvjC,MAAOxgB,KACzCwuC,EAAY5V,IAIPirB,GAAUpsB,EAAYmB,EAAMznC,MAAaumC,EAAUkB,MAGvD5R,EAAM4R,EAAMirB,MAGXjrB,EAAMirB,GAAW,MAIlB3rB,EAAOrW,MAAMwyB,UAAYljD,EAEpB0wB,EAAMszB,wBACV2O,EAAYluB,iBAAkBzkC,EAAMuyD,IAGrC9qB,EAAMznC,KAED0wB,EAAMszB,wBACV2O,EAAYhuB,oBAAqB3kC,EAAMuyD,IAGxCxrB,EAAOrW,MAAMwyB,eAAY/+C,EAEpB0xB,IACJ4R,EAAMirB,GAAW78B,IAMdnF,EAAMgB,SAKdohC,SAAU,SAAU9yD,EAAMynC,EAAM/W,GAC/B,IAAIvrB,EAAI4hC,EAAOmB,OACd,IAAInB,EAAO2b,MACXhyB,EACA,CACC1wB,KAAMA,EACNslD,aAAa,IAIfve,EAAOrW,MAAM+xB,QAASt9C,EAAG,KAAMsiC,MAKjCV,EAAO/5B,GAAGk7B,OAAQ,CAEjBua,QAAS,SAAUziD,EAAM6O,GACxB,OAAOzW,KAAKovC,MAAM,WACjBT,EAAOrW,MAAM+xB,QAASziD,EAAM6O,EAAMzW,UAGpC26D,eAAgB,SAAU/yD,EAAM6O,GAC/B,IAAI44B,EAAOrvC,KAAM,GACjB,GAAKqvC,EACJ,OAAOV,EAAOrW,MAAM+xB,QAASziD,EAAM6O,EAAM44B,GAAM,MAc5CpB,EAAQgsB,SACbtrB,EAAOS,KAAM,CAAErN,MAAO,UAAW+sB,KAAM,aAAc,SAAUK,EAAM1D,GAGpE,IAAIpzB,EAAU,SAAUC,GACvBqW,EAAOrW,MAAMoiC,SAAUjP,EAAKnzB,EAAM9hB,OAAQm4B,EAAOrW,MAAMmzB,IAAKnzB,KAG7DqW,EAAOrW,MAAMqqB,QAAS8I,GAAQ,CAC7BP,MAAO,WAIN,IAAIp3C,EAAM9T,KAAK0b,eAAiB1b,KAAKi6B,UAAYj6B,KAChD46D,EAAWtV,EAASlB,OAAQtwC,EAAK23C,GAE5BmP,GACL9mD,EAAIu4B,iBAAkB8iB,EAAM92B,GAAS,GAEtCitB,EAASlB,OAAQtwC,EAAK23C,GAAOmP,GAAY,GAAM,IAEhDvP,SAAU,WACT,IAAIv3C,EAAM9T,KAAK0b,eAAiB1b,KAAKi6B,UAAYj6B,KAChD46D,EAAWtV,EAASlB,OAAQtwC,EAAK23C,GAAQ,EAEpCmP,EAKLtV,EAASlB,OAAQtwC,EAAK23C,EAAKmP,IAJ3B9mD,EAAIy4B,oBAAqB4iB,EAAM92B,GAAS,GACxCitB,EAAStoC,OAAQlJ,EAAK23C,SAY3B9c,EAAOksB,SAAW,SAAUpkD,GAC3B,IAAI3B,EAAKgmD,EACT,IAAMrkD,GAAwB,iBAATA,EACpB,OAAO,KAKR,IACC3B,GAAM,IAAMxS,EAAOsQ,WAAcmB,gBAAiB0C,EAAM,YACvD,MAAQ1J,IAYV,OAVA+tD,EAAkBhmD,GAAOA,EAAIsP,qBAAsB,eAAiB,GAC9DtP,IAAOgmD,GACZnsB,EAAOttC,MAAO,iBACby5D,EACCnsB,EAAOznC,IAAK4zD,EAAgB19C,YAAY,SAAU/L,GACjD,OAAOA,EAAGinC,eACP/uC,KAAM,MACVkN,IAGI3B,GAIR,IA4MKoyC,GA3MJ6T,GAAW,QACXC,GAAQ,SACRC,GAAkB,wCAClBC,GAAe,qCAEhB,SAASC,GAAa9kD,EAAQlI,EAAKitD,EAAazb,GAC/C,IAAInzC,EAEJ,GAAK9H,MAAMgD,QAASyG,GAGnBwgC,EAAOS,KAAMjhC,GAAK,SAAU3M,EAAG+K,GACzB6uD,GAAeL,GAASxrD,KAAM8G,GAGlCspC,EAAKtpC,EAAQ9J,GAKb4uD,GACC9kD,EAAS,KAAqB,iBAAN9J,GAAuB,MAALA,EAAY/K,EAAI,IAAO,IACjE+K,EACA6uD,EACAzb,WAKG,GAAMyb,GAAiC,WAAlB1sB,EAAQvgC,GAUnCwxC,EAAKtpC,EAAQlI,QAPb,IAAM3B,KAAQ2B,EACbgtD,GAAa9kD,EAAS,IAAM7J,EAAO,IAAK2B,EAAK3B,GAAQ4uD,EAAazb,GAYrEhR,EAAO0sB,MAAQ,SAAUhuD,EAAG+tD,GAC3B,IAAI/kD,EACHxJ,EAAI,GACJ8yC,EAAM,SAAUzxC,EAAKotD,GAGpB,IAAIn0D,EAAQ+mC,EAAYotB,GACvBA,IACAA,EAEDzuD,EAAGA,EAAEnL,QAAW65D,mBAAoBrtD,GAAQ,IAC3CqtD,mBAA6B,MAATp0D,EAAgB,GAAKA,IAG5C,GAAU,MAALkG,EACJ,MAAO,GAIR,GAAK3I,MAAMgD,QAAS2F,IAASA,EAAEyhC,SAAWH,EAAOsB,cAAe5iC,GAG/DshC,EAAOS,KAAM/hC,GAAG,WACfsyC,EAAK3/C,KAAKwM,KAAMxM,KAAKmH,eAOtB,IAAMkP,KAAUhJ,EACf8tD,GAAa9kD,EAAQhJ,EAAGgJ,GAAU+kD,EAAazb,GAKjD,OAAO9yC,EAAEtD,KAAM,MAGhBolC,EAAO/5B,GAAGk7B,OAAQ,CACjB0rB,UAAW,WACV,OAAO7sB,EAAO0sB,MAAOr7D,KAAKy7D,mBAE3BA,eAAgB,WACf,OAAOz7D,KAAKkH,KAAK,WAGhB,IAAI8wC,EAAWrJ,EAAOxiB,KAAMnsB,KAAM,YAClC,OAAOg4C,EAAWrJ,EAAO6B,UAAWwH,GAAah4C,QAC9C+G,QAAQ,WACX,IAAIa,EAAO5H,KAAK4H,KAGhB,OAAO5H,KAAKwM,OAASmiC,EAAQ3uC,MAAOgnC,GAAI,cACvCk0B,GAAa3rD,KAAMvP,KAAK8f,YAAem7C,GAAgB1rD,KAAM3H,KAC3D5H,KAAKs6C,UAAYkN,GAAej4C,KAAM3H,OACtCV,KAAK,SAAU8pC,EAAI3B,GACtB,IAAIb,EAAMG,EAAQ3uC,MAAOwuC,MAEzB,OAAY,MAAPA,EACG,KAGH9pC,MAAMgD,QAAS8mC,GACZG,EAAOznC,IAAKsnC,GAAK,SAAUA,GACjC,MAAO,CAAEhiC,KAAM6iC,EAAK7iC,KAAMrF,MAAOqnC,EAAI/9B,QAASuqD,GAAO,YAIhD,CAAExuD,KAAM6iC,EAAK7iC,KAAMrF,MAAOqnC,EAAI/9B,QAASuqD,GAAO,YAClDh2C,SAKN2pB,EAAO/5B,GAAGk7B,OAAQ,CACjB4rB,QAAS,SAAUtL,GAClB,IAAIpH,EAyBJ,OAvBKhpD,KAAM,KACLkuC,EAAYkiB,KAChBA,EAAOA,EAAKxrD,KAAM5E,KAAM,KAIzBgpD,EAAOra,EAAQyhB,EAAMpwD,KAAM,GAAI0b,eAAgB6zB,GAAI,GAAIS,OAAO,GAEzDhwC,KAAM,GAAImW,YACd6yC,EAAKrnC,aAAc3hB,KAAM,IAG1BgpD,EAAK9hD,KAAK,WAGT,IAFA,IAAImoC,EAAOrvC,KAEHqvC,EAAKssB,mBACZtsB,EAAOA,EAAKssB,kBAGb,OAAOtsB,KACJyhB,OAAQ9wD,OAGNA,MAGR47D,UAAW,SAAUxL,GACpB,OAAKliB,EAAYkiB,GACTpwD,KAAKovC,MAAM,SAAU5tC,GAC3BmtC,EAAQ3uC,MAAO47D,UAAWxL,EAAKxrD,KAAM5E,KAAMwB,OAItCxB,KAAKovC,MAAM,WACjB,IAAIzvC,EAAOgvC,EAAQ3uC,MAClBo/C,EAAWz/C,EAAKy/C,WAEZA,EAAS19C,OACb09C,EAASsc,QAAStL,GAGlBzwD,EAAKmxD,OAAQV,OAKhBpH,KAAM,SAAUoH,GACf,IAAIyL,EAAiB3tB,EAAYkiB,GAEjC,OAAOpwD,KAAKovC,MAAM,SAAU5tC,GAC3BmtC,EAAQ3uC,MAAO07D,QAASG,EAAiBzL,EAAKxrD,KAAM5E,KAAMwB,GAAM4uD,OAIlEpkB,OAAQ,SAAU4C,GAIjB,OAHA5uC,KAAKy5C,OAAQ7K,GAAW3kB,IAAK,QAASmlB,MAAM,WAC3CT,EAAQ3uC,MAAOixD,YAAajxD,KAAKod,eAE3Bpd,QAKT2uC,EAAO/+B,KAAKkjC,QAAQgpB,OAAS,SAAUzsB,GACtC,OAAQV,EAAO/+B,KAAKkjC,QAAQipB,QAAS1sB,IAEtCV,EAAO/+B,KAAKkjC,QAAQipB,QAAU,SAAU1sB,GACvC,SAAWA,EAAK8jB,aAAe9jB,EAAK8kB,cAAgB9kB,EAAK0mB,iBAAiBr0D,SAW3EusC,EAAQ+tB,qBACH9U,GAAOjtB,EAASpiB,eAAemkD,mBAAoB,IAAK9U,MACvDjQ,UAAY,6BACiB,IAA3BiQ,GAAK9pC,WAAW1b,QAQxBitC,EAAOoQ,UAAY,SAAUtoC,EAAMq2B,EAASmvB,GAC3C,MAAqB,iBAATxlD,EACJ,IAEgB,kBAAZq2B,IACXmvB,EAAcnvB,EACdA,GAAU,GAKLA,IAIAmB,EAAQ+tB,qBAMZp5C,GALAkqB,EAAU7S,EAASpiB,eAAemkD,mBAAoB,KAKvC/4C,cAAe,SACzBskB,KAAOtN,EAASjrB,SAASu4B,KAC9BuF,EAAQ2B,KAAK56B,YAAa+O,IAE1BkqB,EAAU7S,GAKZwN,GAAWw0B,GAAe,IAD1BC,EAASvd,EAAW5oB,KAAMtf,IAKlB,CAAEq2B,EAAQ7pB,cAAei5C,EAAQ,MAGzCA,EAASrT,GAAe,CAAEpyC,GAAQq2B,EAASrF,GAEtCA,GAAWA,EAAQ/lC,QACvBitC,EAAQlH,GAAUzqB,SAGZ2xB,EAAOO,MAAO,GAAIgtB,EAAO9+C,cAlChC,IAAIwF,EAAMs5C,EAAQz0B,GAsCnBkH,EAAOpqB,OAAS,CACf43C,UAAW,SAAU9sB,EAAMtvC,EAASyB,GACnC,IAAI46D,EAAaC,EAASC,EAAWC,EAAQC,EAAWC,EACvDzpD,EAAW27B,EAAOoY,IAAK1X,EAAM,YAC7BqtB,EAAU/tB,EAAQU,GAClBud,EAAQ,GAGS,WAAb55C,IACJq8B,EAAKwX,MAAM7zC,SAAW,YAGvBwpD,EAAYE,EAAQn4C,SACpB+3C,EAAY3tB,EAAOoY,IAAK1X,EAAM,OAC9BotB,EAAa9tB,EAAOoY,IAAK1X,EAAM,SACI,aAAbr8B,GAAwC,UAAbA,KAC9CspD,EAAYG,GAAap5D,QAAS,SAAY,GAMhDk5D,GADAH,EAAcM,EAAQ1pD,YACD0jC,IACrB2lB,EAAUD,EAAYjF,OAGtBoF,EAASlJ,WAAYiJ,IAAe,EACpCD,EAAUhJ,WAAYoJ,IAAgB,GAGlCvuB,EAAYnuC,KAGhBA,EAAUA,EAAQ6E,KAAMyqC,EAAM7tC,EAAGmtC,EAAOmB,OAAQ,GAAI0sB,KAGjC,MAAfz8D,EAAQ22C,MACZkW,EAAMlW,IAAQ32C,EAAQ22C,IAAM8lB,EAAU9lB,IAAQ6lB,GAE1B,MAAhBx8D,EAAQo3D,OACZvK,EAAMuK,KAASp3D,EAAQo3D,KAAOqF,EAAUrF,KAASkF,GAG7C,UAAWt8D,EACfA,EAAQ48D,MAAM/3D,KAAMyqC,EAAMud,GAG1B8P,EAAQ3V,IAAK6F,KAKhBje,EAAO/5B,GAAGk7B,OAAQ,CAGjBvrB,OAAQ,SAAUxkB,GAGjB,GAAKY,UAAUe,OACd,YAAmBqK,IAAZhM,EACNC,KACAA,KAAKovC,MAAM,SAAU5tC,GACpBmtC,EAAOpqB,OAAO43C,UAAWn8D,KAAMD,EAASyB,MAI3C,IAAIo7D,EAAMC,EACTxtB,EAAOrvC,KAAM,GAEd,OAAMqvC,EAQAA,EAAK0mB,iBAAiBr0D,QAK5Bk7D,EAAOvtB,EAAK4nB,wBACZ4F,EAAMxtB,EAAK3zB,cAAc+6B,YAClB,CACNC,IAAKkmB,EAAKlmB,IAAMmmB,EAAIC,YACpB3F,KAAMyF,EAAKzF,KAAO0F,EAAIE,cARf,CAAErmB,IAAK,EAAGygB,KAAM,QATxB,GAuBDnkD,SAAU,WACT,GAAMhT,KAAM,GAAZ,CAIA,IAAIg9D,EAAcz4C,EAAQzQ,EACzBu7B,EAAOrvC,KAAM,GACbi9D,EAAe,CAAEvmB,IAAK,EAAGygB,KAAM,GAGhC,GAAwC,UAAnCxoB,EAAOoY,IAAK1X,EAAM,YAGtB9qB,EAAS8qB,EAAK4nB,4BAER,CAON,IANA1yC,EAASvkB,KAAKukB,SAIdzQ,EAAMu7B,EAAK3zB,cACXshD,EAAe3tB,EAAK2tB,cAAgBlpD,EAAIsL,gBAChC49C,IACLA,IAAiBlpD,EAAIozC,MAAQ8V,IAAiBlpD,EAAIsL,kBACT,WAA3CuvB,EAAOoY,IAAKiW,EAAc,aAE1BA,EAAeA,EAAa7mD,WAExB6mD,GAAgBA,IAAiB3tB,GAAkC,IAA1B2tB,EAAaj/C,YAG1Dk/C,EAAetuB,EAAQquB,GAAez4C,UACzBmyB,KAAO/H,EAAOoY,IAAKiW,EAAc,kBAAkB,GAChEC,EAAa9F,MAAQxoB,EAAOoY,IAAKiW,EAAc,mBAAmB,IAKpE,MAAO,CACNtmB,IAAKnyB,EAAOmyB,IAAMumB,EAAavmB,IAAM/H,EAAOoY,IAAK1X,EAAM,aAAa,GACpE8nB,KAAM5yC,EAAO4yC,KAAO8F,EAAa9F,KAAOxoB,EAAOoY,IAAK1X,EAAM,cAAc,MAc1E2tB,aAAc,WACb,OAAOh9D,KAAKkH,KAAK,WAGhB,IAFA,IAAI81D,EAAeh9D,KAAKg9D,aAEhBA,GAA2D,WAA3CruB,EAAOoY,IAAKiW,EAAc,aACjDA,EAAeA,EAAaA,aAG7B,OAAOA,GAAgB59C,SAM1BuvB,EAAOS,KAAM,CAAE8tB,WAAY,cAAeC,UAAW,gBAAiB,SAAU1c,EAAQt0B,GACvF,IAAIuqB,EAAM,gBAAkBvqB,EAE5BwiB,EAAO/5B,GAAI6rC,GAAW,SAAUjS,GAC/B,OAAO4V,EAAQpkD,MAAM,SAAUqvC,EAAMoR,EAAQjS,GAG5C,IAAIquB,EAOJ,GANK1uB,EAAUkB,GACdwtB,EAAMxtB,EACuB,IAAlBA,EAAKtxB,WAChB8+C,EAAMxtB,EAAKoH,kBAGC1qC,IAARyiC,EACJ,OAAOquB,EAAMA,EAAK1wC,GAASkjB,EAAMoR,GAG7Boc,EACJA,EAAIO,SACF1mB,EAAYmmB,EAAIE,YAAVvuB,EACPkI,EAAMlI,EAAMquB,EAAIC,aAIjBztB,EAAMoR,GAAWjS,IAEhBiS,EAAQjS,EAAK7tC,UAAUe,YAU5BitC,EAAOS,KAAM,CAAE,MAAO,SAAU,SAAU4B,EAAI7kB,GAC7CwiB,EAAOqnB,SAAU7pC,GAASimC,GAAcnkB,EAAQylB,eAC/C,SAAUrkB,EAAM0iB,GACf,GAAKA,EAIJ,OAHAA,EAAWD,GAAQziB,EAAMljB,GAGlBqlC,GAAUjiD,KAAMwiD,GACtBpjB,EAAQU,GAAOr8B,WAAYmZ,GAAS,KACpC4lC,QAQLpjB,EAAOS,KAAM,CAAEiuB,OAAQ,SAAUC,MAAO,UAAW,SAAU9wD,EAAM5E,GAClE+mC,EAAOS,KAAM,CACZioB,QAAS,QAAU7qD,EACnByC,QAASrH,EACT,GAAI,QAAU4E,IACZ,SAAU+wD,EAAcC,GAG1B7uB,EAAO/5B,GAAI4oD,GAAa,SAAUpG,EAAQjwD,GACzC,IAAIk9C,EAAY1jD,UAAUe,SAAY67D,GAAkC,kBAAXnG,GAC5D1B,EAAQ6H,KAA6B,IAAXnG,IAA6B,IAAVjwD,EAAiB,SAAW,UAE1E,OAAOi9C,EAAQpkD,MAAM,SAAUqvC,EAAMznC,EAAMT,GAC1C,IAAI2M,EAEJ,OAAKq6B,EAAUkB,GAGyB,IAAhCmuB,EAASn6D,QAAS,SACxBgsC,EAAM,QAAU7iC,GAChB6iC,EAAKpV,SAAS7a,gBAAiB,SAAW5S,GAIrB,IAAlB6iC,EAAKtxB,UACTjK,EAAMu7B,EAAKjwB,gBAIJnV,KAAKotB,IACXgY,EAAK6X,KAAM,SAAW16C,GAAQsH,EAAK,SAAWtH,GAC9C6iC,EAAK6X,KAAM,SAAW16C,GAAQsH,EAAK,SAAWtH,GAC9CsH,EAAK,SAAWtH,UAIDT,IAAV5E,EAGNwnC,EAAOoY,IAAK1X,EAAMznC,EAAM8tD,GAGxB/mB,EAAOkY,MAAOxX,EAAMznC,EAAMT,EAAOuuD,KAChC9tD,EAAMy8C,EAAY+S,OAASrrD,EAAWs4C,UAM5C1V,EAAO/5B,GAAGk7B,OAAQ,CAEjBlvC,KAAM,SAAU8oD,EAAOjzC,EAAM7B,GAC5B,OAAO5U,KAAKuqC,GAAImf,EAAO,KAAMjzC,EAAM7B,IAEpC6oD,OAAQ,SAAU/T,EAAO90C,GACxB,OAAO5U,KAAKqtC,IAAKqc,EAAO,KAAM90C,IAG/B8oD,SAAU,SAAU9uB,EAAU8a,EAAOjzC,EAAM7B,GAC1C,OAAO5U,KAAKuqC,GAAImf,EAAO9a,EAAUn4B,EAAM7B,IAExC+oD,WAAY,SAAU/uB,EAAU8a,EAAO90C,GAGtC,OAA4B,IAArBjU,UAAUe,OAChB1B,KAAKqtC,IAAKuB,EAAU,MACpB5uC,KAAKqtC,IAAKqc,EAAO9a,GAAY,KAAMh6B,IAGrCgpD,MAAO,SAAUC,EAAQC,GACxB,OAAO99D,KAAK+uD,WAAY8O,GAAS7O,WAAY8O,GAASD,MAIxDlvB,EAAOS,KACN,wLAE4DlrC,MAAO,MACnE,SAAU8sC,EAAIxkC,GAGbmiC,EAAO/5B,GAAIpI,GAAS,SAAUiK,EAAM7B,GACnC,OAAOjU,UAAUe,OAAS,EACzB1B,KAAKuqC,GAAI/9B,EAAM,KAAMiK,EAAM7B,GAC3B5U,KAAKqqD,QAAS79C,OAUlB,IAAIwmC,GAAQ,qCAMZrE,EAAOovB,MAAQ,SAAUnpD,EAAIk4B,GAC5B,IAAIrP,EAAKh5B,EAAMs5D,EAUf,GARwB,iBAAZjxB,IACXrP,EAAM7oB,EAAIk4B,GACVA,EAAUl4B,EACVA,EAAK6oB,GAKAyQ,EAAYt5B,GAalB,OARAnQ,EAAOE,EAAMC,KAAMjE,UAAW,GAC9Bo9D,EAAQ,WACP,OAAOnpD,EAAGlU,MAAOosC,GAAW9sC,KAAMyE,EAAKM,OAAQJ,EAAMC,KAAMjE,cAI5Do9D,EAAMjtB,KAAOl8B,EAAGk8B,KAAOl8B,EAAGk8B,MAAQnC,EAAOmC,OAElCitB,GAGRpvB,EAAOqvB,UAAY,SAAUC,GACvBA,EACJtvB,EAAOsV,YAEPtV,EAAOqQ,OAAO,IAGhBrQ,EAAOjnC,QAAUhD,MAAMgD,QACvBinC,EAAOuvB,UAAY98D,KAAKwJ,MACxB+jC,EAAO7uB,SAAWA,EAClB6uB,EAAOT,WAAaA,EACpBS,EAAOR,SAAWA,EAClBQ,EAAOqW,UAAYA,EACnBrW,EAAO/mC,KAAO8mC,EAEdC,EAAOse,IAAM9nD,KAAK8nD,IAElBte,EAAOwvB,UAAY,SAAUhwD,GAK5B,IAAIvG,EAAO+mC,EAAO/mC,KAAMuG,GACxB,OAAkB,WAATvG,GAA8B,WAATA,KAK5B8hC,MAAOv7B,EAAMklD,WAAYllD,KAG5BwgC,EAAOyvB,KAAO,SAAUp8D,GACvB,OAAe,MAARA,EACN,IACEA,EAAO,IAAKyO,QAASuiC,GAAO,UAqB9B,KAFqB,EAAF,WACnB,OAAOrE,GACP,QAFiB,OAEjB,aAMF,IAGC0vB,GAAU/7D,EAAOqsC,OAGjB2vB,GAAKh8D,EAAOi8D,EAwBb,OAtBA5vB,EAAO6vB,WAAa,SAAUh+C,GAS7B,OARKle,EAAOi8D,IAAM5vB,IACjBrsC,EAAOi8D,EAAID,IAGP99C,GAAQle,EAAOqsC,SAAWA,IAC9BrsC,EAAOqsC,OAAS0vB,IAGV1vB,QAMiB,IAAbjB,IACXprC,EAAOqsC,OAASrsC,EAAOi8D,EAAI5vB,GAMrBA,iDC5kRP,mCASA,WACE,aAEA,IAAI/sC,MAAQ,wBACR68D,OAA2B,iBAAXn8D,OAChBjD,KAAOo/D,OAASn8D,OAAS,GACzBjD,KAAKq/D,mBACPD,QAAS,GAEX,IAAIE,YAAcF,QAA0B,iBAAT9+D,KAC/Bi/D,SAAWv/D,KAAKw/D,mBAAwC,iBAAZ9b,SAAwBA,QAAQ+b,UAAY/b,QAAQ+b,SAAS7rD,KACzG2rD,QACFv/D,KAAO,oBAAA0/D,EACEJ,aACTt/D,KAAOM,MAET,IAAIq/D,WAAa3/D,KAAK4/D,qBAAqDz/D,OAAOD,QAC9E2/D,IAAsC,yBACtCC,cAAgB9/D,KAAK+/D,wBAAiD,oBAAhBC,YACtDC,UAAY,mBAAmBp7D,MAAM,IACrCq7D,MAAQ,CAAC,IAAK,MAAO,SAAU,YAC/BC,MAAQ,CAAC,EAAG,EAAG,GAAI,IACnBC,aAAe,CAAC,MAAO,QAAS,SAAU,SAAU,cAAe,UACnEC,mBAAqB,mEAAmEx7D,MAAM,IAE9Fy7D,OAAS,GAAIC,QACjB,GAAIT,aAAc,CAChB,IAAIU,OAAS,IAAIR,YAAY,IAC7BO,QAAU,IAAIvhC,WAAWwhC,QACzBF,OAAS,IAAIG,YAAYD,SAGvBxgE,KAAKw/D,mBAAsBn6D,MAAMgD,UACnChD,MAAMgD,QAAU,SAAUyG,GACxB,MAA+C,mBAAxC/N,OAAOa,UAAUigB,SAAStc,KAAKuJ,MAItCgxD,eAAiB9/D,KAAK0gE,gCAAmCV,YAAYW,SACvEX,YAAYW,OAAS,SAAU7xD,GAC7B,MAAsB,iBAARA,GAAoBA,EAAI0xD,QAAU1xD,EAAI0xD,OAAOzmD,cAAgBimD,cA6D/E,IAAIY,mBAAqB,SAAUC,GACjC,OAAO,SAAUllD,GACf,OAAO,IAAImlD,KAAI,GAAMC,OAAOplD,GAASklD,OAwBrCG,aAAe,WACjB,IAAI5f,EAASwf,mBAAmB,OAC5BrB,UACFne,EAAS6f,SAAS7f,IAEpBA,EAAO7hB,OAAS,WACd,OAAO,IAAIuhC,KAEb1f,EAAO2f,OAAS,SAAUplD,GACxB,OAAOylC,EAAO7hB,SAASwhC,OAAOplD,IAEhC,IAAK,IAAIxZ,EAAI,EAAGA,EAAIi+D,aAAa/9D,SAAUF,EAAG,CAC5C,IAAIoG,EAAO63D,aAAaj+D,GACxBi/C,EAAO74C,GAAQq4D,mBAAmBr4D,GAEpC,OAAO64C,GAGL6f,SAAW,SAAU7f,QACvB,IAAI8f,OAASC,KAAK,qBACdC,OAASD,KAAK,4BACdE,WAAa,SAAU1lD,GACzB,GAAuB,iBAAZA,EACT,OAAOulD,OAAOI,WAAW,OAAOP,OAAOplD,EAAS,QAAQ4lD,OAAO,OAE/D,GAAI5lD,MAAAA,EACF,MAAMpZ,MAKV,OAJaoZ,EAAQ5B,cAAgBimD,cACjCrkD,EAAU,IAAIqjB,WAAWrjB,IAGzBtW,MAAMgD,QAAQsT,IAAYqkD,YAAYW,OAAOhlD,IAC/CA,EAAQ5B,cAAgBqnD,OACjBF,OAAOI,WAAW,OAAOP,OAAO,IAAIK,OAAOzlD,IAAU4lD,OAAO,OAE5DngB,OAAOzlC,IAGlB,OAAO0lD,YAST,SAASP,IAAIU,GACX,GAAIA,EACFlB,OAAO,GAAKA,OAAO,IAAMA,OAAO,GAAKA,OAAO,GAAKA,OAAO,GACxDA,OAAO,GAAKA,OAAO,GAAKA,OAAO,GAAKA,OAAO,GAC3CA,OAAO,GAAKA,OAAO,GAAKA,OAAO,IAAMA,OAAO,IAC5CA,OAAO,IAAMA,OAAO,IAAMA,OAAO,IAAMA,OAAO,IAAM,EACpD3/D,KAAK2/D,OAASA,OACd3/D,KAAK4/D,QAAUA,aAEf,GAAIT,aAAc,CAChB,IAAIU,EAAS,IAAIR,YAAY,IAC7Br/D,KAAK4/D,QAAU,IAAIvhC,WAAWwhC,GAC9B7/D,KAAK2/D,OAAS,IAAIG,YAAYD,QAE9B7/D,KAAK2/D,OAAS,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAGnE3/D,KAAK8gE,GAAK9gE,KAAK+gE,GAAK/gE,KAAKghE,GAAKhhE,KAAKihE,GAAKjhE,KAAKoC,MAAQpC,KAAKkhE,MAAQlhE,KAAKmhE,OAAS,EAChFnhE,KAAKohE,UAAYphE,KAAKqhE,QAAS,EAC/BrhE,KAAKsvC,OAAQ,EAYf6wB,IAAIl/D,UAAUm/D,OAAS,SAAUplD,GAC/B,IAAIhb,KAAKohE,UAAT,CAIA,IAAIE,EAAW15D,SAAcoT,EAC7B,GAAa,WAATpT,EAAmB,CACrB,GAAa,WAATA,EAWF,MAAMhG,MAVN,GAAgB,OAAZoZ,EACF,MAAMpZ,MACD,GAAIu9D,cAAgBnkD,EAAQ5B,cAAgBimD,YACjDrkD,EAAU,IAAIqjB,WAAWrjB,QACpB,KAAKtW,MAAMgD,QAAQsT,IACnBmkD,cAAiBE,YAAYW,OAAOhlD,IACvC,MAAMpZ,MAMZ0/D,GAAY,EAKd,IAHA,IAAIvmD,EAAiBvZ,EAAX8I,EAAQ,EAAM5I,EAASsZ,EAAQtZ,OAAQi+D,EAAS3/D,KAAK2/D,OAC3DC,EAAU5/D,KAAK4/D,QAEZt1D,EAAQ5I,GAAQ,CAUrB,GATI1B,KAAKqhE,SACPrhE,KAAKqhE,QAAS,EACd1B,EAAO,GAAKA,EAAO,IACnBA,EAAO,IAAMA,EAAO,GAAKA,EAAO,GAAKA,EAAO,GAC5CA,EAAO,GAAKA,EAAO,GAAKA,EAAO,GAAKA,EAAO,GAC3CA,EAAO,GAAKA,EAAO,GAAKA,EAAO,IAAMA,EAAO,IAC5CA,EAAO,IAAMA,EAAO,IAAMA,EAAO,IAAMA,EAAO,IAAM,GAGlD2B,EACF,GAAInC,aACF,IAAK39D,EAAIxB,KAAKoC,MAAOkI,EAAQ5I,GAAUF,EAAI,KAAM8I,EAC/Cs1D,EAAQp+D,KAAOwZ,EAAQ1Q,QAGzB,IAAK9I,EAAIxB,KAAKoC,MAAOkI,EAAQ5I,GAAUF,EAAI,KAAM8I,EAC/Cq1D,EAAOn+D,GAAK,IAAMwZ,EAAQ1Q,IAAUk1D,MAAY,EAANh+D,UAI9C,GAAI29D,aACF,IAAK39D,EAAIxB,KAAKoC,MAAOkI,EAAQ5I,GAAUF,EAAI,KAAM8I,GAC/CyQ,EAAOC,EAAQ0B,WAAWpS,IACf,IACTs1D,EAAQp+D,KAAOuZ,EACNA,EAAO,MAChB6kD,EAAQp+D,KAAO,IAAQuZ,GAAQ,EAC/B6kD,EAAQp+D,KAAO,IAAe,GAAPuZ,GACdA,EAAO,OAAUA,GAAQ,OAClC6kD,EAAQp+D,KAAO,IAAQuZ,GAAQ,GAC/B6kD,EAAQp+D,KAAO,IAASuZ,GAAQ,EAAK,GACrC6kD,EAAQp+D,KAAO,IAAe,GAAPuZ,IAEvBA,EAAO,QAAoB,KAAPA,IAAiB,GAAqC,KAA9BC,EAAQ0B,aAAapS,IACjEs1D,EAAQp+D,KAAO,IAAQuZ,GAAQ,GAC/B6kD,EAAQp+D,KAAO,IAASuZ,GAAQ,GAAM,GACtC6kD,EAAQp+D,KAAO,IAASuZ,GAAQ,EAAK,GACrC6kD,EAAQp+D,KAAO,IAAe,GAAPuZ,QAI3B,IAAKvZ,EAAIxB,KAAKoC,MAAOkI,EAAQ5I,GAAUF,EAAI,KAAM8I,GAC/CyQ,EAAOC,EAAQ0B,WAAWpS,IACf,IACTq1D,EAAOn+D,GAAK,IAAMuZ,GAAQykD,MAAY,EAANh+D,KACvBuZ,EAAO,MAChB4kD,EAAOn+D,GAAK,KAAO,IAAQuZ,GAAQ,IAAOykD,MAAY,EAANh+D,KAChDm+D,EAAOn+D,GAAK,KAAO,IAAe,GAAPuZ,IAAiBykD,MAAY,EAANh+D,MACzCuZ,EAAO,OAAUA,GAAQ,OAClC4kD,EAAOn+D,GAAK,KAAO,IAAQuZ,GAAQ,KAAQykD,MAAY,EAANh+D,KACjDm+D,EAAOn+D,GAAK,KAAO,IAASuZ,GAAQ,EAAK,KAAUykD,MAAY,EAANh+D,KACzDm+D,EAAOn+D,GAAK,KAAO,IAAe,GAAPuZ,IAAiBykD,MAAY,EAANh+D,OAElDuZ,EAAO,QAAoB,KAAPA,IAAiB,GAAqC,KAA9BC,EAAQ0B,aAAapS,IACjEq1D,EAAOn+D,GAAK,KAAO,IAAQuZ,GAAQ,KAAQykD,MAAY,EAANh+D,KACjDm+D,EAAOn+D,GAAK,KAAO,IAASuZ,GAAQ,GAAM,KAAUykD,MAAY,EAANh+D,KAC1Dm+D,EAAOn+D,GAAK,KAAO,IAASuZ,GAAQ,EAAK,KAAUykD,MAAY,EAANh+D,KACzDm+D,EAAOn+D,GAAK,KAAO,IAAe,GAAPuZ,IAAiBykD,MAAY,EAANh+D,MAK1DxB,KAAKuhE,cAAgB//D,EACrBxB,KAAKkhE,OAAS1/D,EAAIxB,KAAKoC,MACnBZ,GAAK,IACPxB,KAAKoC,MAAQZ,EAAI,GACjBxB,KAAK26B,OACL36B,KAAKqhE,QAAS,GAEdrhE,KAAKoC,MAAQZ,EAOjB,OAJIxB,KAAKkhE,MAAQ,aACflhE,KAAKmhE,QAAUnhE,KAAKkhE,MAAQ,YAAc,EAC1ClhE,KAAKkhE,MAAQlhE,KAAKkhE,MAAQ,YAErBlhE,OAGTmgE,IAAIl/D,UAAUugE,SAAW,WACvB,IAAIxhE,KAAKohE,UAAT,CAGAphE,KAAKohE,WAAY,EACjB,IAAIzB,EAAS3/D,KAAK2/D,OAAQn+D,EAAIxB,KAAKuhE,cACnC5B,EAAOn+D,GAAK,IAAM+9D,MAAU,EAAJ/9D,GACpBA,GAAK,KACFxB,KAAKqhE,QACRrhE,KAAK26B,OAEPglC,EAAO,GAAKA,EAAO,IACnBA,EAAO,IAAMA,EAAO,GAAKA,EAAO,GAAKA,EAAO,GAC5CA,EAAO,GAAKA,EAAO,GAAKA,EAAO,GAAKA,EAAO,GAC3CA,EAAO,GAAKA,EAAO,GAAKA,EAAO,IAAMA,EAAO,IAC5CA,EAAO,IAAMA,EAAO,IAAMA,EAAO,IAAMA,EAAO,IAAM,GAEtDA,EAAO,IAAM3/D,KAAKkhE,OAAS,EAC3BvB,EAAO,IAAM3/D,KAAKmhE,QAAU,EAAInhE,KAAKkhE,QAAU,GAC/ClhE,KAAK26B,SAGPwlC,IAAIl/D,UAAU05B,KAAO,WACnB,IAAIttB,EAAGD,EAAGD,EAAG6sB,EAAGynC,EAAIC,EAAI/B,EAAS3/D,KAAK2/D,OAElC3/D,KAAKsvC,MAQPliC,IADAA,IALAC,IADAA,EAAIsyD,EAAO,GAAK,YACN,EAAItyD,IAAM,IAAM,WAAa,IAIvCF,IADAA,IAAM,WADN6sB,IADAA,IAAM,WAAiB,WAAJ3sB,GAAkBsyD,EAAO,GAAK,YACvC,GAAK3lC,IAAM,IAAM3sB,GAAK,KACH,UAALA,IAAoBsyD,EAAO,GAAK,aAC9C,GAAKxyD,IAAM,IAAM6sB,GAAK,IACjBA,EAAI3sB,IAAOsyD,EAAO,GAAK,aAC5B,GAAKvyD,IAAM,IAAMD,GAAK,GAEhCE,EAAIrN,KAAK8gE,GACT1zD,EAAIpN,KAAK+gE,GACT5zD,EAAInN,KAAKghE,GAST5zD,IADAA,KALAC,IADAA,KADA2sB,EAAIh6B,KAAKihE,IACE7zD,GAAKD,EAAI6sB,IAAO2lC,EAAO,GAAK,YAC7B,EAAItyD,IAAM,IAAMD,GAAK,IAI/BD,IADAA,IAAMC,GADN4sB,IADAA,IAAM7sB,EAAKE,GAAKD,EAAID,IAAOwyD,EAAO,GAAK,YAC7B,GAAK3lC,IAAM,IAAM3sB,GAAK,IAChBA,EAAID,IAAOuyD,EAAO,GAAK,YAC7B,GAAKxyD,IAAM,IAAM6sB,GAAK,IAChBA,EAAI3sB,IAAOsyD,EAAO,GAAK,aAC7B,GAAKvyD,IAAM,IAAMD,GAAK,GAUlCC,IADAA,KALAC,IADAA,IAAM2sB,EAAK5sB,GAAKD,EAAI6sB,IAAO2lC,EAAO,GAAK,YAC7B,EAAItyD,IAAM,IAAMD,GAAK,IAI/BD,IADAA,IAAMC,GADN4sB,IADAA,IAAM7sB,EAAKE,GAAKD,EAAID,IAAOwyD,EAAO,GAAK,aAC7B,GAAK3lC,IAAM,IAAM3sB,GAAK,IAChBA,EAAID,IAAOuyD,EAAO,GAAK,aAC7B,GAAKxyD,IAAM,IAAM6sB,GAAK,IAChBA,EAAI3sB,IAAOsyD,EAAO,GAAK,WAC7B,GAAKvyD,IAAM,IAAMD,GAAK,EAQhCC,IADAA,KALAC,IADAA,IAAM2sB,EAAK5sB,GAAKD,EAAI6sB,IAAO2lC,EAAO,GAAK,aAC7B,EAAItyD,IAAM,IAAMD,GAAK,IAI/BD,IADAA,IAAMC,GADN4sB,IADAA,IAAM7sB,EAAKE,GAAKD,EAAID,IAAOwyD,EAAO,GAAK,aAC7B,GAAK3lC,IAAM,IAAM3sB,GAAK,IAChBA,EAAID,IAAOuyD,EAAO,IAAM,QAC9B,GAAKxyD,IAAM,IAAM6sB,GAAK,IAChBA,EAAI3sB,IAAOsyD,EAAO,IAAM,aAC9B,GAAKvyD,IAAM,IAAMD,GAAK,EAQhCC,IADAA,KALAC,IADAA,IAAM2sB,EAAK5sB,GAAKD,EAAI6sB,IAAO2lC,EAAO,IAAM,aAC9B,EAAItyD,IAAM,IAAMD,GAAK,IAI/BD,IADAA,IAAMC,GADN4sB,IADAA,IAAM7sB,EAAKE,GAAKD,EAAID,IAAOwyD,EAAO,IAAM,WAC9B,GAAK3lC,IAAM,IAAM3sB,GAAK,IAChBA,EAAID,IAAOuyD,EAAO,IAAM,aAC9B,GAAKxyD,IAAM,IAAM6sB,GAAK,IAChBA,EAAI3sB,IAAOsyD,EAAO,IAAM,aAC9B,GAAKvyD,IAAM,IAAMD,GAAK,EAQhCC,IADAA,KAHA4sB,IADAA,IAAM5sB,EAAKD,IADXE,IADAA,IAAMF,EAAK6sB,GAAK5sB,EAAID,IAAOwyD,EAAO,GAAK,YAC7B,EAAItyD,IAAM,IAAMD,GAAK,GACXA,IAAOuyD,EAAO,GAAK,aAC7B,EAAI3lC,IAAM,IAAM3sB,GAAK,GAGpBA,IADXF,IADAA,IAAME,EAAKD,GAAK4sB,EAAI3sB,IAAOsyD,EAAO,IAAM,YAC9B,GAAKxyD,IAAM,IAAM6sB,GAAK,GACZA,IAAO2lC,EAAO,GAAK,YAC7B,GAAKvyD,IAAM,IAAMD,GAAK,EAQhCC,IADAA,KAHA4sB,IADAA,IAAM5sB,EAAKD,IADXE,IADAA,IAAMF,EAAK6sB,GAAK5sB,EAAID,IAAOwyD,EAAO,GAAK,YAC7B,EAAItyD,IAAM,IAAMD,GAAK,GACXA,IAAOuyD,EAAO,IAAM,WAC9B,EAAI3lC,IAAM,IAAM3sB,GAAK,GAGpBA,IADXF,IADAA,IAAME,EAAKD,GAAK4sB,EAAI3sB,IAAOsyD,EAAO,IAAM,YAC9B,GAAKxyD,IAAM,IAAM6sB,GAAK,GACZA,IAAO2lC,EAAO,GAAK,YAC7B,GAAKvyD,IAAM,IAAMD,GAAK,EAQhCC,IADAA,KAHA4sB,IADAA,IAAM5sB,EAAKD,IADXE,IADAA,IAAMF,EAAK6sB,GAAK5sB,EAAID,IAAOwyD,EAAO,GAAK,YAC7B,EAAItyD,IAAM,IAAMD,GAAK,GACXA,IAAOuyD,EAAO,IAAM,aAC9B,EAAI3lC,IAAM,IAAM3sB,GAAK,GAGpBA,IADXF,IADAA,IAAME,EAAKD,GAAK4sB,EAAI3sB,IAAOsyD,EAAO,GAAK,YAC7B,GAAKxyD,IAAM,IAAM6sB,GAAK,GACZA,IAAO2lC,EAAO,GAAK,aAC7B,GAAKvyD,IAAM,IAAMD,GAAK,EAQhCC,IADAA,KAHA4sB,IADAA,IAAM5sB,EAAKD,IADXE,IADAA,IAAMF,EAAK6sB,GAAK5sB,EAAID,IAAOwyD,EAAO,IAAM,aAC9B,EAAItyD,IAAM,IAAMD,GAAK,GACXA,IAAOuyD,EAAO,GAAK,WAC7B,EAAI3lC,IAAM,IAAM3sB,GAAK,GAGpBA,IADXF,IADAA,IAAME,EAAKD,GAAK4sB,EAAI3sB,IAAOsyD,EAAO,GAAK,aAC7B,GAAKxyD,IAAM,IAAM6sB,GAAK,GACZA,IAAO2lC,EAAO,IAAM,aAC9B,GAAKvyD,IAAM,IAAMD,GAAK,EAUhCC,IADAA,KAHAs0D,GADA1nC,IADAA,KAHAynC,EAAKr0D,EAAID,IAETE,IADAA,IAAMo0D,EAAKznC,GAAK2lC,EAAO,GAAK,SAClB,EAAItyD,IAAM,IAAMD,GAAK,IACfuyD,EAAO,GAAK,aAClB,GAAK3lC,IAAM,IAAM3sB,GAAK,GACvBA,IAETF,IADAA,IAAMu0D,EAAKt0D,GAAKuyD,EAAO,IAAM,aACnB,GAAKxyD,IAAM,IAAM6sB,GAAK,IAChB2lC,EAAO,IAAM,WACnB,GAAKvyD,IAAM,GAAKD,GAAK,EAU/BC,IADAA,KAHAs0D,GADA1nC,IADAA,KAHAynC,EAAKr0D,EAAID,IAETE,IADAA,IAAMo0D,EAAKznC,GAAK2lC,EAAO,GAAK,aAClB,EAAItyD,IAAM,IAAMD,GAAK,IACfuyD,EAAO,GAAK,aAClB,GAAK3lC,IAAM,IAAM3sB,GAAK,GACvBA,IAETF,IADAA,IAAMu0D,EAAKt0D,GAAKuyD,EAAO,GAAK,YAClB,GAAKxyD,IAAM,IAAM6sB,GAAK,IAChB2lC,EAAO,IAAM,aACnB,GAAKvyD,IAAM,GAAKD,GAAK,EAU/BC,IADAA,KAHAs0D,GADA1nC,IADAA,KAHAynC,EAAKr0D,EAAID,IAETE,IADAA,IAAMo0D,EAAKznC,GAAK2lC,EAAO,IAAM,YACnB,EAAItyD,IAAM,IAAMD,GAAK,IACfuyD,EAAO,GAAK,YAClB,GAAK3lC,IAAM,IAAM3sB,GAAK,GACvBA,IAETF,IADAA,IAAMu0D,EAAKt0D,GAAKuyD,EAAO,GAAK,YAClB,GAAKxyD,IAAM,IAAM6sB,GAAK,IAChB2lC,EAAO,GAAK,WAClB,GAAKvyD,IAAM,GAAKD,GAAK,EAU/BC,IADAA,KAHAs0D,GADA1nC,IADAA,KAHAynC,EAAKr0D,EAAID,IAETE,IADAA,IAAMo0D,EAAKznC,GAAK2lC,EAAO,GAAK,YAClB,EAAItyD,IAAM,IAAMD,GAAK,IACfuyD,EAAO,IAAM,YACnB,GAAK3lC,IAAM,IAAM3sB,GAAK,GACvBA,IAETF,IADAA,IAAMu0D,EAAKt0D,GAAKuyD,EAAO,IAAM,YACnB,GAAKxyD,IAAM,IAAM6sB,GAAK,IAChB2lC,EAAO,GAAK,YAClB,GAAKvyD,IAAM,GAAKD,GAAK,EAQ/BC,IADAA,KAHA4sB,IADAA,IAAM5sB,IADNC,IADAA,IAAMF,GAAKC,GAAK4sB,IAAM2lC,EAAO,GAAK,YACxB,EAAItyD,IAAM,IAAMD,GAAK,IACfD,IAAMwyD,EAAO,GAAK,aACxB,GAAK3lC,IAAM,IAAM3sB,GAAK,KAEhCF,IADAA,IAAME,GAAK2sB,GAAK5sB,IAAMuyD,EAAO,IAAM,aACzB,GAAKxyD,IAAM,IAAM6sB,GAAK,IAChB3sB,IAAMsyD,EAAO,GAAK,WACxB,GAAKvyD,IAAM,IAAMD,GAAK,EAQhCC,IADAA,KAHA4sB,IADAA,IAAM5sB,IADNC,IADAA,IAAMF,GAAKC,GAAK4sB,IAAM2lC,EAAO,IAAM,aACzB,EAAItyD,IAAM,IAAMD,GAAK,IACfD,IAAMwyD,EAAO,GAAK,aACxB,GAAK3lC,IAAM,IAAM3sB,GAAK,KAEhCF,IADAA,IAAME,GAAK2sB,GAAK5sB,IAAMuyD,EAAO,IAAM,UACzB,GAAKxyD,IAAM,IAAM6sB,GAAK,IAChB3sB,IAAMsyD,EAAO,GAAK,aACxB,GAAKvyD,IAAM,IAAMD,GAAK,EAQhCC,IADAA,KAHA4sB,IADAA,IAAM5sB,IADNC,IADAA,IAAMF,GAAKC,GAAK4sB,IAAM2lC,EAAO,GAAK,aACxB,EAAItyD,IAAM,IAAMD,GAAK,IACfD,IAAMwyD,EAAO,IAAM,WACzB,GAAK3lC,IAAM,IAAM3sB,GAAK,KAEhCF,IADAA,IAAME,GAAK2sB,GAAK5sB,IAAMuyD,EAAO,GAAK,aACxB,GAAKxyD,IAAM,IAAM6sB,GAAK,IAChB3sB,IAAMsyD,EAAO,IAAM,aACzB,GAAKvyD,IAAM,IAAMD,GAAK,EAQhCC,IADAA,KAHA4sB,IADAA,IAAM5sB,IADNC,IADAA,IAAMF,GAAKC,GAAK4sB,IAAM2lC,EAAO,GAAK,YACxB,EAAItyD,IAAM,IAAMD,GAAK,IACfD,IAAMwyD,EAAO,IAAM,aACzB,GAAK3lC,IAAM,IAAM3sB,GAAK,KAEhCF,IADAA,IAAME,GAAK2sB,GAAK5sB,IAAMuyD,EAAO,GAAK,YACxB,GAAKxyD,IAAM,IAAM6sB,GAAK,IAChB3sB,IAAMsyD,EAAO,GAAK,YACxB,GAAKvyD,IAAM,IAAMD,GAAK,EAE5BnN,KAAKsvC,OACPtvC,KAAK8gE,GAAKzzD,EAAI,YAAc,EAC5BrN,KAAK+gE,GAAK3zD,EAAI,WAAa,EAC3BpN,KAAKghE,GAAK7zD,EAAI,YAAc,EAC5BnN,KAAKihE,GAAKjnC,EAAI,WAAa,EAC3Bh6B,KAAKsvC,OAAQ,IAEbtvC,KAAK8gE,GAAK9gE,KAAK8gE,GAAKzzD,GAAK,EACzBrN,KAAK+gE,GAAK/gE,KAAK+gE,GAAK3zD,GAAK,EACzBpN,KAAKghE,GAAKhhE,KAAKghE,GAAK7zD,GAAK,EACzBnN,KAAKihE,GAAKjhE,KAAKihE,GAAKjnC,GAAK,IAc7BmmC,IAAIl/D,UAAU0gE,IAAM,WAClB3hE,KAAKwhE,WAEL,IAAIV,EAAK9gE,KAAK8gE,GAAIC,EAAK/gE,KAAK+gE,GAAIC,EAAKhhE,KAAKghE,GAAIC,EAAKjhE,KAAKihE,GAExD,OAAO3B,UAAWwB,GAAM,EAAK,IAAQxB,UAAe,GAALwB,GAC7CxB,UAAWwB,GAAM,GAAM,IAAQxB,UAAWwB,GAAM,EAAK,IACrDxB,UAAWwB,GAAM,GAAM,IAAQxB,UAAWwB,GAAM,GAAM,IACtDxB,UAAWwB,GAAM,GAAM,IAAQxB,UAAWwB,GAAM,GAAM,IACtDxB,UAAWyB,GAAM,EAAK,IAAQzB,UAAe,GAALyB,GACxCzB,UAAWyB,GAAM,GAAM,IAAQzB,UAAWyB,GAAM,EAAK,IACrDzB,UAAWyB,GAAM,GAAM,IAAQzB,UAAWyB,GAAM,GAAM,IACtDzB,UAAWyB,GAAM,GAAM,IAAQzB,UAAWyB,GAAM,GAAM,IACtDzB,UAAW0B,GAAM,EAAK,IAAQ1B,UAAe,GAAL0B,GACxC1B,UAAW0B,GAAM,GAAM,IAAQ1B,UAAW0B,GAAM,EAAK,IACrD1B,UAAW0B,GAAM,GAAM,IAAQ1B,UAAW0B,GAAM,GAAM,IACtD1B,UAAW0B,GAAM,GAAM,IAAQ1B,UAAW0B,GAAM,GAAM,IACtD1B,UAAW2B,GAAM,EAAK,IAAQ3B,UAAe,GAAL2B,GACxC3B,UAAW2B,GAAM,GAAM,IAAQ3B,UAAW2B,GAAM,EAAK,IACrD3B,UAAW2B,GAAM,GAAM,IAAQ3B,UAAW2B,GAAM,GAAM,IACtD3B,UAAW2B,GAAM,GAAM,IAAQ3B,UAAW2B,GAAM,GAAM,KAa1Dd,IAAIl/D,UAAUigB,SAAWi/C,IAAIl/D,UAAU0gE,IAYvCxB,IAAIl/D,UAAU2/D,OAAS,WACrB5gE,KAAKwhE,WAEL,IAAIV,EAAK9gE,KAAK8gE,GAAIC,EAAK/gE,KAAK+gE,GAAIC,EAAKhhE,KAAKghE,GAAIC,EAAKjhE,KAAKihE,GACxD,MAAO,CACA,IAALH,EAAYA,GAAM,EAAK,IAAOA,GAAM,GAAM,IAAOA,GAAM,GAAM,IACxD,IAALC,EAAYA,GAAM,EAAK,IAAOA,GAAM,GAAM,IAAOA,GAAM,GAAM,IACxD,IAALC,EAAYA,GAAM,EAAK,IAAOA,GAAM,GAAM,IAAOA,GAAM,GAAM,IACxD,IAALC,EAAYA,GAAM,EAAK,IAAOA,GAAM,GAAM,IAAOA,GAAM,GAAM,MAcjEd,IAAIl/D,UAAUsJ,MAAQ41D,IAAIl/D,UAAU2/D,OAYpCT,IAAIl/D,UAAU2gE,YAAc,WAC1B5hE,KAAKwhE,WAEL,IAAI3B,EAAS,IAAIR,YAAY,IACzBM,EAAS,IAAIG,YAAYD,GAK7B,OAJAF,EAAO,GAAK3/D,KAAK8gE,GACjBnB,EAAO,GAAK3/D,KAAK+gE,GACjBpB,EAAO,GAAK3/D,KAAKghE,GACjBrB,EAAO,GAAK3/D,KAAKihE,GACVpB,GAcTM,IAAIl/D,UAAU4+D,OAASM,IAAIl/D,UAAU2gE,YAYrCzB,IAAIl/D,UAAU4gE,OAAS,WAErB,IADA,IAAIC,EAAIC,EAAIC,EAAIC,EAAY,GAAIf,EAAQlhE,KAAKuK,QACpC/I,EAAI,EAAGA,EAAI,IAClBsgE,EAAKZ,EAAM1/D,KACXugE,EAAKb,EAAM1/D,KACXwgE,EAAKd,EAAM1/D,KACXygE,GAAavC,mBAAmBoC,IAAO,GACrCpC,mBAA0C,IAAtBoC,GAAM,EAAIC,IAAO,IACrCrC,mBAA0C,IAAtBqC,GAAM,EAAIC,IAAO,IACrCtC,mBAAwB,GAALsC,GAMvB,OAJAF,EAAKZ,EAAM1/D,GACXygE,GAAavC,mBAAmBoC,IAAO,GACrCpC,mBAAoBoC,GAAM,EAAK,IAC/B,OAIJ,IAAIviE,QAAU8gE,eAEVrB,UACFx/D,OAAOD,QAAUA,SAmBjBF,KAAK6iE,IAAM3iE,QACP2/D,MACF,yCACE,OAAO3/D,SACR,2IA9pBP,6BCCA,IAGI4iE,EAAiB,4BAGjBC,EAAmB,iBAGnBC,EAAU,qBAEVC,EAAU,mBACVC,EAAU,gBAEVC,EAAU,oBACVC,EAAS,6BACTC,EAAS,eACTC,EAAY,kBACZC,EAAY,kBACZC,EAAa,mBACbC,EAAY,kBACZC,EAAS,eACTC,EAAY,kBACZC,EAAY,kBACZC,EAAa,mBAEbC,EAAiB,uBACjBC,EAAc,oBACdC,EAAa,wBACbC,EAAa,wBACbC,EAAU,qBACVC,EAAW,sBACXC,EAAW,sBACXC,EAAW,sBACXC,EAAkB,6BAClBC,EAAY,uBACZC,EAAY,uBASZC,EAAU,OAGVC,EAAe,8BAGfC,EAAW,mBAGXC,EAAgB,GACpBA,EAAc5B,GAAW4B,EA7CV,kBA8CfA,EAAcd,GAAkBc,EAAcb,GAC9Ca,EAAc3B,GAAW2B,EAAc1B,GACvC0B,EAAcZ,GAAcY,EAAcX,GAC1CW,EAAcV,GAAWU,EAAcT,GACvCS,EAAcR,GAAYQ,EAAcvB,GACxCuB,EAActB,GAAasB,EAAcrB,GACzCqB,EAAcnB,GAAamB,EAAclB,GACzCkB,EAAcjB,GAAaiB,EAAchB,GACzCgB,EAAcP,GAAYO,EAAcN,GACxCM,EAAcL,GAAaK,EAAcJ,IAAa,EACtDI,EArDe,kBAqDWA,EAAczB,GACxCyB,EAAcf,IAAc,EAG5B,IAAIgB,EAA8B,iBAAV,EAAAnF,GAAsB,EAAAA,GAAU,EAAAA,EAAO3+D,SAAWA,QAAU,EAAA2+D,EAGhFoF,EAA0B,iBAARxkE,MAAoBA,MAAQA,KAAKS,SAAWA,QAAUT,KAGxEN,EAAO6kE,GAAcC,GAAYvzD,SAAS,cAATA,GAGjCwzD,EAA4C7kE,IAAYA,EAAQwe,UAAYxe,EAG5E8kE,EAAaD,GAA4C5kE,IAAWA,EAAOue,UAAYve,EAGvF8kE,EAAgBD,GAAcA,EAAW9kE,UAAY6kE,EAUzD,SAASG,EAAYr9D,EAAKs9D,GAGxB,OADAt9D,EAAIge,IAAIs/C,EAAK,GAAIA,EAAK,IACft9D,EAWT,SAASu9D,EAAYv/C,EAAK/d,GAGxB,OADA+d,EAAIy6B,IAAIx4C,GACD+d,EAuDT,SAASw/C,EAAYn6D,EAAOo6D,EAAUC,EAAaC,GACjD,IAAIv6D,GAAS,EACT5I,EAAS6I,EAAQA,EAAM7I,OAAS,EAKpC,IAHImjE,GAAanjE,IACfkjE,EAAcr6D,IAAQD,MAEfA,EAAQ5I,GACfkjE,EAAcD,EAASC,EAAar6D,EAAMD,GAAQA,EAAOC,GAE3D,OAAOq6D,EAyCT,SAASE,EAAa39D,GAGpB,IAAImyB,GAAS,EACb,GAAa,MAATnyB,GAA0C,mBAAlBA,EAAM+Z,SAChC,IACEoY,KAAYnyB,EAAQ,IACpB,MAAO4F,IAEX,OAAOusB,EAUT,SAASyrC,EAAW79D,GAClB,IAAIoD,GAAS,EACTgvB,EAAS50B,MAAMwC,EAAI89D,MAKvB,OAHA99D,EAAI3G,SAAQ,SAAS4G,EAAO+G,GAC1BorB,IAAShvB,GAAS,CAAC4D,EAAK/G,MAEnBmyB,EAWT,SAAS2rC,EAAQtjB,EAAMr7C,GACrB,OAAO,SAAS3E,GACd,OAAOggD,EAAKr7C,EAAU3E,KAW1B,SAASujE,EAAWhgD,GAClB,IAAI5a,GAAS,EACTgvB,EAAS50B,MAAMwgB,EAAI8/C,MAKvB,OAHA9/C,EAAI3kB,SAAQ,SAAS4G,GACnBmyB,IAAShvB,GAASnD,KAEbmyB,EAIT,IASM8rB,EATF+f,EAAazgE,MAAMzD,UACnBmkE,EAAYx0D,SAAS3P,UACrBokE,EAAcjlE,OAAOa,UAGrBqkE,EAAajmE,EAAK,sBAGlBkmE,GACEngB,EAAM,SAASrvB,KAAKuvC,GAAcA,EAAWjlE,MAAQilE,EAAWjlE,KAAKmlE,UAAY,KACvE,iBAAmBpgB,EAAO,GAItCqgB,EAAeL,EAAUlkD,SAGzBzI,GAAiB4sD,EAAY5sD,eAO7BitD,GAAiBL,EAAYnkD,SAG7BykD,GAAa33D,OAAO,IACtBy3D,EAAa7gE,KAAK6T,IAAgBhI,QAzQjB,sBAyQuC,QACvDA,QAAQ,yDAA0D,SAAW,KAI5EgwD,GAAS6D,EAAgBjlE,EAAKohE,YAAS10D,EACvC0yB,GAASp/B,EAAKo/B,OACdJ,GAAah/B,EAAKg/B,WAClBunC,GAAeX,EAAQ7kE,OAAOqsC,eAAgBrsC,QAC9CylE,GAAezlE,OAAOw+B,OACtBknC,GAAuBT,EAAYS,qBACnCtiE,GAAS2hE,EAAW3hE,OAGpBuiE,GAAmB3lE,OAAOmpC,sBAC1By8B,GAAiBvF,GAASA,GAAOwF,cAAWl6D,EAC5Cm6D,GAAajB,EAAQ7kE,OAAOC,KAAMD,QAGlC+lE,GAAWC,GAAU/mE,EAAM,YAC3BgnE,GAAMD,GAAU/mE,EAAM,OACtB0qC,GAAUq8B,GAAU/mE,EAAM,WAC1BinE,GAAMF,GAAU/mE,EAAM,OACtBknE,GAAUH,GAAU/mE,EAAM,WAC1BmnE,GAAeJ,GAAUhmE,OAAQ,UAGjCqmE,GAAqBC,GAASP,IAC9BQ,GAAgBD,GAASL,IACzBO,GAAoBF,GAAS38B,IAC7B88B,GAAgBH,GAASJ,IACzBQ,GAAoBJ,GAASH,IAG7BQ,GAActoC,GAASA,GAAOx9B,eAAY8K,EAC1Ci7D,GAAgBD,GAAcA,GAAYE,aAAUl7D,EASxD,SAASm7D,GAAKC,GACZ,IAAI78D,GAAS,EACT5I,EAASylE,EAAUA,EAAQzlE,OAAS,EAGxC,IADA1B,KAAKonE,UACI98D,EAAQ5I,GAAQ,CACvB,IAAI2lE,EAAQF,EAAQ78D,GACpBtK,KAAKklB,IAAImiD,EAAM,GAAIA,EAAM,KA2F7B,SAASC,GAAUH,GACjB,IAAI78D,GAAS,EACT5I,EAASylE,EAAUA,EAAQzlE,OAAS,EAGxC,IADA1B,KAAKonE,UACI98D,EAAQ5I,GAAQ,CACvB,IAAI2lE,EAAQF,EAAQ78D,GACpBtK,KAAKklB,IAAImiD,EAAM,GAAIA,EAAM,KAyG7B,SAASE,GAASJ,GAChB,IAAI78D,GAAS,EACT5I,EAASylE,EAAUA,EAAQzlE,OAAS,EAGxC,IADA1B,KAAKonE,UACI98D,EAAQ5I,GAAQ,CACvB,IAAI2lE,EAAQF,EAAQ78D,GACpBtK,KAAKklB,IAAImiD,EAAM,GAAIA,EAAM,KAuF7B,SAASG,GAAML,GACbnnE,KAAKynE,SAAW,IAAIH,GAAUH,GAyHhC,SAASO,GAAYn2D,EAAQrD,EAAK/G,GAChC,IAAIwgE,EAAWp2D,EAAOrD,GAChBuK,GAAe7T,KAAK2M,EAAQrD,IAAQqhC,GAAGo4B,EAAUxgE,UACxC4E,IAAV5E,GAAyB+G,KAAOqD,KACnCA,EAAOrD,GAAO/G,GAYlB,SAASygE,GAAar9D,EAAO2D,GAE3B,IADA,IAAIxM,EAAS6I,EAAM7I,OACZA,KACL,GAAI6tC,GAAGhlC,EAAM7I,GAAQ,GAAIwM,GACvB,OAAOxM,EAGX,OAAQ,EA8BV,SAASmmE,GAAU1gE,EAAO2gE,EAAQC,EAAQC,EAAY95D,EAAKqD,EAAQtN,GACjE,IAAIq1B,EAIJ,GAHI0uC,IACF1uC,EAAS/nB,EAASy2D,EAAW7gE,EAAO+G,EAAKqD,EAAQtN,GAAS+jE,EAAW7gE,SAExD4E,IAAXutB,EACF,OAAOA,EAET,IAAK2uC,GAAS9gE,GACZ,OAAOA,EAET,IAAI+gE,EAAQxgE,GAAQP,GACpB,GAAI+gE,GAEF,GADA5uC,EA2XJ,SAAwB/uB,GACtB,IAAI7I,EAAS6I,EAAM7I,OACf43B,EAAS/uB,EAAM6O,YAAY1X,GAO/B,OAJIA,GAA6B,iBAAZ6I,EAAM,IAAkBkO,GAAe7T,KAAK2F,EAAO,WACtE+uB,EAAOhvB,MAAQC,EAAMD,MACrBgvB,EAAOhhB,MAAQ/N,EAAM+N,OAEhBghB,EApYI6uC,CAAehhE,IACnB2gE,EACH,OA6ON,SAAmBz7D,EAAQ9B,GACzB,IAAID,GAAS,EACT5I,EAAS2K,EAAO3K,OAGpB,IADA6I,IAAUA,EAAQ7F,MAAMhD,MACf4I,EAAQ5I,GACf6I,EAAMD,GAAS+B,EAAO/B,GAExB,OAAOC,EArPI69D,CAAUjhE,EAAOmyB,OAErB,CACL,IAAI0d,EAAMqxB,GAAOlhE,GACbmhE,EAAStxB,GAAOwrB,GAAWxrB,GAAOyrB,EAEtC,GAAIwD,GAAS9+D,GACX,OA0HN,SAAqB04D,EAAQiI,GAC3B,GAAIA,EACF,OAAOjI,EAAOl7D,QAEhB,IAAI20B,EAAS,IAAIumC,EAAOzmD,YAAYymD,EAAOn+D,QAE3C,OADAm+D,EAAOhnD,KAAKygB,GACLA,EAhIIivC,CAAYphE,EAAO2gE,GAE5B,GAAI9wB,GAAO4rB,GAAa5rB,GAAOqrB,GAAYiG,IAAW/2D,EAAS,CAC7D,GAAIuzD,EAAa39D,GACf,OAAOoK,EAASpK,EAAQ,GAG1B,GADAmyB,EA+XN,SAAyB/nB,GACvB,MAAqC,mBAAtBA,EAAO6H,aAA8BovD,GAAYj3D,GAE5D,GAxVG02D,GADW73B,EAwVHw1B,GAAar0D,IAvVHs0D,GAAaz1B,GAAS,GADjD,IAAoBA,EAzCLq4B,CAAgBH,EAAS,GAAKnhE,IAClC2gE,EACH,OA6QR,SAAqBz7D,EAAQkF,GAC3B,OAAOm3D,GAAWr8D,EAAQs8D,GAAWt8D,GAASkF,GA9QjCq3D,CAAYzhE,EAhD3B,SAAoBoK,EAAQlF,GAC1B,OAAOkF,GAAUm3D,GAAWr8D,EAAQhM,GAAKgM,GAASkF,GA+ClBs3D,CAAWvvC,EAAQnyB,QAE1C,CACL,IAAK88D,EAAcjtB,GACjB,OAAOzlC,EAASpK,EAAQ,GAE1BmyB,EA0YN,SAAwB/nB,EAAQylC,EAAK8xB,EAAWhB,GAC9C,IA5MmBiB,EA4Mf14B,EAAO9+B,EAAO6H,YAClB,OAAQ49B,GACN,KAAKmsB,EACH,OAAO6F,GAAiBz3D,GAE1B,KAAK+wD,EACL,KAAKC,EACH,OAAO,IAAIlyB,GAAM9+B,GAEnB,KAAK6xD,EACH,OA3QN,SAAuB6F,EAAUnB,GAC/B,IAAIjI,EAASiI,EAASkB,GAAiBC,EAASpJ,QAAUoJ,EAASpJ,OACnE,OAAO,IAAIoJ,EAAS7vD,YAAYymD,EAAQoJ,EAASC,WAAYD,EAAS/rC,YAyQ3DisC,CAAc53D,EAAQu2D,GAE/B,KAAKzE,EAAY,KAAKC,EACtB,KAAKC,EAAS,KAAKC,EAAU,KAAKC,EAClC,KAAKC,EAAU,KAAKC,EAAiB,KAAKC,EAAW,KAAKC,EACxD,OA/MN,SAAyBuF,EAAYtB,GACnC,IAAIjI,EAASiI,EAASkB,GAAiBI,EAAWvJ,QAAUuJ,EAAWvJ,OACvE,OAAO,IAAIuJ,EAAWhwD,YAAYymD,EAAQuJ,EAAWF,WAAYE,EAAW1nE,QA6MjE2nE,CAAgB93D,EAAQu2D,GAEjC,KAAKpF,EACH,OArQN,SAAkBx7D,EAAK4gE,EAAQgB,GAE7B,OAAOpE,EADKoD,EAASgB,EAAU/D,EAAW79D,IAAM,GAAQ69D,EAAW79D,GACzCq9D,EAAa,IAAIr9D,EAAIkS,aAmQpCkwD,CAAS/3D,EAAQu2D,EAAQgB,GAElC,KAAKnG,EACL,KAAKK,EACH,OAAO,IAAI3yB,EAAK9+B,GAElB,KAAKuxD,EACH,OAhQN,SAAqByG,GACnB,IAAIjwC,EAAS,IAAIiwC,EAAOnwD,YAAYmwD,EAAOl9D,OAAQy3D,EAAQ/tC,KAAKwzC,IAEhE,OADAjwC,EAAO/c,UAAYgtD,EAAOhtD,UACnB+c,EA6PIkwC,CAAYj4D,GAErB,KAAKwxD,EACH,OApPN,SAAkB79C,EAAK4iD,EAAQgB,GAE7B,OAAOpE,EADKoD,EAASgB,EAAU5D,EAAWhgD,IAAM,GAAQggD,EAAWhgD,GACzCu/C,EAAa,IAAIv/C,EAAI9L,aAkPpCqwD,CAASl4D,EAAQu2D,EAAQgB,GAElC,KAAK7F,EACH,OA3Oe8F,EA2OIx3D,EA1OhBy1D,GAAgB5mE,OAAO4mE,GAAcpiE,KAAKmkE,IAAW,IAhM/CW,CAAeviE,EAAO6vC,EAAK6wB,GAAWC,IAInD7jE,IAAUA,EAAQ,IAAIujE,IACtB,IAAImC,EAAU1lE,EAAM+gB,IAAI7d,GACxB,GAAIwiE,EACF,OAAOA,EAIT,GAFA1lE,EAAMihB,IAAI/d,EAAOmyB,IAEZ4uC,EACH,IAAItb,EAAQmb,EAsQhB,SAAoBx2D,GAClB,OAnOF,SAAwBA,EAAQq4D,EAAUC,GACxC,IAAIvwC,EAASswC,EAASr4D,GACtB,OAAO7J,GAAQ6J,GAAU+nB,EApwB3B,SAAmB/uB,EAAOjB,GAKxB,IAJA,IAAIgB,GAAS,EACT5I,EAAS4H,EAAO5H,OAChB6iB,EAASha,EAAM7I,SAEV4I,EAAQ5I,GACf6I,EAAMga,EAASja,GAAShB,EAAOgB,GAEjC,OAAOC,EA4vB2Bu/D,CAAUxwC,EAAQuwC,EAAYt4D,IAiOzDw4D,CAAex4D,EAAQlR,GAAMsoE,IAvQbqB,CAAW7iE,GAAS9G,GAAK8G,GAUhD,OA5vBF,SAAmBoD,EAAOo6D,GAIxB,IAHA,IAAIr6D,GAAS,EACT5I,EAAS6I,EAAQA,EAAM7I,OAAS,IAE3B4I,EAAQ5I,IAC8B,IAAzCijE,EAASp6D,EAAMD,GAAQA,MA+uB7B2/D,CAAUrd,GAASzlD,GAAO,SAAS+iE,EAAUh8D,GACvC0+C,IAEFsd,EAAW/iE,EADX+G,EAAMg8D,IAIRxC,GAAYpuC,EAAQprB,EAAK25D,GAAUqC,EAAUpC,EAAQC,EAAQC,EAAY95D,EAAK/G,EAAOlD,OAEhFq1B,EAsGT,SAAS0vC,GAAiBpH,GACxB,IAAItoC,EAAS,IAAIsoC,EAAYxoD,YAAYwoD,EAAY1kC,YAErD,OADA,IAAImB,GAAW/E,GAAQpU,IAAI,IAAImZ,GAAWujC,IACnCtoC,EA8GT,SAASovC,GAAWr8D,EAAQugD,EAAOr7C,EAAQy2D,GACzCz2D,IAAWA,EAAS,IAKpB,IAHA,IAAIjH,GAAS,EACT5I,EAASkrD,EAAMlrD,SAEV4I,EAAQ5I,GAAQ,CACvB,IAAIwM,EAAM0+C,EAAMtiD,GAEZ6/D,EAAWnC,EACXA,EAAWz2D,EAAOrD,GAAM7B,EAAO6B,GAAMA,EAAKqD,EAAQlF,QAClDN,EAEJ27D,GAAYn2D,EAAQrD,OAAkBnC,IAAbo+D,EAAyB99D,EAAO6B,GAAOi8D,GAElE,OAAO54D,EAkCT,SAAS64D,GAAWljE,EAAKgH,GACvB,IAqKiB/G,EACbS,EAtKA6O,EAAOvP,EAAIugE,SACf,OAsKgB,WADZ7/D,SADaT,EApKA+G,KAsKmB,UAARtG,GAA4B,UAARA,GAA4B,WAARA,EACrD,cAAVT,EACU,OAAVA,GAvKDsP,EAAmB,iBAAPvI,EAAkB,SAAW,QACzCuI,EAAKvP,IAWX,SAASk/D,GAAU70D,EAAQrD,GACzB,IAAI/G,EAj8BN,SAAkBoK,EAAQrD,GACxB,OAAiB,MAAVqD,OAAiBxF,EAAYwF,EAAOrD,GAg8B/BuH,CAASlE,EAAQrD,GAC7B,OAvOF,SAAsB/G,GACpB,SAAK8gE,GAAS9gE,KAyYEw6C,EAzYiBx6C,EA0YxBo+D,GAAeA,KAAc5jB,MAvYvBzT,GAAW/mC,IAAU29D,EAAa39D,GAAUw+D,GAAa5B,GACzDx0D,KAAKm3D,GAASv/D,IAqY/B,IAAkBw6C,EAnKT0oB,CAAaljE,GAASA,OAAQ4E,EA7tBvCm7D,GAAKjmE,UAAUmmE,MAnEf,WACEpnE,KAAKynE,SAAWjB,GAAeA,GAAa,MAAQ,IAmEtDU,GAAKjmE,UAAkB,OAtDvB,SAAoBiN,GAClB,OAAOlO,KAAKu/C,IAAIrxC,WAAelO,KAAKynE,SAASv5D,IAsD/Cg5D,GAAKjmE,UAAU+jB,IA1Cf,SAAiB9W,GACf,IAAIuI,EAAOzW,KAAKynE,SAChB,GAAIjB,GAAc,CAChB,IAAIltC,EAAS7iB,EAAKvI,GAClB,OAAOorB,IAAW6oC,OAAiBp2D,EAAYutB,EAEjD,OAAO7gB,GAAe7T,KAAK6R,EAAMvI,GAAOuI,EAAKvI,QAAOnC,GAqCtDm7D,GAAKjmE,UAAUs+C,IAzBf,SAAiBrxC,GACf,IAAIuI,EAAOzW,KAAKynE,SAChB,OAAOjB,QAA6Bz6D,IAAd0K,EAAKvI,GAAqBuK,GAAe7T,KAAK6R,EAAMvI,IAwB5Eg5D,GAAKjmE,UAAUikB,IAXf,SAAiBhX,EAAK/G,GAGpB,OAFWnH,KAAKynE,SACXv5D,GAAQs4D,SAA0Bz6D,IAAV5E,EAAuBg7D,EAAiBh7D,EAC9DnH,MAoHTsnE,GAAUrmE,UAAUmmE,MAjFpB,WACEpnE,KAAKynE,SAAW,IAiFlBH,GAAUrmE,UAAkB,OArE5B,SAAyBiN,GACvB,IAAIuI,EAAOzW,KAAKynE,SACZn9D,EAAQs9D,GAAanxD,EAAMvI,GAE/B,QAAI5D,EAAQ,IAIRA,GADYmM,EAAK/U,OAAS,EAE5B+U,EAAKwgB,MAELzzB,GAAOoB,KAAK6R,EAAMnM,EAAO,GAEpB,KAyDTg9D,GAAUrmE,UAAU+jB,IA7CpB,SAAsB9W,GACpB,IAAIuI,EAAOzW,KAAKynE,SACZn9D,EAAQs9D,GAAanxD,EAAMvI,GAE/B,OAAO5D,EAAQ,OAAIyB,EAAY0K,EAAKnM,GAAO,IA0C7Cg9D,GAAUrmE,UAAUs+C,IA9BpB,SAAsBrxC,GACpB,OAAO05D,GAAa5nE,KAAKynE,SAAUv5D,IAAQ,GA8B7Co5D,GAAUrmE,UAAUikB,IAjBpB,SAAsBhX,EAAK/G,GACzB,IAAIsP,EAAOzW,KAAKynE,SACZn9D,EAAQs9D,GAAanxD,EAAMvI,GAO/B,OALI5D,EAAQ,EACVmM,EAAKvU,KAAK,CAACgM,EAAK/G,IAEhBsP,EAAKnM,GAAO,GAAKnD,EAEZnH,MAkGTunE,GAAStmE,UAAUmmE,MA/DnB,WACEpnE,KAAKynE,SAAW,CACd,KAAQ,IAAIP,GACZ,IAAO,IAAKb,IAAOiB,IACnB,OAAU,IAAIJ,KA4DlBK,GAAStmE,UAAkB,OA/C3B,SAAwBiN,GACtB,OAAOk8D,GAAWpqE,KAAMkO,GAAa,OAAEA,IA+CzCq5D,GAAStmE,UAAU+jB,IAnCnB,SAAqB9W,GACnB,OAAOk8D,GAAWpqE,KAAMkO,GAAK8W,IAAI9W,IAmCnCq5D,GAAStmE,UAAUs+C,IAvBnB,SAAqBrxC,GACnB,OAAOk8D,GAAWpqE,KAAMkO,GAAKqxC,IAAIrxC,IAuBnCq5D,GAAStmE,UAAUikB,IAVnB,SAAqBhX,EAAK/G,GAExB,OADAijE,GAAWpqE,KAAMkO,GAAKgX,IAAIhX,EAAK/G,GACxBnH,MAgGTwnE,GAAMvmE,UAAUmmE,MApEhB,WACEpnE,KAAKynE,SAAW,IAAIH,IAoEtBE,GAAMvmE,UAAkB,OAxDxB,SAAqBiN,GACnB,OAAOlO,KAAKynE,SAAiB,OAAEv5D,IAwDjCs5D,GAAMvmE,UAAU+jB,IA5ChB,SAAkB9W,GAChB,OAAOlO,KAAKynE,SAASziD,IAAI9W,IA4C3Bs5D,GAAMvmE,UAAUs+C,IAhChB,SAAkBrxC,GAChB,OAAOlO,KAAKynE,SAASloB,IAAIrxC,IAgC3Bs5D,GAAMvmE,UAAUikB,IAnBhB,SAAkBhX,EAAK/G,GACrB,IAAImuC,EAAQt1C,KAAKynE,SACjB,GAAInyB,aAAiBgyB,GAAW,CAC9B,IAAIgD,EAAQh1B,EAAMmyB,SAClB,IAAKpB,IAAQiE,EAAM5oE,OAAS6oE,IAE1B,OADAD,EAAMpoE,KAAK,CAACgM,EAAK/G,IACVnH,KAETs1C,EAAQt1C,KAAKynE,SAAW,IAAIF,GAAS+C,GAGvC,OADAh1B,EAAMpwB,IAAIhX,EAAK/G,GACRnH,MAicT,IAAI2oE,GAAa5C,GAAmBd,EAAQc,GAAkB3lE,QAyhB9D,WACE,MAAO,IAjhBLioE,GAtQJ,SAAoBlhE,GAClB,OAAOu+D,GAAe9gE,KAAKuC,IAyX7B,SAASqjE,GAAQrjE,EAAOzF,GAEtB,SADAA,EAAmB,MAAVA,EAAiB0gE,EAAmB1gE,KAE1B,iBAATyF,GAAqB68D,EAASz0D,KAAKpI,KAC1CA,GAAS,GAAKA,EAAQ,GAAK,GAAKA,EAAQzF,EAmC7C,SAAS8mE,GAAYrhE,GACnB,IAAIkpC,EAAOlpC,GAASA,EAAMiS,YAG1B,OAAOjS,KAFqB,mBAARkpC,GAAsBA,EAAKpvC,WAAcokE,GAY/D,SAASqB,GAAS/kB,GAChB,GAAY,MAARA,EAAc,CAChB,IACE,OAAO8jB,EAAa7gE,KAAK+8C,GACzB,MAAO50C,IACT,IACE,OAAQ40C,EAAO,GACf,MAAO50C,KAEX,MAAO,GAyDT,SAASwiC,GAAGpoC,EAAOsjE,GACjB,OAAOtjE,IAAUsjE,GAAUtjE,GAAUA,GAASsjE,GAAUA,GAxOrDtE,IAAYkC,GAAO,IAAIlC,GAAS,IAAI9G,YAAY,MAAQ+D,GACxDiD,IAAOgC,GAAO,IAAIhC,KAAQ3D,GAC1B34B,IAAWs+B,GAAOt+B,GAAQC,YAAc64B,GACxCyD,IAAO+B,GAAO,IAAI/B,KAAQvD,GAC1BwD,IAAW8B,GAAO,IAAI9B,KAAYrD,KACrCmF,GAAS,SAASlhE,GAChB,IAAImyB,EAASosC,GAAe9gE,KAAKuC,GAC7BkpC,EAAO/W,GAAUspC,EAAYz7D,EAAMiS,iBAAcrN,EACjD2+D,EAAar6B,EAAOq2B,GAASr2B,QAAQtkC,EAEzC,GAAI2+D,EACF,OAAQA,GACN,KAAKjE,GAAoB,OAAOrD,EAChC,KAAKuD,GAAe,OAAOjE,EAC3B,KAAKkE,GAAmB,OAAO/D,EAC/B,KAAKgE,GAAe,OAAO9D,EAC3B,KAAK+D,GAAmB,OAAO5D,EAGnC,OAAO5pC,IAuQX,IAAI5xB,GAAUhD,MAAMgD,QA2BpB,SAASmnC,GAAY1nC,GACnB,OAAgB,MAATA,GAqGT,SAAkBA,GAChB,MAAuB,iBAATA,GACZA,GAAS,GAAKA,EAAQ,GAAK,GAAKA,GAASi7D,EAvGnBuI,CAASxjE,EAAMzF,UAAYwsC,GAAW/mC,GAiDhE,IAAI8+D,GAAWD,IAsLf,WACE,OAAO,GApKT,SAAS93B,GAAW/mC,GAGlB,IAAI6vC,EAAMixB,GAAS9gE,GAASu+D,GAAe9gE,KAAKuC,GAAS,GACzD,OAAO6vC,GAAOwrB,GAAWxrB,GAAOyrB,EA2DlC,SAASwF,GAAS9gE,GAChB,IAAIS,SAAcT,EAClB,QAASA,IAAkB,UAARS,GAA4B,YAARA,GA2DzC,SAASvH,GAAKkR,GACZ,OAAOs9B,GAAYt9B,GAn7BrB,SAAuBpK,EAAOyjE,GAG5B,IAAItxC,EAAU5xB,GAAQP,IAsrBxB,SAAqBA,GAEnB,OAmFF,SAA2BA,GACzB,OAmIF,SAAsBA,GACpB,QAASA,GAAyB,iBAATA,EApIlB0jE,CAAa1jE,IAAU0nC,GAAY1nC,GApFnC2jE,CAAkB3jE,IAAUsR,GAAe7T,KAAKuC,EAAO,aAC1D2+D,GAAqBlhE,KAAKuC,EAAO,WAAau+D,GAAe9gE,KAAKuC,IAAUk7D,GAzrBhD0I,CAAY5jE,GAljB9C,SAAmB0J,EAAG8zD,GAIpB,IAHA,IAAIr6D,GAAS,EACTgvB,EAAS50B,MAAMmM,KAEVvG,EAAQuG,GACfyoB,EAAOhvB,GAASq6D,EAASr6D,GAE3B,OAAOgvB,EA4iBH0xC,CAAU7jE,EAAMzF,OAAQmN,QACxB,GAEAnN,EAAS43B,EAAO53B,OAChBupE,IAAgBvpE,EAEpB,IAAK,IAAIwM,KAAO/G,GACTyjE,IAAanyD,GAAe7T,KAAKuC,EAAO+G,IACvC+8D,IAAuB,UAAP/8D,GAAmBs8D,GAAQt8D,EAAKxM,KACpD43B,EAAOp3B,KAAKgM,GAGhB,OAAOorB,EAm6BsB4xC,CAAc35D,GAtuB7C,SAAkBA,GAChB,IAAKi3D,GAAYj3D,GACf,OAAO20D,GAAW30D,GAEpB,IAAI+nB,EAAS,GACb,IAAK,IAAIprB,KAAO9N,OAAOmR,GACjBkH,GAAe7T,KAAK2M,EAAQrD,IAAe,eAAPA,GACtCorB,EAAOp3B,KAAKgM,GAGhB,OAAOorB,EA4tB8C6xC,CAAS55D,GA0ChE/R,EAAOD,QA9VP,SAAmB4H,GACjB,OAAO0gE,GAAU1gE,GAAO,GAAM,mBC52ChC,IASIikE,EAAS,aAGTC,EAAa,qBAGbC,EAAa,aAGbC,EAAY,cAGZC,EAAe/iE,SAGfy7D,EAA8B,iBAAV,EAAAnF,GAAsB,EAAAA,GAAU,EAAAA,EAAO3+D,SAAWA,QAAU,EAAA2+D,EAGhFoF,EAA0B,iBAARxkE,MAAoBA,MAAQA,KAAKS,SAAWA,QAAUT,KAGxEN,EAAO6kE,GAAcC,GAAYvzD,SAAS,cAATA,GAUjC80D,EAPctlE,OAAOa,UAOQigB,SAG7BuqD,EAAYxhE,KAAKotB,IACjBq0C,EAAYzhE,KAAK6uB,IAkBjBm0B,EAAM,WACR,OAAO5tD,EAAK8F,KAAK8nD,OA4MnB,SAASgb,EAAS9gE,GAChB,IAAIS,SAAcT,EAClB,QAASA,IAAkB,UAARS,GAA4B,YAARA,GA4EzC,SAAS+jE,EAASxkE,GAChB,GAAoB,iBAATA,EACT,OAAOA,EAET,GAhCF,SAAkBA,GAChB,MAAuB,iBAATA,GAtBhB,SAAsBA,GACpB,QAASA,GAAyB,iBAATA,EAsBtB0jE,CAAa1jE,IAzTF,mBAyTYu+D,EAAe9gE,KAAKuC,GA8B1CykE,CAASzkE,GACX,OA3VM,IA6VR,GAAI8gE,EAAS9gE,GAAQ,CACnB,IAAIsjE,EAAgC,mBAAjBtjE,EAAM8/D,QAAwB9/D,EAAM8/D,UAAY9/D,EACnEA,EAAQ8gE,EAASwC,GAAUA,EAAQ,GAAMA,EAE3C,GAAoB,iBAATtjE,EACT,OAAiB,IAAVA,EAAcA,GAASA,EAEhCA,EAAQA,EAAMsJ,QAAQ26D,EAAQ,IAC9B,IAAIS,EAAWP,EAAW/7D,KAAKpI,GAC/B,OAAQ0kE,GAAYN,EAAUh8D,KAAKpI,GAC/BqkE,EAAarkE,EAAMxC,MAAM,GAAIknE,EAAW,EAAI,GAC3CR,EAAW97D,KAAKpI,GAxWb,KAwW6BA,EAGvC3H,EAAOD,QAtPP,SAAkBoiD,EAAMuC,EAAMnkD,GAC5B,IAAI+rE,EACAC,EACAC,EACA1yC,EACA2yC,EACAC,EACAC,EAAiB,EACjBC,GAAU,EACVC,GAAS,EACTC,GAAW,EAEf,GAAmB,mBAAR3qB,EACT,MAAM,IAAI5W,UArIQ,uBA+IpB,SAASwhC,EAAW5U,GAClB,IAAIlzD,EAAOqnE,EACPU,EAAUT,EAKd,OAHAD,EAAWC,OAAWhgE,EACtBogE,EAAiBxU,EACjBr+B,EAASqoB,EAAKjhD,MAAM8rE,EAAS/nE,GAI/B,SAASgoE,EAAY9U,GAMnB,OAJAwU,EAAiBxU,EAEjBsU,EAAUzpE,WAAWkqE,EAAcxoB,GAE5BkoB,EAAUG,EAAW5U,GAAQr+B,EAWtC,SAASqzC,EAAahV,GACpB,IAAIiV,EAAoBjV,EAAOuU,EAM/B,YAAyBngE,IAAjBmgE,GAA+BU,GAAqB1oB,GACzD0oB,EAAoB,GAAOP,GANJ1U,EAAOwU,GAM8BH,EAGjE,SAASU,IACP,IAAI/U,EAAO1K,IACX,GAAI0f,EAAahV,GACf,OAAOkV,EAAalV,GAGtBsU,EAAUzpE,WAAWkqE,EAzBvB,SAAuB/U,GACrB,IAEIr+B,EAAS4qB,GAFWyT,EAAOuU,GAI/B,OAAOG,EAASX,EAAUpyC,EAAQ0yC,GAHRrU,EAAOwU,IAGkC7yC,EAoBhCwzC,CAAcnV,IAGnD,SAASkV,EAAalV,GAKpB,OAJAsU,OAAUlgE,EAINugE,GAAYR,EACPS,EAAW5U,IAEpBmU,EAAWC,OAAWhgE,EACfutB,GAeT,SAASyzC,IACP,IAAIpV,EAAO1K,IACP+f,EAAaL,EAAahV,GAM9B,GAJAmU,EAAWnrE,UACXorE,EAAW/rE,KACXksE,EAAevU,EAEXqV,EAAY,CACd,QAAgBjhE,IAAZkgE,EACF,OAAOQ,EAAYP,GAErB,GAAIG,EAGF,OADAJ,EAAUzpE,WAAWkqE,EAAcxoB,GAC5BqoB,EAAWL,GAMtB,YAHgBngE,IAAZkgE,IACFA,EAAUzpE,WAAWkqE,EAAcxoB,IAE9B5qB,EAIT,OAxGA4qB,EAAOynB,EAASznB,IAAS,EACrB+jB,EAASloE,KACXqsE,IAAYrsE,EAAQqsE,QAEpBJ,GADAK,EAAS,YAAatsE,GACH0rE,EAAUE,EAAS5rE,EAAQisE,UAAY,EAAG9nB,GAAQ8nB,EACrEM,EAAW,aAAcvsE,IAAYA,EAAQusE,SAAWA,GAiG1DS,EAAUE,OAnCV,gBACkBlhE,IAAZkgE,GACF1pE,aAAa0pE,GAEfE,EAAiB,EACjBL,EAAWI,EAAeH,EAAWE,OAAUlgE,GA+BjDghE,EAAUtqE,MA5BV,WACE,YAAmBsJ,IAAZkgE,EAAwB3yC,EAASuzC,EAAa5f,MA4BhD8f,6BC/OT,IAGI5K,EAAiB,4BAOjBC,EAAmB,iBAGnBC,EAAU,qBACV6K,EAAW,iBAEX5K,EAAU,mBACVC,EAAU,gBACV4K,EAAW,iBACX3K,EAAU,oBAEVE,EAAS,eACTC,EAAY,kBAEZC,EAAY,kBACZC,EAAa,mBAEbC,EAAY,kBACZC,EAAS,eACTC,EAAY,kBAGZE,EAAa,mBAEbC,EAAiB,uBACjBC,EAAc,oBAkBdW,EAAe,8BAGfC,EAAW,mBAGXoJ,EAAiB,GACrBA,EAxBiB,yBAwBYA,EAvBZ,yBAwBjBA,EAvBc,sBAuBYA,EAtBX,uBAuBfA,EAtBe,uBAsBYA,EArBZ,uBAsBfA,EArBsB,8BAqBYA,EApBlB,wBAqBhBA,EApBgB,yBAoBY,EAC5BA,EAAe/K,GAAW+K,EAAeF,GACzCE,EAAejK,GAAkBiK,EAAe9K,GAChD8K,EAAehK,GAAegK,EAAe7K,GAC7C6K,EAAeD,GAAYC,EAAe5K,GAC1C4K,EAAe1K,GAAU0K,EAAezK,GACxCyK,EAAexK,GAAawK,EAAetK,GAC3CsK,EAAerK,GAAUqK,EAAepK,GACxCoK,EAAelK,IAAc,EAG7B,IAAIgB,EAA8B,iBAAV,EAAAnF,GAAsB,EAAAA,GAAU,EAAAA,EAAO3+D,SAAWA,QAAU,EAAA2+D,EAGhFoF,EAA0B,iBAARxkE,MAAoBA,MAAQA,KAAKS,SAAWA,QAAUT,KAGxEN,EAAO6kE,GAAcC,GAAYvzD,SAAS,cAATA,GAGjCwzD,EAA4C7kE,IAAYA,EAAQwe,UAAYxe,EAG5E8kE,EAAaD,GAA4C5kE,IAAWA,EAAOue,UAAYve,EAGvF8kE,EAAgBD,GAAcA,EAAW9kE,UAAY6kE,EAGrDiJ,EAAc/I,GAAiBJ,EAAWnhB,QAG1CuqB,EAAY,WACd,IACE,OAAOD,GAAeA,EAAYE,SAAWF,EAAYE,QAAQ,QACjE,MAAOxgE,KAHI,GAOXygE,EAAmBF,GAAYA,EAASG,aAuD5C,SAASC,EAAUnjE,EAAOojE,GAIxB,IAHA,IAAIrjE,GAAS,EACT5I,EAAkB,MAAT6I,EAAgB,EAAIA,EAAM7I,SAE9B4I,EAAQ5I,GACf,GAAIisE,EAAUpjE,EAAMD,GAAQA,EAAOC,GACjC,OAAO,EAGX,OAAO,EAkET,SAASw6D,EAAW79D,GAClB,IAAIoD,GAAS,EACTgvB,EAAS50B,MAAMwC,EAAI89D,MAKvB,OAHA99D,EAAI3G,SAAQ,SAAS4G,EAAO+G,GAC1BorB,IAAShvB,GAAS,CAAC4D,EAAK/G,MAEnBmyB,EAwBT,SAAS4rC,EAAWhgD,GAClB,IAAI5a,GAAS,EACTgvB,EAAS50B,MAAMwgB,EAAI8/C,MAKvB,OAHA9/C,EAAI3kB,SAAQ,SAAS4G,GACnBmyB,IAAShvB,GAASnD,KAEbmyB,EAIT,IAeM8rB,EAvCWzD,EAAMr7C,EAwBnB6+D,EAAazgE,MAAMzD,UACnBmkE,EAAYx0D,SAAS3P,UACrBokE,EAAcjlE,OAAOa,UAGrBqkE,EAAajmE,EAAK,sBAGlBomE,EAAeL,EAAUlkD,SAGzBzI,EAAiB4sD,EAAY5sD,eAG7B8sD,GACEngB,EAAM,SAASrvB,KAAKuvC,GAAcA,EAAWjlE,MAAQilE,EAAWjlE,KAAKmlE,UAAY,KACvE,iBAAmBpgB,EAAO,GAQtCwoB,EAAuBvI,EAAYnkD,SAGnCykD,EAAa33D,OAAO,IACtBy3D,EAAa7gE,KAAK6T,GAAgBhI,QA7PjB,sBA6PuC,QACvDA,QAAQ,yDAA0D,SAAW,KAI5EgwD,EAAS6D,EAAgBjlE,EAAKohE,YAAS10D,EACvC0yB,EAASp/B,EAAKo/B,OACdJ,EAAah/B,EAAKg/B,WAClBynC,EAAuBT,EAAYS,qBACnCtiE,EAAS2hE,EAAW3hE,OACpBqqE,EAAiBpvC,EAASA,EAAOC,iBAAc3yB,EAG/Cg6D,GAAmB3lE,OAAOmpC,sBAC1By8B,GAAiBvF,EAASA,EAAOwF,cAAWl6D,EAC5Cm6D,IAnEavkB,EAmEQvhD,OAAOC,KAnETiG,EAmEelG,OAlE7B,SAASuB,GACd,OAAOggD,EAAKr7C,EAAU3E,MAoEtBwkE,GAAWC,GAAU/mE,EAAM,YAC3BgnE,GAAMD,GAAU/mE,EAAM,OACtB0qC,GAAUq8B,GAAU/mE,EAAM,WAC1BinE,GAAMF,GAAU/mE,EAAM,OACtBknE,GAAUH,GAAU/mE,EAAM,WAC1BmnE,GAAeJ,GAAUhmE,OAAQ,UAGjCqmE,GAAqBC,GAASP,IAC9BQ,GAAgBD,GAASL,IACzBO,GAAoBF,GAAS38B,IAC7B88B,GAAgBH,GAASJ,IACzBQ,GAAoBJ,GAASH,IAG7BQ,GAActoC,EAASA,EAAOx9B,eAAY8K,EAC1Ci7D,GAAgBD,GAAcA,GAAYE,aAAUl7D,EASxD,SAASm7D,GAAKC,GACZ,IAAI78D,GAAS,EACT5I,EAAoB,MAAXylE,EAAkB,EAAIA,EAAQzlE,OAG3C,IADA1B,KAAKonE,UACI98D,EAAQ5I,GAAQ,CACvB,IAAI2lE,EAAQF,EAAQ78D,GACpBtK,KAAKklB,IAAImiD,EAAM,GAAIA,EAAM,KA+F7B,SAASC,GAAUH,GACjB,IAAI78D,GAAS,EACT5I,EAAoB,MAAXylE,EAAkB,EAAIA,EAAQzlE,OAG3C,IADA1B,KAAKonE,UACI98D,EAAQ5I,GAAQ,CACvB,IAAI2lE,EAAQF,EAAQ78D,GACpBtK,KAAKklB,IAAImiD,EAAM,GAAIA,EAAM,KA4G7B,SAASE,GAASJ,GAChB,IAAI78D,GAAS,EACT5I,EAAoB,MAAXylE,EAAkB,EAAIA,EAAQzlE,OAG3C,IADA1B,KAAKonE,UACI98D,EAAQ5I,GAAQ,CACvB,IAAI2lE,EAAQF,EAAQ78D,GACpBtK,KAAKklB,IAAImiD,EAAM,GAAIA,EAAM,KA+F7B,SAASyG,GAASxkE,GAChB,IAAIgB,GAAS,EACT5I,EAAmB,MAAV4H,EAAiB,EAAIA,EAAO5H,OAGzC,IADA1B,KAAKynE,SAAW,IAAIF,KACXj9D,EAAQ5I,GACf1B,KAAK2/C,IAAIr2C,EAAOgB,IA2CpB,SAASk9D,GAAML,GACb,IAAI1wD,EAAOzW,KAAKynE,SAAW,IAAIH,GAAUH,GACzCnnE,KAAKglE,KAAOvuD,EAAKuuD,KAsInB,SAAS4C,GAAar9D,EAAO2D,GAE3B,IADA,IAAIxM,EAAS6I,EAAM7I,OACZA,KACL,GAAI6tC,GAAGhlC,EAAM7I,GAAQ,GAAIwM,GACvB,OAAOxM,EAGX,OAAQ,EA0BV,SAASqsE,GAAW5mE,GAClB,OAAa,MAATA,OACe4E,IAAV5E,EAt1BQ,qBARL,gBAg2BJ0mE,GAAkBA,KAAkBztE,OAAO+G,GA0arD,SAAmBA,GACjB,IAAI6mE,EAAQv1D,EAAe7T,KAAKuC,EAAO0mE,GACnC72B,EAAM7vC,EAAM0mE,GAEhB,IACE1mE,EAAM0mE,QAAkB9hE,EACxB,IAAIkiE,GAAW,EACf,MAAOlhE,IAET,IAAIusB,EAASs0C,EAAqBhpE,KAAKuC,GAQvC,OAPI8mE,IACED,EACF7mE,EAAM0mE,GAAkB72B,SAEjB7vC,EAAM0mE,IAGVv0C,EA1bH40C,CAAU/mE,GA4iBhB,SAAwBA,GACtB,OAAOymE,EAAqBhpE,KAAKuC,GA5iB7Bu+D,CAAev+D,GAUrB,SAASgnE,GAAgBhnE,GACvB,OAAO0jE,GAAa1jE,IAAU4mE,GAAW5mE,IAAUk7D,EAiBrD,SAAS+L,GAAYjnE,EAAOsjE,EAAO4D,EAASrG,EAAY/jE,GACtD,OAAIkD,IAAUsjE,IAGD,MAATtjE,GAA0B,MAATsjE,IAAmBI,GAAa1jE,KAAW0jE,GAAaJ,GACpEtjE,GAAUA,GAASsjE,GAAUA,EAmBxC,SAAyBl5D,EAAQk5D,EAAO4D,EAASrG,EAAYsG,EAAWrqE,GACtE,IAAIsqE,EAAW7mE,GAAQ6J,GACnBi9D,EAAW9mE,GAAQ+iE,GACnBgE,EAASF,EAAWrB,EAAW7E,GAAO92D,GACtCm9D,EAASF,EAAWtB,EAAW7E,GAAOoC,GAKtCkE,GAHJF,EAASA,GAAUpM,EAAUO,EAAY6L,IAGhB7L,EACrBgM,GAHJF,EAASA,GAAUrM,EAAUO,EAAY8L,IAGhB9L,EACrBiM,EAAYJ,GAAUC,EAE1B,GAAIG,GAAa5I,GAAS10D,GAAS,CACjC,IAAK00D,GAASwE,GACZ,OAAO,EAET8D,GAAW,EACXI,GAAW,EAEb,GAAIE,IAAcF,EAEhB,OADA1qE,IAAUA,EAAQ,IAAIujE,IACd+G,GAAYd,GAAal8D,GAC7Bu9D,GAAYv9D,EAAQk5D,EAAO4D,EAASrG,EAAYsG,EAAWrqE,GAiKnE,SAAoBsN,EAAQk5D,EAAOzzB,EAAKq3B,EAASrG,EAAYsG,EAAWrqE,GACtE,OAAQ+yC,GACN,KAAKosB,EACH,GAAK7xD,EAAO2rB,YAAcutC,EAAMvtC,YAC3B3rB,EAAO23D,YAAcuB,EAAMvB,WAC9B,OAAO,EAET33D,EAASA,EAAOsuD,OAChB4K,EAAQA,EAAM5K,OAEhB,KAAKsD,EACH,QAAK5xD,EAAO2rB,YAAcutC,EAAMvtC,aAC3BoxC,EAAU,IAAIjwC,EAAW9sB,GAAS,IAAI8sB,EAAWosC,KAKxD,KAAKnI,EACL,KAAKC,EACL,KAAKI,EAGH,OAAOpzB,IAAIh+B,GAASk5D,GAEtB,KAAK0C,EACH,OAAO57D,EAAO/E,MAAQi+D,EAAMj+D,MAAQ+E,EAAOyJ,SAAWyvD,EAAMzvD,QAE9D,KAAK8nD,EACL,KAAKE,EAIH,OAAOzxD,GAAWk5D,EAAQ,GAE5B,KAAK/H,EACH,IAAIqM,EAAUhK,EAEhB,KAAKhC,EACH,IAAIiM,EAroCiB,EAqoCLX,EAGhB,GAFAU,IAAYA,EAAU7J,GAElB3zD,EAAOyzD,MAAQyF,EAAMzF,OAASgK,EAChC,OAAO,EAGT,IAAIrF,EAAU1lE,EAAM+gB,IAAIzT,GACxB,GAAIo4D,EACF,OAAOA,GAAWc,EAEpB4D,GA/oCuB,EAkpCvBpqE,EAAMihB,IAAI3T,EAAQk5D,GAClB,IAAInxC,EAASw1C,GAAYC,EAAQx9D,GAASw9D,EAAQtE,GAAQ4D,EAASrG,EAAYsG,EAAWrqE,GAE1F,OADAA,EAAc,OAAEsN,GACT+nB,EAET,IAhoCY,kBAioCV,GAAI0tC,GACF,OAAOA,GAAcpiE,KAAK2M,IAAWy1D,GAAcpiE,KAAK6lE,GAG9D,OAAO,EA9NDwE,CAAW19D,EAAQk5D,EAAOgE,EAAQJ,EAASrG,EAAYsG,EAAWrqE,GAExE,KAj8ByB,EAi8BnBoqE,GAAiC,CACrC,IAAIa,EAAeP,GAAYl2D,EAAe7T,KAAK2M,EAAQ,eACvD49D,EAAeP,GAAYn2D,EAAe7T,KAAK6lE,EAAO,eAE1D,GAAIyE,GAAgBC,EAAc,CAChC,IAAIC,EAAeF,EAAe39D,EAAOpK,QAAUoK,EAC/C89D,EAAeF,EAAe1E,EAAMtjE,QAAUsjE,EAGlD,OADAxmE,IAAUA,EAAQ,IAAIujE,IACf8G,EAAUc,EAAcC,EAAchB,EAASrG,EAAY/jE,IAGtE,QAAK4qE,IAGL5qE,IAAUA,EAAQ,IAAIujE,IA6NxB,SAAsBj2D,EAAQk5D,EAAO4D,EAASrG,EAAYsG,EAAWrqE,GACnE,IAAI+qE,EA9qCqB,EA8qCTX,EACZiB,EAAWtF,GAAWz4D,GACtBg+D,EAAYD,EAAS5tE,OAIzB,GAAI6tE,GAHWvF,GAAWS,GACD/oE,SAEMstE,EAC7B,OAAO,EAGT,IADA,IAAI1kE,EAAQilE,EACLjlE,KAAS,CACd,IAAI4D,EAAMohE,EAAShlE,GACnB,KAAM0kE,EAAY9gE,KAAOu8D,EAAQhyD,EAAe7T,KAAK6lE,EAAOv8D,IAC1D,OAAO,EAIX,IAAIy7D,EAAU1lE,EAAM+gB,IAAIzT,GACxB,GAAIo4D,GAAW1lE,EAAM+gB,IAAIylD,GACvB,OAAOd,GAAWc,EAEpB,IAAInxC,GAAS,EACbr1B,EAAMihB,IAAI3T,EAAQk5D,GAClBxmE,EAAMihB,IAAIulD,EAAOl5D,GAGjB,IADA,IAAIi+D,EAAWR,IACN1kE,EAAQilE,GAAW,CAE1B,IAAI5H,EAAWp2D,EADfrD,EAAMohE,EAAShlE,IAEXmlE,EAAWhF,EAAMv8D,GAErB,GAAI85D,EACF,IAAI0H,EAAWV,EACXhH,EAAWyH,EAAU9H,EAAUz5D,EAAKu8D,EAAOl5D,EAAQtN,GACnD+jE,EAAWL,EAAU8H,EAAUvhE,EAAKqD,EAAQk5D,EAAOxmE,GAGzD,UAAmB8H,IAAb2jE,EACG/H,IAAa8H,GAAYnB,EAAU3G,EAAU8H,EAAUpB,EAASrG,EAAY/jE,GAC7EyrE,GACD,CACLp2C,GAAS,EACT,MAEFk2C,IAAaA,EAAkB,eAAPthE,GAE1B,GAAIorB,IAAWk2C,EAAU,CACvB,IAAIG,EAAUp+D,EAAO6H,YACjBw2D,EAAUnF,EAAMrxD,YAGhBu2D,GAAWC,KACV,gBAAiBr+D,MAAU,gBAAiBk5D,IACzB,mBAAXkF,GAAyBA,aAAmBA,GACjC,mBAAXC,GAAyBA,aAAmBA,IACvDt2C,GAAS,GAKb,OAFAr1B,EAAc,OAAEsN,GAChBtN,EAAc,OAAEwmE,GACTnxC,EAzRAu2C,CAAat+D,EAAQk5D,EAAO4D,EAASrG,EAAYsG,EAAWrqE,IA3D5D6rE,CAAgB3oE,EAAOsjE,EAAO4D,EAASrG,EAAYoG,GAAanqE,IA2HzE,SAAS6qE,GAAYvkE,EAAOkgE,EAAO4D,EAASrG,EAAYsG,EAAWrqE,GACjE,IAAI+qE,EAlhCqB,EAkhCTX,EACZ0B,EAAYxlE,EAAM7I,OAClBsuE,EAAYvF,EAAM/oE,OAEtB,GAAIquE,GAAaC,KAAehB,GAAagB,EAAYD,GACvD,OAAO,EAGT,IAAIpG,EAAU1lE,EAAM+gB,IAAIza,GACxB,GAAIo/D,GAAW1lE,EAAM+gB,IAAIylD,GACvB,OAAOd,GAAWc,EAEpB,IAAIngE,GAAS,EACTgvB,GAAS,EACT22C,EA/hCuB,EA+hCf5B,EAAoC,IAAIP,QAAW/hE,EAM/D,IAJA9H,EAAMihB,IAAI3a,EAAOkgE,GACjBxmE,EAAMihB,IAAIulD,EAAOlgE,KAGRD,EAAQylE,GAAW,CAC1B,IAAIG,EAAW3lE,EAAMD,GACjBmlE,EAAWhF,EAAMngE,GAErB,GAAI09D,EACF,IAAI0H,EAAWV,EACXhH,EAAWyH,EAAUS,EAAU5lE,EAAOmgE,EAAOlgE,EAAOtG,GACpD+jE,EAAWkI,EAAUT,EAAUnlE,EAAOC,EAAOkgE,EAAOxmE,GAE1D,QAAiB8H,IAAb2jE,EAAwB,CAC1B,GAAIA,EACF,SAEFp2C,GAAS,EACT,MAGF,GAAI22C,GACF,IAAKvC,EAAUjD,GAAO,SAASgF,EAAUU,GACnC,GA72BajiE,EA62BOiiE,GAANF,EA52BX1wB,IAAIrxC,KA62BFgiE,IAAaT,GAAYnB,EAAU4B,EAAUT,EAAUpB,EAASrG,EAAY/jE,IAC/E,OAAOgsE,EAAK/tE,KAAKiuE,GA/2B/B,IAAyBjiE,KAi3BX,CACNorB,GAAS,EACT,YAEG,GACD42C,IAAaT,IACXnB,EAAU4B,EAAUT,EAAUpB,EAASrG,EAAY/jE,GACpD,CACLq1B,GAAS,EACT,OAKJ,OAFAr1B,EAAc,OAAEsG,GAChBtG,EAAc,OAAEwmE,GACTnxC,EAyKT,SAAS0wC,GAAWz4D,GAClB,OApZF,SAAwBA,EAAQq4D,EAAUC,GACxC,IAAIvwC,EAASswC,EAASr4D,GACtB,OAAO7J,GAAQ6J,GAAU+nB,EAhuB3B,SAAmB/uB,EAAOjB,GAKxB,IAJA,IAAIgB,GAAS,EACT5I,EAAS4H,EAAO5H,OAChB6iB,EAASha,EAAM7I,SAEV4I,EAAQ5I,GACf6I,EAAMga,EAASja,GAAShB,EAAOgB,GAEjC,OAAOC,EAwtB2Bu/D,CAAUxwC,EAAQuwC,EAAYt4D,IAkZzDw4D,CAAex4D,EAAQlR,GAAMsoE,IAWtC,SAASyB,GAAWljE,EAAKgH,GACvB,IAsHiB/G,EACbS,EAvHA6O,EAAOvP,EAAIugE,SACf,OAuHgB,WADZ7/D,SADaT,EArHA+G,KAuHmB,UAARtG,GAA4B,UAARA,GAA4B,WAARA,EACrD,cAAVT,EACU,OAAVA,GAxHDsP,EAAmB,iBAAPvI,EAAkB,SAAW,QACzCuI,EAAKvP,IAWX,SAASk/D,GAAU70D,EAAQrD,GACzB,IAAI/G,EAxjCN,SAAkBoK,EAAQrD,GACxB,OAAiB,MAAVqD,OAAiBxF,EAAYwF,EAAOrD,GAujC/BuH,CAASlE,EAAQrD,GAC7B,OArTF,SAAsB/G,GACpB,SAAK8gE,GAAS9gE,IAwahB,SAAkBw6C,GAChB,QAAS4jB,GAAeA,KAAc5jB,EAzadyuB,CAASjpE,MAGnB+mC,GAAW/mC,GAASw+D,EAAa5B,GAChCx0D,KAAKm3D,GAASv/D,IAgTtBkjE,CAAaljE,GAASA,OAAQ4E,EAp2BvCm7D,GAAKjmE,UAAUmmE,MAvEf,WACEpnE,KAAKynE,SAAWjB,GAAeA,GAAa,MAAQ,GACpDxmE,KAAKglE,KAAO,GAsEdkC,GAAKjmE,UAAkB,OAzDvB,SAAoBiN,GAClB,IAAIorB,EAASt5B,KAAKu/C,IAAIrxC,WAAelO,KAAKynE,SAASv5D,GAEnD,OADAlO,KAAKglE,MAAQ1rC,EAAS,EAAI,EACnBA,GAuDT4tC,GAAKjmE,UAAU+jB,IA3Cf,SAAiB9W,GACf,IAAIuI,EAAOzW,KAAKynE,SAChB,GAAIjB,GAAc,CAChB,IAAIltC,EAAS7iB,EAAKvI,GAClB,OAAOorB,IAAW6oC,OAAiBp2D,EAAYutB,EAEjD,OAAO7gB,EAAe7T,KAAK6R,EAAMvI,GAAOuI,EAAKvI,QAAOnC,GAsCtDm7D,GAAKjmE,UAAUs+C,IA1Bf,SAAiBrxC,GACf,IAAIuI,EAAOzW,KAAKynE,SAChB,OAAOjB,QAA8Bz6D,IAAd0K,EAAKvI,GAAsBuK,EAAe7T,KAAK6R,EAAMvI,IAyB9Eg5D,GAAKjmE,UAAUikB,IAZf,SAAiBhX,EAAK/G,GACpB,IAAIsP,EAAOzW,KAAKynE,SAGhB,OAFAznE,KAAKglE,MAAQhlE,KAAKu/C,IAAIrxC,GAAO,EAAI,EACjCuI,EAAKvI,GAAQs4D,SAA0Bz6D,IAAV5E,EAAuBg7D,EAAiBh7D,EAC9DnH,MAuHTsnE,GAAUrmE,UAAUmmE,MApFpB,WACEpnE,KAAKynE,SAAW,GAChBznE,KAAKglE,KAAO,GAmFdsC,GAAUrmE,UAAkB,OAvE5B,SAAyBiN,GACvB,IAAIuI,EAAOzW,KAAKynE,SACZn9D,EAAQs9D,GAAanxD,EAAMvI,GAE/B,QAAI5D,EAAQ,IAIRA,GADYmM,EAAK/U,OAAS,EAE5B+U,EAAKwgB,MAELzzB,EAAOoB,KAAK6R,EAAMnM,EAAO,KAEzBtK,KAAKglE,KACA,KA0DTsC,GAAUrmE,UAAU+jB,IA9CpB,SAAsB9W,GACpB,IAAIuI,EAAOzW,KAAKynE,SACZn9D,EAAQs9D,GAAanxD,EAAMvI,GAE/B,OAAO5D,EAAQ,OAAIyB,EAAY0K,EAAKnM,GAAO,IA2C7Cg9D,GAAUrmE,UAAUs+C,IA/BpB,SAAsBrxC,GACpB,OAAO05D,GAAa5nE,KAAKynE,SAAUv5D,IAAQ,GA+B7Co5D,GAAUrmE,UAAUikB,IAlBpB,SAAsBhX,EAAK/G,GACzB,IAAIsP,EAAOzW,KAAKynE,SACZn9D,EAAQs9D,GAAanxD,EAAMvI,GAQ/B,OANI5D,EAAQ,KACRtK,KAAKglE,KACPvuD,EAAKvU,KAAK,CAACgM,EAAK/G,KAEhBsP,EAAKnM,GAAO,GAAKnD,EAEZnH,MAyGTunE,GAAStmE,UAAUmmE,MAtEnB,WACEpnE,KAAKglE,KAAO,EACZhlE,KAAKynE,SAAW,CACd,KAAQ,IAAIP,GACZ,IAAO,IAAKb,IAAOiB,IACnB,OAAU,IAAIJ,KAkElBK,GAAStmE,UAAkB,OArD3B,SAAwBiN,GACtB,IAAIorB,EAAS8wC,GAAWpqE,KAAMkO,GAAa,OAAEA,GAE7C,OADAlO,KAAKglE,MAAQ1rC,EAAS,EAAI,EACnBA,GAmDTiuC,GAAStmE,UAAU+jB,IAvCnB,SAAqB9W,GACnB,OAAOk8D,GAAWpqE,KAAMkO,GAAK8W,IAAI9W,IAuCnCq5D,GAAStmE,UAAUs+C,IA3BnB,SAAqBrxC,GACnB,OAAOk8D,GAAWpqE,KAAMkO,GAAKqxC,IAAIrxC,IA2BnCq5D,GAAStmE,UAAUikB,IAdnB,SAAqBhX,EAAK/G,GACxB,IAAIsP,EAAO2zD,GAAWpqE,KAAMkO,GACxB82D,EAAOvuD,EAAKuuD,KAIhB,OAFAvuD,EAAKyO,IAAIhX,EAAK/G,GACdnH,KAAKglE,MAAQvuD,EAAKuuD,MAAQA,EAAO,EAAI,EAC9BhlE,MAyDT8tE,GAAS7sE,UAAU0+C,IAAMmuB,GAAS7sE,UAAUiB,KAnB5C,SAAqBiF,GAEnB,OADAnH,KAAKynE,SAASviD,IAAI/d,EAAOg7D,GAClBniE,MAkBT8tE,GAAS7sE,UAAUs+C,IANnB,SAAqBp4C,GACnB,OAAOnH,KAAKynE,SAASloB,IAAIp4C,IAqG3BqgE,GAAMvmE,UAAUmmE,MA3EhB,WACEpnE,KAAKynE,SAAW,IAAIH,GACpBtnE,KAAKglE,KAAO,GA0EdwC,GAAMvmE,UAAkB,OA9DxB,SAAqBiN,GACnB,IAAIuI,EAAOzW,KAAKynE,SACZnuC,EAAS7iB,EAAa,OAAEvI,GAG5B,OADAlO,KAAKglE,KAAOvuD,EAAKuuD,KACV1rC,GA0DTkuC,GAAMvmE,UAAU+jB,IA9ChB,SAAkB9W,GAChB,OAAOlO,KAAKynE,SAASziD,IAAI9W,IA8C3Bs5D,GAAMvmE,UAAUs+C,IAlChB,SAAkBrxC,GAChB,OAAOlO,KAAKynE,SAASloB,IAAIrxC,IAkC3Bs5D,GAAMvmE,UAAUikB,IArBhB,SAAkBhX,EAAK/G,GACrB,IAAIsP,EAAOzW,KAAKynE,SAChB,GAAIhxD,aAAgB6wD,GAAW,CAC7B,IAAIgD,EAAQ7zD,EAAKgxD,SACjB,IAAKpB,IAAQiE,EAAM5oE,OAAS6oE,IAG1B,OAFAD,EAAMpoE,KAAK,CAACgM,EAAK/G,IACjBnH,KAAKglE,OAASvuD,EAAKuuD,KACZhlE,KAETyW,EAAOzW,KAAKynE,SAAW,IAAIF,GAAS+C,GAItC,OAFA7zD,EAAKyO,IAAIhX,EAAK/G,GACdnH,KAAKglE,KAAOvuD,EAAKuuD,KACVhlE,MA+hBT,IAAI2oE,GAAc5C,GAA+B,SAASx0D,GACxD,OAAc,MAAVA,EACK,IAETA,EAASnR,OAAOmR,GA9sClB,SAAqBhH,EAAOojE,GAM1B,IALA,IAAIrjE,GAAS,EACT5I,EAAkB,MAAT6I,EAAgB,EAAIA,EAAM7I,OACnC2uE,EAAW,EACX/2C,EAAS,KAEJhvB,EAAQ5I,GAAQ,CACvB,IAAIyF,EAAQoD,EAAMD,GAwsCkCy+D,EAvsCtC5hE,EAwsCP2+D,EAAqBlhE,KAAK2M,EAAQw3D,KAvsCvCzvC,EAAO+2C,KAAclpE,GAssCoB,IAAS4hE,EAnsCtD,OAAOzvC,EAmsCAg3C,CAAYvK,GAAiBx0D,MAudtC,WACE,MAAO,IA5cL82D,GAAS0F,GAkCb,SAASvD,GAAQrjE,EAAOzF,GAEtB,SADAA,EAAmB,MAAVA,EAAiB0gE,EAAmB1gE,KAE1B,iBAATyF,GAAqB68D,EAASz0D,KAAKpI,KAC1CA,GAAS,GAAKA,EAAQ,GAAK,GAAKA,EAAQzF,EA4D7C,SAASglE,GAAS/kB,GAChB,GAAY,MAARA,EAAc,CAChB,IACE,OAAO8jB,EAAa7gE,KAAK+8C,GACzB,MAAO50C,IACT,IACE,OAAQ40C,EAAO,GACf,MAAO50C,KAEX,MAAO,GAmCT,SAASwiC,GAAGpoC,EAAOsjE,GACjB,OAAOtjE,IAAUsjE,GAAUtjE,GAAUA,GAASsjE,GAAUA,GA5IrDtE,IAAYkC,GAAO,IAAIlC,GAAS,IAAI9G,YAAY,MAAQ+D,GACxDiD,IAAOgC,GAAO,IAAIhC,KAAQ3D,GAC1B34B,IAAWs+B,GAAOt+B,GAAQC,YAAc64B,GACxCyD,IAAO+B,GAAO,IAAI/B,KAAQvD,GAC1BwD,IAAW8B,GAAO,IAAI9B,KAAYrD,KACrCmF,GAAS,SAASlhE,GAChB,IAAImyB,EAASy0C,GAAW5mE,GACpBkpC,EAAO/W,GAAUspC,EAAYz7D,EAAMiS,iBAAcrN,EACjD2+D,EAAar6B,EAAOq2B,GAASr2B,GAAQ,GAEzC,GAAIq6B,EACF,OAAQA,GACN,KAAKjE,GAAoB,OAAOrD,EAChC,KAAKuD,GAAe,OAAOjE,EAC3B,KAAKkE,GAAmB,OAAO/D,EAC/B,KAAKgE,GAAe,OAAO9D,EAC3B,KAAK+D,GAAmB,OAAO5D,EAGnC,OAAO5pC,IA8IX,IAAIyxC,GAAcoD,GAAgB,WAAa,OAAOxtE,UAApB,IAAsCwtE,GAAkB,SAAShnE,GACjG,OAAO0jE,GAAa1jE,IAAUsR,EAAe7T,KAAKuC,EAAO,YACtD2+D,EAAqBlhE,KAAKuC,EAAO,WA0BlCO,GAAUhD,MAAMgD,QAgDhBu+D,GAAWD,IA4Of,WACE,OAAO,GA1LT,SAAS93B,GAAW/mC,GAClB,IAAK8gE,GAAS9gE,GACZ,OAAO,EAIT,IAAI6vC,EAAM+2B,GAAW5mE,GACrB,OAAO6vC,GAAOwrB,GAnmDH,8BAmmDcxrB,GAxmDZ,0BAwmD6BA,GA7lD7B,kBA6lDgDA,EA6B/D,SAAS2zB,GAASxjE,GAChB,MAAuB,iBAATA,GACZA,GAAS,GAAKA,EAAQ,GAAK,GAAKA,GAASi7D,EA4B7C,SAAS6F,GAAS9gE,GAChB,IAAIS,SAAcT,EAClB,OAAgB,MAATA,IAA0B,UAARS,GAA4B,YAARA,GA2B/C,SAASijE,GAAa1jE,GACpB,OAAgB,MAATA,GAAiC,iBAATA,EAoBjC,IAAIsmE,GAAeD,EAhiDnB,SAAmB7rB,GACjB,OAAO,SAASx6C,GACd,OAAOw6C,EAAKx6C,IA8hDsBopE,CAAU/C,GAnvBhD,SAA0BrmE,GACxB,OAAO0jE,GAAa1jE,IAClBwjE,GAASxjE,EAAMzF,WAAa0rE,EAAeW,GAAW5mE,KA+wB1D,SAAS9G,GAAKkR,GACZ,OA1NgB,OADGpK,EA2NAoK,IA1NKo5D,GAASxjE,EAAMzF,UAAYwsC,GAAW/mC,GA1vBhE,SAAuBA,EAAOyjE,GAC5B,IAAI1C,EAAQxgE,GAAQP,GAChBqpE,GAAStI,GAAS6C,GAAY5jE,GAC9BspE,GAAUvI,IAAUsI,GAASvK,GAAS9+D,GACtCupE,GAAUxI,IAAUsI,IAAUC,GAAUhD,GAAatmE,GACrD8jE,EAAc/C,GAASsI,GAASC,GAAUC,EAC1Cp3C,EAAS2xC,EAloBf,SAAmBp6D,EAAG8zD,GAIpB,IAHA,IAAIr6D,GAAS,EACTgvB,EAAS50B,MAAMmM,KAEVvG,EAAQuG,GACfyoB,EAAOhvB,GAASq6D,EAASr6D,GAE3B,OAAOgvB,EA2nBoB0xC,CAAU7jE,EAAMzF,OAAQmN,QAAU,GACzDnN,EAAS43B,EAAO53B,OAEpB,IAAK,IAAIwM,KAAO/G,GACTyjE,IAAanyD,EAAe7T,KAAKuC,EAAO+G,IACvC+8D,IAEQ,UAAP/8D,GAECuiE,IAAkB,UAAPviE,GAA0B,UAAPA,IAE9BwiE,IAAkB,UAAPxiE,GAA0B,cAAPA,GAA8B,cAAPA,IAEtDs8D,GAAQt8D,EAAKxM,KAElB43B,EAAOp3B,KAAKgM,GAGhB,OAAOorB,EA47BsB4xC,CAAc35D,GAtwB7C,SAAkBA,GAChB,GAyZI8+B,GADelpC,EAxZFoK,IAyZGpK,EAAMiS,YAGnBjS,KAFqB,mBAARkpC,GAAsBA,EAAKpvC,WAAcokE,GAzZ3D,OAAOa,GAAW30D,GAuZtB,IAAqBpK,EACfkpC,EAtZA/W,EAAS,GACb,IAAK,IAAIprB,KAAO9N,OAAOmR,GACjBkH,EAAe7T,KAAK2M,EAAQrD,IAAe,eAAPA,GACtCorB,EAAOp3B,KAAKgM,GAGhB,OAAOorB,EA4vB8C6xC,CAAS55D,GA3NhE,IAAqBpK,EAqQrB3H,EAAOD,QAlNP,SAAiB4H,EAAOsjE,GACtB,OAAO2D,GAAYjnE,EAAOsjE,aCtmD5B,IAAIn+D,EAAU9M,EAAOD,QAAU,CAC7BgN,EAAG,CAAC,CACFC,KAAM,UACNC,IAAK,YAEPC,EAAG,CAAC,CAGFF,KAAM,SACNC,IAAK,wCACLE,MAAO,CAAC,WAAY,YAAa,iBAAkB,UAAW,QAAS,WACvEC,OAAQ,wBAGVC,EAAG,CAAC,CAAEL,KAAM,SACZhL,EAAG,CAAC,CAAEgL,KAAM,gBACZM,EAAG,CAAC,CAAEN,KAAM,QACZO,EAAG,CAAC,CAAEP,KAAM,UACZQ,EAAG,CAAC,CAAER,KAAM,UACZS,EAAG,CAAC,CAAET,KAAM,cACZU,EAAG,CAAC,CAAEV,KAAM,YAEZxH,EAAG,CAAC,CAEFwH,KAAM,SACNC,IAAK,eACLE,MAAO,CAAC,QAAS,QACjBC,OAAQ,UAEVO,EAAG,CAAC,CAEFX,KAAM,aACNC,IAAK,mBACLE,MAAO,CAAC,UAAW,MACnBC,OAAQ,eAEVQ,EAAG,CAAC,CAEFlL,KAAM,YACNuK,IAAK,4BACLE,MAAO,CAAC,OAAQ,SAChBC,OAAQ,UAEVzI,EAAG,CAAC,CAIFsI,IAAK,kCACLE,MAAO,CAAC,OAAQ,OAAQ,WAAY,YACpCC,OAAQ,gBAEVS,EAAG,CACD,CAEEnL,KAAM,MACNuK,IAAK,yDACLE,MAAO,CAAC,UAAW,QAAS,OAAQ,YACpCC,OAAQ,SAAUF,GAChB,OAAQA,EAAU,SACd,qBACAA,EAAEY,KACA,kBACA,iBAGV,CAGEpL,KAAM,OACNuK,IAAK,wBACLE,MAAO,CAAC,UAAW,UACnBC,OAAQ,cAEV,CAEEJ,KAAM,UACNC,IAAK,gBACLG,OAAQ,cAEV,CAEEJ,KAAM,OACNC,IAAK,sCACLE,MAAO,CAAC,OAAQ,UAAW,QAAS,WACpCC,OAAQ,SAAUF,GAChB,OAAqB,MAAbA,EAAEa,QACN,qBACA,YAGR,CAEErL,KAAM,eACNuK,IAAK,kCACLE,MAAO,CAAC,UAAW,SACnBC,OAAQ,yBAEV,CAEE1K,KAAM,SACNuK,IAAK,6CACLE,MAAO,CAAC,UAAW,OAAQ,WAC3BC,OAAQ,SAAUF,GAChB,OAAqB,MAAbA,EAAEc,QACN,mBACA,kBAGR,CAIEtL,KAAM,MACNuK,IAAK,uFACLE,MAAO,CAAC,QAAS,YAAa,cAAe,MAAO,UACpDC,OAAQ,SAAUF,GAChB,MACE,aACCA,EAAEN,UAAY,MAAQ,OACtBM,EAAE,eAAiB,MAAQ,MAC5B,OACCA,EAAEe,OAAS,MAAQ,MAI1B,CAEEjB,KAAM,mBACNC,IAAK,yBAEP,CAEEvK,KAAM,SACNuK,IAAK,0CACLE,MAAO,CAAC,KAAM,QAAS,SAAU,iBACjCC,OAAQ,SAAUF,GAChB,OAA2B,MAAnBA,EAAEgB,cACN,qBACA,oBAGR,CAEElB,KAAM,QACNC,IAAK,eACLG,OAAQ,YAEV,CAEEJ,KAAM,iBACNC,IAAK,6BACLG,OAAQ,iBAEV,CAEEJ,KAAM,MACNC,IAAK,gBACLG,OAAQ,UAEV,CAEEJ,KAAM,OACNC,IAAK,aACLG,OAAQ,WAEV,CAEEJ,KAAM,QACNC,IAAK,yBACLG,OAAQ,YAEV,CAEEJ,KAAM,WACNC,IAAK,4BACLG,OAAQ,eAEV,CAEEJ,KAAM,YACNC,IAAK,0CAEP,CAEED,KAAM,UACNC,IAAK,eAEP,CAEED,KAAM,WACNC,IAAK,mBACLG,OAAQ,gBAEV,CAEEJ,KAAM,SACNC,IAAK,iBACLG,OAAQ,cAEV,CAEEJ,KAAM,cACNC,IAAK,2BACLE,MAAO,CAAC,OAAQ,QAChBC,OAAQ,qBAEV,CAME1K,KAAK,aACLuK,IAAK,+KACLE,MAAO,CAAC,aAAc,YAAa,YAAa,WAAY,KAAM,OAAQ,OAAQ,QAAS,QAAS,UAAW,aAAc,aAAc,gBAC3IC,OAAQ,SAAUF,GAChB,IAAIiB,EAAM,qCAaV,OAXAA,GAAmB,MAAXjB,EAAEkB,MAAiB,qBAAuB,OAGlDD,GAAqB,MAAbjB,EAAEmB,QAAmB,cAAgB,KAEzB,MAAhBnB,EAAEoB,aACJH,GAAO,mBAGTA,GAA2B,MAAnBjB,EAAE,cAAyB,iBAAmB,OACzB,MAArBA,EAAE,gBAA2B,mBAAqB,QAI9D,CAEEF,KAAM,kBACNC,IAAK,wBAEP,CAEED,KAAM,mBACNC,IAAK,0BACLG,OAAQ,wBAEV,CAEEJ,KAAM,aACNC,IAAK,qBACLG,OAAQ,kBAEV,CAEE1K,KAAM,QACNuK,IAAK,kCACLE,MAAO,CAAC,KAAM,YAAa,SAC3BC,OAAQ,SAAUF,GAChB,IAAIiB,EAAM,UAOV,OANmB,MAAfjB,EAAEzF,YACJ0G,GAAO,MACQ,MAAXjB,EAAEvF,QACJwG,GAAO,QAGJA,IAGX,CAGEzL,KAAM,aAENuK,IAAK,mEACLE,MAAO,CAAC,YAAa,SACrBC,OAAQ,oBAEV,CAEEJ,KAAM,eACNC,IAAK,gCACLE,MAAO,CAAC,WAAY,SACpBC,OAAQ,wBAEV,CAEE1K,KAAM,SACNuK,IAAK,oBACLE,MAAO,CAAC,OAAQ,QAChBC,OAAQ,eAEV,CAEEJ,KAAM,UACNC,IAAK,eAEP,CAEED,KAAM,YACNC,IAAK,iBAEP,CAEED,KAAM,UACNC,IAAK,sCACLE,MAAO,CAAC,gBAAiB,MAAO,kBAChCC,OAAQ,SAAUF,GAChB,OAA4B,MAApBA,EAAEqB,eACN,mBACA,kBAGR,CAEEvB,KAAM,cACNC,IAAK,0BACLG,OAAQ,oBAEV,CAEE1K,KAAM,OACNuK,IAAK,sCACLE,MAAO,CAAC,KAAM,YAAa,UAC3BC,OAAQ,SAAUF,GAChB,OAAQA,EAAQ,OAAI,eAAiB,cAGzC,CAIExK,KAAM,aACNuK,IAAK,IAAIuB,OAEP,wKAMFrB,MAAO,CAAC,KAAM,OAAQ,SAAU,OAAQ,UACxCC,OAAQ,SAAUF,GAChB,MAAO,sBAAwBA,EAAEuB,KAAO,SAAW,MAGvD,CAGEzB,KAAM,YACNC,IAAK,IAAIuB,OAEP,2FAQFrB,MAAO,CAAC,OAAQ,QAAS,OAAQ,SACjCC,OAAQ,SAAUF,GAChB,MAAO,mBAAqBA,EAAEuB,KAAO,SAAW,MAGpD,CAKEzB,KAAM,eACNC,IAAK,kCACLE,MAAO,CAAC,SACRC,OAAQ,iBAEV,CAGEJ,KAAM,YACNC,IAAK,8BACLG,OAAQ,gBAEV,CAGEJ,KAAM,eACNC,IAAK,6DACLE,MAAO,CAAC,aAAc,UAAW,eAAgB,cAAe,WAChEC,OAAQ,iCAEV,CAEEJ,KAAM,aACNC,IAAK,kBAEP,CAEED,KAAM,QACNC,IAAK,cACLG,OAAQ,YAEV,CAGEJ,KAAM,WACNC,IAAK,oBACLG,OAAQ,gBAEV,CAGEJ,KAAM,iBACNC,IAAK,2BACLG,OAAQ,uBAEV,CAGE1K,KAAK,cACLuK,IAAK,kCACLE,MAAO,CAAC,SAAU,aAClBC,OAAQ,SAAUF,GAChB,MAAO,gBAAiC,MAAfA,EAAEikE,UAAoB,MAAQ,MAG3D,CAGEnkE,KAAK,WACLC,IAAK,wEACLE,MAAO,CAAC,KAAM,iBAAkB,kBAAmB,gBAAiB,mBACpEC,OAAQ,SAAUF,GAChB,IAAIiB,EAAM,YAKV,OAJAA,GAAgB,MAARjB,EAAErH,GAAa,WAAa,OACpCsI,GAA6B,MAArBjB,EAAEkkE,gBAA0B,MAAQ,IAC5CjjE,GAA2B,MAAnBjB,EAAEmkE,cAAwB,WAAa,KAClB,MAArBnkE,EAAEokE,gBAA0B,MAAQ,MAIhD,CAEEtkE,KAAM,WACNC,IAAK,gBACLG,OAAQ,aAEV,CAEEJ,KAAM,UACNC,IAAK,gBACLG,OAAQ,cAGV,CAEEJ,KAAM,gBACNC,IAAK,iCACLG,OAAQ,gBAEV,CAEEJ,KAAM,aACNC,IAAK,gBACLG,OAAQ,aAEV,CAEEJ,KAAM,aACNC,IAAK,gBACLG,OAAQ,aAEV,CAEEJ,KAAM,cACNC,IAAK,wCACLE,MAAO,CAAC,KAAM,WACdC,OAAQ,uBAEV,CAEE1K,KAAM,UACNyK,MAAO,CAAC,YAMdvM,OAAOC,KAAKiM,GAAS/L,SAAQ,SAAU2N,GAC1B5B,EAAQ4B,GACd3N,SAAQ,SAAU4N,GAChBA,EAAI1B,MACP0B,EAAI1B,IAAM,QAEP0B,EAAIvB,SACPuB,EAAIvB,OAAS,2BC1enB,IAAIwB,EAAS,EAAQ,KACjBC,EAAS,EAAQ,KAErB9O,EAAQ2M,MAAQmC,EAChB9O,EAAQqL,MAAQwD,EAAOxD,MACvBrL,EAAQgP,YAAcH,EAAOG,YAC7BhP,EAAQ+O,gBAAkBF,EAAOE,gBACjC/O,EAAQiP,cAAgBJ,EAAOI,cAC/BjP,EAAQkP,sBAAwBL,EAAOK,sBACvClP,EAAQmP,qBAAuBN,EAAOM,qBACtCnP,EAAQoP,yBAA2BP,EAAOO,wCCV1C,IAAIC,EAAa,SAAUrC,GACzB,OAAOsC,OAAOC,OAAOvC,MAAQA,EAAIuC,OAAOvC,GAAKA,GAgB3CwC,EAAW,SAAUZ,EAAKa,EAAUC,GACtC,IAAIC,EAAaf,EAAI3B,MAAQ2B,EAAIxB,MAC7BwB,EAAIjM,OAAS8M,EAASb,EAAIjM,MAC5B8M,EAASb,EAAIjM,MAAQ,GAEdgN,IAAeF,EAASb,EAAI3B,QACnCwC,EAASb,EAAI3B,MAAQ,IAEvB,IAAI2C,EAAchB,EAAIjM,KACpB,GACAgN,EAAaF,EAASb,EAAI3B,MAAQwC,GAvBf,SAAU5K,EAAO4K,EAAUrC,EAAOyC,GACvD,GAAIA,IAAYzC,EACdqC,EAASI,GAAWR,EAAWxK,EAAM,SAGrC,IAAK,IAAI5C,EAAI,EAAGA,EAAImL,EAAMjL,OAAQF,GAAK,EACnB,MAAd4C,EAAM5C,EAAE,KACVwN,EAASrC,EAAMnL,IAAMoN,EAAWxK,EAAM5C,EAAE,KAkB9C6N,CAAiBJ,EAAQ7K,MAAM+J,EAAI1B,KAAM0C,EAAahB,EAAIxB,MAAOwB,EAAI3B,MAEjE2B,EAAIjM,MACN8M,EAASb,EAAIjM,MAAMA,KAAKiN,IAIxB7C,EAAU,EAAQ,KAClBgD,EAAYtB,OAAO/M,UAAUsO,KAAK3O,KAAK,iBAE3CrB,EAAQqL,MAAQ,SAAU7C,GACxB,IAAIP,EAAU,GACVG,EAAQ,GACRqH,EAAWxH,EAoBf,OAjBAO,EAAI7D,MAAM,gBAAgB6C,OAAOuI,GAAW/O,SAAQ,SAAU0E,GAC5D,IAAI2C,EAAO3C,EAAE,GACTgK,EAAUhK,EAAEN,MAAM,GACT,MAATiD,IACFD,EAAMzF,KAAK,CAACsN,IAAK,GAAIC,KAAM,KAC3BT,EAAWrH,EAAMA,EAAMjG,OAAO,IAGhC,IAAK,IAAIsJ,EAAI,EAAGA,GAAKsB,EAAQ1E,IAAS,IAAIlG,OAAQsJ,GAAK,EAAG,CACxD,IAAImD,EAAM7B,EAAQ1E,GAAMoD,GACxB,GAAImD,EAAI1B,IAAI8C,KAAKN,GACf,OAAOF,EAASZ,EAAKa,EAAUC,OAKrCzH,EAAQG,MAAQA,EACTH,GAGT,IAAIkI,EAAe,SAAUC,EAAKC,GAChC,IAAI/C,EAAI+C,EAAK1L,MAAM,QAAS,GAM5B,OALiB,IAAb2I,EAAEnL,OACJiO,EAAI9C,EAAE,IAAM+B,EAAW/B,EAAE,IACH,IAAbA,EAAEnL,QAAgBkO,EAAKlO,OAAS,IACzCiO,EAAI9C,EAAE,SAAMd,GAEP4D,GAGTpQ,EAAQgP,YAAc,SAAUZ,GAC9B,OAAOA,EAAIzJ,MAAM,QAAQ2L,OAAOH,EAAc,KAIhDnQ,EAAQ+O,gBAAkB/O,EAAQgP,YAElChP,EAAQiP,cAAgB,SAAUb,GAChC,OAAOA,EAAIuT,WAAWhd,MAAM,KAAKgD,IAAI4H,SAGvCvP,EAAQkP,sBAAwB,SAAUd,GAGxC,IAFA,IAAImC,EAAa,GACb5E,EAAQyC,EAAIzJ,MAAM,KAAKgD,IAAI0H,GACtBpN,EAAI,EAAGA,EAAI0J,EAAMxJ,OAAQF,GAAK,EACrCsO,EAAW5N,KAAK,CACd6N,UAAW7E,EAAM1J,GACjBwO,GAAI9E,EAAM1J,EAAI,GACdyO,KAAM/E,EAAM1J,EAAI,KAGpB,OAAOsO,GAGTvQ,EAAQmP,qBAAuB,SAAUf,GACvC,OAAOA,EAAIzJ,MAAM,KAAKgD,KAAI,SAAUgJ,GAClC,OAAOA,EAAKC,UAAU,EAAGD,EAAKxO,OAAO,GAAGwC,MAAM,KAAK2L,OAAOH,EAAc,QAI5EnQ,EAAQoP,yBAA2B,SAAUhB,GAC3C,OAAOA,EAAIzJ,MAAM,KAAKgD,KAAI,SAAUkJ,GAClC,OAAOA,EAAOlM,MAAM,KAAKgD,KAAI,SAAU0F,GACrC,IAAIyD,EAAMC,GAAS,EASnB,MAPkB,MAAd1D,EAAO,GACTyD,EAAOzB,EAAWhC,IAElByD,EAAOzB,EAAWhC,EAAOuD,UAAU,EAAGvD,EAAOlL,SAC7C4O,GAAS,GAGJ,CACLD,KAAMA,EACNC,OAAQA,yBCvHhB,IAAIhE,EAAU,EAAQ,KAGlBiE,EAAe,WACf3D,EAAS,SAAU4D,GACrB,IAAIhP,EAAI,EACJiD,EAAO9D,UACPc,EAAMgD,EAAK/C,OACf,OAAO8O,EAAUC,QAAQF,GAAc,SAAUG,GAC/C,GAAIlP,GAAKC,EACP,OAAOiP,EAET,IAAI/O,EAAM8C,EAAKjD,GAEf,OADAA,GAAK,EACGkP,GACR,IAAK,KACH,MAAO,IACT,IAAK,KACH,OAAO7B,OAAOlN,GAChB,IAAK,KACH,OAAOmN,OAAOnN,GAChB,IAAK,KACH,MAAO,QAMTgP,EAAW,SAAU/I,EAAMuG,EAAKa,GAClC,IAIIvK,EAAO,CAACmD,EAAO,KAJTuG,EAAIvB,kBAAkBgE,SAC7BzC,EAAIvB,OAAOuB,EAAIjM,KAAO8M,EAAWA,EAASb,EAAI3B,OAC/C2B,EAAIvB,SAGN,GAAIuB,EAAIxB,MACN,IAAK,IAAInL,EAAI,EAAGA,EAAI2M,EAAIxB,MAAMjL,OAAQF,GAAK,EAAG,CAC5C,IAAIqP,EAAI1C,EAAIxB,MAAMnL,GACd2M,EAAI3B,KACN/H,EAAKvC,KAAK8M,EAASb,EAAI3B,MAAMqE,IAG7BpM,EAAKvC,KAAK8M,EAASb,EAAIxB,MAAMnL,UAKjCiD,EAAKvC,KAAK8M,EAASb,EAAI3B,OAEzB,OAAOI,EAAOlM,MAAM,KAAM+D,IAKxBqM,EAAoB,CACtB,IAAK,IAAK,IAAK,IACf,IAAK,IAAK,IAAK,IACf,IAAK,IAAK,IAAK,IAAK,KAElBC,EAAoB,CAAC,IAAK,IAAK,IAAK,KAGxCvR,EAAOD,QAAU,SAAUiI,EAASwJ,GAClCA,EAAOA,GAAQ,GAEQ,MAAnBxJ,EAAQyJ,UACVzJ,EAAQyJ,QAAU,GAEA,MAAhBzJ,EAAQgF,OACVhF,EAAQgF,KAAO,KAEjBhF,EAAQG,MAAMpH,SAAQ,SAAUoG,GACR,MAAlBA,EAAMuK,WACRvK,EAAMuK,SAAW,OAIrB,IAAIC,EAAaH,EAAKG,YAAcL,EAChCM,EAAaJ,EAAKI,YAAcL,EAChChJ,EAAM,GAkCV,OA/BAoJ,EAAW5Q,SAAQ,SAAUqH,GAC3B0E,EAAQ1E,GAAMrH,SAAQ,SAAU4N,GAC1BA,EAAI3B,QAAQhF,GAAgC,MAArBA,EAAQ2G,EAAI3B,MACrCzE,EAAI7F,KAAKyO,EAAS/I,EAAMuG,EAAK3G,IAEtB2G,EAAIjM,QAAQsF,GAAgC,MAArBA,EAAQ2G,EAAIjM,OAC1CsF,EAAQ2G,EAAIjM,MAAM3B,SAAQ,SAAU8Q,GAClCtJ,EAAI7F,KAAKyO,EAAS/I,EAAMuG,EAAKkD,aAOrC7J,EAAQG,MAAMpH,SAAQ,SAAUoG,GAC9BoB,EAAI7F,KAAKyO,EAAS,IAAKrE,EAAQnI,EAAE,GAAIwC,IAErCyK,EAAW7Q,SAAQ,SAAUqH,GAC3B0E,EAAQ1E,GAAMrH,SAAQ,SAAU4N,GAC1BA,EAAI3B,QAAQ7F,GAA4B,MAAnBA,EAAMwH,EAAI3B,MACjCzE,EAAI7F,KAAKyO,EAAS/I,EAAMuG,EAAKxH,IAEtBwH,EAAIjM,QAAQyE,GAA4B,MAAnBA,EAAMwH,EAAIjM,OACtCyE,EAAMwH,EAAIjM,MAAM3B,SAAQ,SAAU8Q,GAChCtJ,EAAI7F,KAAKyO,EAAS/I,EAAMuG,EAAKkD,gBAOhCtJ,EAAIwB,KAAK,QAAU,8BC5G5B,MAAMwnE,EAAW,CAIjBA,mBAA8B,WAC5B,OAAO9mE,KAAKE,SAAS+W,SAAS,IAAI7c,OAAO,EAAG,MAI9C0sE,EAASC,WAAaD,EAASE,qBAG/BF,EAASG,WAAa,SAASC,GAC7B,OAAOA,EAAK/S,OAAOl6D,MAAM,MAAMgD,KAAIpD,GAAQA,EAAKs6D,UAGlD2S,EAASK,cAAgB,SAASD,GAEhC,OADcA,EAAKjtE,MAAM,QACZgD,KAAI,CAACqkB,EAAMjhB,KAAWA,EAAQ,EACzC,KAAOihB,EAAOA,GAAM6yC,OAAS,UAIjC2S,EAASM,eAAiB,SAASF,GACjC,MAAMG,EAAWP,EAASK,cAAcD,GACxC,OAAOG,GAAYA,EAAS,IAI9BP,EAASQ,iBAAmB,SAASJ,GACnC,MAAMG,EAAWP,EAASK,cAAcD,GAExC,OADAG,EAASnkC,QACFmkC,GAITP,EAASS,YAAc,SAASL,EAAM96D,GACpC,OAAO06D,EAASG,WAAWC,GAAMpqE,QAAOjD,GAAiC,IAAzBA,EAAKT,QAAQgT,MAO/D06D,EAASU,eAAiB,SAAS3tE,GACjC,IAAIoH,EAGFA,EADmC,IAAjCpH,EAAKT,QAAQ,gBACPS,EAAKqM,UAAU,IAAIjM,MAAM,KAEzBJ,EAAKqM,UAAU,IAAIjM,MAAM,KAGnC,MAAMwtE,EAAY,CAChBC,WAAYzmE,EAAM,GAClB6E,UAAW,CAAC,EAAG,MAAO,EAAG,QAAQ7E,EAAM,KAAOA,EAAM,GACpD0mE,SAAU1mE,EAAM,GAAGisB,cACnB06C,SAAUppE,SAASyC,EAAM,GAAI,IAC7B8E,GAAI9E,EAAM,GACVqC,QAASrC,EAAM,GACf+E,KAAMxH,SAASyC,EAAM,GAAI,IAEzBtD,KAAMsD,EAAM,IAGd,IAAK,IAAI1J,EAAI,EAAGA,EAAI0J,EAAMxJ,OAAQF,GAAK,EACrC,OAAQ0J,EAAM1J,IACZ,IAAK,QACHkwE,EAAUI,eAAiB5mE,EAAM1J,EAAI,GACrC,MACF,IAAK,QACHkwE,EAAUK,YAActpE,SAASyC,EAAM1J,EAAI,GAAI,IAC/C,MACF,IAAK,UACHkwE,EAAUM,QAAU9mE,EAAM1J,EAAI,GAC9B,MACF,IAAK,QACHkwE,EAAUO,MAAQ/mE,EAAM1J,EAAI,GAC5BkwE,EAAUQ,iBAAmBhnE,EAAM1J,EAAI,GACvC,MACF,aAC8BuK,IAAxB2lE,EAAUxmE,EAAM1J,MAClBkwE,EAAUxmE,EAAM1J,IAAM0J,EAAM1J,EAAI,IAKxC,OAAOkwE,GAKTX,EAASoB,eAAiB,SAAST,GACjC,MAAM3pE,EAAM,GACZA,EAAI7F,KAAKwvE,EAAUC,YAEnB,MAAM5hE,EAAY2hE,EAAU3hE,UACV,QAAdA,EACFhI,EAAI7F,KAAK,GACc,SAAd6N,EACThI,EAAI7F,KAAK,GAET6F,EAAI7F,KAAK6N,GAEXhI,EAAI7F,KAAKwvE,EAAUE,SAAS7sB,eAC5Bh9C,EAAI7F,KAAKwvE,EAAUG,UACnB9pE,EAAI7F,KAAKwvE,EAAUnkE,SAAWmkE,EAAU1hE,IACxCjI,EAAI7F,KAAKwvE,EAAUzhE,MAEnB,MAAMrI,EAAO8pE,EAAU9pE,KAkBvB,OAjBAG,EAAI7F,KAAK,OACT6F,EAAI7F,KAAK0F,GACI,SAATA,GAAmB8pE,EAAUI,gBAC7BJ,EAAUK,cACZhqE,EAAI7F,KAAK,SACT6F,EAAI7F,KAAKwvE,EAAUI,gBACnB/pE,EAAI7F,KAAK,SACT6F,EAAI7F,KAAKwvE,EAAUK,cAEjBL,EAAUM,SAAgD,QAArCN,EAAUE,SAASz6C,gBAC1CpvB,EAAI7F,KAAK,WACT6F,EAAI7F,KAAKwvE,EAAUM,WAEjBN,EAAUQ,kBAAoBR,EAAUO,SAC1ClqE,EAAI7F,KAAK,SACT6F,EAAI7F,KAAKwvE,EAAUQ,kBAAoBR,EAAUO,QAE5C,aAAelqE,EAAIwB,KAAK,MAMjCwnE,EAASqB,gBAAkB,SAAStuE,GAClC,OAAOA,EAAKO,OAAO,IAAIH,MAAM,MAK/B6sE,EAASsB,YAAc,SAASvuE,GAC9B,IAAIoH,EAAQpH,EAAKO,OAAO,GAAGH,MAAM,KACjC,MAAMg4D,EAAS,CACboW,YAAa7pE,SAASyC,EAAMiiC,QAAS,KAUvC,OAPAjiC,EAAQA,EAAM,GAAGhH,MAAM,KAEvBg4D,EAAO1vD,KAAOtB,EAAM,GACpBgxD,EAAOqW,UAAY9pE,SAASyC,EAAM,GAAI,IACtCgxD,EAAOsW,SAA4B,IAAjBtnE,EAAMxJ,OAAe+G,SAASyC,EAAM,GAAI,IAAM,EAEhEgxD,EAAOuW,YAAcvW,EAAOsW,SACrBtW,GAKT6U,EAAS2B,YAAc,SAASC,GAC9B,IAAIx5D,EAAKw5D,EAAML,iBACoBvmE,IAA/B4mE,EAAMC,uBACRz5D,EAAKw5D,EAAMC,sBAEb,MAAMJ,EAAWG,EAAMH,UAAYG,EAAMF,aAAe,EACxD,MAAO,YAAct5D,EAAK,IAAMw5D,EAAMnmE,KAAO,IAAMmmE,EAAMJ,WACvC,IAAbC,EAAiB,IAAMA,EAAW,IAAM,QAM/CzB,EAAS8B,YAAc,SAAS/uE,GAC9B,MAAMoH,EAAQpH,EAAKO,OAAO,GAAGH,MAAM,KACnC,MAAO,CACLmB,GAAIoD,SAASyC,EAAM,GAAI,IACvBkB,UAAWlB,EAAM,GAAG7H,QAAQ,KAAO,EAAI6H,EAAM,GAAGhH,MAAM,KAAK,GAAK,WAChE+N,IAAK/G,EAAM,KAMf6lE,EAAS+B,YAAc,SAASC,GAC9B,MAAO,aAAeA,EAAgB1tE,IAAM0tE,EAAgBC,cACvDD,EAAgB3mE,WAA2C,aAA9B2mE,EAAgB3mE,UAC1C,IAAM2mE,EAAgB3mE,UACtB,IACJ,IAAM2mE,EAAgB9gE,IAAM,QAMlC8+D,EAASkC,UAAY,SAASnvE,GAC5B,MAAMo4D,EAAS,GACf,IAAIgX,EACJ,MAAMhoE,EAAQpH,EAAKO,OAAOP,EAAKT,QAAQ,KAAO,GAAGa,MAAM,KACvD,IAAK,IAAI8G,EAAI,EAAGA,EAAIE,EAAMxJ,OAAQsJ,IAChCkoE,EAAKhoE,EAAMF,GAAGozD,OAAOl6D,MAAM,KAC3Bg4D,EAAOgX,EAAG,GAAG9U,QAAU8U,EAAG,GAE5B,OAAOhX,GAIT6U,EAASoC,UAAY,SAASR,GAC5B,IAAI7uE,EAAO,GACPqV,EAAKw5D,EAAML,YAIf,QAHmCvmE,IAA/B4mE,EAAMC,uBACRz5D,EAAKw5D,EAAMC,sBAETD,EAAMS,YAAchzE,OAAOC,KAAKsyE,EAAMS,YAAY1xE,OAAQ,CAC5D,MAAM2xE,EAAS,GACfjzE,OAAOC,KAAKsyE,EAAMS,YAAY7yE,SAAQ86D,SACJtvD,IAA5B4mE,EAAMS,WAAW/X,GACnBgY,EAAOnxE,KAAKm5D,EAAQ,IAAMsX,EAAMS,WAAW/X,IAE3CgY,EAAOnxE,KAAKm5D,MAGhBv3D,GAAQ,UAAYqV,EAAK,IAAMk6D,EAAO9pE,KAAK,KAAO,OAEpD,OAAOzF,GAKTitE,EAASuC,YAAc,SAASxvE,GAC9B,MAAMoH,EAAQpH,EAAKO,OAAOP,EAAKT,QAAQ,KAAO,GAAGa,MAAM,KACvD,MAAO,CACL0D,KAAMsD,EAAMiiC,QACZomC,UAAWroE,EAAM3B,KAAK,OAK1BwnE,EAASyC,YAAc,SAASb,GAC9B,IAAIc,EAAQ,GACRt6D,EAAKw5D,EAAML,YAYf,YAXmCvmE,IAA/B4mE,EAAMC,uBACRz5D,EAAKw5D,EAAMC,sBAETD,EAAMe,cAAgBf,EAAMe,aAAahyE,QAE3CixE,EAAMe,aAAanzE,SAAQozE,IACzBF,GAAS,aAAet6D,EAAK,IAAMw6D,EAAG/rE,MACrC+rE,EAAGJ,WAAaI,EAAGJ,UAAU7xE,OAAS,IAAMiyE,EAAGJ,UAAY,IACxD,UAGDE,GAKT1C,EAAS6C,eAAiB,SAAS9vE,GACjC,MAAM+vE,EAAK/vE,EAAKT,QAAQ,KAClB6H,EAAQ,CACZtE,KAAM6B,SAAS3E,EAAKO,OAAO,EAAGwvE,EAAK,GAAI,KAEnCC,EAAQhwE,EAAKT,QAAQ,IAAKwwE,GAOhC,OANIC,GAAS,GACX5oE,EAAMjE,UAAYnD,EAAKO,OAAOwvE,EAAK,EAAGC,EAAQD,EAAK,GACnD3oE,EAAM/D,MAAQrD,EAAKO,OAAOyvE,EAAQ,IAElC5oE,EAAMjE,UAAYnD,EAAKO,OAAOwvE,EAAK,GAE9B3oE,GAKT6lE,EAASgD,eAAiB,SAASjwE,GACjC,MAAMoH,EAAQpH,EAAKO,OAAO,IAAIH,MAAM,KACpC,MAAO,CACLqE,UAAW2C,EAAMiiC,QACjBrmC,MAAOoE,EAAMhE,KAAIN,GAAQ6B,SAAS7B,EAAM,QAM5CmqE,EAASiD,OAAS,SAASC,GACzB,MAAMC,EAAMnD,EAASS,YAAYyC,EAAc,UAAU,GACzD,GAAIC,EACF,OAAOA,EAAI7vE,OAAO,IAKtB0sE,EAASoD,iBAAmB,SAASrwE,GACnC,MAAMoH,EAAQpH,EAAKO,OAAO,IAAIH,MAAM,KACpC,MAAO,CACLkwE,UAAWlpE,EAAM,GAAGisB,cACpBhwB,MAAO+D,EAAM,GAAG65C,gBAOpBgsB,EAASsD,kBAAoB,SAASJ,EAAcK,GAIlD,MAAO,CACLC,KAAM,OACNC,aALYzD,EAASS,YAAYyC,EAAeK,EAChD,kBAIoBptE,IAAI6pE,EAASoD,oBAKrCpD,EAAS0D,oBAAsB,SAASpB,EAAQqB,GAC9C,IAAI3sE,EAAM,WAAa2sE,EAAY,OAInC,OAHArB,EAAOmB,aAAaj0E,SAAQo0E,IAC1B5sE,GAAO,iBAAmB4sE,EAAGP,UAAY,IAAMO,EAAGxtE,MAAQ,UAErDY,GAKTgpE,EAAS6D,gBAAkB,SAAS9wE,GAClC,MAAMoH,EAAQpH,EAAKO,OAAO,GAAGH,MAAM,KACnC,MAAO,CACL8yC,IAAKvuC,SAASyC,EAAM,GAAI,IACxB2pE,YAAa3pE,EAAM,GACnB4pE,UAAW5pE,EAAM,GACjB6pE,cAAe7pE,EAAMvG,MAAM,KAI/BosE,EAASiE,gBAAkB,SAAS5B,GAClC,MAAO,YAAcA,EAAWp8B,IAAM,IACpCo8B,EAAWyB,YAAc,KACQ,iBAAzBzB,EAAW0B,UACf/D,EAASkE,qBAAqB7B,EAAW0B,WACzC1B,EAAW0B,YACd1B,EAAW2B,cAAgB,IAAM3B,EAAW2B,cAAcxrE,KAAK,KAAO,IACvE,QAKJwnE,EAASmE,qBAAuB,SAASJ,GACvC,GAAqC,IAAjCA,EAAUzxE,QAAQ,WACpB,OAAO,KAET,MAAM6H,EAAQ4pE,EAAUzwE,OAAO,GAAGH,MAAM,KACxC,MAAO,CACLixE,UAAW,SACXC,QAASlqE,EAAM,GACfmqE,SAAUnqE,EAAM,GAChBoqE,SAAUpqE,EAAM,GAAKA,EAAM,GAAGhH,MAAM,KAAK,QAAK6H,EAC9CwpE,UAAWrqE,EAAM,GAAKA,EAAM,GAAGhH,MAAM,KAAK,QAAK6H,IAInDglE,EAASkE,qBAAuB,SAASH,GACvC,OAAOA,EAAUK,UAAY,IACzBL,EAAUM,SACXN,EAAUO,SAAW,IAAMP,EAAUO,SAAW,KAChDP,EAAUQ,UAAYR,EAAUS,UAC7B,IAAMT,EAAUQ,SAAW,IAAMR,EAAUS,UAC3C,KAIRxE,EAASyE,oBAAsB,SAASvB,EAAcK,GAGpD,OAFcvD,EAASS,YAAYyC,EAAeK,EAChD,aACWptE,IAAI6pE,EAAS6D,kBAM5B7D,EAAS0E,iBAAmB,SAASxB,EAAcK,GACjD,MAAMrC,EAAQlB,EAASS,YAAYyC,EAAeK,EAChD,gBAAgB,GACZoB,EAAM3E,EAASS,YAAYyC,EAAeK,EAC9C,cAAc,GAChB,OAAMrC,GAASyD,EAGR,CACLxD,iBAAkBD,EAAM5tE,OAAO,IAC/Bw2C,SAAU66B,EAAIrxE,OAAO,KAJd,MASX0sE,EAAS4E,mBAAqB,SAAStC,GACrC,IAAItrE,EAAM,eAAiBsrE,EAAOnB,iBAAxB,iBACSmB,EAAOx4B,SAAW,OAIrC,OAHIw4B,EAAOuC,UACT7tE,GAAO,kBAEFA,GAITgpE,EAAS8E,mBAAqB,SAAS5B,GACrC,MAAM6B,EAAc,CAClBC,OAAQ,GACRC,iBAAkB,GAClBC,cAAe,GACfC,KAAM,IAGFC,EADQpF,EAASG,WAAW+C,GACd,GAAG/vE,MAAM,KAC7B,IAAK,IAAI1C,EAAI,EAAGA,EAAI20E,EAAMz0E,OAAQF,IAAK,CACrC,MAAM2X,EAAKg9D,EAAM30E,GACX40E,EAAarF,EAASS,YAC1ByC,EAAc,YAAc96D,EAAK,KAAK,GACxC,GAAIi9D,EAAY,CACd,MAAMzD,EAAQ5B,EAASsB,YAAY+D,GAC7BC,EAAQtF,EAASS,YACrByC,EAAc,UAAY96D,EAAK,KAQjC,OANAw5D,EAAMS,WAAaiD,EAAM30E,OAASqvE,EAASkC,UAAUoD,EAAM,IAAM,GACjE1D,EAAMe,aAAe3C,EAASS,YAC5ByC,EAAc,aAAe96D,EAAK,KACjCjS,IAAI6pE,EAASuC,aAChBwC,EAAYC,OAAO7zE,KAAKywE,GAEhBA,EAAMnmE,KAAKu4C,eACjB,IAAK,MACL,IAAK,SACH+wB,EAAYG,cAAc/zE,KAAKywE,EAAMnmE,KAAKu4C,iBAWlD,OAJAgsB,EAASS,YAAYyC,EAAc,aAAa1zE,SAAQuD,IACtDgyE,EAAYE,iBAAiB9zE,KAAK6uE,EAAS8B,YAAY/uE,OAGlDgyE,GAKT/E,EAASuF,oBAAsB,SAASC,EAAMC,GAC5C,IAAIzuE,EAAM,GAGVA,GAAO,KAAOwuE,EAAO,IACrBxuE,GAAOyuE,EAAKT,OAAOr0E,OAAS,EAAI,IAAM,IACtCqG,GAAO,sBACPA,GAAOyuE,EAAKT,OAAO7uE,KAAIyrE,QACc5mE,IAA/B4mE,EAAMC,qBACDD,EAAMC,qBAERD,EAAML,cACZ/oE,KAAK,KAAO,OAEfxB,GAAO,uBACPA,GAAO,8BAGPyuE,EAAKT,OAAOx1E,SAAQoyE,IAClB5qE,GAAOgpE,EAAS2B,YAAYC,GAC5B5qE,GAAOgpE,EAASoC,UAAUR,GAC1B5qE,GAAOgpE,EAASyC,YAAYb,MAE9B,IAAI8D,EAAW,EAgBf,OAfAD,EAAKT,OAAOx1E,SAAQoyE,IACdA,EAAM8D,SAAWA,IACnBA,EAAW9D,EAAM8D,aAGjBA,EAAW,IACb1uE,GAAO,cAAgB0uE,EAAW,QAGhCD,EAAKR,kBACPQ,EAAKR,iBAAiBz1E,SAAQm2E,IAC5B3uE,GAAOgpE,EAAS+B,YAAY4D,MAIzB3uE,GAKTgpE,EAAS4F,2BAA6B,SAAS1C,GAC7C,MAAM2C,EAAqB,GACrBd,EAAc/E,EAAS8E,mBAAmB5B,GAC1C4C,GAAuD,IAA9Cf,EAAYG,cAAc5yE,QAAQ,OAC3CyzE,GAA6D,IAAjDhB,EAAYG,cAAc5yE,QAAQ,UAG9CyD,EAAQiqE,EAASS,YAAYyC,EAAc,WAC9C/sE,KAAIpD,GAAQitE,EAAS6C,eAAe9vE,KACpCiD,QAAOmE,GAA6B,UAApBA,EAAMjE,YACnBwC,EAAc3C,EAAMpF,OAAS,GAAKoF,EAAM,GAAGF,KACjD,IAAImwE,EAEJ,MAAMC,EAAQjG,EAASS,YAAYyC,EAAc,oBAC9C/sE,KAAIpD,GACWA,EAAKO,OAAO,IAAIH,MAAM,KACvBgD,KAAIqkB,GAAQ9iB,SAAS8iB,EAAM,QAExCyrD,EAAMt1E,OAAS,GAAKs1E,EAAM,GAAGt1E,OAAS,GAAKs1E,EAAM,GAAG,KAAOvtE,IAC7DstE,EAAgBC,EAAM,GAAG,IAG3BlB,EAAYC,OAAOx1E,SAAQoyE,IACzB,GAAiC,QAA7BA,EAAMnmE,KAAKu4C,eAA2B4tB,EAAMS,WAAW6D,IAAK,CAC9D,IAAIC,EAAW,CACbtwE,KAAM6C,EACN0tE,iBAAkB1uE,SAASkqE,EAAMS,WAAW6D,IAAK,KAE/CxtE,GAAestE,IACjBG,EAASE,IAAM,CAACxwE,KAAMmwE,IAExBH,EAAmB10E,KAAKg1E,GACpBL,IACFK,EAAW91E,KAAKwJ,MAAMxJ,KAAKF,UAAUg2E,IACrCA,EAASG,IAAM,CACbzwE,KAAM6C,EACN6tE,UAAWR,EAAY,aAAe,OAExCF,EAAmB10E,KAAKg1E,QAII,IAA9BN,EAAmBl1E,QAAgB+H,GACrCmtE,EAAmB10E,KAAK,CACtB0E,KAAM6C,IAKV,IAAI8tE,EAAYxG,EAASS,YAAYyC,EAAc,MAenD,OAdIsD,EAAU71E,SAEV61E,EADsC,IAApCA,EAAU,GAAGl0E,QAAQ,WACXoF,SAAS8uE,EAAU,GAAGlzE,OAAO,GAAI,IACF,IAAlCkzE,EAAU,GAAGl0E,QAAQ,SAEqB,IAAvCoF,SAAS8uE,EAAU,GAAGlzE,OAAO,GAAI,IAAa,IACpD,UAEM0H,EAEd6qE,EAAmBr2E,SAAQ8yE,IACzBA,EAAOmE,WAAaD,MAGjBX,GAIT7F,EAAS0G,oBAAsB,SAASxD,GACtC,MAAMyD,EAAiB,GAIjBC,EAAa5G,EAASS,YAAYyC,EAAc,WACnD/sE,KAAIpD,GAAQitE,EAAS6C,eAAe9vE,KACpCiD,QAAOoH,GAAyB,UAAlBA,EAAIlH,YAAuB,GACxC0wE,IACFD,EAAevsE,MAAQwsE,EAAWxwE,MAClCuwE,EAAe9wE,KAAO+wE,EAAW/wE,MAKnC,MAAMgxE,EAAQ7G,EAASS,YAAYyC,EAAc,gBACjDyD,EAAeG,YAAcD,EAAMl2E,OAAS,EAC5Cg2E,EAAeI,SAA4B,IAAjBF,EAAMl2E,OAIhC,MAAMq2E,EAAMhH,EAASS,YAAYyC,EAAc,cAG/C,OAFAyD,EAAeK,IAAMA,EAAIr2E,OAAS,EAE3Bg2E,GAGT3G,EAASiH,oBAAsB,SAASN,GACtC,IAAI3vE,EAAM,GAWV,OAVI2vE,EAAeG,cACjB9vE,GAAO,oBAEL2vE,EAAeK,MACjBhwE,GAAO,uBAEmBgE,IAAxB2rE,EAAe9wE,MAAsB8wE,EAAevsE,QACtDpD,GAAO,UAAY2vE,EAAe9wE,KAChC,UAAY8wE,EAAevsE,MAAQ,QAEhCpD,GAMTgpE,EAASkH,UAAY,SAAShE,GAC5B,IAAI/oE,EACJ,MAAMgtE,EAAOnH,EAASS,YAAYyC,EAAc,WAChD,GAAoB,IAAhBiE,EAAKx2E,OAEP,OADAwJ,EAAQgtE,EAAK,GAAG7zE,OAAO,GAAGH,MAAM,KACzB,CAACkM,OAAQlF,EAAM,GAAIitE,MAAOjtE,EAAM,IAEzC,MAAMktE,EAAQrH,EAASS,YAAYyC,EAAc,WAC9C/sE,KAAIpD,GAAQitE,EAAS6C,eAAe9vE,KACpCiD,QAAOsxE,GAAqC,SAAxBA,EAAUpxE,YACjC,OAAImxE,EAAM12E,OAAS,GACjBwJ,EAAQktE,EAAM,GAAGjxE,MAAMjD,MAAM,KACtB,CAACkM,OAAQlF,EAAM,GAAIitE,MAAOjtE,EAAM,UAFzC,GASF6lE,EAASuH,qBAAuB,SAASrE,GACvC,MAAMkC,EAAQpF,EAASwH,WAAWtE,GAC5BuE,EAAczH,EAASS,YAAYyC,EAAc,uBACvD,IAAIlmE,EACAyqE,EAAY92E,OAAS,IACvBqM,EAAiBtF,SAAS+vE,EAAY,GAAGn0E,OAAO,IAAK,KAEnDqlC,MAAM37B,KACRA,EAAiB,OAEnB,MAAM0qE,EAAW1H,EAASS,YAAYyC,EAAc,gBACpD,GAAIwE,EAAS/2E,OAAS,EACpB,MAAO,CACLuO,KAAMxH,SAASgwE,EAAS,GAAGp0E,OAAO,IAAK,IACvCutE,SAAUuE,EAAMuC,IAChB3qE,eAAAA,GAGJ,MAAM4qE,EAAe5H,EAASS,YAAYyC,EAAc,cACxD,GAAI0E,EAAaj3E,OAAS,EAAG,CAC3B,MAAMwJ,EAAQytE,EAAa,GACxBt0E,OAAO,IACPH,MAAM,KACT,MAAO,CACL+L,KAAMxH,SAASyC,EAAM,GAAI,IACzB0mE,SAAU1mE,EAAM,GAChB6C,eAAAA,KAUNgjE,EAAS6H,qBAAuB,SAASjxE,EAAOkxE,GAC9C,IAAIt6C,EAAS,GAiBb,OAfEA,EADqB,cAAnB52B,EAAMiqE,SACC,CACP,KAAOjqE,EAAM4uE,KAAO,MAAQ5uE,EAAMiqE,SAAW,IAAMiH,EAAKjH,SAAW,OACnE,uBACA,eAAiBiH,EAAK5oE,KAAO,QAGtB,CACP,KAAOtI,EAAM4uE,KAAO,MAAQ5uE,EAAMiqE,SAAW,IAAMiH,EAAK5oE,KAAO,OAC/D,uBACA,aAAe4oE,EAAK5oE,KAAO,IAAM4oE,EAAKjH,SAAW,mBAGzB7lE,IAAxB8sE,EAAK9qE,gBACPwwB,EAAOr8B,KAAK,sBAAwB22E,EAAK9qE,eAAiB,QAErDwwB,EAAOh1B,KAAK,KAOrBwnE,EAAS+H,kBAAoB,WAC3B,OAAO7uE,KAAKE,SAAS+W,WAAW7c,OAAO,EAAG,KAQ5C0sE,EAASgI,wBAA0B,SAASC,EAAQC,EAASC,GAC3D,IAAIC,EACJ,MAAMloE,OAAsBlF,IAAZktE,EAAwBA,EAAU,EAQlD,OANEE,EADEH,GAGUjI,EAAS+H,oBAIhB,aAFMI,GAAY,qBAGP,IAAMC,EAAY,IAAMloE,EADnC,yCAQT8/D,EAASqI,aAAe,SAASnF,EAAcK,GAE7C,MAAMb,EAAQ1C,EAASG,WAAW+C,GAClC,IAAK,IAAIzyE,EAAI,EAAGA,EAAIiyE,EAAM/xE,OAAQF,IAChC,OAAQiyE,EAAMjyE,IACZ,IAAK,aACL,IAAK,aACL,IAAK,aACL,IAAK,aACH,OAAOiyE,EAAMjyE,GAAG6C,OAAO,GAK7B,OAAIiwE,EACKvD,EAASqI,aAAa9E,GAExB,YAGTvD,EAASsI,QAAU,SAASpF,GAG1B,OAFclD,EAASG,WAAW+C,GACd,GAAG/vE,MAAM,KAChB,GAAGG,OAAO,IAGzB0sE,EAASuI,WAAa,SAASrF,GAC7B,MAAyC,MAAlCA,EAAa/vE,MAAM,IAAK,GAAG,IAGpC6sE,EAASwH,WAAa,SAAStE,GAC7B,MACM/oE,EADQ6lE,EAASG,WAAW+C,GACd,GAAG5vE,OAAO,GAAGH,MAAM,KACvC,MAAO,CACLqyE,KAAMrrE,EAAM,GACZ+E,KAAMxH,SAASyC,EAAM,GAAI,IACzB0mE,SAAU1mE,EAAM,GAChBwtE,IAAKxtE,EAAMvG,MAAM,GAAG4E,KAAK,OAI7BwnE,EAASwI,WAAa,SAAStF,GAC7B,MACM/oE,EADO6lE,EAASS,YAAYyC,EAAc,MAAM,GACnC5vE,OAAO,GAAGH,MAAM,KACnC,MAAO,CACLs1E,SAAUtuE,EAAM,GAChBiuE,UAAWjuE,EAAM,GACjBuuE,eAAgBhxE,SAASyC,EAAM,GAAI,IACnCwuE,QAASxuE,EAAM,GACfyuE,YAAazuE,EAAM,GACnBqC,QAASrC,EAAM,KAKnB6lE,EAAS6I,WAAa,SAASzI,GAC7B,GAAoB,iBAATA,GAAqC,IAAhBA,EAAKzvE,OACnC,OAAO,EAET,MAAM+xE,EAAQ1C,EAASG,WAAWC,GAClC,IAAK,IAAI3vE,EAAI,EAAGA,EAAIiyE,EAAM/xE,OAAQF,IAChC,GAAIiyE,EAAMjyE,GAAGE,OAAS,GAA4B,MAAvB+xE,EAAMjyE,GAAGszB,OAAO,GACzC,OAAO,EAIX,OAAO,GAKPt1B,EAAOD,QAAUwxE,mqJC3wBZ,IAAK8I,YAAAA,GAAAA,EAAAA,wBAAAA,oCAAAA,EAAAA,WAAAA,uBAAAA,EAAAA,eAAAA,2BAAAA,EAAAA,qBAAAA,uBAAAA,EAAAA,qBAAAA,uBAAAA,EAAAA,iBAAAA,6BAAAA,EAAAA,qBAAAA,uBAAAA,EAAAA,kBAAAA,wCAAAA,EAAAA,mBAAAA,yCAAAA,EAAAA,yBAAAA,0CAAAA,EAAAA,mBAAAA,+BAAAA,EAAAA,WAAAA,uBAAAA,EAAAA,kBAAAA,8BAAAA,EAAAA,WAAAA,uBAAAA,EAAAA,6BAAAA,0CAAAA,EAAAA,oBAAAA,+BAAAA,EAAAA,uBAAAA,kCAAAA,EAAAA,kBAAAA,8BAAAA,EAAAA,kBAAAA,8BAAAA,EAAAA,0BAAAA,sCAAAA,IAAAA,EAAAA,KA4GL,MAAMC,EAA0BD,EAAsBC,wBAChDC,EAAaF,EAAsBE,WACnCC,EAAiBH,EAAsBG,eACvCC,EAAuBJ,EAAsBI,qBAC7CC,EAAuBL,EAAsBK,qBAC7CC,EAAmBN,EAAsBM,iBACzCC,EAAuBP,EAAsBO,qBAC7CC,EAAoBR,EAAsBQ,kBAC1CC,EAAqBT,EAAsBS,mBAC3CC,EAA2BV,EAAsBU,yBACjDC,EAAqBX,EAAsBW,mBAC3CC,EAAaZ,EAAsBY,WACnCC,EAAoBb,EAAsBa,kBAC1CC,EAAad,EAAsBc,WACnCC,EAA+Bf,EAAsBe,6BACrDC,EAAsBhB,EAAsBgB,oBAC5CC,EAAyBjB,EAAsBiB,uBAC/CC,EAAoBlB,EAAsBkB,kBAC1CC,EAAoBnB,EAAsBmB,kBAC1CC,EAA4BpB,EAAsBoB,0BC/HxD,IAAKC,YAAAA,GAAAA,EAAAA,yBAAAA,uCAAAA,EAAAA,iCAAAA,8CAAAA,EAAAA,oBAAAA,iCAAAA,EAAAA,2BAAAA,sCAAAA,EAAAA,iBAAAA,mBAAAA,EAAAA,kBAAAA,oBAAAA,EAAAA,4BAAAA,8BAAAA,EAAAA,kBAAAA,oBAAAA,EAAAA,gBAAAA,kBAAAA,EAAAA,yBAAAA,2BAAAA,EAAAA,uBAAAA,mCAAAA,EAAAA,uBAAAA,mCAAAA,EAAAA,oBAAAA,gCAAAA,EAAAA,oBAAAA,+BAAAA,EAAAA,qBAAAA,gCAAAA,EAAAA,yBAAAA,6BAAAA,EAAAA,6BAAAA,8BAAAA,EAAAA,qBAAAA,gCAAAA,EAAAA,0BAAAA,uCAAAA,EAAAA,wBAAAA,qCAAAA,EAAAA,cAAAA,0BAAAA,EAAAA,OAAAA,oBAAAA,EAAAA,mBAAAA,gCAAAA,EAAAA,yBAAAA,mCAAAA,EAAAA,0BAAAA,qCAAAA,EAAAA,mBAAAA,gCAAAA,EAAAA,sBAAAA,mCAAAA,EAAAA,uBAAAA,mCAAAA,EAAAA,8BAAAA,0CAAAA,EAAAA,qBAAAA,gCAAAA,EAAAA,iBAAAA,6BAAAA,EAAAA,eAAAA,4BAAAA,EAAAA,UAAAA,uBAAAA,EAAAA,iCAAAA,8CAAAA,EAAAA,yBAAAA,oCAAAA,EAAAA,gCAAAA,6CAAAA,EAAAA,4BAAAA,yCAAAA,EAAAA,6BAAAA,0CAAAA,EAAAA,WAAAA,uBAAAA,EAAAA,qBAAAA,gCAAAA,EAAAA,mBAAAA,+BAAAA,EAAAA,uBAAAA,kCAAAA,EAAAA,kCAAAA,2CAAAA,EAAAA,mCAAAA,2CAAAA,EAAAA,2BAAAA,wCAAAA,EAAAA,cAAAA,2BAAAA,EAAAA,gBAAAA,4BAAAA,EAAAA,iBAAAA,6BAAAA,EAAAA,iBAAAA,8BAAAA,EAAAA,YAAAA,wBAAAA,EAAAA,0BAAAA,gCAAAA,EAAAA,mBAAAA,8BAAAA,EAAAA,cAAAA,0BAAAA,EAAAA,sBAAAA,iCAAAA,EAAAA,6BAAAA,wCAAAA,EAAAA,YAAAA,wBAAAA,EAAAA,UAAAA,sBAAAA,EAAAA,kBAAAA,yBAAAA,EAAAA,oBAAAA,2BAAAA,EAAAA,iCAAAA,8CAAAA,EAAAA,iBAAAA,8BAAAA,EAAAA,kBAAAA,8BAAAA,EAAAA,mBAAAA,+BAAAA,EAAAA,gBAAAA,4BAAAA,EAAAA,uBAAAA,oCAAAA,EAAAA,uBAAAA,oCAAAA,EAAAA,sBAAAA,mCAAAA,EAAAA,mCAAAA,gDAAAA,EAAAA,mCAAAA,gDAAAA,EAAAA,wBAAAA,qCAAAA,EAAAA,4BAAAA,yCAAAA,EAAAA,uBAAAA,qCAAAA,IAAAA,EAAAA,KAidL,MAAMC,EAA2BD,EAAsBC,yBACjDC,EAAmCF,EAAsBE,iCACzDC,EAAsBH,EAAsBG,oBAC5CC,EAA6BJ,EAAsBI,2BACnDC,EAAmBL,EAAsBK,iBACzCC,EAAoBN,EAAsBM,kBAC1CC,EAA8BP,EAAsBO,4BACpDC,EAAoBR,EAAsBQ,kBAC1CC,EAAkBT,EAAsBS,gBACxCC,EAA2BV,EAAsBU,yBACjDC,EAAyBX,EAAsBW,uBAC/CC,EAAyBZ,EAAsBY,uBAC/CC,EAAsBb,EAAsBa,oBAC5CC,EAAsBd,EAAsBc,oBAC5CC,EAAuBf,EAAsBe,qBAC7C7gD,GAA2B8/C,EAAsB9/C,yBACjD8gD,GAA+BhB,EAAsBgB,6BACrDC,GAAuBjB,EAAsBiB,qBAC7C5/C,GAA4B2+C,EAAsB3+C,0BAClDC,GAA0B0+C,EAAsB1+C,wBAChD4/C,GAAgBlB,EAAsBkB,cACtCC,GAASnB,EAAsBmB,OAC/BC,GAAqBpB,EAAsBoB,mBAC3CC,GAA2BrB,EAAsBqB,yBACjDjhD,GAA4B4/C,EAAsB5/C,0BAClDkhD,GAAqBtB,EAAsBsB,mBAC3CC,GAAwBvB,EAAsBuB,sBAC9CC,GAAyBxB,EAAsBwB,uBAC/CC,GAAgCzB,EAAsByB,8BACtDC,GAAuB1B,EAAsB0B,qBAC7CC,GAAmB3B,EAAsB2B,iBACzCC,GAAiB5B,EAAsB4B,eACvCC,GAAY7B,EAAsB6B,UAClCC,GAAmC9B,EAAsB8B,iCACzDC,GAA2B/B,EAAsB+B,yBACjDC,GAAkChC,EAAsBgC,gCACxDC,GAA8BjC,EAAsBiC,4BACpDC,GAA+BlC,EAAsBkC,6BACrDC,GAAanC,EAAsBmC,WACnCC,GAAuBpC,EAAsBoC,qBAC7CC,GAAqBrC,EAAsBqC,mBAC3CC,GAAyBtC,EAAsBsC,uBAC/CC,GAAoCvC,EAAsBuC,kCAC1DC,GAAqCxC,EAAsBwC,mCAC3DC,GAA6BzC,EAAsByC,2BACnDC,GAAgB1C,EAAsB0C,cACtCC,GAAkB3C,EAAsB2C,gBACxCC,GAAmB5C,EAAsB4C,iBACzCC,GAAmB7C,EAAsB6C,iBACzCC,GAAc9C,EAAsB8C,YACpCC,GAA4B/C,EAAsB+C,0BAClDC,GAAqBhD,EAAsBgD,mBAC3CC,GAAgBjD,EAAsBiD,cACtCC,GAAwBlD,EAAsBkD,sBAC9CC,GAA+BnD,EAAsBmD,6BACrDC,GAAcpD,EAAsBoD,YACpCC,GAAYrD,EAAsBqD,UAClCC,GAAoBtD,EAAsBsD,kBAC1CC,GAAsBvD,EAAsBuD,oBAC5CC,GAAmCxD,EAAsBwD,iCACzDC,GAAmBzD,EAAsByD,iBACzCC,GAAoB1D,EAAsB0D,kBAC1CC,GAAqB3D,EAAsB2D,mBAC3CC,GAAkB5D,EAAsB4D,gBACxCC,GAAyB7D,EAAsB6D,uBAC/CC,GAAyB9D,EAAsB8D,uBAC/CC,GAAwB/D,EAAsB+D,sBAC9CC,GAAqChE,EAAsBgE,mCAC3DC,GAAqCjE,EAAsBiE,mCAC3DC,GAA0BlE,EAAsBkE,wBAChDC,GAA8BnE,EAAsBmE,4BACpDC,GAAyBpE,EAAsBoE,mGC5hBrD,MAAMC,GAAuB,sDCI7B,IAAKC,aAAAA,GAAAA,EAAAA,kBAAAA,wBAAAA,EAAAA,8BAAAA,oCAAAA,EAAAA,kCAAAA,wCAAAA,EAAAA,QAAAA,cAAAA,EAAAA,UAAAA,gBAAAA,EAAAA,kBAAAA,wBAAAA,EAAAA,4BAAAA,kCAAAA,EAAAA,4BAAAA,kCAAAA,EAAAA,QAAAA,cAAAA,EAAAA,kBAAAA,0BAAAA,EAAAA,sBAAAA,wBAAAA,EAAAA,uBAAAA,8BAAAA,KAAAA,GAAAA,KAsEL,MAAMC,GAAoBD,GAAiBC,kBACrCC,GAAgCF,GAAiBE,8BACjDC,GAAoCH,GAAiBG,kCACrDC,GAAUJ,GAAiBI,QAC3BC,GAAYL,GAAiBK,UAC7BC,GAAoBN,GAAiBM,kBACrCC,GAA8BP,GAAiBO,4BAC/CC,GAA8BR,GAAiBQ,4BAC/CC,GAAUT,GAAiBS,QAC3BC,GAAoBV,GAAiBU,kBACrCC,GAAwBX,GAAiBW,sBACzCC,GAAyBZ,GAAiBY,uBCnFjDC,GAA6B,GA6CnC,SAASC,GAAgBj/E,EAAOtB,EAASwgF,GACrC,GAAqB,iBAAVl/E,QAA4C,IAAfA,EAAMmL,KAkB1C,OARAxM,KAAKwgF,IAAM,CACPn/E,MAAAA,EACAo/E,YAAa1gF,EACbwgF,QAASA,GAAW77E,MAAMgD,QAAQ64E,GAC5BA,EAAQ57E,MAAM,QACdoH,GAGF1K,EAAMmL,MACd,IAAK,kBACL,IAAK,wBACL,IAAK,gBACDxM,KAAKwM,KAAOgzE,GACZx/E,KAAKgb,QACCqlE,GAA2BrgF,KAAKwM,OAC3BxM,KAAKwgF,IAAID,SAAW,IAAIh3E,KAAK,MACxC,MACJ,IAAK,uBACL,IAAK,gBACDvJ,KAAKwM,KAAOgzE,GACZx/E,KAAKgb,QACCqlE,GAA2BrgF,KAAKwM,OAC3BxM,KAAKwgF,IAAID,SAAW,IAAIh3E,KAAK,MACxC,MACJ,IAAK,8BACL,IAAK,uBAAwB,CACzB,MAAMm3E,EAAiBr/E,EAAMq/E,gBAAkBr/E,EAAMs/E,WAKjD5gF,GACOA,EAAQ6gF,SACNL,GAAWA,EAAQl9E,QAAQ,UAAY,KACrB,aAAnBq9E,GACsB,aAAnBA,GACmB,cAAnBA,GACmB,cAAnBA,GACmB,UAAnBA,GACmB,WAAnBA,GACmB,aAAnBA,IACX1gF,KAAKwM,KAAOgzE,GACZx/E,KAAKgb,QACCqlE,GAA2BrgF,KAAKwM,MA6CtD,SAA2Cq0E,EAAsBJ,GAC7D,GAAIA,GAAeA,EAAYG,OAASH,EAAYG,MAAME,UACtD,OAAQD,GACR,IAAK,QACD,OAAOJ,EAAYG,MAAME,UAAU9uB,SACvC,IAAK,SACD,OAAOyuB,EAAYG,MAAME,UAAUC,UACvC,QACI,OAAON,EAAYG,MAAME,UAAUD,IAAyB,GAIpE,MAAO,GAxDeG,CACEN,EACA3gF,KAEZC,KAAKwM,KAAOgzE,GACZx/E,KAAKgb,QACCqlE,GAA2BrgF,KAAKwM,MAC5BnL,EAAMq/E,gBAEpB,MAGJ,QACI1gF,KAAKwM,KAAOgzE,GACZx/E,KAAKgb,QACC3Z,EAAM2Z,SAAWqlE,GAA2BrgF,KAAKwM,UAGxD,IAAqB,iBAAVnL,EAWd,MAAM,IAAI2C,MAAM,qBAVZq8E,GAA2Bh/E,IAC3BrB,KAAKwM,KAAOnL,EACZrB,KAAKgb,QAAUjb,GAAWsgF,GAA2Bh/E,IAKrDrB,KAAKgb,QAAU3Z,EAMvBrB,KAAKiE,MAAQ5C,EAAM4C,QAAS,IAAID,OAAQC,MAlI5Co8E,GAA2Bb,IACrB,sCACNa,GAA2Bb,IACrB,sCACNa,GAA2Bb,IACrB,mCACNa,GAA2Bb,IACrB,mCACNa,GAA2Bb,IACrB,kCACNa,GAA2Bb,IACrB,6BACNa,GAA2Bb,IACrB,4CACNa,GAA2Bb,IACrB,2CACNa,GAA2Bb,IACrB,sCACNa,GAA2Bb,IACrB,iDACNa,GAA2Bb,IACrB,kCACNa,GAA2Bb,IACrB,iDA8GNc,GAAgBr/E,UAAYb,OAAOw+B,OAAO56B,MAAM/C,WAChDq/E,GAAgBr/E,UAAUmY,YAAcknE,GAuBxC,YCzIO,IAAKW,aAAAA,GAAAA,EAAAA,iBAAAA,cAAAA,EAAAA,UAAAA,OAAAA,EAAAA,WAAAA,QAAAA,EAAAA,QAAAA,KAAAA,EAAAA,sBAAAA,UAAAA,EAAAA,yBAAAA,yBAAAA,EAAAA,0BAAAA,4BAAAA,EAAAA,yBAAAA,2BAAAA,EAAAA,wBAAAA,YAAAA,EAAAA,0BAAAA,6BAAAA,EAAAA,yBAAAA,4BAAAA,EAAAA,oBAAAA,UAAAA,EAAAA,uBAAAA,cAAAA,EAAAA,kBAAAA,SAAAA,EAAAA,yBAAAA,gBAAAA,EAAAA,iBAAAA,mBAAAA,EAAAA,wBAAAA,0BAAAA,EAAAA,SAAAA,WAAAA,EAAAA,aAAAA,eAAAA,EAAAA,gCAAAA,kCAAAA,EAAAA,kBAAAA,oBAAAA,EAAAA,cAAAA,sBAAAA,EAAAA,cAAAA,iBAAAA,KAAAA,GAAAA,KAiML,MAAMC,GAAmBD,GAAgBC,iBACnCC,GAAYF,GAAgBE,UAC5BC,GAAaH,GAAgBG,WAC7BC,GAAUJ,GAAgBI,QAC1BC,GAAwBL,GAAgBK,sBACxCC,GAA2BN,GAAgBM,yBAC3CC,GAA4BP,GAAgBO,0BAC5CC,GAA2BR,GAAgBQ,yBAC3CC,GAA0BT,GAAgBS,wBAC1CC,GAA4BV,GAAgBU,0BAC5CC,GAA2BX,GAAgBW,yBAC3CC,GAAsBZ,GAAgBY,oBACtCC,GAAyBb,GAAgBa,uBACzCC,GAAoBd,GAAgBc,kBACpCC,GAA2Bf,GAAgBe,yBAC3CC,GAAmBhB,GAAgBgB,iBACnCC,GAA0BjB,GAAgBiB,wBAC1CC,GAAWlB,GAAgBkB,SAC3BC,GAAenB,GAAgBmB,aAC/BC,GAAkCpB,GAAgBoB,gCAClDC,GAAoBrB,GAAgBqB,kBACpCC,GAAgBtB,GAAgBsB,cAChCC,GAAgBvB,GAAgBuB,cAkChCC,GAAwB,CAAEh7E,EAAgBoY,KAAlB,CACjCpY,OAAAA,EACAoY,WAAAA,EACAxT,OAAQ,aACRzE,KAAMq5E,GAAgBC,mBAcbwB,GAAoC,CAAEC,EAAgB9iE,KAAlB,CAC7CpY,OAAQ,2BACRm7E,cAAeD,EACf9iE,WAAAA,EACAxT,OAAQ,2BACRzE,KAAMq5E,GAAgBC,mBAoCb2B,GAA0B,SAAEp7E,GAAF,IAAoDoY,EAApD,uDAAyE,GAAzE,MAAmF,CACtHjY,KAAMq5E,GAAgBC,iBACtB70E,OAAQ,iBACR5E,OAAAA,EACAoY,WAAAA,IAgCSijE,GAAoB,SAAEr7E,GAAF,IAAmBoY,EAAnB,uDAAwC,GAAxC,MAAkD,CAC/EjY,KAAMq5E,GAAgBC,iBACtBz5E,OAAAA,EACA4E,OAAQ,SACRwT,WAAAA,IAwBSkjE,GAAiB,SAAEt7E,GAAF,IAAmBoY,EAAnB,uDAAwC,GAAxC,MAAkD,CAC5EjY,KAAMq5E,GAAgBC,iBACtBz5E,OAAAA,EACA4E,OAAQ,MACRwT,WAAAA,IAMSmjE,GAA6BC,IAAF,CACpCr7E,KAAMq5E,GAAgBC,iBACtBz5E,OAAQ,iBACRw7E,UAAAA,IA8CSC,GAAwBrjE,IAAF,CAC/BjY,KAAMq5E,GAAgBC,iBACtBz5E,OAAQ,YACRoY,WAAAA,IC1cG,IAAKsjE,aAAAA,GAAAA,EAAAA,YAAAA,wBAAAA,EAAAA,gBAAAA,6BAAAA,EAAAA,gBAAAA,6BAAAA,EAAAA,iBAAAA,6BAAAA,EAAAA,iBAAAA,+BAAAA,KAAAA,GAAAA,KAyCL,MAAMC,GAAcD,GAAOC,YACrBC,GAAkBF,GAAOE,gBACzBC,GAAkBH,GAAOG,gBACzBC,GAAmBJ,GAAOI,iBAC1BC,GAAmBL,GAAOK,sCCzChC,MAAMC,GAAS,SAETC,GAAQ,QAERC,GAAU,UAEVC,GAAoB,YAEpBC,GAAS,SAETC,GAAO,OAEPC,GAAW,WAEXC,GAAe,eAEfC,GAAU,UCFjBC,GAAwB,CAC1B,OAAUT,GACV,SAAYA,GACZ,MAASC,GACT,QAAWC,GACX,oBAAqBC,GACrB,OAAUC,IA2Cd,SAASM,KACL,MAAMC,EAAYC,UAAUD,UAE5B,GAAIA,EAAUhgF,MAAM,YAAa,CAC7B,MAAM6M,EAAUmzE,EAAUhgF,MAAM,6BAA6B,GAE7D,MAAO,CACHoI,KAAMu3E,GACN9yE,QAAAA,GAED,QAAwC,IAA7B3O,OAAOgiF,kBACrB,MAAO,CACH93E,KAAMu3E,GACN9yE,aAASlF,GAUrB,SAASw4E,KACL,MAAMH,EAAYC,UAAUD,UAE5B,GAAIA,EAAUhgF,MAAM,eAAgB,CAChC,MAAM6M,EAAUmzE,EAAUhgF,MAAM,yBAAyB,GAEzD,MAAO,CACHoI,KAAMs3E,GACN7yE,QAAAA,IASZ,SAASuzE,KACL,MAAMpgF,EACAigF,UAAUD,UAAUhgF,MAAM,wCAChC,IAAI6M,EAMJ,GAAI7M,GAA+B,gBAAtBigF,UAAUI,QAA2B,CAC9C,IAAIj4E,EASJ,OAPIpI,GAASA,EAAM1C,OAAS,IACxB8K,EAAOpI,EAAM,GACb6M,EAAU7M,EAAM,IAEpBoI,IAASA,EAAO,gBAChByE,IAAYA,EAAU,WAEf,CACHzE,KAAMw3E,GACN/yE,QAAAA,IC3HZ,MAAMyzE,WAA0B/6C,GAAa,4CAK9B,MAL8B,+GAYzCy9B,QACIpnE,KAAK2kF,SAAW,GAQhBjjF,aACA,OAAOtB,OAAOC,KAAKL,KAAK2kF,UAAUjjF,OAStCkjF,QAAQC,GACJ,OAAO7kF,KAAK2kF,SAASE,GAWzBC,QAAQD,EAASE,GACb/kF,KAAK2kF,SAASE,GAAWE,EAS7BC,WAAWH,UACA7kF,KAAK2kF,SAASE,GASzB32E,IAAI2C,GACA,MAAMxQ,EAAOD,OAAOC,KAAKL,KAAK2kF,UAE9B,KAAItkF,EAAKqB,QAAUmP,GAInB,OAAOxQ,EAAKwQ,GAQhB2qD,YACI,OAAOp6D,KAAKF,UAAUlB,KAAK2kF,WA8H5B,MAAMM,GAAoB,IAvHjC,cAAgCt7C,GAK5BvwB,cACI8rE,QAEA,IACIllF,KAAK2kF,SAAWriF,OAAO6iF,aACvBnlF,KAAKolF,uBAAwB,EAC/B,MAAOC,IAIJrlF,KAAK2kF,WACN1hF,QAAQiV,KAAK,8BACblY,KAAK2kF,SAAW,IAAID,GACpB1kF,KAAKolF,uBAAwB,GASrCE,yBACI,OAAOtlF,KAAKolF,sBAQhBhe,QACIpnE,KAAK2kF,SAASvd,QACdpnE,KAAK63B,KAAK,WAQVn2B,aACA,OAAO1B,KAAK2kF,SAASjjF,OAUzBkjF,QAAQC,GACJ,OAAO7kF,KAAK2kF,SAASC,QAAQC,GAUjCC,QAAQD,EAASE,GAAwC,IAA9BQ,EAA8B,wDACrDvlF,KAAK2kF,SAASG,QAAQD,EAASE,GAE1BQ,GACDvlF,KAAK63B,KAAK,WAQlBmtD,WAAWH,GACP7kF,KAAK2kF,SAASK,WAAWH,GACzB7kF,KAAK63B,KAAK,WAUd3pB,IAAI1M,GACA,OAAOxB,KAAK2kF,SAASz2E,IAAI1M,GAQ7Bg6D,YACI,GAAIx7D,KAAKslF,yBACL,OAAOtlF,KAAK2kF,SAASnpB,YAGzB,MAAM95D,EAAS1B,KAAK2kF,SAASjjF,OACvB8jF,EAAsB,GAE5B,IAAK,IAAIhkF,EAAI,EAAGA,EAAIE,EAAQF,IAAK,CAC7B,MAAM0M,EAAMlO,KAAK2kF,SAASz2E,IAAI1M,GAE9BgkF,EAAoBt3E,GAAOlO,KAAK2kF,SAASC,QAAQ12E,GAGrD,OAAO9M,KAAKF,UAAUskF,KC3MxBjhF,IAAS2B,EAAAA,EAAAA,qDCDf,ODiBe,cF+JA,MAQXkT,YAAYqsE,GACR,IAAIj5E,EAAMyE,EAGV,GADAjR,KAAK0lF,QAAUC,GAAAA,UAAiBtB,UAAUD,gBACf,IAAhBqB,EAA6B,CACpC,MAAMG,EArDlB,SAAiBC,GACb,IAAIJ,EACJ,MAAMK,EAAY,CACdtB,GACAL,GACAI,IAIJ,IAAK,IAAI/iF,EAAI,EAAGA,EAAIskF,EAAUpkF,OAAQF,IAElC,GADAikF,EAAcK,EAAUtkF,KACpBikF,EACA,OAAOA,EAIf,MAAMj5E,EAAOq5E,EAAOngD,iBAEpB,OAAIl5B,KAAQ03E,GACD,CACH13E,KAAM03E,GAAsB13E,GAC5ByE,QAAS40E,EAAOlgD,sBAKxB8/C,EAhIJ,WACI,MAAMrB,EAAYC,UAAUD,UACtBqB,EAAc,CAChBj5E,KAAMy3E,GACNhzE,aAASlF,GAGb,GAAIq4E,EAAUhgF,MAAM,YAAcggF,EAAUhgF,MAAM,QAE9C,GAAIggF,EAAUhgF,MAAM,WAAY,CAE5B,MAAM6M,EAAUmzE,EAAUhgF,MAAM,oBAAoB,GAEhD0K,OAAOrG,SAASwI,EAAS,IAAM,KAC/Bw0E,EAAYj5E,KAAOi3E,GACnBgC,EAAYx0E,QAAUA,QAG1Bw0E,EAAYj5E,KAAOi3E,GACnBgC,EAAYx0E,QAAUmzE,EAAUhgF,MAAM,oBAAoB,GAIlE,OAAOqhF,EAyGOM,GACVN,GAIG,CACHj5E,KAAMy3E,GACNhzE,aAASlF,IAoBuBi6E,CAAQhmF,KAAK0lF,SAEzCl5E,EAAOo5E,EAAoBp5E,KAC3ByE,EAAU20E,EAAoB30E,aACvBw0E,EAAYj5E,QAAQ03E,IAC3B13E,EAAO03E,GAAsBuB,EAAYj5E,MACzCyE,EAAUw0E,EAAYx0E,UAEtBzE,EAAOy3E,GACPhzE,OAAUlF,GAGd/L,KAAKi+C,MAAQzxC,EACbxM,KAAKimF,SAAWh1E,EAOpBi1E,UACI,OAAOlmF,KAAKi+C,MAOhBkoC,WACI,OAAOnmF,KAAKi+C,QAAUwlC,GAO1B2C,UACI,OAAOpmF,KAAKi+C,QAAUylC,GAO1B2C,YACI,OAAOrmF,KAAKi+C,QAAU0lC,GAO1B2C,cACI,OAAOtmF,KAAKi+C,QAAU2lC,GAO1B2C,WACI,OAAOvmF,KAAKi+C,QAAU4lC,GAO1B2C,SACI,OAAOxmF,KAAKi+C,QAAU6lC,GAO1B2C,aACI,OAAOzmF,KAAKi+C,QAAU8lC,GAO1B2C,gBACI,OAAO1mF,KAAKi+C,QAAU+lC,GAO1B2C,aACI,OAAO3mF,KAAKimF,SAgBhBW,gBAAgBC,GACZ,GAAI7mF,KAAKimF,SACL,OAAOjmF,KAAK0lF,QAAQh/C,UAAUmgD,GAatCC,qBAAqB71E,GACjB,OAAOjR,KAAK4mF,gBAAgB,CAAE,CAAC5mF,KAAKi+C,OAAS,IAAGhtC,MAYpD81E,kBAAkB91E,GACd,OAAOjR,KAAK4mF,gBAAgB,CAAE,CAAC5mF,KAAKi+C,OAAS,IAAGhtC,MAapD+1E,iBAAiB/1E,GACb,OAAOjR,KAAK4mF,gBAAgB,CAAE,CAAC5mF,KAAKi+C,OAAS,IAAGhtC,QEhUpDmI,cACI8rE,QACA3gF,GAAOiH,KACF,sBAAqBxL,KAAKkmF,mBAAmBlmF,KAAK2mF,gBAU3DM,8BACI,OAAOjnF,KAAKknF,mBAAqBlnF,KAAKmnF,iBAAmBnnF,KAAKqmF,YAelEa,kBACI,OAAQlnF,KAAKmmF,YACNnmF,KAAKymF,cACLzmF,KAAKwmF,UACLxmF,KAAKomF,aACJpmF,KAAKmnF,gBAQjBC,eACI,MAAM,UAAEhD,EAAF,eAAaiD,EAAb,SAA6BnhD,GAAam+C,UAEhD,OAAOiD,QAAQlD,EAAUhgF,MAAM,qBACvBijF,GAAkBA,EAAiB,GAAK,WAAW93E,KAAK22B,GAWpEihD,gBAEI,OAAOnnF,KAAK0lF,QAAQ3+C,SAAS,gBACY,IAA3Bs9C,UAAUkD,mBAC8B,IAAxClD,UAAUkD,aAAaC,mBACM,IAA7BllF,OAAOmlF,mBAEdrnF,OAAOC,KAAKonF,kBAAkBxmF,WAAWoC,QAAQ,qBAAuB,EAQnFqkF,QACI,MAAO,eAAgBplF,QAAUA,OAAOqlF,WAAW,6BAA6B7kE,QAQpFb,cACI,QAAIjiB,KAAKumF,YAAcvmF,KAAK4nF,oBAlGA,MAsGpB5nF,KAAKknF,mBAAqBlnF,KAAK6nF,4BAvGX,IAwGrB7nF,KAAKqmF,aACLrmF,KAAK0mF,iBACL1mF,KAAKmnF,iBAOhBW,4BACI,OAAO9nF,KAAKknF,mBAAqBlnF,KAAKqmF,YAO1C0B,wBACI,OAAO/nF,KAAKgoF,kBAxHa,GAiI7BC,qCACI,OAAOjoF,KAAKqmF,aAAermF,KAAK+mF,kBAAkB,MAStDmB,qCACI,OAAOloF,KAAKknF,mBAAqBlnF,KAAK0mF,gBAQ1CyB,8BAGI,OAAQnoF,KAAKqmF,cAAgBrmF,KAAKmnF,gBAOtCiB,2BACI,OAAOd,QAAQhlF,OAAOmlF,mBACf,wBAAyBnlF,OAAOmlF,kBAAkBxmF,WAClDqB,OAAO+lF,qBAC0C,IAA1C/lF,OAAO+lF,eAAeC,mBAI5BtoF,KAAKmnF,gBAOjBoB,4BACI,OAAOlE,UAAUkD,mBACuC,IAA1ClD,UAAUkD,aAAaiB,qBACqB,IAA5CnE,UAAUkD,aAAal7C,iBAOzCo8C,sCACI,OAAOzoF,KAAKknF,mBAAqBlnF,KAAK0mF,iBAAmB1mF,KAAKmnF,gBAQlEuB,8BACI,YAA6C,IAA/BpmF,OAAOqmF,qBACdA,oBAAoBC,oBAAoBvlF,QAAQ,aAAe,EAM1EwlF,wBACI,YAAwC,IAA1BvmF,OAAO+lF,gBACdjoF,OAAOC,KAAKgoF,eAAepnF,WAAWoC,QAAQ,8BAAgC,IAI7ErD,KAAKmnF,gBAQjB2B,wBASI,OAAQ9oF,KAAKqmF,YAQjB0C,cACI,OAAO/oF,KAAKknF,mBAAqBlnF,KAAK0mF,gBAQ1CsC,6BACI,OAAOhpF,KAAKknF,mBAAqBlnF,KAAK0mF,iBAAmB1mF,KAAKmnF,gBAQlE8B,cACI,OAAQjpF,KAAK0mF,gBAOjBwC,uBACI,OAAO,EAOXC,0BACI,YAA4C,IAA9B9E,UAAU+E,sBACkB,IAA3B/E,UAAUkD,mBAET,IADElD,UAAUkD,aAAa6B,gBAa7CC,2BACI,OAAO/B,QAAQhlF,OAAOgnF,uBAO1BC,4BACI,QAAqC,IAAxBjnF,OAAOknF,eACblnF,OAAOknF,aAAavoF,UAAUwoF,qBACjC,OAAO,EAKX,MAAMr5E,EAAS,IAAIs5E,eAEnB,IAGI,OAFApnF,OAAOqnF,YAAYv5E,EAAQ,IAAK,CAAEA,KAE3B,EACT,MACE,OAAO,GAOfw5E,mBACI,OAAOtC,QAAQhlF,OAAOknF,cACflnF,OAAOknF,aAAalB,iBACpBhmF,OAAOknF,aAAalB,gBAAgB,SAASvS,OAAOnqE,MAAK+mE,GAA4B,cAAnBA,EAAM3+D,YACxE1R,OAAO+lF,gBACP/lF,OAAO+lF,eAAeC,iBACtBhmF,OAAO+lF,eAAeC,gBAAgB,SAASvS,OAAOnqE,MAAK+mE,GAA4B,cAAnBA,EAAM3+D,YAQrF61E,sBACI,OAAQ7pF,KAAK0mF,gBAQjBoD,uBACI,OAAO9pF,KAAKknF,kBAQhB6C,cAGI,QAAS/pF,KAAKqmF,aAAermF,KAAK+mF,kBAAkB,OAQxDc,2BACI,GAAI7nF,KAAKknF,kBAAmB,CAExB,GAAIlnF,KAAKwmF,SAEL,OAAO13E,OAAOrG,SAASs6C,QAAQ+b,SAASl9B,SAAU,IAQtD,MAAMooD,EAAK3F,UAAUD,UAErB,GAAI4F,EAAG5lF,MAAM,UAIT,OAFM0K,OAAOrG,SAASuhF,EAAG5lF,MAAM,oBAAoB,GAAI,IAM/D,OAAQ,EAQZwjF,oBACI,OAAI5nF,KAAKumF,WACEz3E,OAAOrG,SAASzI,KAAK2mF,aAAc,KAGtC,EAQZqB,iBACI,OAAIhoF,KAAKmnF,gBACEr4E,OAAOrG,SAASzI,KAAK2mF,aAAc,KAGtC,6BEjZhB,MAGMpiF,IAAS2B,EAAAA,EAAAA,qDAoVf,OAxSA,MAIIkT,cACIpZ,KAAKg7C,QAQTA,QAOIh7C,KAAKiqF,UAAW,EAMhBjqF,KAAKkqF,kBAAoB,IAAI5jB,IAO7BtmE,KAAKs1C,MAAQ,GAMbt1C,KAAKmqF,oBAAsB,GAO3BnqF,KAAKoqF,eAAiB,GAEtBpqF,KAAKqqF,uBAAuB,CACxB,WAAchG,UAAUD,UACxB,aAAgB7+C,GAAQ2gD,YAOhCoE,UACI/lF,GAAO2T,KAAK,mCAERlY,KAAKkqF,mBAAqBlqF,KAAKkqF,kBAAkBllB,KAAO,GACxDhlE,KAAKkqF,kBAAkB3pF,SAAQ83B,IACI,mBAApBA,EAAQiyD,SACfjyD,EAAQiyD,aAKpBtqF,KAAKuqF,qBAAqB,IAC1BvqF,KAAKiqF,UAAW,EAQpBM,qBAAqBvyD,GACjB,GAAIh4B,KAAKiqF,SACL,OAGJjqF,KAAKkqF,kBAAoB,IAAI5jB,IAAItuC,GAEjCh4B,KAAKwqF,qBAGL,MAAMl1C,EAAQt1C,KAAKs1C,MAEnBt1C,KAAKs1C,MAAQ,KACTA,GACAA,EAAM/0C,SAAQ+3B,GAASt4B,KAAKyqF,WAAWnyD,KAS/CkyD,qBACIxqF,KAAKkqF,kBAAkB3pF,SAAQ83B,IAC3B,IACIA,EAAQqyD,kBAAkB1qF,KAAKmqF,qBACjC,MAAO9oF,GACLkD,GAAO2T,KACA,uEAAsB7W,SAezCgpF,uBAAuBM,GACnB3qF,KAAKmqF,oBAAsB,IACpBnqF,KAAKmqF,uBACLQ,GAGP3qF,KAAKwqF,qBAQTI,kBAAkBp+E,GACdxM,KAAKoqF,eAAiB59E,EACtBxM,KAAKqqF,uBAAuB,CAAE,gBAAmB79E,IAgBrDq+E,UAAUC,GAA4B,IAAjBH,EAAiB,uDAAJ,GAC9B,GAAI3qF,KAAKiqF,SACL,OAGJ,IAAI3xD,EAAQ,KAEa,iBAAdwyD,EACPxyD,EAAQ,CACJ1wB,KAAMs5E,GACNz5E,OAAQqjF,EACRlI,cAAekI,EACfz+E,OAAQy+E,EACRjrE,WAAY8qE,GAEY,iBAAdG,IACdxyD,EAAQwyD,GAGP9qF,KAAK+qF,sBAAsBzyD,GAOhCt4B,KAAKyqF,WAAWnyD,GANZ/zB,GAAOlD,MACF,mCAAkCD,KAAKF,UAAUo3B,MAoB9DyyD,sBAAsBzyD,GAClB,IAAKA,EACD,OAAO,EAGNA,EAAM1wB,OACP0wB,EAAM1wB,KAAOs5E,IAGjB,MAAMt5E,EAAO0wB,EAAM1wB,KAEnB,OAAIA,IAASs5E,IAAoBt5E,IAASu5E,IACnCv5E,IAASy5E,IAAWz5E,IAASw5E,IAChC78E,GAAOlD,MAAO,uBAAsBuG,MAE7B,GAGPA,IAASu5E,GACFmG,QAAQhvD,EAAM9rB,OAKzB8rB,EAAM7wB,OAAS6wB,EAAM7wB,QAAU6wB,EAAM9rB,MAAQ8rB,EAAMsqD,cACnDtqD,EAAMsqD,cAAgBtqD,EAAMsqD,eAAiBtqD,EAAM9rB,MAAQ8rB,EAAM7wB,OACjE6wB,EAAMjsB,OAASisB,EAAMjsB,QAAUisB,EAAM9rB,MAAQ8rB,EAAM7wB,QAC5C6wB,EAAMsqD,cAERtqD,EAAM7wB,QAAW6wB,EAAMsqD,eAAkBtqD,EAAMjsB,UAQhDzE,IAASw5E,KACT9oD,EAAM0yD,WAAa1yD,EAAM0yD,YAAc,sBACvC1yD,EAAM2yD,cAAgB3yD,EAAM2yD,eAAiB,aACjB,eAAxB3yD,EAAM2yD,eAAmC3yD,EAAM4yD,cAC/C5yD,EAAM4yD,YAAclrF,KAAKoqF,gBAIxB9xD,EAAM0yD,YAAe1yD,EAAM6yD,UACxB7yD,EAAM2yD,eAAkB3yD,EAAM4yD,gBAClC3mF,GAAOlD,MACH,gFAGG,IArBXkD,GAAOlD,MACH,6DAEG,IAgCf+pF,iBAAiB9yD,GACb,QAAIt4B,KAAKs1C,QACLt1C,KAAKs1C,MAAMpzC,KAAKo2B,GAIZt4B,KAAKs1C,MAAM5zC,OAxTJ,KAyTP1B,KAAKs1C,MAAM9xC,OAAO,EAAG,IAGlB,GAYfinF,WAAWnyD,GACHt4B,KAAKorF,iBAAiB9yD,IAGtBt4B,KAAKkqF,kBAAkB3pF,SAAQ83B,IAC3B,IACIA,EAAQwyD,UAAUvyD,GACpB,MAAOvrB,GACLxI,GAAO2T,KAAM,kCAAiCnL,mCCrVlE,MAAMxI,GAASi1B,EAAAA,IAAAA,6CAQT6xD,GASc,iBAmCdC,GACK,QADLA,GAEK,QAFLA,GAGe,gBAOrB,IAAIC,GAcW,MAAMC,GAOW,6BAACnqF,EAAOE,GAC5BiqF,GAAUC,SAAqB,YAAVpqF,GACrBkD,GAAOlD,MAAO,sBAAqBA,UAAcE,KAUrC,qBAACF,EAAOE,GAIxB,GAHAgD,GAAOD,IAAK,yBAAwBjD,SAAaE,KAGnC,YAAVF,EACA,OAGJmqF,GAAUE,oBAAqB,EAG/B,IAAIC,GAAmB,EACnBC,EAAkB,KAEtB,IAAK,MAAMC,KAAqBL,GAAUM,QAAQxiF,SACzCuiF,EAAkBE,YACnBxnF,GAAOynF,MAAM,+BACTH,EAAkBI,kBAClBN,GAAmB,EACdC,IACDA,EAAkBC,KAM7BF,GAILH,GAAUU,kBAAkBN,GASR,yBAACO,GAIrB,MAAMC,EAAgBD,EAAWE,OAC3BC,EAAYH,EAAWI,eAG7B,IAAK,MAAMC,KAAUhB,GAAUiB,aAC3B,GAAID,EAAO5kF,OAAS0jF,GAAkB,CAClC,MAAMoB,EAAYF,EAAO/1E,KAEzB+0E,GAAUmB,aACNR,EACAO,EAAU9kF,KACV8kF,EAAUrrF,MACVqrF,EAAUE,IAAMN,QACjB,GAAIE,EAAO5kF,OAAS0jF,GAAkB,CAIzC,MAAMuB,EAAYL,EAAO/1E,KAEzB+0E,GAAUC,QAAQqB,gBACdN,EAAOI,IAAMN,EACbO,EAAUv0D,MACV8zD,EACAS,EAAUA,gBACX,GAAIL,EAAO5kF,OAAS0jF,GAA4B,CACnD,MAAM70E,EAAO+1E,EAAO/1E,KAEpB+0E,GAAUC,QAAQsB,uBACdP,EAAOI,IAAMN,EACb71E,EAAKu2E,YACLZ,EACA31E,EAAK7P,KACL6P,EAAKw2E,WACLx2E,EAAKy0E,aAIjBM,GAAUiB,aAAa/qF,OAAS,EAajB,oBAACyb,EAAIvV,EAAMvG,EAAOurF,GACjC,IAAIM,EAAS7rF,EAER6rF,IACD3oF,GAAO2T,KAAK,uBACZg1E,EAAS,IAAIlpF,MAAM,kBAEnBwnF,GAAUE,oBAAsBvuE,EAChCquE,GAAUC,QAAQ0B,YAAYP,EAAIzvE,EAAGkvE,OAAQzkF,EAAMslF,GAEnD1B,GAAUiB,aAAavqF,KAAK,CACxB0F,KAAM0jF,GACN70E,KAAM,CACFpV,MAAO6rF,EACPN,GAAAA,EACAhlF,KAAAA,KAkBG,oBAACuV,EAAImb,EAAOu0D,GAC3B,MAAMD,EAAKzvE,GAAMA,EAAGovE,eACdF,EAASlvE,GAAMA,EAAGkvE,OAEpBb,GAAUE,oBAAsBvuE,EAChCquE,GAAUC,QAAQqB,gBAAgBF,EAAIt0D,EAAO+zD,EAAQQ,GAErDrB,GAAUiB,aAAavqF,KAAK,CACxBmqF,OAAAA,EACAO,GAAAA,EACAhlF,KAAM0jF,GACN70E,KAAM,CAAE6hB,MAAAA,EACJu0D,UAAAA,KAaiB,kCAACO,GAC9B,MAAMC,EAAkB,CACpB,yBACA,kBACA,oBAKJ,IAAK,MAAMzpF,KAAcypF,EAAiB,CACtC,MAAMC,EAAiBF,EAAWxpF,GAElCwpF,EAAWxpF,GAAc,WACrB,IAAI,2BAD6B2pF,EAC7B,yBAD6BA,EAC7B,gBACA,OAAOD,EAAe5sF,MAAM0sF,EAAYG,GAC1C,MAAOxgF,GACLyrB,KAAAA,iBAAsCzrB,KAIlD,MAAMygF,EAAe,CACjB,yBACA,kBACA,oBAKJ,IAAK,MAAM5pF,KAAc4pF,EAAc,CACnC,MAAMF,EAAiBF,EAAWxpF,GAElCwpF,EAAWxpF,GAAc,WAA0B,2BAAd2pF,EAAc,yBAAdA,EAAc,gBAC/ChpF,GAAOynF,MAAMpoF,EAAY2pF,GACzBD,EAAe5sF,MAAM0sF,EAAYG,IAGzC,MAAME,EAAsBL,EAAWD,YAGvCC,EAAWD,YAAc,SAASP,EAAIzvE,EAAIvV,GAAe,2BAANnD,EAAM,iCAANA,EAAM,kBAIjDmD,IAASyjF,GAQJ9lD,GAAQmhD,iBACTzjF,SAAWA,QAAQ+oF,MAAM,cAAeY,EAAIzvE,EAAIvV,GAGpDrD,GAAOynF,MAAM,cAAeY,EAAIzvE,EAAIvV,KAASnD,GAEjD,IACIgpF,EAAoB7oF,KAAKwoF,EAAYR,EAAIzvE,EAAIvV,KAASnD,GACxD,MAAOipF,GACD9lF,IAASyjF,GACTpoF,SAAWA,QAAQ5B,MAAM,cAAeqsF,GAExCl1D,KAAAA,iBAAsCk1D,KAa3C5B,qBAKP,OAJKP,KACDA,GAAW,IAAIjlB,KAGZilB,GAiBO,mBAACxrF,GACf,GAAIyrF,GAAUC,QACV,MAAM,IAAIznF,MAAM,mDAEpB,IACI,MAAM2pF,EAAmBC,UAEzBpC,GAAUC,QAAU,IAAIkC,EACxBnC,GAAUqC,2BAA2BrC,GAAUC,SAC/CD,GAAUsC,OAAS,CACfC,UAAWhuF,EAAQguF,UACnBC,SAAUjuF,EAAQiuF,UAEtBxC,GAAUyC,YAAcluF,EAAQkuF,YAChCzC,GAAU0C,gBAAkBnuF,EAAQmuF,gBAEpC,MAAMC,EAAe,IAAKpuF,EAAQouF,cAMlC,GAJIpuF,EAAQquF,kBACRD,EAAaE,mBAAsB,GAAEtuF,EAAQquF,oBAAoB7oD,GAAQ2gD,cAGzEnmF,EAAQssF,OAAQ,CAEhB,MAAMjoF,EAAQrE,EAAQssF,OAAOjoF,MAAM,gBAGnC+pF,EAAaG,OAASvuF,EAAQuuF,QAAWlqF,GAASA,EAAM,IAAO,IAInEonF,GAAUC,QAAQ8C,WACd/C,GAAUyC,YACVzC,GAAU0C,gBACV1C,GAAUsC,OACVtC,GAAUgD,mBACVziF,EACAoiF,GAEJ,MAAMM,EAAqB1uF,EAAQ0uF,mBAcnC,OAZIA,IACAjD,GAAUC,QAAQiD,uBAAuBD,GAEzCA,IAAqB7tC,MAAKtnB,IAClBA,GACA/0B,GAAOiH,KAAK,2BACNpK,KAAKwJ,MAAM0uB,GAAQq1D,cAGhC3qC,OAAM,WAGJ,EACT,MAAOj3C,GAQL,OAJAyrB,KAAAA,iBAAsCzrB,GACtCy+E,GAAUC,QAAU,KACpBlnF,GAAOlD,MAAM0L,IAEN,GAWY,8BACvB,OAAOu6E,QAAQkE,GAAUC,SASG,iCAACmD,EAAazxE,GAC1CquE,GAAUqD,aAAa1xE,EArYT,mBAqY2CyxE,GASpC,0BAAC7hF,EAAGoQ,GACzB,IACIquE,GAAUmB,aACNxvE,EACAkuE,GACAt+E,EACAoQ,GAAMA,EAAGovE,gBACf,MAAOlrF,GAID4B,SAAqC,mBAAlBA,QAAQ5B,OAE3B4B,QAAQ5B,MAAM,4BAA6BA,IAcpC,oBAACytF,EAAcC,EAAS13E,GACvC,OAAO,IAAI0yB,SAAQ,CAACC,EAASC,KACzB,GAAIuhD,GAAUC,QACVD,GAAUC,QAAQuD,iBACdF,EACA,CACIhB,OAAQtC,GAAUsC,OAClBiB,QAAAA,EACA13E,QAAAA,IAEJ,CAAC43E,EAAQj0E,KACU,YAAXi0E,EACAjlD,EAAQhvB,GAERivB,EAAOjvB,UAGhB,CACH,MAAMud,EAAS,sDAEfh0B,GAAOlD,MAAMk3B,GACb0R,EAAO1R,OAWU,8BAACxrB,EAAGoQ,GAC7BquE,GAAUmB,aAAaxvE,EAneb,eAme6CpQ,EAAG,MAS1C,qBAACmiF,EAAMtnF,EAAMuV,GAC7B,IAAImb,EAGAA,EADS,UAAT1wB,EACQsnF,EA/dJ,aACC,cAgeGA,EAneL,YACE,cAqeT1D,GAAUqD,aAAa1xE,EAAImb,GAe/Blf,YAAY+1E,EAAKpvF,GACbC,KAAKqsF,OAAStsF,EAAQssF,OACtBrsF,KAAKmvF,IAAMA,EACXnvF,KAAKusF,eAAiB4C,EAAI5C,eAC1BvsF,KAAKovF,aAAervF,EAAQqvF,cAxeR,QAyepBpvF,KAAK+rF,WAAY,EAEjBP,GAAUM,QAAQnsC,IAAI3/C,MAElBwrF,GAAUE,qBACV1rF,KAAKisF,gBAK0B,IAA3BT,GAAUM,QAAQ9mB,MAClBwmB,GAAUU,kBAAkBlsF,OAUxCisF,gBACI1nF,GAAOiH,KAAK,eAAgBxL,KAAKovF,cACjC,IACI,MAAMC,EAAmB,CACrBC,mBACItvF,KAAKmvF,IAAII,MACH/D,GAAUC,QAAQ+D,aAAaC,KAC/BjE,GAAUC,QAAQ+D,aAAaE,QAEvCt2D,EACAoyD,GAAUC,QAAQkE,aAChB3vF,KAAKusF,eACLvsF,KAAKovF,aACL5D,GAAUC,QAAQmE,YAAYC,UAC9B7vF,KAAKqsF,OACLgD,EACA7D,GAAUsE,uBAElB9vF,KAAK+rF,WAAY,EAEjB,MAAMgE,EAAyB,YAAf32D,EAAI61D,OAMpB,OAJKc,GACDxrF,GAAOlD,MAAM,kCAAmC+3B,EAAIpe,SAGjD+0E,EAET,MAAO1uF,GAGL,OAFAm3B,KAAAA,iBAAsCn3B,IAE/B,GAoBf2uF,4BACQppF,EACAqpF,EACAC,EACAjD,EACA/B,GACJ,IAAKM,GAAUC,QACX,OAGJ,MAAMuB,EAAciD,EAAUzE,GAAUsC,OAASoC,EAE7C1E,GAAUE,mBACVF,GAAUC,QAAQsB,uBACd/sF,KAAKusF,eACLS,EACAhtF,KAAKqsF,OACLzlF,EACAqmF,EACA/B,GAEJM,GAAUiB,aAAavqF,KAAK,CACxB0F,KAAM0jF,GACNsB,GAAI5sF,KAAKusF,eACT91E,KAAM,CACFu2E,YAAAA,EACA9B,YAAAA,EACAtkF,KAAAA,EACAqmF,WAAAA,KAYhBkD,2BACI3E,GAAUqD,aAAa7uF,KAlmBV,mBAymBjBowF,qBACQ5E,GAAUE,oBACVF,GAAUC,QAAQqB,gBACd9sF,KAAKusF,eACLf,GAAUC,QAAQ4E,YAAYC,iBAC9BtwF,KAAKqsF,QAEbb,GAAUM,QAAQyE,OAAOvwF,MAM7BwwF,+BACIhF,GAAUmB,aACN3sF,KA/oBc,uBAipBd,KACAA,KAAKusF,gBAQbkE,sBAAsB1jF,GAClBy+E,GAAUmB,aACN3sF,KAlqBK,cAkqB4B+M,EAAG/M,KAAKusF,gBAQjDmE,uBAAuB3jF,GACnBy+E,GAAUmB,aACN3sF,KA3qBM,eA2qB4B+M,EAAG/M,KAAKusF,gBAQlDoE,sBAAsBC,GAClBpF,GAAUqD,aACN7uF,KACA4wF,EApqBM,eADF,cA+qBZC,uBAAuBzuF,EAAOwE,GAC1B,IAAIimF,EAEAjmF,IACAimF,EAAY,CAAEjmF,KAAAA,IAGlB4kF,GAAUqD,aACN7uF,KACAoC,EA/qBU,mBACD,kBA+qBTyqF,GAQRiE,uBAAuB/jF,GACnBy+E,GAAUmB,aACN3sF,KAntBa,sBAmtB4B+M,EAAG/M,KAAKusF,gBAQzDwE,wBAAwBhkF,GACpBy+E,GAAUmB,aACN3sF,KA5tBc,uBA4tB4B+M,EAAG/M,KAAKusF,gBAQ1DyE,0BAA0BjkF,GACtBy+E,GAAUmB,aACN3sF,KAruBS,kBAquB4B+M,EAAG/M,KAAKusF,iBAQzDf,GAAUC,QAAU,KAKpBD,GAAUiB,aAAe,GAOzBjB,GAAUE,oBAAqB,EAM/BF,GAAUyC,YAAc,KAMxBzC,GAAU0C,gBAAkB,KAS5B1C,GAAUsC,OAAS,KChxBnBxrF,OAAO2uF,aAAe3uF,OAAO2uF,cAAgB3uF,OAAO4uF,mBAEpD,IAAIpkD,GAAU,KAkEC,SAASqkD,GAAoB/gF,EAAQghF,EAAUx0E,GAC1D5c,KAAKoQ,OAASA,EACdpQ,KAAKqxF,WAAa,KAClBrxF,KAAKsxF,cAAgBF,EACrBpxF,KAAKuxF,WAAa,EAClBvxF,KAAK4c,SAAWA,EChFb,SAAS40E,GAAqBC,GACjC,IAAIC,EAAYD,EAMhB,OAJIA,GAAU3iF,OAAOszD,mBACjBsvB,EAAY,GAGTA,EAAY,EAShB,SAASC,GAAiBC,GAC7B,OAAOA,EAAWlwF,OAAS,EAAIkwF,EAAW/hF,QAAO,CAACxC,EAAGD,IAAMC,EAAID,IAAKwkF,EAAWlwF,OAAS,EA6BrF,SAASmwF,GAAqBD,GACjC,OAAOA,EAAW7qF,QAAOI,GAASA,GAAS,IDpC3C7E,OAAO2uF,eACPnkD,GAAU,IAAImkD,aAUdnkD,GAAQglD,SAAWhlD,GAAQglD,WAgE/BX,GAAoBlwF,UAAUmB,MAAQ,WAClC,IAAK+uF,GAAoBY,wBACrB,OAEJjlD,GAAQklD,SACR,MAAMC,EAAWnlD,GAAQolD,iBAEzBD,EAASE,sBAxF2B,GAyFpCF,EAASG,QA/FsB,KAiGhBtlD,GAAQulD,wBAAwBryF,KAAKoQ,QAE7CkiF,QAAQL,GAEfjyF,KAAKqxF,WAAakB,aACd,KACI,MAAMhoF,EAAQ,IAAI8zB,WAAW4zD,EAASO,mBAEtCP,EAASQ,sBAAsBloF,GAC/B,MAAMgnF,EA3ElB,SAAoCmB,GAEhC,IAAIC,EAAY,EAEhB,MAAMjxF,EAASgxF,EAAQhxF,OAEvB,IAAK,IAAIF,EAAI,EAAGA,EAAIE,EAAQF,IACpBmxF,EAAYD,EAAQlxF,KACpBmxF,EAAYD,EAAQlxF,IAI5B,OAAO6xD,aAAas/B,EAAY,KAAO,KAAKC,QAAQ,IA+DzBC,CAA2BtoF,GAM9CvK,KAAKuxF,WA5DjB,SAAsBuB,EAAUC,GAC5B,IAAI5rF,EAAQ,EACZ,MAAM2uC,EAAOi9C,EAAYD,EAUzB,OAPI3rF,EADA2uC,EAAO,GACCi9C,EAAY,GACbj9C,GAAQ,GACPi9C,EAAY,GAEZD,EAGLz/B,WAAWlsD,EAAMyrF,QAAQ,IAgDNI,CAAazB,EAAYvxF,KAAKuxF,YAChDvxF,KAAK4c,SAAS5c,KAAKuxF,cAEvBvxF,KAAKsxF,gBAObH,GAAoBlwF,UAAU8B,KAAO,WAC7B/C,KAAKqxF,aACL4B,cAAcjzF,KAAKqxF,YACnBrxF,KAAKqxF,WAAa,OAU1BF,GAAoBY,sBAAwB,WACxC,OAAOzK,QAAQx6C,KCjFZ,MAAMomD,GAIT95E,cACIpZ,KAAKmzF,QAAU,EACfnzF,KAAK6Q,EAAI,EASbuiF,QAAQjsF,GACiB,iBAAVA,IAGXnH,KAAK6Q,GAAK,EACV7Q,KAAKmzF,QAAUnzF,KAAKmzF,SAAYhsF,EAAQnH,KAAKmzF,SAAWnzF,KAAK6Q,GAOjEwiF,aACI,OAAOrzF,KAAKmzF,SCrFpB,MAAM5uF,IAAS2B,EAAAA,EAAAA,6DAUR,MAAMotF,GAOTl6E,YAAY0wB,EAASypD,GACjBvzF,KAAKwzF,aAAe1pD,EACpB9pC,KAAKyzF,UAAY,EACjBzzF,KAAK0zF,YAAc,EACnB1zF,KAAK2zF,yBAA2BJ,EAChCvzF,KAAK4zF,MAAQ,IAAIV,GAQrBW,oBACI,MAAO,CACHC,kBA9BI,GA8Be9zF,KAAK4zF,MAAMP,cAAwBT,QAAQ,GAC9DmB,cAAe/zF,KAAK0zF,aAS5BM,gBAEIh0F,KAAKi0F,qBAAuBt7E,IACxB,MAAMwuD,EAAUxuD,EAAKu7E,aAErB,IAAK,MAAMC,KAAQhtB,EACfnnE,KAAKyzF,YACLzzF,KAAK0zF,YAAczpF,KAAKotB,IAAIr3B,KAAK0zF,YAAaS,EAAKC,UAAUxB,QAAQ,IAK7EruF,GAAOiH,KAAK,6DACZxL,KAAKq0F,SAAW,IAAI1L,oBAAoB3oF,KAAKi0F,sBAC7Cj0F,KAAKq0F,SAASC,QAAQ,CAAE1sF,KAAM,WAC1B2sF,UAAU,IACd,MAAMC,EAAYrvF,KAAK8nD,MAGvBjtD,KAAKy0F,oBAAsBlC,aAAY,KACnC,MAAMtlC,EAAM9nD,KAAK8nD,MACXmkC,EAAWpxF,KAAK00F,gBACfznC,EAAMjtD,KAAK00F,gBA/DR,KAgEHznC,EAAMunC,GAhEH,IAiEJlnF,EAAOtN,KAAKyzF,UAAYrC,EAE9BpxF,KAAK4zF,MAAMR,QAAQ9lF,GACnBtN,KAAKwzF,aAAa37D,KACd88D,GAAmC30F,KAAK6zF,qBAG5C7zF,KAAKyzF,UAAY,EACjBzzF,KAAK00F,eAAiBvvF,KAAK8nD,QAC5BjtD,KAAK2zF,0BAOZiB,eACI50F,KAAKq0F,UAAYr0F,KAAKq0F,SAASQ,aAC/B70F,KAAKi0F,qBAAuB,KACxBj0F,KAAKy0F,sBACLxB,cAAcjzF,KAAKy0F,qBACnBz0F,KAAKy0F,oBAAsB,OC7FhC,IAAKK,aAAAA,GAAAA,EAAAA,MAAAA,QAAAA,EAAAA,UAAAA,YAAAA,EAAAA,MAAAA,SAAAA,KAAAA,GAAAA,KCMZ,MAAMt8D,GAAuBgB,EAAQ,IAE/Bj1B,IAAS2B,EAAAA,EAAAA,sDASf,SAAS6uF,GAAoBC,EAAaC,GACtC,OAAKA,GAAgBA,GAAgB,IACzBD,GAAeA,GAAe,EAC/B,EAGJ/qF,KAAKo+B,MAAO2sD,EAAcC,EAAgB,KAOrD,SAASC,KACLl1F,KAAKm1F,KAAO,GACZn1F,KAAKo1F,QAAU,CACXC,SAAU,EACVC,OAAQ,GAEZt1F,KAAKu1F,WAAa,GAClBv1F,KAAKw1F,UAAY,EACjBx1F,KAAK2yE,MAAQ,GAqDjB,SAAS8iB,KAMLz1F,KAAKu3E,UAAY,GAMjBv3E,KAAKo1F,QAAU,GAMfp1F,KAAK01F,WAAa,KAMlB11F,KAAKoD,UAAY,GAkBN,SAASuyF,GAAepJ,EAAgBqJ,EAAqBrC,EAAeC,GACvFxzF,KAAKusF,eAAiBA,EACtBvsF,KAAK61F,0BAA4B,KACjC71F,KAAK81F,yBAA2B,KAChC91F,KAAK+1F,mBAAqB,KAC1B/1F,KAAKg2F,oBAAsB,KAC3Bh2F,KAAKi2F,wBAA0B,GAC/Bj2F,KAAKk2F,sBAAwB,KAC7Bl2F,KAAKwzF,aAAeA,EACpBxzF,KAAKm2F,gBAAkB,IAAIV,GAG3Bz1F,KAAKo2F,yBAA2BR,EAEhC51F,KAAKq2F,YAAc,GACnBr2F,KAAKs2F,gBAAkB,KACvBt2F,KAAKu2F,mBAAqBhD,EAM1BvzF,KAAKw2F,WAAa,IAAInwB,IA9G1B6uB,GAAUj0F,UAAUw1F,QAAU,SAAStB,GACnCn1F,KAAKm1F,KAAOA,GAAQ,IAOxBD,GAAUj0F,UAAUy1F,cAAgB,SAASnB,GACzCv1F,KAAKu1F,WAAaA,GAAc,IAQpCL,GAAUj0F,UAAU01F,WAAa,SAASvB,GACtCp1F,KAAKo1F,QAAQC,UAAYD,EAAQC,SACjCr1F,KAAKo1F,QAAQE,QAAUF,EAAQE,QAOnCJ,GAAUj0F,UAAU21F,aAAe,WAC/B52F,KAAKo1F,QAAQC,SAAW,EACxBr1F,KAAKo1F,QAAQE,OAAS,GAO1BJ,GAAUj0F,UAAU41F,aAAe,SAASrB,GACxCx1F,KAAKw1F,UAAYA,GAAa,GAGlCN,GAAUj0F,UAAU61F,SAAW,SAASnkB,GACpC3yE,KAAK2yE,MAAQA,GAAS,IA+E1BgjB,GAAe10F,UAAU81F,eAAiB,SAASV,GAC/Cr2F,KAAKq2F,YAAcA,GAMvBV,GAAe10F,UAAU8B,KAAO,WACxB/C,KAAKk2F,wBACLjD,cAAcjzF,KAAKk2F,uBACnBl2F,KAAKk2F,sBAAwB,MAG7Bl2F,KAAKs2F,kBACLrD,cAAcjzF,KAAKs2F,iBACnBt2F,KAAKs2F,gBAAkB,OAQ/BX,GAAe10F,UAAU84B,cAAgB,SAAS14B,GAC9Cm3B,GAAqBE,iBAAiBr3B,GACtCkD,GAAOlD,MAAM,kBAAmBA,GAChCrB,KAAK+C,QAMT4yF,GAAe10F,UAAUmB,MAAQ,SAAS40F,GAClCA,IACIzxD,GAAQsjD,yBACRtkF,GAAOiH,KAAK,6DAEhBxL,KAAKk2F,sBAAwB3D,aACzB,KACI,GAAIhtD,GAAQsjD,wBAAyB,CACjC,MAAMoO,EAAcj3F,KAAKusF,eAAe2K,eAAel3F,KAAKq2F,aAE5D,IAAK,MAAMzvF,KAAQqwF,EACf,GAAIA,EAAYx+E,eAAe7R,GAAO,CAGlC,MAAM2qF,EAAiC,IAApB0F,EAAYrwF,GAE/B5G,KAAKwzF,aAAa37D,KACd88D,GACA30F,KAAKusF,eACLz9E,OAAOrG,SAAS7B,EAAM,IACtB2qF,GACA,SAKZvxF,KAAKusF,eAAe4K,WACfv2C,MAAK4rC,IACFxsF,KAAK81F,yBAAqD,mBAAnBtJ,MAAAA,OAAP,EAAOA,EAAQlzD,QACzCkzD,EAAOlzD,SACPkzD,EACNxsF,KAAKo3F,0BACLp3F,KAAK61F,0BAA4B71F,KAAK81F,4BAEzC9xC,OAAM3iD,GAASrB,KAAK+5B,cAAc14B,OAG/CrB,KAAKo2F,2BAIb,MAAMiB,EAAe,KAEjBr3F,KAAKusF,eAAe4K,WACfv2C,MAAK4rC,IACFxsF,KAAK+1F,mBAA+C,mBAAnBvJ,MAAAA,OAAP,EAAOA,EAAQlzD,QACnCkzD,EAAOlzD,SACPkzD,EAEN,IACIxsF,KAAKs3F,qBACP,MAAOj2F,GACLm3B,GAAqBE,iBAAiBr3B,GACtCkD,GAAOlD,MAAM,kCAAmCA,GAEpDrB,KAAKg2F,oBAAsBh2F,KAAK+1F,sBAEnC/xC,OAAM3iD,GAASrB,KAAK+5B,cAAc14B,MAG3Cg2F,IACAr3F,KAAKs2F,gBAAkB/D,YAAY8E,EAAcr3F,KAAKu2F,qBAM1DZ,GAAe10F,UAAUs2F,sBAAwB,WAE7C,MAAMtC,EAAe,CACjBI,SAAU,EACVC,OAAQ,GAENN,EAAc,CAChBK,SAAU,EACVC,OAAQ,GAEZ,IAAIkC,EAAkB,EAClBC,EAAgB,EACpB,MAAMC,EAAc,GACdC,EAAa,GACb5hB,EAAS,GACf,IAEI6hB,EAGAC,EALAC,EAAuB,EACvBC,EAAqB,EAErBC,EAAuB,EACvBC,EAAqB,EAGzB,IAAK,MAAQrxF,EAAMsxF,KAAel4F,KAAKw2F,WAAY,CAE/C,MAAMrB,EAAO+C,EAAU/C,KACjBvtF,EAAOutF,EAAKgD,iBAAmB,WAAa,SAElDlD,EAAartF,IAASutF,EAAKiD,aAC3BpD,EAAYptF,IAASutF,EAAKkD,YAG1Bb,GAAmBU,EAAU9C,QAAQC,SACrCoC,GAAiBS,EAAU9C,QAAQE,OAGnC,MAAMnd,EAAQn4E,KAAKusF,eAAe+L,eAAe1xF,GAEjD,GAAIuxE,EAAO,CACHA,EAAMogB,gBACNT,GAAwBI,EAAU9C,QAAQC,SAC1C0C,GAAsBG,EAAU9C,QAAQE,OACxCsC,EAAaM,EAAUvlB,QAEvBqlB,GAAwBE,EAAU9C,QAAQC,SAC1C4C,GAAsBC,EAAU9C,QAAQE,OACxCuC,EAAaK,EAAUvlB,OAG3B,MAAM6lB,EAAgBrgB,EAAMsgB,mBAE5B,GAAID,EAAe,CACf,MAAMjD,EAAa2C,EAAU3C,WAE7B,GAAIA,EAAW34D,OACJ24D,EAAW14D,SACW,IAAtB04D,EAAW34D,QACY,IAAvB24D,EAAW14D,OAAe,CACjC,MAAM67D,EAAkBhB,EAAYc,IAAkB,GAEtDE,EAAgB9xF,GAAQ2uF,EACxBmC,EAAYc,GAAiBE,EAEjC,GAA4B,IAAxBR,EAAU1C,UAAiB,CAC3B,MAAMmD,EAAiBhB,EAAWa,IAAkB,GAEpDG,EAAe/xF,GAAQsxF,EAAU1C,UACjCmC,EAAWa,GAAiBG,EAEhC,GAAIf,GAAcC,EAAY,CAC1B,MAAMe,EAAY,CACd,MAAShB,EACT,MAASC,GAGPgB,EAAa9iB,EAAOyiB,IAAkB,GAE5CK,EAAWjyF,GAAQgyF,EACnB7iB,EAAOyiB,GAAiBK,QAG5Bt0F,GAAOlD,MAAO,iCAAgC82E,KAItD+f,EAAUtB,eAGd52F,KAAKm2F,gBAAgBf,QAAU,CAC3B,OAAUqC,EACV,SAAYD,GAGhBx3F,KAAKm2F,gBAAgBf,QAAQ0D,MAAQ,CACjC,OAAUf,EACV,SAAYD,GAGhB93F,KAAKm2F,gBAAgBf,QAAQxU,MAAQ,CACjC,OAAUqX,EACV,SAAYD,GAGhBh4F,KAAKm2F,gBAAgBT,WAAa,CAC9BqD,MACIhE,GACIC,EAAYK,SAAWL,EAAYM,OACnCL,EAAaI,SAAWJ,EAAaK,QAC7CD,SACIN,GAAoBC,EAAYK,SAAUJ,EAAaI,UAC3DC,OACIP,GAAoBC,EAAYM,OAAQL,EAAaK,SAG7D,MAAM0D,EAAiB,GACvB,IAAIC,EAEJ74F,OAAOC,KAAKL,KAAKi2F,yBAAyB11F,SAAQqG,IAC9C,MAAM,KAAE6P,EAAF,QAAQw5E,GAAYjwF,KAAKi2F,wBAAwBrvF,GACjDsyF,EAAgBziF,EAAK5G,QAAO,CAACkc,EAAK2qC,IAAiB3qC,EAAM2qC,IAAgBjgD,EAAK/U,OAEpF,GAAIuuF,EACAgJ,EAAsBC,MACnB,CACH,MAAM/gB,EAAQn4E,KAAKusF,eAAe+L,eAAexpF,OAAOlI,IAExD,GAAIuxE,EAAO,CACP,MAAMqgB,EAAgBrgB,EAAMsgB,mBAExBD,IACAQ,EAAeR,GAAiBU,QAKhDl5F,KAAKi2F,wBAA0B,GAE/Bj2F,KAAKwzF,aAAa37D,KACd88D,GACA30F,KAAKusF,eACL,CACI,UAAavsF,KAAKm2F,gBAAgB5e,UAClC,QAAWv3E,KAAKm2F,gBAAgBf,QAChC,WAAcp1F,KAAKm2F,gBAAgBT,WACnC,WAAcgC,EACd,UAAaC,EACb,MAAS5hB,EACT,UAAa/1E,KAAKm2F,gBAAgB/yF,UAClC61F,oBAAAA,EACAD,eAAAA,IAERh5F,KAAKm2F,gBAAgB/yF,UAAY,IAUrCuyF,GAAe10F,UAAUk4F,oBAAsB,SAAS5sF,GACpD,IAAIpF,EAAQoF,EAMZ,MAJqB,iBAAVpF,IACPA,EAAQ2H,OAAO3H,IAGfuiC,MAAMviC,GACC,EAGJ8C,KAAKotB,IAAI,EAAGlwB,IAavBwuF,GAAe10F,UAAUm4F,kBAAoB,SAASnsC,EAAK8D,EAAQsoC,GAC/D,MAAMC,EAAWt5F,KAAKm5F,oBAAoBlsC,EAAIosC,IACxCE,EAAcv5F,KAAKm5F,oBAAoBpoC,EAAOsoC,IAC9CG,EAAiBvvF,KAAKotB,IAAI,EAAGiiE,EAAWC,GAExCE,EAASxsC,EAAIprD,UAAYkvD,EAAOlvD,UACtC,IAAI63F,EAAc,EAOlB,OALID,EAAS,IAETC,EAAczvF,KAAKo+B,MAAwB,EAAjBmxD,EAAsBC,IAG7CC,GAMX/D,GAAe10F,UAAUq2F,mBAAqB,WAC1C,IAAKt3F,KAAKg2F,oBACN,OAEJ,MAAM2D,EAAgB,GAEtB35F,KAAK+1F,mBAAmBx1F,SAAQ0sD,IAE5B,GAAiB,mBAAbA,EAAIrlD,MAA6BqlD,EAAI2sC,WAA2B,cAAd3sC,EAAIphB,MAAuB,CAC7E,MAAMguD,EAA2B5sC,EAAI4sC,yBAC/BC,EAA2B7sC,EAAI6sC,0BAEjCD,GAA4BC,KAC5B95F,KAAKm2F,gBAAgB5e,UAAY,CAC7B,SAAYttE,KAAKo+B,MAAMwxD,EAA2B,KAClD,OAAU5vF,KAAKo+B,MAAMyxD,EAA2B,OAIxD,MAAMC,EAAsB/5F,KAAK+1F,mBAAmB/wE,IAAIioC,EAAI+sC,mBACtDC,EAAqBj6F,KAAK+1F,mBAAmB/wE,IAAIioC,EAAIitC,kBAI3D,GAAIH,GAAuBE,EAAoB,CAC3C,MAIMjqF,EAAM,GAJYu1B,GAAQ2hD,kBAC1B6S,EAAoB/pF,GACpB+pF,EAAoBxsF,WACPwsF,EAAoB9pF,OAOjCkqF,EAAW,GAJM50D,GAAQ2hD,kBACzB+S,EAAmBjqF,GACnBiqF,EAAmB1sF,WACP0sF,EAAmBhqF,OAE/BrI,EAAOmyF,EAAoBnoB,SAG3BwoB,EAA2Bp6F,KAAKm2F,gBAAgB/yF,UAEjDg3F,EAAyBxuF,MAAK5G,GAC/BA,EAAEgL,KAAOA,GACNhL,EAAE4C,OAASA,GACX5C,EAAEm1F,UAAYA,KACjBC,EAAyBl4F,KAAK,CAC1B8N,GAAAA,EACApI,KAAAA,EACAuyF,QAAAA,EACAE,IAAKr6F,KAAKusF,eAAegD,MACzB+K,mBAAoBL,EAAmBM,cACvCC,oBAAqBT,EAAoBQ,cACzCE,YAAaR,EAAmBQ,YAChCC,IAAgC,IAA3BztC,EAAI0tC,6BASlB,GAAiB,gBAAb1tC,EAAIrlD,MAAuC,iBAAbqlD,EAAIrlD,KAAyB,CAClE,MAAMmpD,EAAS/wD,KAAKg2F,oBAAoBhxE,IAAIioC,EAAI5nD,IAC1CuB,EAAO5G,KAAKm5F,oBAAoBlsC,EAAIrmD,MAE1C,IAAKmqD,IAAWnqD,EACZ,OAGJ,IAAIsxF,EAAYl4F,KAAKw2F,WAAWxxE,IAAIpe,GAE/BsxF,IACDA,EAAY,IAAIhD,GAChBl1F,KAAKw2F,WAAWtxE,IAAIte,EAAMsxF,IAG9B,IAAIC,GAAmB,EACnBjqF,EAAM,kBAEO,iBAAb++C,EAAIrlD,OACJuwF,GAAmB,EACnBjqF,EAAM,eAGV,IAAI0sF,EAAa3tC,EAAI/+C,KAEhB0sF,GAAcA,EAAa,KAC5BA,EAAa,GAGjB,MAAMC,EAAgB76F,KAAKm5F,oBAAoBpoC,EAAO7iD,IAChD4sF,EAAc7wF,KAAKotB,IAAI,EAAGujE,EAAaC,GAEvCE,EAAiB/6F,KAAKm5F,oBAAoBlsC,EAAIorC,aAC9C2C,EAAoBh7F,KAAKm5F,oBAAoBpoC,EAAOsnC,aACpD4C,EAAkBhxF,KAAKotB,IAAI,EAAG0jE,EAAiBC,GAarD,GAXA9C,EAAUzB,QAAQ,CACd2B,aAAc0C,EAAcG,EAC5B5C,YAAa4C,EACb9C,iBAAAA,IAQa,gBAAblrC,EAAIrlD,KAAwB,CAC5B,MAAM2tF,EAAa,CACf14D,OAAQowB,EAAIiuC,YACZt+D,MAAOqwB,EAAIkuC,YAETC,EAAYnuC,EAAIouC,gBAElB9F,EAAW14D,QAAU04D,EAAW34D,OAChCs7D,EAAUxB,cAAcnB,GAE5B2C,EAAUrB,aAAa5sF,KAAKo+B,MAAM+yD,GAAa,IAE/ClD,EAAUvB,WAAW,CACjB,SAAY32F,KAAKo5F,kBAAkBnsC,EAAK8D,EAAQ,iBAChD,OAAU,SAGd4oC,EAAc/yF,GAAQ5G,KAAKm5F,oBAAoBlsC,EAAIquC,WACnDpD,EAAUvB,WAAW,CACjB,SAAY,EACZ,OAAU32F,KAAKo5F,kBAAkBnsC,EAAK8D,EAAQ,eAItD,MAAM4hB,EAAQ3yE,KAAK+1F,mBAAmB/wE,IAAIioC,EAAIsuC,SAE9C,GAAI5oB,EAAO,CAMP,MAAM6oB,EAAiB7oB,EAAM3+D,SAAS9P,MAAM,KAAK,GAEjDs3F,GAAkBtD,EAAUpB,SAAS0E,SAMtC,GAAiB,UAAbvuC,EAAIrlD,MAAoBqlD,EAAIspB,OAASue,GAAU2G,QAAUxuC,EAAIyuC,aAAc,CAClF,MAAMnG,EAAa,CACf14D,OAAQowB,EAAIiuC,YACZt+D,MAAOqwB,EAAIkuC,YAETQ,EAAmB37F,KAAKusF,eAAeqP,eAAe9G,GAAU2G,OAEtE,GAAKE,MAAAA,IAAAA,EAAkBj6F,OACnB,OAGJ,MAAMkF,EAAO5G,KAAKusF,eAAesP,aAAaF,EAAiB,IAE/D,IAAK/0F,EACD,OAEJ,IAAIsxF,EAAYl4F,KAAKw2F,WAAWxxE,IAAIpe,GAE/BsxF,IACDA,EAAY,IAAIhD,GAChBl1F,KAAKw2F,WAAWtxE,IAAIte,EAAMsxF,IAE1B3C,EAAW14D,QAAU04D,EAAW34D,OAChCs7D,EAAUxB,cAAcnB,GAK5B,IAAI6F,EAAYnuC,EAAIouC,gBAEpB,IAAKD,EAAW,CACZ,MAAMrqC,EAAS/wD,KAAKg2F,oBAAoBhxE,IAAIioC,EAAI5nD,IAEhD,GAAI0rD,EAAQ,CACR,MAAM0oC,EAASxsC,EAAIprD,UAAYkvD,EAAOlvD,UAElC43F,EAAS,GAAKxsC,EAAI6uC,aAGlBV,GAFkCnuC,EAAI6uC,WAAa/qC,EAAO+qC,YAEjBrC,EAAU,KAI3D,IAAK2B,EACD,OAKR,MAAMW,EAAwB/7F,KAAKusF,eAAeyP,4BAGlDZ,EAAYW,EAAwB9xF,KAAKo+B,MAAM+yD,EAAYW,GAAyB,EACpF7D,EAAUrB,aAAauE,OAI/Bp7F,KAAKwzF,aAAa37D,KAAK88D,GAAkC30F,KAAKusF,eAAgBoN,GAC9E35F,KAAKu3F,yBAMT5B,GAAe10F,UAAUm2F,wBAA0B,WAC1Cp3F,KAAK61F,2BAIV71F,KAAK81F,yBAAyBv1F,SAAQ0sD,IAClC,GAAiB,UAAbA,EAAIrlD,KACJ,OAIJ,MAAM2pF,EAAatkC,EAAIskC,WAEvB,IAAKA,EACD,OAGJ,MAAM0K,EAAkBhvC,EAAIgvC,gBACtBr1F,EAAO5G,KAAKusF,eAAe2P,iBAAiBD,GAElD,GAAIr1F,EAAM,CACN,MAAMqpF,EACArpF,IAAS5G,KAAKusF,eAAesP,aAC/B77F,KAAKusF,eAAeqP,eAAe9G,GAAUqH,QAEjDn8F,KAAKwzF,aAAa37D,KACd88D,GACA30F,KAAKusF,eACL3lF,EACA2qF,EACAtB,QCrrBhB,MAAM1rF,GAASi1B,EAAAA,IAAAA,8CAMf,IAAI4iE,GAKAC,IAAoB,EAkCxB,SAASC,GAAsBv8F,GACvByrF,GAAU+Q,wBAIT/Q,GAAUgR,YAAY,CACvBvO,YAAaluF,EAAQkuF,YACrBC,gBAAiBnuF,EAAQmuF,gBACzBF,SAAUjuF,EAAQiuF,SAClBD,UAAWhuF,EAAQguF,UACnBK,gBAAiBruF,EAAQquF,gBACzBK,mBAAoB1uF,EAAQ0uF,mBAC5BpC,OAAQtsF,EAAQssF,OAChBiC,OAAQvuF,EAAQuuF,OAChBH,aAAcpuF,EAAQouF,gBAEtB5pF,GAAOlD,MAAM,+CA4EN,SAASo7F,GAAWC,EAAM38F,GAMrCC,KAAK28F,YAAc,IAAIt2B,IACvBrmE,KAAKwzF,aAAe,IAAI7pD,MACxB3pC,KAAK08F,KAAOA,EACZ18F,KAAKD,QAAUA,GAAW,GAE1BC,KAAK48F,4BACC58F,KAAKD,QAAQkuF,aAAejuF,KAAKD,QAAQmuF,iBAAmBluF,KAAKD,QAAQ88F,kBAK1B,IAAzCJ,GAAWK,0BACnB98F,KAAK48F,8BACL58F,KAAK+8F,iCACC/8F,KAAKD,QAAQg9F,iCACfx3D,GAAQmhD,gBACR4V,GAAsBt8F,KAAKD,SAtIvC,SAA0BA,GACjBs8F,KACD5iE,KAAAA,WACI15B,EAAQi9F,iBAAmBzd,IACf,GACE,OACIxzE,GACC,IAAMuwF,GAAsBv8F,KAEnDs8F,IAAoB,GA+HhBY,CAAiBj9F,KAAKD,SAGrBC,KAAKD,QAAQssF,QACd9nF,GAAO2T,KAAK,4BAUpBlY,KAAKk9F,oBAAsB,IAAI72B,IAE/Bo2B,GAAWU,UAAUx9C,IAAI3/C,MA/E7By8F,GAAW7yD,KAAO,SAAS7pC,GACvB08F,GAAWW,oBAAsBr9F,EAAQs9F,mBACF,iBAA5Bt9F,EAAQu9F,kBACfb,GAAWa,gBAAkBv9F,EAAQu9F,iBAGE,iBAAhCv9F,EAAQ61F,sBACf6G,GAAW7G,oBAAsB71F,EAAQ61F,qBAGC,iBAAnC71F,EAAQw9F,yBACfd,GAAWc,uBAAyBx9F,EAAQw9F,wBAGhDd,GAAWK,0BAA4B/8F,EAAQ+8F,2BAmEnDL,GAAWW,oBAAqB,EAChCX,GAAW7G,oBAAsB,IACjC6G,GAAWa,gBAAkB,IAC7Bb,GAAWK,2BAA4B,EACvCL,GAAWe,UAAYA,GAEvBp9F,OAAO0kB,eAAe23E,GAAY,YAAa,CAM3Cz3E,IAAG,KACMo3E,KACDA,GAAa,IAAI91B,KAGd81B,MAQfK,GAAWx7F,UAAUw8F,iBAAmB,SAASlR,GAC7CvsF,KAAK09F,gBAAgBnR,GAErB,IACI,MAAMoR,EACA,IAAIC,GACFrR,EACAkQ,GAAW7G,oBACX6G,GAAWa,gBACXt9F,KAAKwzF,cAEbmK,EAASv7F,MAAMq6F,GAAWW,oBAC1Bp9F,KAAK28F,YAAYz3E,IAAIqnE,EAAelnF,GAAIs4F,GAC1C,MAAO5wF,GACLxI,GAAOlD,MAAO,iDAAgD0L,OAItE0vF,GAAWoB,WAAa,GAExBpB,GAAWqB,gBAAkB,SAAS1tF,EAAQwM,GAC1C,IAAK6/E,GAAWW,mBACZ,OAEJ,MAAMS,EAAa,IAAIE,GAAW3tF,EAAQqsF,GAAW7G,oBACjDh5E,GAEJ5c,KAAK69F,WAAW37F,KAAK27F,GACrBA,EAAWz7F,SAGfq6F,GAAWx7F,UAAU+8F,sBAAwB,SAASlzD,GAC7C2xD,GAAWW,oBAGhBp9F,KAAKwzF,aAAajpD,GAAGoqD,GAA8B7pD,IAGvD2xD,GAAWx7F,UAAUg9F,yBAA2B,SAASnzD,GAChD2xD,GAAWW,oBAGhBp9F,KAAKwzF,aAAarpD,eAAewqD,GAA8B7pD,IAGnE2xD,GAAWx7F,UAAUi9F,0BAA4B,SAASpzD,GACtD9qC,KAAKwzF,aAAajpD,GAAGoqD,GAAkC7pD,IAG3D2xD,GAAWx7F,UAAUk9F,6BAA+B,SAASrzD,GACzD9qC,KAAKwzF,aAAarpD,eACdwqD,GAAkC7pD,IAG1C2xD,GAAWx7F,UAAUm9F,2BAA6B,SAAStzD,GACvD9qC,KAAKwzF,aAAajpD,GAAGoqD,GAAmC7pD,IAG5D2xD,GAAWx7F,UAAUo9F,8BAAgC,SAASvzD,GAC1D9qC,KAAKwzF,aAAarpD,eACdwqD,GACA7pD,IAGR2xD,GAAWx7F,UAAUq9F,yBAA2B,SAASxzD,GACrD9qC,KAAKwzF,aAAajpD,GAAGoqD,GAAkC7pD,IAG3D2xD,GAAWx7F,UAAUs9F,4BAA8B,SAASzzD,GACxD9qC,KAAKwzF,aAAarpD,eAAewqD,GAC7B7pD,IASR2xD,GAAWx7F,UAAUu9F,0BAA4B,SAAS1zD,GACtD9qC,KAAKwzF,aAAajpD,GAAGoqD,GAAmC7pD,IAS5D2xD,GAAWx7F,UAAUw9F,qBAAuB,SAASC,GAC5Cn5D,GAAQmjD,+BAMb1oF,KAAK2+F,yBAA2B,IAAIrL,GAChCtzF,KAAKwzF,aACLiJ,GAAWc,wBAEfmB,EAAWn0D,GACP2wC,GACA,IAAMl7E,KAAK2+F,yBAAyB3K,kBACxC0K,EAAWn0D,GACP2wC,GACA,IAAMl7E,KAAK2+F,yBAAyB/J,kBAdpCrwF,GAAO2T,KAAK,kEAuBpBukF,GAAWx7F,UAAU4yF,kBAAoB,WACrC,OAAO7zF,KAAK2+F,yBACN3+F,KAAK2+F,yBAAyB9K,oBAC9B,MASV4I,GAAWx7F,UAAU29F,6BAA+B,SAAS9zD,GACzD9qC,KAAKwzF,aAAarpD,eAAewqD,GAAmC7pD,IASxE2xD,GAAWx7F,UAAU81F,eAAiB,SAASV,GAC3C,IAAK,MAAMsH,KAAYj5F,MAAMm6F,KAAK7+F,KAAK28F,YAAYrzF,UAC1Cq0F,EAASpR,eAAegD,OACzBoO,EAAS5G,eAAeV,IAKpCoG,GAAWx7F,UAAUqpF,QAAU,WAC3B,IAQStqF,KAAKk9F,oBAAoBl4B,MAC1BhlE,KAAKwzF,aAAa37D,KAAK88D,IAE3B,IAAK,MAAMmK,KAAa9+F,KAAKk9F,oBAAoB5zF,SAC7CtJ,KAAK++F,cAAcD,EAAU3P,KAEjC,IAAK,MAAM6P,KAASh/F,KAAK28F,YAAYt8F,OACjCL,KAAKi/F,iBAAiBD,GAEtBh/F,KAAKwzF,cACLxzF,KAAKwzF,aAAalmD,qBAlB1B,QAqBImvD,GAAWU,UAAU5M,OAAOvwF,QAIpCy8F,GAAWyC,eAAiB,SAAS9uF,GACjC,GAAKqsF,GAAWW,mBAIhB,IAAK,IAAI57F,EAAI,EAAGA,EAAIi7F,GAAWoB,WAAWn8F,OAAQF,IAC9C,GAAIi7F,GAAWoB,WAAWr8F,GAAG4O,SAAWA,EAAQ,CACzBqsF,GAAWoB,WAAWr6F,OAAOhC,EAAG,GAExC,GAAGuB,OACd,QAUZ05F,GAAWx7F,UAAUg+F,iBAAmB,SAASD,GAC7C,MAAMrB,EAAW39F,KAAK28F,YAAY33E,IAAIg6E,GAElCrB,IACAA,EAAS56F,OACT/C,KAAK28F,YAAYpM,OAAOyO,KAQhCvC,GAAWx7F,UAAUy8F,gBAAkB,SAASvO,GAC5CnvF,KAAKi/F,iBAAiB9P,EAAI9pF,KAW9Bo3F,GAAWx7F,UAAUk+F,eAAiB,SAAShQ,EAAKC,GAChD,IAAKpvF,KAAK48F,4BACN,OACG,GAAI58F,KAAKk9F,oBAAoB39C,IAAI4vC,EAAI9pF,IAGxC,YAFAd,GAAOlD,MAAM,gDAKjBkD,GAAOiH,KAAM,0BAAyB2jF,QAEtC,MAAMiQ,EACA,IAAI5T,GACF2D,EACA,CACI9C,OAAQrsF,KAAKD,QAAQssF,OACrB+C,aAAAA,IAGZpvF,KAAKk9F,oBAAoBh4E,IAAIiqE,EAAI9pF,GAAI+5F,IASzC3C,GAAW4C,0BAA4B,WACnC,MAAMC,EAAc,IAAIh5B,IAExB,IAAK,MAAMi5B,KAAc9C,GAAWU,UAChC,IAAK,MAAMhgF,KAAMoiF,EAAWrC,oBAAoB5zF,SAC5Cg2F,EAAY3/C,IAAIxiC,GAIxB,OAAOmiF,GAMX7C,GAAWx7F,UAAU89F,cAAgB,SAAS5P,GAC1C,MAAMtD,EAAoB7rF,KAAKk9F,oBAAoBl4E,IAAImqE,EAAI9pF,IAEvDwmF,IAUsC,IAAlC7rF,KAAKk9F,oBAAoBl4B,MACzBhlE,KAAKwzF,aAAa37D,KAAK88D,IAE3B30F,KAAKk9F,oBAAoB3M,OAAOpB,EAAI9pF,IAGpCwmF,EAAkBuE,uBAW1BqM,GAAWx7F,UAAUu+F,mBAAqB,WACtC,OAAOx/F,KAAK48F,6BAShBH,GAAWx7F,UAAUw+F,gCAAkC,SAAStQ,EAAKyB,GACjE,MAAM8O,EAAW1/F,KAAKk9F,oBAAoBl4E,IAAImqE,EAAI9pF,IAE9Cq6F,GACAA,EAAS/O,sBAAsBC,IAQvC6L,GAAWx7F,UAAUuvF,6BAA+B,SAASrB,GACzD,MAAMuQ,EAAW1/F,KAAKk9F,oBAAoBl4E,IAAImqE,EAAI9pF,IAE9Cq6F,GACAA,EAASlP,gCAUjBiM,GAAWx7F,UAAU0+F,cAAgB,SAASxQ,EAAKyQ,EAAOh4F,GACtD,MAAM83F,EAAWvQ,GAAOnvF,KAAKk9F,oBAAoBl4E,IAAImqE,EAAI9pF,IAEzDmmF,GAAUmU,cAAcC,EAAOh4F,EAAM83F,IAUzCjD,GAAWx7F,UAAU4vF,uBACf,SAASzuF,EAAOwE,GACd,IAAK,MAAMuW,KAAMnd,KAAKk9F,oBAAoB5zF,SACtC6T,EAAG0zE,uBAAuBzuF,EAAOwE,IAS7C61F,GAAWx7F,UAAUkvF,yBAA2B,SAAS0P,GACrD,IAAK,MAAM1iF,KAAMnd,KAAKk9F,oBAAoB5zF,SACtC6T,EAAGgzE,2BAIPnwF,KAAK08F,KAAKvM,yBAAyB0P,IAQvCpD,GAAWqD,0BAA4B,SAASlR,GAC5C,MAAMmR,EAAYtD,GAAW4C,4BAE7B,GAAIU,EAAU/6B,KACV,IAAK,MAAM7nD,KAAM4iF,EACbvU,GAAUsU,0BAA0BlR,EAAazxE,QAGrDquE,GAAUsU,0BAA0BlR,EAAa,OAmBzD6N,GAAWx7F,UAAU+uF,4BAA8B,SAC3Cb,EACAvoF,EACAqpF,EACA+P,EACA/S,EACA/B,GACJ,MAAMwU,EAAW1/F,KAAKk9F,oBAAoBl4E,IAAImqE,EAAI9pF,IAE9Cq6F,GACAA,EAAS1P,4BACLppF,EACAqpF,EACA+P,EACA/S,EACA/B,IAWZuR,GAAWwD,uBAAyB,SAASlzF,GACzC,MAAM1L,EACA0L,aAAauzE,GAtiBvB,SAA2Cj/E,GACvC,MAAMonC,EAAM,IAAIzkC,MAkBhB,OAfAykC,EAAIxkC,MAAQ5C,EAAM4C,MAGlBwkC,EAAIj8B,MAAQnL,EAAMmL,MAAQ,kBAAoBnL,EAAMm/E,KAAOn/E,EAAMm/E,IAAIn/E,OAC9DA,EAAMm/E,IAAIn/E,MAAMmL,KAAQ,MAAKnL,EAAMm/E,IAAIn/E,MAAMmL,OAAS,IAK7Di8B,EAAIi4C,eAAiBr/E,EAAMm/E,KAAOn/E,EAAMm/E,IAAIC,YACtCr/E,KAAKF,UAAUG,EAAMm/E,IAAIC,aAAe,GAG9Ch4C,EAAIztB,QAAU3Z,EAAM2Z,QAEbytB,EAohBGy3D,CAAkCnzF,GAAKA,EAC3CgzF,EAAYtD,GAAW4C,4BAE7B,GAAIU,EAAU/6B,KACV,IAAK,MAAM7nD,KAAM4iF,EACbvU,GAAUyU,uBAAuB5+F,EAAO8b,QAG5CquE,GAAUyU,uBAAuB5+F,EAAO,OAUhDo7F,GAAWx7F,UAAUwvF,sBAAwB,SAAS1jF,EAAGoiF,GACrD,MAAMuQ,EAAW1/F,KAAKk9F,oBAAoBl4E,IAAImqE,EAAI9pF,IAE9Cq6F,GACAA,EAASjP,sBAAsB1jF,IAUvC0vF,GAAWx7F,UAAUyvF,uBAAyB,SAAS3jF,EAAGoiF,GACtD,MAAMuQ,EAAW1/F,KAAKk9F,oBAAoBl4E,IAAImqE,EAAI9pF,IAE9Cq6F,GACAA,EAAShP,uBAAuB3jF,IAUxC0vF,GAAWx7F,UAAU6vF,uBAAyB,SAAS/jF,EAAGoiF,GACtD,MAAMuQ,EAAW1/F,KAAKk9F,oBAAoBl4E,IAAImqE,EAAI9pF,IAE9Cq6F,GACAA,EAAS5O,uBAAuB/jF,IAUxC0vF,GAAWx7F,UAAU8vF,wBAA0B,SAAShkF,EAAGoiF,GACvD,MAAMuQ,EAAW1/F,KAAKk9F,oBAAoBl4E,IAAImqE,EAAI9pF,IAE9Cq6F,GACAA,EAAS3O,wBAAwBhkF,IAUzC0vF,GAAWx7F,UAAU+vF,0BAA4B,SAASjkF,EAAGoiF,GACzD,MAAMuQ,EAAW1/F,KAAKk9F,oBAAoBl4E,IAAImqE,EAAI9pF,IAE9Cq6F,GACAA,EAAS1O,0BAA0BjkF,IAS3C0vF,GAAW0D,QAAU,SAASh8F,GAC1B,MAAMi8F,EAAe,IAAI95B,IAMzB,IAAK,MAAMstB,KAAS6I,GAAWU,UAAW,CACtC,GAAIvJ,EAAMmJ,iCACN,OAGAnJ,EAAMsJ,oBAAoBl4B,MAC1Bo7B,EAAazgD,IAAIi0C,EAAMsJ,oBAAoB5zF,SAASmU,OAAOtW,OAInE,GAAIi5F,EAAap7B,KACb,IAAK,MAAMq7B,KAAcD,EACrB5U,GAAU8U,mBAAmBn8F,EAAGk8F,QAGpC7U,GAAU8U,mBAAmBn8F,EAAG,OAYxCs4F,GAAWx7F,UAAUs/F,aAAe,SAASxR,EAAS13E,GAUlD,OAPAolF,GAAWe,UAAU3S,UACjB1I,GACA,CACIqe,OAAQzR,EACR13E,QAAAA,IAGDm0E,GAAU+U,aAAavgG,KAAKD,QAAQssF,OAAQ0C,EAAS13E,IAGhEolF,GAAWgE,UAAYjnE,EAAAA,KAAAA,UAOvBijE,GAAWiE,kBAAoB,SAASr/F,GAChCA,aAAiBi/E,IAAmBj/E,EAAMm/E,IAC1Cic,GAAWwD,uBAAuB5+F,GAElCo7F,GAAW0D,QAAQ9+F,IAa3Bo7F,GAAWkE,oBAAsB,SAASroE,GAAwB,IAO1DsoE,EAPyCjW,EAAiB,uDAAJ,GACrDryD,GAUDsoE,EADiB,iBAAVtoE,EACMA,EAEA,CACT9rB,KAAM8rB,EACNqyD,WAAAA,GAIRpmF,GAAOD,IAAIlD,KAAKF,UAAU0/F,IAG1B5gG,KAAKw9F,UAAU3S,UAAUvyD,EAAOqyD,IApB5BpmF,GAAO2T,KAAK,kCA8BpBukF,GAAWoE,cAAgB,SAAS/V,GAA4B,IAAjBH,EAAiB,uDAAJ,GACxD3qF,KAAKw9F,UAAU3S,UAAUC,EAAWH,qECvyBxC,MAAMpmF,IAAS2B,EAAAA,EAAAA,6CAMA,SAAS46F,GAA4BpC,GAChD1+F,KAAK0+F,WAAaA,EAClB1+F,KAAK+gG,cAAgB,GAGrBrC,EAAWn0D,GAAG2wC,IACV/C,IACI,IAAKA,EAAM8X,YAAcyO,EAAWa,WAChC,OAEJ,MAAM/3F,EACA2wE,EAAMoX,MACFmP,EAAWsC,iBAAmBtC,EAAWuC,iBAI7C9R,EAAO3nF,GAAWA,EAAQ+kF,gBAAmB,KAEnDmS,EAAWa,WAAWI,cAClBxQ,EACAhX,EAAM+oB,UACN/oB,EAAMgpB,cClDf,IAAKC,GDyDZN,GAA4B7/F,UAAUogG,uBAAyB,WAC3D,MAAM3C,EAAa1+F,KAAK0+F,WAClB4C,EAAW5C,EAAW6C,KAE5BvhG,KAAKwhG,kBAAoB,IAAI7pE,KAAJ,CAA0B2pE,EAC/CthG,KAAK0+F,WAAWlL,cAEpB8N,EAAS1pE,YAAYqF,GAAW,WAAXA,gBAA2BwkE,IACvCA,EAAclS,OAMfmP,EAAWgD,IAAIC,wBAMvBL,EAAS1pE,YAAYqF,GAAW,WAAXA,8BAAyC,CAAC4hE,EAAM+C,KACjE,MAAMC,EAAcnD,EAAWoD,mBAAmBC,GAAAA,QAAAA,mBAA2BlD,IAEzEgD,IACAA,EAAYG,YAAYJ,GACxBlD,EAAWlL,aAAa37D,KAAKqjD,GAAmD2mB,OAIxFP,EAAS1pE,YACLqF,GAAW,WAAXA,qBACA,CAACwkE,EAAeQ,MAGXR,EAAclS,OACRmP,EAAWwD,kBACVD,EAASR,EAAclV,mBAIvC+U,EAAS1pE,YAAYqF,GAAW,WAAXA,sBACjBklE,IAII1F,GAAWoE,cAAc7d,GAAyB8R,GAAUqH,QAE5DuC,EAAW0D,kBAAoBD,EAG/BzD,EAAWgD,IAAIW,cAAa,GAAMzhD,MAC9B,KACI89C,EAAW4D,gBAAiB,EAC5B5D,EAAW0D,kBAAoB,QAElCp+C,OACG3iD,IACIq9F,EAAW0D,kBAAoB,KAC/B79F,GAAO2T,KACH,gDAAiD7W,SAKzEigG,EAAS1pE,YAAYqF,GAAW,WAAXA,sBACjBklE,IAII1F,GAAWoE,cAAc7d,GAAyB8R,GAAU2G,QAE5DiD,EAAW6D,uBAAyBJ,EAGpCzD,EAAWgD,IAAIc,cAAa,GAAM5hD,MAC9B,KACI89C,EAAW+D,qBAAsB,EACjC/D,EAAW6D,uBAAyB,QAEvCv+C,OACG3iD,IACIq9F,EAAW6D,uBAAyB,KACpCh+F,GAAO2T,KACH,gDAAiD7W,SAKzErB,KAAKwhG,kBAAkB1pE,QAAQmF,GAAW,WAAXA,gBAC3Bi+C,IAEJl7E,KAAKwhG,kBAAkB1pE,QAAQmF,GAAW,WAAXA,WAC3Bi+C,GAEJl7E,KAAKwhG,kBAAkB1pE,QAAQmF,GAAW,WAAXA,qBAC3Bi+C,GAEJl7E,KAAKwhG,kBAAkB1pE,QAAQmF,GAAW,WAAXA,eAC3Bi+C,GAGJomB,EAAS1pE,YAAYqF,GAAW,WAAXA,YACjB,KACIj9B,KAAK0+F,WAAWgE,eAEhB1iG,KAAK0+F,WAAWiE,4BAA6B,EAG7CviG,OAAOC,KAAKihG,EAASsB,iBAAiBriG,SAAQ2N,IAC1C,MAAMoqB,EACAoqD,GACG,cAAax0E,IACd,CAAE/G,MAAOm6F,EAASsB,gBAAgB10F,KAE1CuuF,GAAWoE,cAAcvoE,MAI7Bl4B,OAAOC,KAAKihG,EAAS5E,KAAKkG,iBAAiBriG,SAAQ2N,IAC/C,MAAMoqB,EACAoqD,GACG,QAAOx0E,IACR,CAAE/G,MAAOm6F,EAAS5E,KAAKkG,gBAAgB10F,KAE/CuuF,GAAWoE,cAAcvoE,SAIrCgpE,EAAS1pE,YAAYqF,GAAW,WAAXA,sBAAiC,CAAClwB,EAAGvF,KACjDA,EAAQ+nF,OACTmP,EAAWlL,aAAa37D,KAAKqjD,EACzBrB,EAA2C9sE,MAIvD/M,KAAKwhG,kBAAkB1pE,QAAQmF,GAAW,WAAXA,gBAC3Bi+C,EACArB,GAEJ75E,KAAKwhG,kBAAkB1pE,QAAQmF,GAAW,WAAXA,mBAC3Bi+C,EACArB,GACJ75E,KAAKwhG,kBAAkB1pE,QAAQmF,GAAW,WAAXA,+BAC3Bi+C,EACArB,GACJ75E,KAAKwhG,kBAAkB1pE,QAAQmF,GAAW,WAAXA,gCAC3Bi+C,EACArB,GAEJ75E,KAAKwhG,kBAAkB1pE,QAAQmF,GAAW,WAAXA,qBAC3Bi+C,EACArB,GAEJ75E,KAAKwhG,kBAAkB1pE,QAAQmF,GAAW,WAAXA,kBAC3Bi+C,EACArB,GAEJ75E,KAAKwhG,kBAAkB1pE,QAAQmF,GAAW,WAAXA,wBAC3Bi+C,EACArB,GAEJ75E,KAAKwhG,kBAAkB1pE,QAAQmF,GAAW,WAAXA,YAC3Bi+C,EACArB,GACJynB,EAAS1pE,YACLqF,GAAW,WAAXA,aACA,IAAMw/D,GAAWoE,cfsBkB,CACvCp5F,OAAQ,cACRm7E,cAAe,cACfh7E,KAAMs5E,OevBNogB,EAAS1pE,YAAYqF,GAAW,WAAXA,sBACjBwkE,IACI/C,EAAWmE,uBAAuBpB,MAG1CzhG,KAAKwhG,kBAAkB1pE,QAAQmF,GAAW,WAAXA,kBAC3Bi+C,EACArB,GACJynB,EAAS1pE,YAAYqF,GAAW,WAAXA,mBACjB,KACIyhE,EAAWhC,KAAKoG,WAAWC,KAAKC,QAAQtE,EAAW6C,KAAK0B,YAGhEjjG,KAAKwhG,kBAAkB1pE,QAAQmF,GAAW,WAAXA,kBAC3Bi+C,EACArB,GAEJynB,EAAS1pE,YAAYqF,GAAW,WAAXA,uBACjBwkE,IACI/C,EAAWwE,uBAAuBzB,MAG1CzhG,KAAKwhG,kBAAkB1pE,QAAQmF,GAAW,WAAXA,cAC3Bi+C,EACArB,GAEJ75E,KAAKwhG,kBAAkB1pE,QAAQmF,GAAW,WAAXA,oBAC3Bi+C,EACArB,GAEJ75E,KAAKwhG,kBAAkB1pE,QAAQmF,GAAW,WAAXA,wBAC3Bi+C,EACArB,GAEJ75E,KAAKwhG,kBAAkB1pE,QAAQmF,GAAW,WAAXA,mBAC3Bi+C,EACArB,GAEJynB,EAAS1pE,YAAYqF,GAAW,WAAXA,YACjB,KACIw/D,GAAWoE,cfsDmB,CACtCp5F,OAAQ,aACRm7E,cAAe,aACfh7E,KAAMq5E,GAAgBC,mBexDdwd,EAAWlL,aAAa37D,KACpBqjD,EACArB,MAGZynB,EAAS1pE,YAAYqF,GAAW,WAAXA,wBACjBwkE,IACIhF,GAAWkE,oBACP7d,GACIvB,GACA,CAAE8Y,IAAKoH,EAAclS,YAGrC+R,EAAS1pE,YAAYqF,GAAW,WAAXA,wBACjB,CAACz1B,EAAS27F,KAEN,GAAIA,EAAK,CACL,MAAMC,EAAWrB,GAAAA,QAAAA,mBAA2BoB,GACtCtB,EAAcnD,EAAWoD,mBAAmBsB,IAAaA,EAEnC,QAAxB57F,EAAQ67F,YACR77F,EAAQ87F,cAAczB,GACS,OAAxBr6F,EAAQ67F,aACf77F,EAAQ+7F,aAAa1B,GAI7BnD,EAAWlL,aAAa37D,KACpBqjD,GACA1zE,MAGZxH,KAAKwhG,kBAAkB1pE,QAAQmF,GAAW,WAAXA,6BAC3Bi+C,IAEJl7E,KAAKwhG,kBAAkB1pE,QAAQmF,GAAW,WAAXA,kCAC3Bi+C,IAEJl7E,KAAKwhG,kBAAkB1pE,QACnBmF,GAAW,WAAXA,mCACAi+C,IAEJl7E,KAAKwhG,kBAAkB1pE,QAAQmF,GAAW,WAAXA,qBAC3Bi+C,IAEJomB,EAASkC,gCAA+B,CAACvwF,EAAM4rF,KAC3C,MAAMgD,EAAcnD,EAAWoD,mBAAmBjD,GAE7CgD,GAILA,EAAY9qC,YACR9jD,EAAKiD,QAAQ/F,UAAU,qBAAqBzO,QAC5CuR,EAAK9L,UAGbm6F,EAAS1pE,YAAYqF,GAAW,WAAXA,OACjByhE,EAAW+E,eAAe7iG,KAAK89F,IACnC4C,EAAS1pE,YAAYqF,GAAW,WAAXA,iBACjByhE,EAAWgF,kBAAkB9iG,KAAK89F,IAEtC1+F,KAAKwhG,kBAAkB1pE,QAAQmF,GAAW,WAAXA,iBAC3Bi+C,IAEJl7E,KAAKwhG,kBAAkB1pE,QAAQmF,GAAW,WAAXA,yBAC3Bi+C,IAEJomB,EAAS1pE,YAAYqF,GAAW,WAAXA,kBACjByhE,EAAWiF,eAAe/iG,KAAK89F,IACnC1+F,KAAKwhG,kBAAkB1pE,QAAQmF,GAAW,WAAXA,wBAC3Bi+C,IACJl7E,KAAKwhG,kBAAkB1pE,QAAQmF,GAAW,WAAXA,yBAC3Bi+C,IACJl7E,KAAKwhG,kBAAkB1pE,QAAQmF,GAAW,WAAXA,sBAC3Bi+C,IACJomB,EAAS1pE,YAAYqF,GAAW,WAAXA,4BACjByhE,EAAWkF,wBAAwBhjG,KAAK89F,IAC5C4C,EAAS1pE,YAAYqF,GAAW,WAAXA,gBACjByhE,EAAWmF,aAAajjG,KAAK89F,IACjC1+F,KAAKwhG,kBAAkB1pE,QAAQmF,GAAW,WAAXA,SAC3Bi+C,GACJl7E,KAAKwhG,kBAAkB1pE,QAAQmF,GAAW,WAAXA,kBAC3Bi+C,EACArB,GAEJynB,EAAS1pE,YAAYqF,GAAW,WAAXA,qBACjByhE,EAAWoF,qBAAqBljG,KAAK89F,IAEzC4C,EAAS1pE,YAAYqF,GAAW,WAAXA,oBAA+Bs3C,IAChDmqB,EAAWqF,mBAAmBxvB,GAG1BmqB,EAAWa,YAAcb,EAAWsF,eACpCtF,EAAWn0D,GAAG2wC,IACV+oB,IACI,MAAMC,EAAY,CACd7iG,MAAO4iG,EAAgBE,WACvB9+F,GAAI,kBACJ4pF,OAAQgV,EAAgBZ,aAG5B5G,GAAW0D,QAAQ/+F,KAAKF,UAAUgjG,UAKlD5C,EAAS1pE,YAAYqF,GAAW,WAAXA,iBACjByhE,EAAW0F,kBAAkBxjG,KAAK89F,IAEtC4C,EAAS1pE,YAAYmF,GAAAA,QAAAA,kBACjB,CAACsnE,EAAaC,KACV5F,EAAW2F,YAAcA,EACzB3F,EAAW4F,aAAeA,EAC1B5F,EAAWlL,aAAa37D,KACpBqjD,EAA2CmpB,EAC3CC,MAGZhD,EAAS1pE,YACLqF,GAAW,WAAXA,kBAGA,CAACkmE,EAAKoB,EAAKC,EAAOC,KACd,MAAMp/F,EAAK08F,GAAAA,QAAAA,mBAA2BoB,GAEtCzE,EAAWlL,aAAa37D,KACpBqjD,GACA71E,EAAIk/F,EAAKE,MAGrBnD,EAAS1pE,YACLqF,GAAW,WAAXA,0BAGA,CAACkmE,EAAKoB,EAAKC,EAAOC,KACd,MAAMp/F,EAAK08F,GAAAA,QAAAA,mBAA2BoB,GAEtCzE,EAAWlL,aAAa37D,KACpBqjD,GACA71E,EAAIk/F,EAAKE,MAGrBnD,EAAS1pE,YAAYqF,GAAW,WAAXA,iBACjB,CAACkmE,EAAKlU,KACF,MAAM5pF,EAAK08F,GAAAA,QAAAA,mBAA2BoB,GAChCtB,EAAcnD,EAAWoD,mBAAmBz8F,GAE7Cw8F,GAAeA,EAAY6C,UAAYzV,IAG5C4S,EAAY6C,QAAUzV,EACtByP,EAAWlL,aAAa37D,KACpBqjD,GAA2C71E,EAAI4pF,OAG3DqS,EAAS1pE,YAAYqF,GAAW,WAAXA,uBACjB,CAAC4hE,EAAM8F,KACH,MAAMt/F,EAAK08F,GAAAA,QAAAA,mBAA2BlD,GAChCgD,EAAcnD,EAAWoD,mBAAmBz8F,GAE9Cw8F,EACAnD,EAAWlL,aAAa37D,KACpBqjD,GACA2mB,EAAa8C,GAEjBjG,EAAWlL,aAAa37D,KACpBqjD,GACA71E,EAAIs/F,MAIpBrD,EAASsD,oBAAoB,cAAc,CAACnuF,EAAMooF,KAC9C,IAAImF,GAAc,EAElB,GAAItF,EAAWmG,aAAehG,GAAQH,EAAWsF,cAC7CA,GAAc,MACX,CACH,MAAMnC,EAAcnD,EAAWoD,mBAAmBjD,GAE9CgD,GAAeA,EAAYmC,gBAC3BA,GAAc,GAItB,IAAKA,EACD,OAGJ,MAAMc,EAA4C,SAA1BruF,EAAKoJ,WAAWi5E,MAClCiM,EAA4C,SAA1BtuF,EAAKoJ,WAAW+gE,MAExC,IAAIokB,GAAU,EAEVF,IAAoBpG,EAAWuG,iBAAiBnM,QAChD4F,EAAWuG,iBAAiBnM,MAAQgM,EACpCE,GAAU,GAGVD,IAAoBrG,EAAWuG,iBAAiBrkB,QAChD8d,EAAWuG,iBAAiBrkB,MAAQmkB,EACpCC,GAAU,GAGVA,GACAtG,EAAWlL,aAAa37D,KACpBqjD,GACAwjB,EAAWuG,qBAKnBvG,EAAWa,aAEX+B,EAAS1pE,YAAYqF,GAAW,WAAXA,uBACjBz1B,IACIk3F,EAAWa,WAAW/O,6BAClBhpF,EAAQ+kF,mBAIpB+U,EAAS1pE,YAAYqF,GAAW,WAAXA,0BACjB,CAAClwB,EAAG6/E,KACA8R,EAAWa,WAAWvO,0BAA0BjkF,EAAG6/E,OAK/D5sF,KAAKwhG,kBAAkB1pE,QAAQmF,GAAW,WAAXA,4BAC3Bi+C,IACJl7E,KAAKwhG,kBAAkB1pE,QAAQmF,GAAW,WAAXA,uBAC3Bi+C,KAMR4lB,GAA4B7/F,UAAUikG,kBAAoB,WACtD,MAAMxG,EAAa1+F,KAAK0+F,WAClBgD,EAAMhD,EAAWgD,IAEvBA,EAAI9pE,YACAmD,GAAAA,QAAAA,mBACA2jE,EAAWyG,mBAAmBvkG,KAAK89F,IAEvCgD,EAAI9pE,YACAmD,GAAAA,QAAAA,qBACA2jE,EAAW0G,qBAAqBxkG,KAAK89F,IAEzCgD,EAAI9pE,YAAYmD,GAAAA,QAAAA,0BACZ,CAACsqE,EAAU9nF,KACP,GAAImhF,EAAW4G,sBAAwBD,GAAY3G,EAAW6C,KAAM,CAKhE,GAJA7C,EAAW4G,oBAAsBD,EACjC3G,EAAWlL,aAAa37D,KACpBqjD,GAAgDmqB,EAAU9nF,GAE1DA,GAAYA,EAAS7b,OAAQ,CAC7B,MAAM20F,EAAc94E,EAAS5Y,MAAM,GAG/B+5F,EAAWmG,WAAaQ,GACxBhP,EAAY7yF,OAAO,EAAG,EAAG6hG,GAIzBhP,EAAY30F,OlB5gBC,GkB6gBb20F,EAAY7yF,OlB7gBC,EkB6gB6B6yF,EAAY30F,OlB7gBzC,GkB+gBjBg9F,EAAWa,YAAcb,EAAWa,WAAWxI,eAAeV,GAE9DqI,EAAWa,YAAcb,EAAWmG,aAAeQ,GAEnD3G,EAAWa,WAAWpP,yBAAyBuO,EAAW6C,KAAK0B,aAK/EvB,EAAI9pE,YAAYmD,GAAAA,QAAAA,mBAA6B,KACzC,MAAMkyB,EAAM3qD,OAAOijG,YAAYt4C,MACzB/+C,EAAM,sBAGZ3J,GAAOD,IAAK,UAAS4J,OAAU++C,GAC/ByxC,EAAW6C,KAAKqB,gBAAgB10F,GAAO++C,EACvCwvC,GAAWoE,cACPne,GAAkCx0E,EAAK,CAAE/G,MAAO8lD,KAEpDyxC,EAAWlL,aAAa37D,KAAKqjD,MAGjCwmB,EAAI9pE,YAAYmD,GAAAA,QAAAA,2BACZ,CAAC8jE,EAAM8F,KACH,MAAM9C,EAAcnD,EAAWoD,mBAAmBjD,GAE9CgD,EACAnD,EAAWlL,aAAa37D,KACpBqjD,GACA2mB,EAAa8C,GAEjBpgG,GAAO2T,KAEI,mEAAe2mF,IACtB8F,MAIhBjD,EAAI9pE,YAAYmD,GAAAA,QAAAA,yBACZ,CAAC8jE,EAAM8F,KACH,MAAM9C,EAAcnD,EAAWoD,mBAAmBjD,GAE9CgD,EACAnD,EAAWlL,aAAa37D,KAAKqjD,GAA+C2mB,EAAa8C,GAEzFpgG,GAAO2T,KAAM,oEAAmE2mF,QAI5F6C,EAAI9pE,YAAYmD,GAAAA,QAAAA,qBACZ,CAACo0D,EAAKld,KACGkd,EAAII,OACLkN,GAAW0D,QACP/+F,KAAKF,UAAU,CACXmE,GAAI,cACJ8B,MAAO8qE,QAI3ByvB,EAAI9pE,YAAYmD,GAAAA,QAAAA,sBACZ,CAACo0D,EAAKld,KACGkd,EAAII,OACLkN,GAAW0D,QACP/+F,KAAKF,UAAU,CACXmE,GAAI,eACJ8B,MAAO8qE,QAK3ByvB,EAAI9pE,YAAYmD,GAAAA,QAAAA,sBACZ,CAAChuB,EAAGoiF,KACAuP,EAAWa,WAAW7O,uBAAuB3jF,EAAGoiF,GAC3CA,EAAII,OACLmP,EAAWlL,aAAa37D,KAAKqjD,EACzBrB,EAA2C9sE,MAI3D20F,EAAI9pE,YAAYmD,GAAAA,QAAAA,qBACZ,CAAChuB,EAAGoiF,KACAuP,EAAWa,WAAW9O,sBAAsB1jF,EAAGoiF,GAC1CA,EAAII,OACLmP,EAAWlL,aAAa37D,KAAKqjD,EACzBrB,EAA2C9sE,MAI3D20F,EAAI9pE,YAAYmD,GAAAA,QAAAA,8BACZ,CAAChuB,EAAGoiF,KACAuP,EAAWa,WAAWzO,uBAAuB/jF,EAAGoiF,GAC3CA,EAAII,OACLmP,EAAWlL,aAAa37D,KAAKqjD,EACzBrB,EAA2C9sE,MAI3D20F,EAAI9pE,YAAYmD,GAAAA,QAAAA,+BACZ,CAAChuB,EAAGoiF,KACAuP,EAAWa,WAAWxO,wBAAwBhkF,EAAGoiF,GAC5CA,EAAII,OACLmP,EAAWlL,aAAa37D,KAAKqjD,EACzBrB,EAA2C9sE,MAI3D20F,EAAI9pE,YAAYmD,GAAAA,QAAAA,0BACZ,CAACo9C,EAAOvxE,KAKAuxE,EAAMqtB,gBAAkBrtB,EAAMstB,YAAc3oE,GAAU,UAAVA,SAC5C4hE,EAAWa,WAAW1O,wBAAuB,EAAMjqF,OAQnEk6F,GAA4B7/F,UAAUykG,oBAAsB,WACxD,MAAMhH,EAAa1+F,KAAK0+F,WAExBt+F,OAAOC,KAAKL,KAAK+gG,eAAexgG,SAAQuqF,IACpC4T,EAAWhC,KAAKvyD,eACZ2gD,EACA9qF,KAAK+gG,cAAcjW,OAE3B9qF,KAAK+gG,cAAgB,IAOzBD,GAA4B7/F,UAAU0kG,mBAAqB,WACvD,MAAMjH,EAAa1+F,KAAK0+F,WAExB1+F,KAAK4lG,2BACD3oE,GAAW,WAAXA,cACAyhE,EAAWmH,eAAejlG,KAAK89F,IACnC1+F,KAAK4lG,2BACD3oE,GAAW,WAAXA,cACAyhE,EAAWoH,eAAellG,KAAK89F,IACnC1+F,KAAK4lG,2BACD3oE,GAAW,WAAXA,eACAyhE,EAAWqH,gBAAgBnlG,KAAK89F,IACpC1+F,KAAK4lG,2BACD3oE,GAAW,WAAXA,WACAyhE,EAAWsH,YAAYplG,KAAK89F,IAEhC1+F,KAAK4lG,2BAA2B3oE,GAAW,WAAXA,wBAC5B,CAACgpE,EAAYC,KACLxH,EAAW3+F,QAAQ0N,OAAO04F,mBAI9BzH,EAAWoG,gBAAkBmB,EAC7BvH,EAAWqG,gBAAkBmB,EAI7BxH,EAAW9C,iBAAiBr7F,SAAQ43E,IAChC,OAAQA,EAAMgpB,WACd,KAAKrM,GAAUqH,MACXuC,EAAWoG,iBAAmB3sB,EAAM+W,OACpC,MACJ,KAAK4F,GAAU2G,MACXiD,EAAWqG,iBAAmB5sB,EAAM+W,WAK5CwP,EAAWlL,aAAa37D,KAAKqjD,QAGrCl7E,KAAK4lG,2BAA2B3oE,GAAW,WAAXA,+BAC5BmpE,IACI1H,EAAWlL,aAAa37D,KAAKqjD,GAAoDkrB,MAGzFpmG,KAAK4lG,2BAA2B3oE,GAAW,WAAXA,uBAC5B,CAAC91B,EAAO87E,EAAWojB,KACf,MAAMC,EAAmB5H,EAAW6H,kBAAkBl+F,MAAK2E,GAAKA,EAAEw5F,WAAaH,IAE/E3H,EAAWlL,aAAa37D,KAAKqjD,GAA6C,CACtEurB,QAASt/F,EACT87E,UAAAA,EACAkf,MAAOmE,OAGnBtmG,KAAK4lG,2BAA2B3oE,GAAW,WAAXA,oCAC5B,CAACgmD,EAAWkgB,KACR,MAAMtB,EAAcnD,EAAWoD,mBAAmBC,GAAAA,QAAAA,mBAA2BoB,IAEzEtB,GACAnD,EAAWlL,aAAa37D,KAAKqjD,GAA0D,CACnF2mB,YAAAA,EACA5e,UAAAA,OAIhBjjF,KAAK4lG,2BAA2B3oE,GAAW,WAAXA,oCAC5B,CAACgmD,EAAWkgB,KACR,MAAMtB,EAAcnD,EAAWoD,mBAAmBC,GAAAA,QAAAA,mBAA2BoB,IAEzEtB,GACAnD,EAAWlL,aAAa37D,KAAKqjD,GAA0D,CACnF2mB,YAAAA,EACA5e,UAAAA,OAIhBjjF,KAAK4lG,2BAA2B3oE,GAAW,WAAXA,wBAC5B91B,GAASu3F,EAAWlL,aAAa37D,KAAKqjD,GAA8C,CAAE+H,UAAW97E,MACrGnH,KAAK4lG,2BAA2B3oE,GAAW,WAAXA,wBAC5B91B,IACIu3F,EAAWlL,aAAa37D,KAAKqjD,GAA8C,CAAE+H,UAAW97E,QAOpG25F,GAA4B7/F,UAAU2kG,2BAA6B,SAC3D9a,EAAWhgD,GACf9qC,KAAK+gG,cAAcjW,GAAahgD,EAChC9qC,KAAK0+F,WAAWhC,KAAK9kE,YAAYkzD,EAAWhgD,IAMhDg2D,GAA4B7/F,UAAUylG,yBAA2B,WAC7D,MAAMhI,EAAa1+F,KAAK0+F,WAEnBA,EAAWa,aAKhBb,EAAWa,WAAWvB,uBAAsB,CAAC7O,EAAKvoF,EAAMpC,EAAOyrF,KAC3DyO,EAAWgD,IAAIiF,cAAcxX,EAAKvoF,EAAMpC,EAAOyrF,MAMnDyO,EAAWa,WAAWrB,2BAA0B,KAC5CQ,EAAWlL,aAAa37D,KACpBqjD,MAIHwjB,EAAW3+F,QAAQ0N,OAAOm5F,aAC3BlI,EAAWa,WAAWjB,0BAAyB,CAACnP,EAAKyE,KACjD8K,EAAW9C,eAAe9G,GAAUqH,OAAO57F,SAAQ43E,IAC/C,MAAMvxE,EAAOuoF,EAAI0M,aAAa1jB,GAEzBvxE,GAASgtF,EAAMn7E,eAAe7R,IAInCuxE,EAAM0uB,wBAAwB1X,EAAKyE,EAAMhtF,qBC9xB7Cw6F,GAAAA,EAAAA,oBAAAA,gBAAAA,EAAAA,0BAAAA,2BAAAA,EAAAA,2BAAAA,2BAAAA,EAAAA,mBAAAA,yBAAAA,EAAAA,wBAAAA,yBAAAA,EAAAA,oBAAAA,4BAAAA,EAAAA,eAAAA,uBAAAA,EAAAA,+BAAAA,kCAAAA,KAAAA,GAAAA,KA8DL,MAAM0F,GAAsB1F,GAAiB0F,oBACvC7oB,GAA4BmjB,GAAiBnjB,0BAC7C8oB,GAA6B3F,GAAiB2F,2BAC9C7oB,GAAqBkjB,GAAiBljB,mBACtC8oB,GAA0B5F,GAAiB4F,wBAC3CC,GAAsB7F,GAAiB6F,oBACvCnqB,GAAiBskB,GAAiBtkB,eAClCoqB,GAAiC9F,GAAiB8F,+BC3DzD3iG,IAAS2B,EAAAA,EAAAA,kEAyCFihG,GAA8B,CAIvCC,OAAQ,SAQRC,SAAU,WAKVC,YAAa,cAKbC,UAAW,aAOA,MAAMC,GAwBY,8BACrBC,EACAC,EACAC,EACAC,EACAC,GACJ,OAAKJ,EAKMG,EAIAT,GAA4BC,OAInC7hE,GAAQ2iD,qCACH2f,EAGMH,EACAC,EACDR,GAA4BG,YAC5BH,GAA4BI,UAG/BJ,GAA4BE,SAPxBF,GAA4BC,OAYpCM,EACDP,GAA4BC,OAC5BD,GAA4BE,SA1BvBF,GAA4BG,YAyCd,8BAACM,EAAcC,GACxC,OAAKtiE,GAAQ2iD,qCAMN0f,IAAiBC,EAClBV,GAA4BC,OAC5BD,GAA4BG,YALvBH,GAA4BC,OAsB3ChuF,YAAYsoF,EAAKhD,EAAY3+F,GACzBC,KAAK0hG,IAAMA,EACX1hG,KAAK0+F,WAAaA,EAQlB1+F,KAAK8nG,YAAc,GAQnB9nG,KAAK+nG,kBAAoB,GAazB/nG,KAAKgoG,kBACsC,iBAA9BjoG,EAAQioG,kBACXjoG,EAAQioG,kBArMY,IA8M9BhoG,KAAKioG,kBAAyD,iBAA9BloG,EAAQkoG,kBAClCloG,EAAQkoG,kBA1Me,KAoN7BjoG,KAAKkoG,eACmC,iBAA3BnoG,EAAQmoG,eACXnoG,EAAQmoG,eA/MO,IAsOzBloG,KAAKmoG,kBAAoB,GACzB5jG,GAAOiH,KAAM,0BAAyBxL,KAAKkoG,kBAY3CloG,KAAKooG,sBAAwB,IAAI/hC,IASjCrmE,KAAKqoG,gBAAkB,IAAIhiC,IAQ3BrmE,KAAKsoG,oBAAsB,IAAIjiC,IAUnCkiC,uBAAuBljG,GACnB,OAAOrF,KAAK0hG,IAAIgG,UAAUriG,GACpBrF,KAAKkoG,eACLloG,KAAK0+F,WAAW8J,cAAgBxoG,KAAKioG,kBAAoBjoG,KAAKgoG,kBAOxEp+D,OAEI5pC,KAAKyoG,6BACCzoG,KAAK0oG,4BAA4B9nG,KAAKZ,MAE5CA,KAAK0hG,IAAI9pE,YACLmD,GAAAA,QAAAA,6BACA/6B,KAAKyoG,8BAGTzoG,KAAK2oG,aAAe3oG,KAAK4oG,8BAA8BhoG,KAAKZ,MAC5DA,KAAK0+F,WAAWn0D,GAAG2wC,GAAkCl7E,KAAK2oG,cAG1D3oG,KAAK6oG,YAAc7oG,KAAK8oG,WAAWloG,KAAKZ,MACxCA,KAAK0+F,WAAWn0D,GAAG2wC,GAAiCl7E,KAAK6oG,aAKrDtjE,GAAQ2iD,uCAERloF,KAAK+oG,iBAAmB/oG,KAAKgpG,gBAAgBpoG,KAAKZ,MAClDA,KAAK0hG,IAAI9pE,YACLmD,GAAAA,QAAAA,kBAA6B/6B,KAAK+oG,kBAEtC/oG,KAAKipG,mBAAqBjpG,KAAKkpG,kBAAkBtoG,KAAKZ,MACtDA,KAAK0hG,IAAI9pE,YACLmD,GAAAA,QAAAA,oBAA+B/6B,KAAKipG,oBAIxCjpG,KAAKmpG,oBAAsBnpG,KAAKmlG,mBAAmBvkG,KAAKZ,MACxDA,KAAK0+F,WAAWn0D,GACZ2wC,GACAl7E,KAAKmpG,qBAETnpG,KAAKopG,sBAAwBppG,KAAKolG,qBAAqBxkG,KAAKZ,MAC5DA,KAAK0+F,WAAWn0D,GACZ2wC,GACAl7E,KAAKopG,uBAITppG,KAAKqpG,yBACCrpG,KAAKspG,wBAAwB1oG,KAAKZ,MAGxCA,KAAKupG,yBACCvpG,KAAKwpG,wBAAwB5oG,KAAKZ,OAG5CA,KAAKypG,gBAAkBzpG,KAAKypG,gBAAgB7oG,KAAKZ,MACjDA,KAAK0+F,WAAWn0D,GACZ2wC,GACAl7E,KAAKypG,iBAETzpG,KAAK0pG,qBACC1pG,KAAK4oG,8BAA8BhoG,KAAKZ,MAC9CA,KAAK0hG,IAAIn3D,GACLxP,GAAAA,QAAAA,oBAA+B/6B,KAAK0pG,sBAO5Cpf,UAEItqF,KAAK0hG,IAAIv3D,eACLpP,GAAAA,QAAAA,6BACA/6B,KAAKyoG,8BAELljE,GAAQ2iD,uCACRloF,KAAK0hG,IAAIv3D,eACLpP,GAAAA,QAAAA,kBACA/6B,KAAK+oG,kBACT/oG,KAAK0hG,IAAIv3D,eACLpP,GAAAA,QAAAA,oBACA/6B,KAAKipG,oBAETjpG,KAAK0+F,WAAWrxD,IACZ6tC,GACAl7E,KAAKmpG,qBACTnpG,KAAK0+F,WAAWrxD,IACZ6tC,GACAl7E,KAAKopG,wBAGbppG,KAAK0+F,WAAWrxD,IACZ6tC,GACAl7E,KAAKypG,iBAETzpG,KAAK0hG,IAAIv3D,eACLpP,GAAAA,QAAAA,oBAA+B/6B,KAAK0pG,sBAExC1pG,KAAK0+F,WAAWrxD,IACZ6tC,GAAkCl7E,KAAK2oG,cAE3C3oG,KAAK0+F,WAAWrxD,IACZ6tC,GAAiCl7E,KAAK6oG,aAE1C,MAAMc,EAAiBvpG,OAAOC,KAAKL,KAAK8nG,aAExC,IAAK,MAAMtP,KAAiBmR,EACxB3pG,KAAKuC,aAAai2F,GAClBx4F,KAAK4pG,uBAAuBpR,GAGhC,IAAK,MAAMnzF,KAAMrF,KAAKsoG,oBACdtoG,KAAKsoG,oBAAoB7vF,eAAepT,IACxCrF,KAAK8oG,WAAWzjG,GAKxBrF,KAAK+nG,kBAAoB,GAU7BW,4BAA4BmB,EAAYC,GAEpCvlG,GAAOynF,MACF,mDAAkD7mF,KAAK8nD,WACpD48C,MAAeC,KAGnBD,IAAe7pG,KAAK0+F,WAAWmG,aAE/B7kG,KAAK+nG,kBAAkB8B,GAAcC,EACrC9pG,KAAK+pG,0BAA0BF,IASvCG,wBAAwBnI,EAAaoI,GACjC,GAAIpI,EAAYqI,wBAA0BD,EAAW,CAEjD,MAAMJ,EAAahI,EAAYsI,QAE/BtI,EAAYuI,qBAAqBH,GAEjC1lG,GAAOynF,MACF,6BAA4B7mF,KAAK8nD,UAAU48C,MACxCI,KAGRxN,GAAW0D,QACP/+F,KAAKF,UAAU,CACXmE,GAAI,mBACJw8F,YAAagI,EACb5a,OAAQgb,KAIhBjqG,KAAK0+F,WAAWlL,aAAa37D,KACzBqjD,GACA2uB,EAAYI,IAWxB1nG,aAAai2F,GACLx4F,KAAK8nG,YAAYtP,KACjBl2F,OAAOC,aAAavC,KAAK8nG,YAAYtP,IACrCx4F,KAAK8nG,YAAYtP,GAAiB,MAU1CoR,uBAAuBpR,GACnBx4F,KAAKmoG,kBAAkB3P,GAAiB,KAU5C2M,mBAAmBkF,GACVA,EAAYpa,WACNoa,EAAYlJ,YAAcrM,GAAU2G,QAE3Cl3F,GAAOynF,MACF,uCACGqe,EAAY5R,sBAEpB4R,EAAY9/D,GACR62D,GACAphG,KAAKqpG,0BACTgB,EAAY9/D,GACR62D,IACAqE,GAAazlG,KAAKupG,yBAAyBc,EAAa5E,MAWpEL,qBAAqBiF,GACjB,IAAKA,EAAYpa,WACNoa,EAAYlJ,YAAcrM,GAAU2G,MAAO,CAElD,MAAMoO,EAAaQ,EAAY5R,mBAE/Bl0F,GAAOynF,MAAO,qCAAoC6d,KAElDQ,EAAYh9D,IACR+zD,GACAphG,KAAKqpG,0BAETrpG,KAAKuC,aAAasnG,GAClB7pG,KAAK4pG,uBAAuBC,GAE5B7pG,KAAK+pG,0BAA0BF,IAiBvChC,mBAAmBhG,GACf,IAAKt8D,GAAQ2iD,qCACT,OAAO,EAGX,MAAM7iF,EAAKw8F,EAAYsI,QACjBG,EAAsBzI,EAAY0I,8BAClCpC,EAAoBnoG,KAAKmoG,kBAAkB9iG,GAC3CyyD,EAAU93D,KAAKuoG,uBAAuBljG,GAE5C,OAAOilG,GAC6B,iBAAtBnC,GACNhjG,KAAK8nD,MAAQk7C,GAAsBrwC,EAQ/C8wC,gCACI,MAAM4B,EAAexqG,KAAK0+F,WAAW6H,kBAErC,IAAK,MAAM1E,KAAe2I,EACtBxqG,KAAK+pG,0BAA0BlI,EAAYsI,SAUnDJ,0BAA0B1kG,GACtB,MAAMw8F,EAAc7hG,KAAK0+F,WAAWoD,mBAAmBz8F,GAEvD,IAAKw8F,EAQD,YAFAt9F,GAAOynF,MAAO,gDAA+C3mF,KAKjE,MAAMolG,EAAYzqG,KAAK0+F,WAAW8J,cAC5BkC,EAAsB1qG,KAAK2qG,qBAAqBtlG,GAChDulG,EAA+C,IAA/B5qG,KAAK0+F,WAAWmM,WAIhCjD,EAAe/F,EAAY+F,gBAAkBgD,EAC7C/C,EAAqB7nG,KAAK6nG,mBAAmBhG,GAC7C6F,EAAY1nG,KAAK0hG,IAAIgG,UAAUriG,GACrC,IAAIylG,EAAoB9qG,KAAK+nG,kBAAkB1iG,GAEd,kBAAtBylG,IAGPA,GAAoB,GAGxB,MAAMC,EACAN,EACIjD,GAAmCwD,uBACjCpD,EACAC,GACFL,GAAmCyD,uBACjCH,EACApD,EACAgD,EACA9C,EACAC,GAIRkD,IAAa5D,GAA4BI,WACzCvnG,KAAKkrG,qBAAqB7lG,GAG9Bd,GAAOynF,MACF,8BAA6B3mF,sBAC1BuiG,qBACAkD,yBACAjD,eACA4C,mBACA/C,iCACA7F,EAAYqI,4BAA4Ba,KAEhD,MAAMI,EAAsBnrG,KAAKsoG,oBAAoBjjG,IAAO,GAI5D,KAAM,QAAS8lG,MACN,qBAAsBA,IACxBA,EAAoB9Q,MAAQoQ,GAC5BU,EAAoBC,mBAAqBL,EAAU,CAEtD,MAAMM,EAAQlmG,KAAK8nD,MAanB,GAXAjtD,KAAKsrG,0CAA0CjmG,EAAIgmG,GAEnDrrG,KAAKsoG,oBAAoBjjG,GAAM,IACxB8lG,EACHC,iBAAkBL,EAClB1Q,IAAKoQ,EACLc,UAAWF,KAKT,cAAerrG,KAAKsoG,oBAAoBjjG,IAAM,CAChD,MAAMmmG,EAAc3J,EAAY4J,qBAAqB3W,GAAU2G,OAE3D/2F,MAAMgD,QAAQ8jG,IAAuC,IAAvBA,EAAY9pG,SAC1C1B,KAAKsoG,oBAAoBjjG,GAAIogG,UAAY+F,EAAY,GAAG/F,YAIpEzlG,KAAKgqG,wBAAwBnI,EAAakJ,GAU9CO,0CAA0CjmG,EAAIgmG,GAC1C,MAAMK,EAA8B1rG,KAAKsoG,oBAAoBjjG,GAEzDqmG,GACG,cAAeA,GACf,cAAeA,GACf,qBAAsBA,GACtB,QAASA,IACZA,EAA4BvkG,MAAQkkG,EAAQK,EAA4BH,UACxE9O,GAAWoE,cjB5W+B,eAAEhhF,EAAF,uDAAuB,GAAvB,MAAiC,CACnFjY,KAAMq5E,GAAgBC,iBACtB70E,OAAQ,mBACR5E,OAAQ,WACRoY,WAAAA,GiByWY8rF,CAAuCD,KAYnDjC,kBAAuD,IAAvCmC,EAAuC,uDAAxB,GAAIC,EAAoB,uDAAJ,GAC/C,MAAM5+C,EAAM9nD,KAAK8nD,MAEjB1oD,GAAOynF,MAAO,mCAAkC4f,eAA0BC,QAAoB5+C,KAKzF1nB,GAAQ2iD,sCACTloF,KAAK4oG,gCAGT,IAAK,MAAMvjG,KAAMumG,EACb5rG,KAAKooG,sBAAsB7X,OAAOlrF,GAClCrF,KAAKkrG,qBAAqB7lG,GAC1BkgC,GAAQ2iD,sCAAwCloF,KAAK+pG,0BAA0B1kG,GAEnF,IAAK,MAAMA,KAAMwmG,EAEb7rG,KAAKooG,sBAAsBljF,IAAI7f,EAAI4nD,GACnC1nB,GAAQ2iD,sCAAwCloF,KAAK+pG,0BAA0B1kG,GAYvF6lG,qBAAqB1S,GACjB,MAAMsT,EAAS9rG,KAAKqoG,gBAAgBrjF,IAAIwzE,GAEpCsT,IACAvpG,aAAaupG,GACb9rG,KAAKqoG,gBAAgB9X,OAAOiI,IAkBpCmS,qBAAqBnS,GACjB,MAAM4P,EACApoG,KAAKooG,sBAAsBpjF,IAAIwzE,GAErC,SAAI4P,GACIjjG,KAAK8nD,MAAQm7C,GAtuBK,OA8uBXpoG,KAAKqoG,gBAAgBrjF,IAAIwzE,IAGpCx4F,KAAKqoG,gBAAgBnjF,IAAIszE,EAAeh2F,YACpC,IAAMxC,KAAK+pG,0BAA0BvR,IAlvBnB,OAsvBnB,GAQXsQ,WAAWzjG,GACPrF,KAAKsrG,0CAA0CjmG,EAAIF,KAAK8nD,cACjDjtD,KAAKsoG,oBAAoBjjG,GASpC2jG,gBAAgB7wB,GACZ,MAAMqgB,EAAgBrgB,EAAMsgB,mBACtBoJ,EAAc7hG,KAAK0+F,WAAWoD,mBAAmBtJ,GAGvD,GADAj0F,GAAOynF,MAAO,6BAA4BwM,IAAiBrzF,KAAK8nD,OAC3D40C,GAML,GADA7hG,KAAKmoG,kBAAkB3P,GAAiBrzF,KAAK8nD,OACxC40C,EAAY+F,eAAgB,CAI7B5nG,KAAKuC,aAAai2F,GAGlB,MAAM1gC,EAAU93D,KAAKuoG,uBAAuB/P,GAE5Cx4F,KAAK8nG,YAAYtP,GAAiBl2F,OAAOE,YAAW,KAChD+B,GAAOynF,MACF,6BAA4BwM,4BACvB1gC,QACV93D,KAAKuC,aAAai2F,GAClBx4F,KAAK+pG,0BAA0BvR,KAChC1gC,SApBHvzD,GAAOlD,MAAO,0BAAyBm3F,KA8B/C0Q,kBAAkB/wB,GACd,MAAMqgB,EAAgBrgB,EAAMsgB,mBAE5Bl0F,GAAOynF,MACF,+BAA8BwM,IAAiBrzF,KAAK8nD,OAEzDjtD,KAAKuC,aAAai2F,GAClBx4F,KAAK4pG,uBAAuBpR,GAE5Bx4F,KAAK+pG,0BAA0BvR,GASnC8Q,wBAAwBnxB,GACpB,MAAMqgB,EAAgBrgB,EAAMsgB,mBAE5Bl0F,GAAOynF,MACF,8CAA6CwM,IAC9CrgB,EAAM+oB,WAEVlhG,KAAK+pG,0BAA0BvR,GAUnCgR,wBAAwBrxB,EAAOvwE,GAC3B,MAAMvC,EAAK8yE,EAAMsgB,mBACX4S,EAAQlmG,KAAK8nD,MAEnBjtD,KAAKsrG,0CAA0CjmG,EAAIgmG,GAEnDrrG,KAAKsoG,oBAAoBjjG,GAAM,IACxBrF,KAAKsoG,oBAAoBjjG,IAAO,GACnCogG,UAAW79F,EACX2jG,UAAWF,ICp3BR,MAAMU,GAmBjB3yF,YAAY+pF,EAAKzE,EAAYsN,EAAalwC,EAAQmwC,EAAShd,EAAQid,EAAUC,EAAaC,GACtFpsG,KAAKqsG,KAAOlJ,EACZnjG,KAAKssG,IAAMvK,GAAAA,QAAAA,mBAA2BoB,GACtCnjG,KAAKusG,YAAc7N,EACnB1+F,KAAKwsG,aAAeR,EACpBhsG,KAAKysG,eAAgB,EACrBzsG,KAAK0sG,QAAU,GACf1sG,KAAK2sG,MAAQ,OACb3sG,KAAK0kG,QAAUzV,EACfjvF,KAAK4sG,QAAU9wC,EACf97D,KAAK6sG,SAAWZ,EAChBjsG,KAAK8sG,kBAAoB3F,GAA4BC,OACrDpnG,KAAK+sG,YAAc,GACnB/sG,KAAKgtG,UAAYd,EACjBlsG,KAAKitG,aAAed,EACpBnsG,KAAKktG,YAAcd,EACnBpsG,KAAKmtG,UAAY,IAAI7mC,IASzB8mC,gBACI,OAAOptG,KAAKusG,YAMhBc,YAAY7gG,GACR,OAAOxM,KAAK+sG,YAAYvgG,GAW5B+9F,8BACI,OACIvqG,KAAKstG,YAAY1hG,MACb2hG,GACIA,EAAWpM,YAAcrM,GAAU2G,OAC5B8R,EAAWC,uBASlCpD,qBAAqBnb,GACjBjvF,KAAK8sG,kBAAoB7d,EAU7Bib,sBACI,OAAOlqG,KAAK8sG,kBAShB/1C,YAAYvqD,EAAMrF,GACd,MAAMsmG,EAAWztG,KAAK+sG,YAAYvgG,GAE9BrF,IAAUsmG,IACVztG,KAAK+sG,YAAYvgG,GAAQrF,EACzBnH,KAAKusG,YAAY/Y,aAAa37D,KAC1BqjD,GACAl7E,KACAwM,EACAihG,EACAtmG,IAQZmmG,YACI,OAAOttG,KAAK0sG,QAAQ/nG,QAQxB8mG,qBAAqBxoB,GACjB,OAAOjjF,KAAKstG,YAAYvmG,QAAOoxE,GAASA,EAAMgpB,YAAcle,IAMhEknB,QACI,OAAOnqG,KAAKssG,IAMhB9F,SACI,OAAOxmG,KAAKqsG,KAMhBqB,iBACI,OAAO1tG,KAAKwsG,aAMhBmB,aACI,OAAO3tG,KAAK6sG,SAMhBxJ,YACI,OAAOrjG,KAAK0kG,QAMhBV,cACI,MAAsB,cAAfhkG,KAAK2sG,MAQhBiB,WACI,OAAO5tG,KAAK4sG,QAQhBiB,uBAAuB,QACnB,OAAOvmB,QAAO,UAACtnF,KAAKgtG,iBAAN,iBAAC,EAAgBc,YAAjB,aAAC,EAAuB,yBAO1C3B,cACI,OAAOnsG,KAAKitG,aAOhBb,aACI,OAAOpsG,KAAKktG,YAMhBa,eACI,OAAO/tG,KAAKguG,kBAAkBlZ,GAAUqH,OAc5C6R,kBAAkB/qB,GACd,OAAOjjF,KAAKstG,YAAYz9F,QACpB,CAAC+vF,EAAOznB,IACJynB,IAAUznB,EAAMgpB,YAAcle,GAAa9K,EAAM+oB,aACrD,GAMR0G,eACI,OAAO5nG,KAAKguG,kBAAkBlZ,GAAU2G,OAM5CwS,UACI,OAAOjuG,KAAK2sG,MAOhBuB,QAAQC,GACJnuG,KAAK2sG,MAAQwB,EAOjBC,eAAeC,GACXruG,KAAKitG,aAAeoB,EAOxBC,cAAcC,GACVvuG,KAAKktG,YAAcqB,EAMvBC,eACI,OAAOxuG,KAAKysG,cAOhBgC,cACI,OAAO1kE,QAAQC,QAAQhqC,KAAKmtG,WAShC1rF,WAAWC,GACP,OAAO1hB,KAAKmtG,UAAU5tD,IAAI79B,GAO9BsgF,YAAY0M,GACR1uG,KAAKmtG,UAAYuB,GAAe,IAAIpoC,IAQxCqoC,aACI,OAAO3uG,KAAK4uG,SAOhBC,WAAWC,GACP9uG,KAAK4uG,SAAWE,GCnUjB,IAAKC,aAAAA,GAAAA,EAAAA,wBAAAA,oCAAAA,EAAAA,uBAAAA,mCAAAA,EAAAA,kBAAAA,8BAAAA,EAAAA,YAAAA,wBAAAA,EAAAA,sBAAAA,oCAAAA,KAAAA,GAAAA,KA+CL,MAAM7sB,GAA0B6sB,GAAsB7sB,wBAChDrG,GAAyBkzB,GAAsBlzB,uBAC/CmzB,GAAoBD,GAAsBC,kBAC1CC,GAAcF,GAAsBE,YACpCC,GAAwBH,GAAsBG,sBCnDpD,IAAKC,mBAAAA,GAAAA,EAAAA,yBAAAA,0BAAAA,EAAAA,YAAAA,wBAAAA,EAAAA,kBAAAA,8BAAAA,EAAAA,aAAAA,0BAAAA,KAAAA,GAAAA,KAgCL,MAAMC,GAA2BD,GAAsBC,yBACjDC,GAAcF,GAAsBE,YACpCt0B,GAAoBo0B,GAAsBp0B,kBAC1Cu0B,GAAeH,GAAsBG,aC/BnC,MAAM5tD,GAIjBtoC,cAAc,WACVpZ,KAAK0gD,QAAU,IAAI3W,SAAQ,CAACC,EAASC,KACjCjqC,KAAKgqC,QAAU,WACX,EAAKulE,qBACLvlE,KAAW,YAEfhqC,KAAKiqC,OAAS,WACV,EAAKslE,qBACLtlE,KAAU,eAGlBjqC,KAAK4gD,KAAO5gD,KAAK0gD,QAAQE,KAAKhgD,KAAKZ,KAAK0gD,SACxC1gD,KAAKgkD,MAAQhkD,KAAK0gD,QAAQsD,MAAMpjD,KAAKZ,KAAK0gD,SAM9C6uD,qBACIhtG,aAAavC,KAAKwvG,UAMtBC,iBAAiBC,GACb1vG,KAAKwvG,SAAWhtG,YAAW,KACvBxC,KAAKiqC,OAAO,IAAIjmC,MAAM,cACvB0rG,ICjCI,MAAMC,GAMjBv2F,cAA+C,IAAnCo6E,EAAmC,uDAApB,IAAI7pD,MAC3B3pC,KAAKwzF,aAAeA,EAGpBxzF,KAAKqsC,iBAAmBrsC,KAAKuqC,GAAKvqC,KAAK43B,YACvC53B,KAAKusC,oBAAsBvsC,KAAKqtC,IAAMrtC,KAAKmqC,eAS/CvS,YAAYkzD,EAAWhgD,GAGnB,OAFA9qC,KAAKwzF,aAAa57D,YAAYkzD,EAAWhgD,GAElC,IAAM9qC,KAAKusC,oBAAoBu+C,EAAWhgD,GASrDX,eAAe2gD,EAAWhgD,GACtB9qC,KAAKwzF,aAAarpD,eAAe2gD,EAAWhgD,ICpCpD,MAAMvmC,IAAS2B,EAAAA,EAAAA,0CAIT0pG,GAAanxE,OAAO,cAcX,MAAMoxE,GAKjBz2F,cAAgC,IAApB,UAAE02F,GAAkB,uDAAJ,GAGpBC,EAAU,GACd,MAAMC,EAAM/1E,SAASg2E,cAAc,iCAEnC,GAAID,EAAK,CACL,MAAMl2D,EAAMk2D,EAAIl3F,IAAI6c,YAAY,KAEhCo6E,EAAW,GAAEC,EAAIl3F,IAAI3I,UAAU,EAAG2pC,MAGtC,IAAIo2D,EAAa,GAAEH,iCAKnB,GAAIA,GAAuB,MAAZA,EAAiB,CAG5B,MAAMI,EACA,IAAIC,KAAK,CAAG,kBAAiBF,QAAkB,CAAEtoG,KAAM,2BAE7DsoG,EAAY5tG,OAAO+tG,IAAIC,gBAAgBH,GAG3CnwG,KAAKuwG,QAAU,IAAIC,OAAON,EAAW,CAAE1jG,KAAM,gBAE7CxM,KAAKuwG,QAAQr4E,QAAUnrB,GAAKxI,GAAOlD,MAAM0L,GAEzC/M,KAAKuwG,QAAQ5mB,YAAY,CACrB8mB,UAAW,aACXX,UAAAA,IAURY,QAAQlY,GACJx4F,KAAKuwG,QAAQ5mB,YAAY,CACrB8mB,UAAW,UACXjY,cAAAA,IAQRmY,aACI3wG,KAAKuwG,QAAQ5mB,YAAY,CACrB8mB,UAAW,eAYnBG,eAAevnE,EAAUktC,EAAMiiB,GAC3B,IAAInvD,EAASumE,IAKb,GAFAvmE,EAASumE,KAAc,EAEnBttG,OAAOgnF,sBAAuB,CAC9B,MAAMvpF,EAAU,CACZ0wG,UAAW,SACXjY,cAAAA,GAGJnvD,EAAS/iC,UAAY,IAAIgjF,sBAAsBtpF,KAAKuwG,QAASxwG,OAC1D,CACH,MAAM8wG,EAAkBxnE,EAASogD,uBAEjCzpF,KAAKuwG,QAAQ5mB,YAAY,CACrB8mB,UAAW,SACXK,eAAgBD,EAAgBE,SAChCC,eAAgBH,EAAgB7rE,SAChCwzD,cAAAA,GACD,CAAEqY,EAAgBE,SAAUF,EAAgB7rE,YAYvDisE,aAAaC,EAAQ36B,EAAMiiB,GACvB,IAAI0Y,EAAOtB,IAKX,GAFAsB,EAAOtB,KAAc,EAEjBttG,OAAOgnF,sBAAuB,CAC9B,MAAMvpF,EAAU,CACZ0wG,UAAW,SACXjY,cAAAA,GAGJ0Y,EAAO5qG,UAAY,IAAIgjF,sBAAsBtpF,KAAKuwG,QAASxwG,OACxD,CACH,MAAMoxG,EAAgBD,EAAOznB,uBAE7BzpF,KAAKuwG,QAAQ5mB,YAAY,CACrB8mB,UAAW,SACXK,eAAgBK,EAAcJ,SAC9BC,eAAgBG,EAAcnsE,SAC9BwzD,cAAAA,GACD,CAAE2Y,EAAcJ,SAAUI,EAAcnsE,YAWnDosE,OAAO5Y,EAAetqF,EAAKmjG,GACvBrxG,KAAKuwG,QAAQ5mB,YAAY,CACrB8mB,UAAW,SACXviG,IAAAA,EACAmjG,SAAAA,EACA7Y,cAAAA,KC1JZ,MAAMj0F,IAAS2B,EAAAA,EAAAA,yCAKR,MAAMorG,WAAmB3B,GAM5Bv2F,YAAYslF,GAA0B,IAAd3+F,EAAc,uDAAJ,GAC9BmlF,QAEAllF,KAAK0+F,WAAaA,EAClB1+F,KAAKuxG,QAAU,IAAIC,GAAYzxG,GAE/BC,KAAKymG,SAAU,EACfzmG,KAAKyxG,eAAY1lG,EAOjB/L,KAAK0+F,WAAWn0D,GACZ2wC,GACAl7E,KAAK0xG,uBAAuB9wG,KAAKZ,OACrCA,KAAK0+F,WAAWn0D,GACZ2wC,IACA/C,GAASA,EAAM8X,WAAajwF,KAAK2xG,mBAAmBx5B,KACxDn4E,KAAK0+F,WAAWgD,IAAIn3D,GAChBxP,GAAAA,QAAAA,oBACA,CAACo9C,EAAOgX,IAAQnvF,KAAK4xG,2BAA2BziB,EAAKhX,KACzDn4E,KAAK0+F,WAAWn0D,GACZ2wC,GACAl7E,KAAK6xG,kBAAkBjxG,KAAKZ,OAQpC8xG,YACI,OAAO9xG,KAAKymG,QASA,iBAACA,GACTA,IAAYzmG,KAAKymG,UAIrBzmG,KAAKyxG,iBAAmBzxG,KAAKyxG,UAE7BzxG,KAAKyxG,UAAY,IAAI/vD,GAErB1hD,KAAKymG,QAAUA,EAEVA,GACDzmG,KAAKuxG,QAAQZ,aAGjB3wG,KAAK+xG,mBAAqB/xG,KAAK+xG,YAAYtL,GAE3CzmG,KAAK0+F,WAAWsT,4BAA4B,eAAgBvL,GAE5DzmG,KAAK0+F,WAAWuT,wBAEhBjyG,KAAKyxG,UAAUznE,WAQnBkoE,mBACI,MAAM,IAAIluG,MAAM,+BAQpB2tG,mBAAmBx5B,GACf,IAAK,MAAM3wE,KAAWxH,KAAK0+F,WAAWyT,mBAClCnyG,KAAKoyG,yBAAyB5qG,EAAS2wE,GAS/Cu5B,uBAAuBlqG,GACnB,MAAM6qG,EAAcryG,KAAK0+F,WAAW9C,iBAEpC,IAAK,MAAMzjB,KAASk6B,EAChBryG,KAAKoyG,yBAAyB5qG,EAAS2wE,GAS/Cy5B,2BAA2BziB,EAAKhX,GAC5B,IAAKn4E,KAAKymG,QACN,OAGJ,MAAMp9D,EAAW8lD,EAAImjB,qBAAqBn6B,EAAMA,OAE5C9uC,EACArpC,KAAKuxG,QAAQX,eAAevnE,EAAU8uC,EAAMgpB,UAAWhpB,EAAMsgB,oBAE7Dl0F,GAAO2T,KAAM,6BAA4BigE,6BAAiCgX,KAWlFijB,yBAAyB5qG,EAAS2wE,GAC9B,IAAKn4E,KAAKymG,QACN,OAGJ,MAAM7Z,EAAKplF,EAAQ+kF,eACb2kB,EAAStkB,GAAMA,EAAG2lB,mBAAmBp6B,EAAMA,OAE7C+4B,EACAlxG,KAAKuxG,QAAQN,aAAaC,EAAQ/4B,EAAMgpB,UAAWhpB,EAAMsgB,oBAEzDl0F,GAAO2T,KAAM,6BAA4BigE,0BAA8ByU,KAS/EilB,kBAAkB15B,GACd,GAAI5yC,GAAQ0hD,+BAAiC9O,EAAM8X,WAAa9X,EAAMqtB,iBAAmBrtB,EAAM+oB,UAC3F,IAAK,MAAM15F,KAAWxH,KAAK0+F,WAAWyT,mBAClCnyG,KAAKoyG,yBAAyB5qG,EAAS2wE,ICrKhD,MAAMq6B,WAAoClB,GAK7Cl4F,YAAYslF,GACRxZ,MAAMwZ,EAAY,CAAEoR,WAAW,IAUnCsB,OAAOqB,GACHzyG,KAAKuxG,QAAQH,YAAOrlG,EAAW,CAAE2mG,cAAeD,EAAQC,eAAiBD,EAAQnoG,YCnBrFqoG,kCACAC,GAAQ,IAAIv0E,WAAW,IACZ,SAASw0E,KAEtB,IAAKF,MAGHA,GAAoC,oBAAXpyC,QAA0BA,OAAOoyC,iBAAmBpyC,OAAOoyC,gBAAgB/xG,KAAK2/D,SAA+B,oBAAbuyC,UAAgE,mBAA7BA,SAASH,iBAAkCG,SAASH,gBAAgB/xG,KAAKkyG,WAGrO,MAAM,IAAI9uG,MAAM,4GAIpB,OAAO2uG,GAAgBC,ICjBzB,+HCMA,GAJA,SAAkBG,GAChB,MAAuB,iBAATA,GAAqB,QAAWA,ICKhD,IAFA,IAAIC,GAAY,GAEPxxG,GAAI,EAAGA,GAAI,MAAOA,GACzBwxG,GAAU9wG,MAAMV,GAAI,KAAO0f,SAAS,IAAI7c,OAAO,IAoBjD,MCNA,GApBA,SAAYtE,EAASmf,EAAKqF,GAExB,IAAI0uF,GADJlzG,EAAUA,GAAW,IACFoK,SAAWpK,EAAQ8yG,KAAOA,MAK7C,GAHAI,EAAK,GAAe,GAAVA,EAAK,GAAY,GAC3BA,EAAK,GAAe,GAAVA,EAAK,GAAY,IAEvB/zF,EAAK,CACPqF,EAASA,GAAU,EAEnB,IAAK,IAAI/iB,EAAI,EAAGA,EAAI,KAAMA,EACxB0d,EAAIqF,EAAS/iB,GAAKyxG,EAAKzxG,GAGzB,OAAO0d,EAGT,ODRF,SAAmB8Z,GACjB,IAAIzU,EAAS5jB,UAAUe,OAAS,QAAsBqK,IAAjBpL,UAAU,GAAmBA,UAAU,GAAK,EAG7EoyG,GAAQC,GAAUh6E,EAAIzU,EAAS,IAAMyuF,GAAUh6E,EAAIzU,EAAS,IAAMyuF,GAAUh6E,EAAIzU,EAAS,IAAMyuF,GAAUh6E,EAAIzU,EAAS,IAAM,IAAMyuF,GAAUh6E,EAAIzU,EAAS,IAAMyuF,GAAUh6E,EAAIzU,EAAS,IAAM,IAAMyuF,GAAUh6E,EAAIzU,EAAS,IAAMyuF,GAAUh6E,EAAIzU,EAAS,IAAM,IAAMyuF,GAAUh6E,EAAIzU,EAAS,IAAMyuF,GAAUh6E,EAAIzU,EAAS,IAAM,IAAMyuF,GAAUh6E,EAAIzU,EAAS,KAAOyuF,GAAUh6E,EAAIzU,EAAS,KAAOyuF,GAAUh6E,EAAIzU,EAAS,KAAOyuF,GAAUh6E,EAAIzU,EAAS,KAAOyuF,GAAUh6E,EAAIzU,EAAS,KAAOyuF,GAAUh6E,EAAIzU,EAAS,MAAM4S,cAMzf,IAAK,GAAS47E,GACZ,MAAMhoE,UAAU,+BAGlB,OAAOgoE,ECNA,CAAUE,ICRb1uG,IAAS2B,EAAAA,EAAAA,yCAGTgtG,GAAmB,MACnBC,GACK,QADLA,GAEQ,WAFRA,GAGY,eAHZA,GAIW,cAJXA,GAKY,eAGZC,GAAW30E,OAAO,WAElB40E,GAAmB,CACrBC,iBAAkB,mBAClBC,+BAAgC,qCAChCC,wBAAyB,+BAuBtB,MAAMC,WAAmB9D,GAI5Bv2F,YAAYslF,GACRxZ,QAEAllF,KAAK0zG,MAAQhV,EACb1+F,KAAK2zG,MAAQ,IAAIjyD,GACjB1hD,KAAKykD,UAAO14C,EACZ/L,KAAK4zG,WAAa,EAClB5zG,KAAK6zG,MAAQ,IAAIxtC,IACjBrmE,KAAK8zG,4BAAyB/nG,EAE1B0nG,GAAWxxF,eACXjiB,KAAK+zG,gBAEL/zG,KAAK0zG,MAAMnpE,GAAG2wC,GAAiDl7E,KAAKg0G,2BAA2BpzG,KAAKZ,OACpGA,KAAK0zG,MAAMnpE,GAAG2wC,EAAuCl7E,KAAKi0G,kBAAkBrzG,KAAKZ,OACjFA,KAAK0zG,MAAMnpE,GAAG2wC,GAAiCl7E,KAAKk0G,mBAAmBtzG,KAAKZ,OAC5EA,KAAK0zG,MAAMnpE,GAAG2wC,GACVl7E,KAAKm0G,8BAA8BvzG,KAAKZ,QAE5CA,KAAK2zG,MAAM1pE,OAAO,IAAIjmC,MAAM,sBAOlB,qBACd,GAAIhE,KAAK8zG,uBACL,MAAM,IAAI9vG,MAAM,iDACb,CACHhE,KAAK8zG,uBAAyB,IAAIpyD,SAE5B1hD,KAAK2zG,MAEX,MAAMS,EAAW,GACXC,EAAqBr0G,KAAK0zG,MAAM7O,WAEtC,IAAK,MAAMhD,KAAe7hG,KAAK0zG,MAAMnN,kBAC7B1E,EAAYpgF,WAAW6yF,KAAiBD,EAAqBxS,EAAYsI,SACzEiK,EAASlyG,KAAKlC,KAAKu0G,iBAAiB1S,UAItC93D,QAAQyqE,WAAWJ,GAIzBp0G,KAAK8zG,uBAAuB9pE,UAC5BhqC,KAAK8zG,4BAAyB/nG,GASpB,qBACd,YAA6B,IAAfzJ,OAAOmyG,IAUV,gBAACvmG,GAEZlO,KAAKykD,KAAOv2C,EACZlO,KAAK4zG,YAGL,MAAMQ,EAAW,GAEjB,IAAK,MAAMvS,KAAe7hG,KAAK0zG,MAAMnN,kBAAmB,CACpD,MAAMmO,EAAM7S,EAAYsI,QAClBwK,EAAU30G,KAAK40G,uBAAuB/S,GAG5C,IAAK8S,EAAQntG,QAAS,CAClBjD,GAAO2T,KAAM,oCAAmCw8F,4BAGhD,SAGJ,MAAM3B,EAAO8B,KACPp+F,EAAO,CACT,CAACq+F,IAAsB5B,GACvB6B,IAAK,CACDntG,KAAMurG,GACN18F,KAAM,CACFu+F,WAAYh1G,KAAKi1G,gBAAgBN,EAAQntG,SACzCurG,KAAAA,KAIN/4E,EAAI,IAAI0nB,GAEd1nB,EAAEy1E,iBA/IM,KAgJRz1E,EAAEgqB,OAAM,KACJhkD,KAAK6zG,MAAMtjB,OAAOwiB,MAEtB/yG,KAAK6zG,MAAM3uF,IAAI6tF,EAAM/4E,GACrBo6E,EAASlyG,KAAK83B,GAEdh6B,KAAKk1G,aAAaz+F,EAAMi+F,GAO5B,aAJM3qE,QAAQyqE,WAAWJ,GAIlBp0G,KAAK4zG,UAQhBuB,iBAAiBjnG,GAGb,OAFAlO,KAAKykD,KAAOv2C,EAELlO,KAAK4zG,UAOhBwB,wBAAwBvT,GACpB,MAAM8S,EAAU30G,KAAK40G,uBAAuB/S,GAExC8S,EAAQntG,UACRmtG,EAAQntG,QAAQ6tG,OAChBV,EAAQntG,aAAUuE,GAS1BupG,+BACI,IAAK,MAAMzT,KAAe7hG,KAAK0zG,MAAMnN,kBACjCvmG,KAAKo1G,wBAAwBvT,GAUlB,sBACft9F,GAAOynF,MAAM,uBAEb,UACUyoB,IAAI7qE,OAEV5pC,KAAKu1G,YAAc,IAAId,IAAIe,QAC3Bx1G,KAAKu1G,YAAY32E,SAEjB,MAAM62E,EAASr0G,KAAKwJ,MAAM5K,KAAKu1G,YAAYG,iBAE3C11G,KAAK21G,OAASF,EAAOG,WAErBrxG,GAAOynF,MAAO,OAAMyoB,IAAIoB,sBAAsBtsG,KAAK,oBACnDvJ,KAAK2zG,MAAM3pE,UACXhqC,KAAK81G,cAAc91G,KAAK21G,QAC1B,MAAO5oG,GACLxI,GAAOlD,MAAM,2BAA4B0L,GACzC/M,KAAK2zG,MAAM1pE,OAAOl9B,IAS1B+oG,cAAcC,GACVxxG,GAAOynF,MAAO,qBAAoB+pB,KAGlC/1G,KAAK0zG,MAAM1B,4BAA4B,aAAc+D,GAOzDC,+BAA+B3wG,GAC3Bd,GAAOynF,MAAO,iCAAgC3mF,cAUlD4vG,gBAAgBztG,GACZ,MAAMirG,EAAU,GAOhB,YALkB1mG,IAAd/L,KAAKykD,OACLguD,EAAQvkG,MAAMlO,KAAKykD,MAAOwxD,GAAAA,cAAuBj2G,KAAKykD,MACtDguD,EAAQpB,SAAWrxG,KAAK4zG,WAGrBpsG,EAAQ0uG,QAAQ90G,KAAKF,UAAUuxG,IAU1CmC,uBAAuB/S,GAGnB,OAFAA,EAAYuR,IAAYvR,EAAYuR,KAAa,GAE1CvR,EAAYuR,IAQA,0BACnB7uG,GAAOynF,MAAM,yBAEPhsF,KAAK2zG,MAEX,IAAK,MAAM9R,KAAe7hG,KAAK0zG,MAAMnN,kBACjCvmG,KAAKk0G,mBAAmBrS,EAAYsI,QAAStI,GAG7C7hG,KAAKu1G,cACLv1G,KAAKu1G,YAAYF,OACjBr1G,KAAKu1G,iBAAcxpG,GAUK,iCAAC81F,EAAa8C,GAC1C,GAAIA,EAAQmQ,MAAyB5B,GACjC,OAGJ,IAAKvO,EAAQoQ,IAGT,YAFAxwG,GAAO2T,KAAK,uCAKVlY,KAAK2zG,MAEX,MAAMpyG,EAAMojG,EAAQoQ,IACdL,EAAM7S,EAAYsI,QAClBwK,EAAU30G,KAAK40G,uBAAuB/S,GAE5C,OAAQtgG,EAAIqG,MACZ,KAAKurG,GACD,GAAIwB,EAAQntG,QACRjD,GAAO2T,KAAM,eAAcw8F,2BAE3B10G,KAAKm2G,WAAWtU,EAAa,mCAC1B,CAGH,MAAMr6F,EAAU,IAAIitG,IAAI2B,QAExB5uG,EAAQ6uG,gBAAgBr2G,KAAKu1G,YAAah0G,EAAIkV,KAAKs/F,MAAOx0G,EAAIkV,KAAK6/F,OACnE3B,EAAQntG,QAAUA,EAGlB,MAAM+uG,EAAM,CACR,CAACzB,IAAsB5B,GACvB6B,IAAK,CACDntG,KAAMurG,GACN18F,KAAM,CACFu+F,WAAYh1G,KAAKi1G,gBAAgBztG,GACjCurG,KAAMxxG,EAAIkV,KAAKs8F,QAK3B/yG,KAAKk1G,aAAaqB,EAAK7B,GACvB10G,KAAKg2G,+BAA+BtB,GAExC,MAEJ,KAAKvB,GACD,GAAIwB,EAAQntG,QACRjD,GAAO2T,KAAM,eAAcw8F,2BAE3B10G,KAAKm2G,WAAWtU,EAAa,yBAC1B,GAAItgG,EAAIkV,KAAKs8F,OAAS4B,EAAQ6B,mBAAoB,CACrD,MAAM,WAAExB,GAAezzG,EAAIkV,KACrBujB,EAAIh6B,KAAK6zG,MAAM7uF,IAAIzjB,EAAIkV,KAAKs8F,MAC5BvrG,EAAU,IAAIitG,IAAI2B,QAExB5uG,EAAQivG,eAAez2G,KAAKu1G,YAAaP,EAAW9tD,MAGpDlnD,KAAKu1G,YAAYmB,qBAAqBlvG,GAGtC,MAAMiP,EAAOjP,EAAQmvG,QAAQ3B,EAAWptG,KAAMotG,EAAW9tD,MAEzDytD,EAAQntG,QAAUA,EAClBmtG,EAAQ6B,wBAAqBzqG,EAE7B/L,KAAKg2G,+BAA+BtB,GAEpC10G,KAAK6zG,MAAMtjB,OAAOhvF,EAAIkV,KAAKs8F,MAC3B/4E,EAAEgQ,UAEF,MAAM4sE,EAAOC,GAAcpgG,GAE3B,GAAImgG,EAAK1oG,IAAK,CACV,MAAMA,EAAM+nG,GAAAA,YAAqBW,EAAK1oG,KAChCmjG,EAAWuF,EAAKvF,SAEtBsD,EAAQmC,QAAU5oG,EAClBlO,KAAKwzF,aAAa37D,KAAKw7E,GAAiBG,wBAAyBkB,EAAKxmG,EAAKmjG,SAG/E9sG,GAAO2T,KAAK,oCAEZlY,KAAKm2G,WAAWtU,EAAa,gBAEjC,MAEJ,KAAKsR,GACD5uG,GAAOlD,MAAME,EAAIkV,KAAKpV,OAEtB,MAEJ,KAAK8xG,GACD,GAAIwB,EAAQntG,QAAS,CACjB,MAAM,WAAEwtG,GAAezzG,EAAIkV,KAErBmgG,EAAOC,GADAlC,EAAQntG,QAAQmvG,QAAQ3B,EAAWptG,KAAMotG,EAAW9tD,OAGjE,QAAiBn7C,IAAb6qG,EAAK1oG,UAAuCnC,IAAlB6qG,EAAKvF,SAAwB,CACvD,MAAMnjG,IAAM0oG,EAAK1oG,KAAM+nG,GAAAA,YAAqBW,EAAK1oG,KAC3CmjG,EAAWuF,EAAKvF,SAEjB0F,IAAAA,CAAQpC,EAAQmC,QAAS5oG,KAC1BymG,EAAQmC,QAAU5oG,EAClBlO,KAAKwzF,aAAa37D,KAAKw7E,GAAiBG,wBAAyBkB,EAAKxmG,EAAKmjG,IAI/E,MAAMkF,EAAM,CACR,CAACzB,IAAsB5B,GACvB6B,IAAK,CACDntG,KAAMurG,GACN18F,KAAM,CACFu+F,WAAYh1G,KAAKi1G,gBAAgBN,EAAQntG,SACzCurG,KAAMxxG,EAAIkV,KAAKs8F,QAK3B/yG,KAAKk1G,aAAaqB,EAAK7B,SAG3BnwG,GAAOynF,MAAO,kCAAiC0oB,sCAE/C10G,KAAKm2G,WAAWtU,EAAa,8CAEjC,MAEJ,KAAKsR,GACD,GAAIwB,EAAQntG,QAAS,CACjB,MAAM,WAAEwtG,GAAezzG,EAAIkV,KAErBmgG,EAAOC,GADAlC,EAAQntG,QAAQmvG,QAAQ3B,EAAWptG,KAAMotG,EAAW9tD,OAGjE,QAAiBn7C,IAAb6qG,EAAK1oG,UAAuCnC,IAAlB6qG,EAAKvF,SAAwB,CACvD,MAAMnjG,IAAM0oG,EAAK1oG,KAAM+nG,GAAAA,YAAqBW,EAAK1oG,KAC3CmjG,EAAWuF,EAAKvF,SAEjB0F,IAAAA,CAAQpC,EAAQmC,QAAS5oG,KAC1BymG,EAAQmC,QAAU5oG,EAClBlO,KAAKwzF,aAAa37D,KAAKw7E,GAAiBG,wBAAyBkB,EAAKxmG,EAAKmjG,IAInF,MAAMr3E,EAAIh6B,KAAK6zG,MAAM7uF,IAAIzjB,EAAIkV,KAAKs8F,MAElC/yG,KAAK6zG,MAAMtjB,OAAOhvF,EAAIkV,KAAKs8F,MAC3B/4E,EAAEgQ,eAEFzlC,GAAOynF,MAAO,sCAAqC0oB,sCAEnD10G,KAAKm2G,WAAWtU,EAAa,mDAYzCqS,mBAAmB7uG,EAAIw8F,GACnBt9F,GAAOynF,MAAO,eAAc3mF,UAE5BrF,KAAKo1G,wBAAwBvT,GAYE,oCAACA,EAAar1F,EAAMihG,EAAUtjC,GAC7D,GACK,iBADG39D,GAEA29D,GAAYnqE,KAAK0zG,MAAMsD,gBAAiB,CACxC,MAAM3C,EAAqBr0G,KAAK0zG,MAAM7O,WAChCrM,EAAgBqJ,EAAYsI,QAGlC,UAFkCtI,EAAY4M,eAEtBlvD,IAAI+0D,KAAiBD,EAAqB7b,EAAe,CACzEx4F,KAAK8zG,8BACC9zG,KAAK8zG,6BAET9zG,KAAKu0G,iBAAiB1S,GAE5B,MAAM8S,EAAU30G,KAAK40G,uBAAuB/S,GACtCkR,EAAO8B,KACPp+F,EAAO,CACT,CAACq+F,IAAsB5B,GACvB6B,IAAK,CACDntG,KAAMurG,GACN18F,KAAM,CACFu+F,WAAYh1G,KAAKi1G,gBAAgBN,EAAQntG,SACzCurG,KAAAA,KAKZ/yG,KAAKk1G,aAAaz+F,EAAM+hF,KAcxC2d,WAAWtU,EAAaxgG,GACpB,MAAMqzG,EAAM7S,EAAYsI,QAClB1hE,EAAM,CACR,CAACqsE,IAAsB5B,GACvB6B,IAAK,CACDntG,KAAMurG,GACN18F,KAAM,CACFpV,MAAAA,KAKZrB,KAAKk1G,aAAazsE,EAAKisE,GAW3BQ,aAAaz+F,EAAM+hF,GACfx4F,KAAK0zG,MAAMuD,YAAYxgG,EAAM+hF,GAUjC+b,iBAAiB1S,GACb,MAAM6S,EAAM7S,EAAYsI,QAClBwK,EAAU30G,KAAK40G,uBAAuB/S,GAE5C,GAAI8S,EAAQntG,QAGR,OAFAjD,GAAO2T,KAAM,iCAAgCw8F,mCAEtC3qE,QAAQE,SAGnB,QAAmCl+B,IAA/B4oG,EAAQ6B,mBAGR,OAFAjyG,GAAO2T,KAAM,iCAAgCw8F,2CAEtC3qE,QAAQE,SAInBjqC,KAAKu1G,YAAY2B,uBAAuB,GAExC,MAAMC,EAAS/1G,KAAKwJ,MAAM5K,KAAKu1G,YAAY6B,iBACrCd,EAAQl2G,OAAOkJ,OAAO6tG,EAAOvB,YAAY,GAE/C,IAAKU,EACD,OAAOvsE,QAAQE,OAAO,IAAIjmC,MAAM,+BAIpChE,KAAKu1G,YAAY8B,yBAEjB,MAAMtE,EAAO8B,KACPjrE,EAAO,CACT,CAACkrE,IAAsB5B,GACvB6B,IAAK,CACDntG,KAAMurG,GACN18F,KAAM,CACFs/F,MAAO/1G,KAAK21G,OACZW,MAAAA,EACAvD,KAAAA,KAKN/4E,EAAI,IAAI0nB,GAcd,OAZA1nB,EAAEy1E,iBAxlBU,KAylBZz1E,EAAEgqB,OAAM,KACJhkD,KAAK6zG,MAAMtjB,OAAOwiB,GAClB4B,EAAQ6B,wBAAqBzqG,KAEjC/L,KAAK6zG,MAAM3uF,IAAI6tF,EAAM/4E,GAErBh6B,KAAKk1G,aAAatrE,EAAM8qE,GAGxBC,EAAQ6B,mBAAqBzD,EAEtB/4E,GAUf,SAAS68E,GAAcpgG,GACnB,IACI,OAAOrV,KAAKwJ,MAAM6L,GACpB,MAAO1J,GACL,MAAO,IAIf0mG,GAAWtoE,OAASkoE,GC3nBpB,MAAM9uG,IAAS2B,EAAAA,EAAAA,gDASR,MAAMoxG,WAA0BhG,GAInCl4F,YAAYslF,GACRxZ,MAAMwZ,GAEN1+F,KAAKykD,UAAO14C,EACZ/L,KAAKu3G,mBAAoB,EAEzBv3G,KAAKw3G,YAAc,IAAI/D,GAAW/U,GAElC1+F,KAAKy3G,WAAaC,IAAAA,CAAS13G,KAAK23G,eAjBhB,KAkBhB33G,KAAK43G,YAAcF,IAAAA,CAAS13G,KAAK63G,gBAlBjB,KAqBhB73G,KAAKw3G,YAAYjtE,GACbkpE,GAAWtoE,OAAOqoE,wBAClBxzG,KAAK83G,yBAAyBl3G,KAAKZ,OAEvCA,KAAK0+F,WAAWn0D,GACZ2wC,GACAl7E,KAAKm0G,8BAA8BvzG,KAAKZ,OAC5CA,KAAK0+F,WAAWn0D,GACZ2wC,GACAl7E,KAAK+3G,qBAAqBn3G,KAAKZ,OACnCA,KAAK0+F,WAAWn0D,GACZ2wC,GACAl7E,KAAKk0G,mBAAmBtzG,KAAKZ,OACjCA,KAAK0+F,WAAWn0D,GACR2wC,GACA,KACIl7E,KAAKu3G,mBAAoB,KAWxB,kBAAC9Q,GACVA,QACMzmG,KAAKw3G,YAAYQ,eAEvBh4G,KAAKw3G,YAAYlC,+BAIrBt1G,KAAKykD,OAAOgiD,GAAUzmG,KAAKi4G,eAG3B,MAAM3tG,QAActK,KAAKw3G,YAAYU,UAAUl4G,KAAKykD,MAGpDzkD,KAAKuxG,QAAQH,OAAOpxG,KAAK0+F,WAAWmG,WAAY7kG,KAAKykD,KAAMn6C,GAY5B,oCAACu3F,EAAar1F,EAAMihG,EAAUtjC,GAC7D,OAAQ39D,GACR,IAAK,aACDjI,GAAOynF,MAAO,eAAc6V,EAAYsI,iCAAiChgC,KACzE,MACJ,IAAK,gBACIA,GAAYnqE,KAAKymG,SAClBzmG,KAAKw3G,YAAYpC,wBAAwBvT,IAUrDkW,uBACQ/3G,KAAKu3G,mBAAqBv3G,KAAKymG,SAC/BzmG,KAAK43G,cAQb1D,mBAAmB7uG,GACfrF,KAAKuxG,QAAQb,QAAQrrG,GAEjBrF,KAAKymG,SACLzmG,KAAKy3G,aAUO,uBAChBlzG,GAAOynF,MAAM,gBAEbhsF,KAAKykD,KAAOzkD,KAAKi4G,eACjB,MAAM3tG,QAActK,KAAKw3G,YAAYU,UAAUl4G,KAAKykD,MAEpDzkD,KAAKuxG,QAAQH,OAAOpxG,KAAK0+F,WAAWmG,WAAY7kG,KAAKykD,KAAMn6C,GAQ1C,wBACjB/F,GAAOynF,MAAM,mBAEb,MAAMmsB,QC5FPx+E,eAAyBy+E,GAE5B,OAAO73C,OAAO83C,OAAOC,UAAU,MAAOF,EAAU,QAAQ,EAAO,CAAE,aAAc,cD0FpDE,CAAUt4G,KAAKykD,MAChC8zD,QChHP5+E,eAAuBw+E,GAC1B,MAAMK,EAAc,IAAIC,YAGxB,OAAOl4C,OAAO83C,OAAOK,WAAW,CAC5BlsG,KAAM,OACNmsG,KAAMH,EAAYI,OAAO,oBACzBj+E,KAAM,UACNnvB,KAAM,IAAI6zD,aACX84C,EAAU,KDuGYU,CAAQV,GAE7Bn4G,KAAKykD,KAAO,IAAIpmB,WAAWk6E,GAE3B,MAAMjuG,EAAQtK,KAAKw3G,YAAYrC,iBAAiBn1G,KAAKykD,MAErDzkD,KAAKuxG,QAAQH,OAAOpxG,KAAK0+F,WAAWmG,WAAY7kG,KAAKykD,KAAMn6C,GAW/DwtG,yBAAyBzyG,EAAI6I,EAAK5D,GAC9B/F,GAAOynF,MAAO,eAAc3mF,uBAE5BrF,KAAKuxG,QAAQH,OAAO/rG,EAAI6I,EAAK5D,GASjC2tG,eACI,OAAO31G,OAAOi+D,OAAOoyC,gBAAgB,IAAIt0E,WAAW,MEvKrD,MAAMy6E,GAKT1/F,YAAYslF,GACR,MAAM,KAAEqa,EAAO,IAAOra,EAAW3+F,QAAQ0N,OAEzCzN,KAAKg5G,mBAAqBD,EAAKE,qBAE3Bj5G,KAAKg5G,mBACLh5G,KAAKk5G,YAAc,IAAI1G,GAA4B9T,GAEnD1+F,KAAKk5G,YAAc,IAAI5B,GAAkB5Y,GAU/B,mBAACjxF,GACf,MAAM,KAAEsrG,EAAO,IAAOtrG,EAEtB,SAAKsrG,EAAKE,uBAAyBxF,GAAWxxF,kBAIrCxU,EAAO0rG,SAAW1rG,EAAO0rG,QAAQC,eAClC7zE,GAAQgkD,6BACJ97E,EAAO4rG,+BAAiC9zE,GAAQ8jD,4BAQhEyoB,YACI,OAAO9xG,KAAKk5G,YAAYpH,YASZ,iBAACrL,SACPzmG,KAAKk5G,YAAYI,WAAW7S,GAUtCyL,iBAAiBO,GACbzyG,KAAKk5G,YAAY9H,OAAOqB,6BC9DhC,MAAM8G,GAAsB,CAAE,WAAY,OAAQ,OAAQ,QACpDC,GAAkC,CAAE,WAAY,OAAQ,QAQ9D,SAASC,GAAkBpsG,EAAGD,GAC1B,IAAIssG,EAAM,EAMV,OAJAF,GAAgC5tG,MAAKsC,GACiC,KAAjEwrG,EAAQrsG,EAAEa,GAAOd,EAAEc,GAAS,EAAQb,EAAEa,GAAOd,EAAEc,KAAU,KAGvDwrG,EA+BJ,SAASC,GAAe1mG,GAC3B,MAAM2uF,EAAW,IAAIt7B,IACfszC,EAAa,IAAItzC,IAWvB,OATA/H,IAAAA,CAAEtrD,GAAM5K,KAAK,kBACR+mC,MAAK,CAAC0R,EAAGzvC,IAAOuwF,EAASjiD,IAAItuC,EAAGmR,aAAa,UAClD+7C,IAAAA,CAAEtrD,GAAM5K,KAAK,mBACR+mC,MAAK,CAAC0R,EAAGzvC,IAAOuoG,EAAWj6D,IAAI,CAC5B/3C,KAAMyJ,EAAGmR,aAAa,QACtBhW,KAAM6E,EAAGmR,aAAa,QACtBq3F,SAAUxoG,EAAGmR,aAAa,gBAG3B,CACHo/E,SAAAA,EACAgY,WAAAA,GAOO,MAAME,WAAanK,GAO9Bv2F,cAAkE,IAAtD0pF,EAAsD,uDAAzC,GAAI7vF,EAAqC,uDAA9B,6BAIhC,GAHAiyE,QACAllF,KAAKiT,KAAOA,EACZjT,KAAK+5G,MAAQjX,EAAWiX,OACnB/5G,KAAK+5G,MACN,MAAM,IAAI/1G,MACN,uDAIRhE,KAAKiR,QAAU,GACfjR,KAAKg6G,MAAQ,IAAI1zC,IAIjBtmE,KAAKi6G,iBAAmB,IAAI3zC,IAE5B,MAAMy8B,EAAOD,EAAWC,KAExBA,EAAKnrE,YAAYqF,GAAW,WAAXA,iBACbskE,GAAQvhG,KAAKk6G,aAAa3Y,KAC9BwB,EAAKnrE,YAAYqF,GAAW,WAAXA,mBACbskE,GAAQvhG,KAAKm6G,gBAAgB5Y,KACjCnhG,OAAOC,KAAK0iG,EAAKiX,OAAOz5G,SAAQ4iG,IAC5BnjG,KAAKk6G,aAAanX,EAAKiX,MAAM7W,OAGjCpB,GAAAA,QAAAA,aAAqB,OAAQ,mCAC7B/hG,KAAK+5G,MAAMK,WAAWrY,GAAAA,QAAAA,GAAAA,MAa1BqY,WAAW14F,GAA2C,IAAlCq5B,EAAkC,wDAAlBs/D,EAAkB,wDAClDr6G,KAAK+5G,MAAMK,WAAW14F,GACtB1hB,KAAKs6G,mBAEDD,IAAar6G,KAAKi6G,iBAAiB16D,IAAI79B,KACvC1hB,KAAKi6G,iBAAiBt6D,IAAIj+B,GAC1B1hB,KAAKg6G,MAAMz5G,SAAQghG,GAAQvhG,KAAKu6G,gCAAgChZ,MAGhExmD,GACA/6C,KAAK+6C,SAYby/D,cAAc94F,GAA2C,IAAlCq5B,EAAkC,wDAAlBs/D,EAAkB,wDACrDr6G,KAAK+5G,MAAMS,cAAc94F,GACzB1hB,KAAKs6G,mBAEDD,GAAYr6G,KAAKi6G,iBAAiB16D,IAAI79B,KACtC1hB,KAAKi6G,iBAAiB1pB,OAAO7uE,GAC7B1hB,KAAKg6G,MAAMz5G,SAAQghG,GAAQvhG,KAAKu6G,gCAAgChZ,MAGhExmD,GACA/6C,KAAK+6C,SAObA,SACI/6C,KAAKg6G,MAAMz5G,SAAQghG,GAAQA,EAAKkZ,iBAQpCF,gCAAgChZ,GAC5B,GAAmC,IAA/BvhG,KAAKi6G,iBAAiBj1C,KACtBu8B,EAAKmZ,mBAAmB,gBACrB,CACH,MAAMv7D,EAAW,GAEjBn/C,KAAKi6G,iBAAiB15G,SAAQ6zB,IAC1B+qB,EAASj9C,KAAK,CACV,QAAW,UACX2d,WAAY,CAAE,IAAOuU,QAI7BmtE,EAAKoZ,uBAAuB,WAAY,CAAEx7D,SAAAA,KAUlDy7D,yBAAyBzX,EAAKlwF,GAAsB,IAAhB6kD,EAAgB,uDAAN,IAC1C,OAAO93D,KAAK66G,cAAc1X,EAAKlwF,EAAM6kD,GAWzC+iD,cAAc1X,EAAKlwF,EAAM6kD,GACrB,OAAO,IAAI/tB,SAAQ,CAACC,EAASC,IACzBjqC,KAAK+5G,MAAMvuG,KAAK23F,EAAKlwF,GAAM6nG,IACvB9wE,EAAQ2vE,GAAemB,MACxB7wE,EAAQ6tB,KASnBoiD,aAAa3Y,GACTvhG,KAAKg6G,MAAMr6D,IAAI4hD,GACfvhG,KAAK+6G,wBAAwBxZ,GAE7BvhG,KAAKu6G,gCAAgChZ,GAQzC4Y,gBAAgB5Y,GACZvhG,KAAKg6G,MAAMzpB,OAAOgR,GAOtBwZ,wBAAwBxZ,GACpBA,EAAKoZ,uBAAuB,IAAK,CAC7B96F,WAAY,CACRzL,MAAO2tF,GAAAA,QAAAA,GAAAA,KACPpnE,KA3OH,QA4OG1nB,KAAMjT,KAAKiT,KACX+nG,IAAKh7G,KAAKiR,WAQtBgqG,wBAEIj7G,KAAKg6G,MAAMz5G,SAAQghG,GAAQvhG,KAAK+6G,wBAAwBxZ,KAM5D+Y,mBACIt6G,KAAKiR,QAtOb,SAAqB2oG,EAAYhY,GAC7B,MAAMsZ,EAAmBtB,EAAW/pE,KAAK4pE,IAAmB5pG,QACxD,CAACsrG,EAAkBjP,IAAc,GAC7BqN,GAAoB1pG,QAChB,CAAC4tB,EAAKvvB,EAAK4rC,IACPrc,GACe,IAARqc,EAAY,GAAK,MACjBoyD,EAASh+F,GAAOg+F,EAASh+F,GAAO,KAC3C,QACH,IACHktG,EAAiBxZ,EAAS/xD,OAAOhgC,QACnC,CAAC4tB,EAAK/b,IAAa,GAAE+b,EAAM/b,MAAY,IAE3C,OAAO25F,EAAAA,GAAAA,UAASH,EAAmBE,GA0NzBE,CAAYt7G,KAAK+5G,MAAMwB,YAAav7G,KAAK+5G,MAAM5M,WAErDntG,KAAKi7G,gCCxQN,MAAMO,GAAqB,uBAE5Bj3G,IAAS2B,EAAAA,EAAAA,kDA8Cf,GAFoB,IAnCb,cAA0BypG,GAI7Bv2F,cACI8rE,QACAllF,KAAKy7G,SAAW,CACZC,UAAU,GAQlBC,kBAAkB,GAAc,IAAd,SAAED,GAAY,EAC5Bn3G,GAAOynF,MAAM,oBAAqB,CAAE0vB,SAAAA,IACpC17G,KAAKy7G,SAAW,CACZC,UAAuB,IAAbA,GAEd17G,KAAKwzF,aAAa37D,KAAK2jF,GAAoBx7G,KAAKy7G,UAUpDC,WACI,OAAkC,IAA3B17G,KAAKy7G,SAASC,WCtCvBn3G,IAAS2B,EAAAA,EAAAA,yCAQA,MAAM01G,GAKjBxiG,YAAYyiG,GACR77G,KAAK87G,aAAeD,EAOpB77G,KAAK+7G,cAAgB,EAErB/7G,KAAKg8G,iBAAcjwG,EAOnBkwG,iBACA,OAAOj8G,KAAKg8G,YAQhBE,WACIl8G,KAAKm8G,gBAELn8G,KAAK+7G,eAAiB,EAEtB/7G,KAAKo8G,uBACCC,GAAAA,iBACEb,IACA,IAAkB,IAAjB,SAAEE,GAAe,EACVA,EACA17G,KAAKs8G,kBAELt8G,KAAKm8G,mBAIrBE,GAAAA,YAA0Br8G,KAAKs8G,kBAQnCA,kBACQt8G,KAAKu8G,iBAUTv8G,KAAK+7G,cAAgB9xG,KAAK6uB,IAAI,EAAG94B,KAAK+7G,eACtC/7G,KAAKg8G,YCxEN,SAAwBQ,GAAiC,IAA1BC,EAA0B,uDAAf,IAAK75F,EAAU,uDAAH,EACzD,OAAO3Y,KAAKC,MAAOD,KAAKE,UAAqC,IAAxBF,KAAK2wB,IAAIhY,EAAM45F,GAAiBC,GAAaA,GDuE3DC,CACH18G,KAAK+7G,cACmB,KAArB/7G,KAAK+7G,cACpB,GAEJx3G,GAAOiH,KAAM,6CAA4CxL,KAAKi8G,gBAE9Dj8G,KAAKu8G,eAAiB/5G,YAAW,IAAMxC,KAAK28G,qBAAqB38G,KAAKi8G,aAS1EE,gBACQn8G,KAAKu8G,iBACLh4G,GAAOiH,KAAK,oCACZjJ,aAAavC,KAAKu8G,gBAClBv8G,KAAKu8G,oBAAiBxwG,EACtB/L,KAAKg8G,iBAAcjwG,GAU3B4wG,oBACI,MAAM,iBAAEC,GAAqB58G,KAAK87G,aAC5Be,EAAcD,EAAiBE,iBAGrC,IAAKD,EACD,OAGJt4G,GAAOiH,KAAK,wCAEZ,MAAM28B,EAAM,IAAIkoE,IAAIrwG,KAAK87G,aAAaiB,SACtC,IAAI,OAAE91E,GAAWkB,EACjB,MAAM2Q,EAAU,oBACVkkE,EAAW/1E,EAAO7iC,MAAM00C,GAG1BkkE,IAA+C,IAAnCA,EAAS35G,QAAQw5G,GAC7B51E,EAASA,EAAOx2B,QAAQqoC,EAAU,KAAI+jE,KAG9BG,IACR/1E,IAAmC,IAAzBA,EAAO5jC,QAAQ,KAAe,WAAUw5G,IAAiB,WAAUA,KAGjF10E,EAAIlB,OAASA,EAEbjnC,KAAK87G,aAAaiB,QAAU50E,EAAIjnB,WAEhC07F,EAAiB5qB,SASrB/kB,SACIjtE,KAAKm8G,gBACLn8G,KAAK+7G,cAAgB,EACjB/7G,KAAKo8G,yBACLp8G,KAAKo8G,yBACLp8G,KAAKo8G,uBAAyB,OE1J3B,MAAMa,GAIjB7jG,cACIpZ,KAAKk9G,aAAe,KACpBl9G,KAAKm9G,mBAAqB,KAS9BC,cAAcC,EAAgBxB,GAAmB,WAC7C,MAAMyB,EAAmBzB,EAAkB0B,SAE3C1B,EAAkB0B,SAAW,WAAa,2BAAT94G,EAAS,yBAATA,EAAS,gBACtC,MAAM+4G,EAAa/4G,EAAK,GAEpB+4G,EAAWC,SAAS,aACpB,EAAKN,mBAAqBK,GAK1BH,EAAeK,YACf,EAAKR,aAAe/3G,KAAK8nD,OAE7BqwD,EAAiB58G,MAAMm7G,EAAmBp3G,IASlDk5G,uBACI,OAAO39G,KAAKm9G,mBAQhBS,0BACI,OAAO59G,KAAKk9G,aACN/3G,KAAK8nD,MAAQjtD,KAAKk9G,aAClB,MC/Cd,SAASW,KAA+C,IAAjBj7F,EAAiB,uDAAV,QAI1C,OAAO,cAAcA,EAIjBxJ,cACI8rE,SAAS,WACTllF,KAAK8iG,WAAa,KAOtBl5D,KAAKk5D,GACD9iG,KAAK8iG,WAAaA,IAQ9B,SAAe+a,KAKFC,GACPD,GAA8BlO,IC/B9BprG,IAAS2B,EAAAA,EAAAA,2CAwBA,MAAM63G,WAA6BC,GAW9C5kG,YAAY,GAA+E,IAA/E,+BAAE6kG,EAAF,wBAAkCC,EAAlC,YAA2DC,EAAc,IAAM,EACvFj5B,QACAllF,KAAKo+G,YAAc,EACnBp+G,KAAKq+G,yBAA2BH,EAChCl+G,KAAKs+G,gCAAkCL,EAEvCj+G,KAAKu+G,aAA+C,iBAAzBJ,EAAY/sB,SAAwB+sB,EAAY/sB,SApCrD,IAqCtBpxF,KAAKw+G,YAA6C,iBAAxBL,EAAYrmD,QAAuBqmD,EAAYrmD,QAhCpD,IAiCrB93D,KAAKy+G,cAAiD,iBAA1BN,EAAYO,UAClCP,EAAYO,UA3BK,EA+BvB1+G,KAAK2+G,qBAAuB10G,KAAKo+B,MAAM,KAASroC,KAAKu+G,cACrDv+G,KAAK4+G,kBAAoB,IAAIl6G,MAAM1E,KAAK2+G,sBAO5C/0E,KAAKk5D,GACD5d,MAAMt7C,KAAKk5D,GACXf,GAAAA,QAAAA,aAAqB,OAAQ,iBAajC8c,KAAK1b,EAAKpT,EAAS1uF,EAAOy2D,GACtB93D,KAAK8+G,6BAEL,MAAMC,GAAKC,EAAAA,GAAAA,KAAI,CACXp3G,KAAM,MACNq3G,GAAI9b,IAGR4b,EAAG5xG,EAAE,OAAQ,CAAEiH,MAAO2tF,GAAAA,QAAAA,GAAAA,OACtB/hG,KAAK8iG,WAAWoc,QAAQH,EAAI,CAAEjnD,QAAAA,IACzBlX,KAAKmvC,EAAS1uF,GAWvB89G,cAAcC,GACVnsB,cAAcjzF,KAAKqxF,YACnBrxF,KAAKqxF,WAAa/uF,OAAOiwF,aAAY,KAKjC,MAAMtlC,EAAM9nD,KAAK8nD,MAEjB,GAAIjtD,KAAKs+G,kCAAoCrxD,EAAMjtD,KAAKq/G,iBAOpD,OALAr/G,KAAK8+G,6BAEL9+G,KAAKq/G,iBAAmBpyD,OACxBjtD,KAAKo+G,YAAc,GAKvBp+G,KAAK6+G,KAAKO,GAAW,KAIjBp/G,KAAKq/G,iBAAmBr/G,KAAKs+G,kCAAoCn5G,KAAK8nD,MAEtEjtD,KAAKo+G,YAAc,KACpB/8G,IACCrB,KAAKo+G,aAAe,EACpB,MAAMkB,EAAU,SAAOj+G,EAAQ,QAAU,WAErCrB,KAAKo+G,aAAep+G,KAAKy+G,eACzBjmF,KAAAA,iBAAsC,IAAIx0B,MAAMs7G,IAChD/6G,GAAOlD,MAAMi+G,EAAQj+G,GACrBrB,KAAKq+G,0BAA4Br+G,KAAKq+G,4BAEtC95G,GAAO2T,KAAKonG,EAAQj+G,KAEzBrB,KAAKw+G,eACTx+G,KAAKu+G,cACRh6G,GAAOiH,KAAM,iCAAgCxL,KAAKu+G,mBAMtDgB,eACQv/G,KAAKqxF,aACL/uF,OAAO2wF,cAAcjzF,KAAKqxF,YAC1BrxF,KAAKqxF,WAAa,KAClBrxF,KAAKo+G,YAAc,EACnB75G,GAAOiH,KAAK,0BAQpBszG,6BACI9+G,KAAK4+G,kBAAkB18G,MAAK,IAAIiD,MAAOq6G,WAGnCx/G,KAAK4+G,kBAAkBl9G,OAAS1B,KAAK2+G,sBACrC3+G,KAAK4+G,kBAAkBzxE,QAY/BsyE,qBACI,MAAMC,EAAgB1/G,KAAK4+G,kBAAkBj6G,QAM7C+6G,EAAcx9G,MAAK,IAAIiD,MAAOq6G,WAE9B,IAAIG,EAAc,EACdC,EAAaF,EAAc,GAkB/B,OAhBAA,EAAcn/G,SAAQwM,IAClB,MAAM8yG,EAAkB9yG,EAAI6yG,EAExBC,EAAkBF,IAClBA,EAAcE,GAGlBD,EAAa7yG,KAMjB4yG,GAAe3/G,KAAKu+G,aAGbt0G,KAAKotB,IAAIsoF,EAAa,ICjMrC,MAAMp7G,IAAS2B,EAAAA,EAAAA,6CAKA,MAAM45G,WAAuBnQ,GAM7BxsB,oBACP,MAAO,CACH48B,oBAAqB,sBACrBC,mBAAoB,sBASjBC,oBACP,OAAOle,GAAAA,QAAAA,OAmBX3oF,YAAY,GAAmG,IAAnG,sBAAE8mG,EAAF,mBAAyBC,EAAzB,sBAA6CC,EAA7C,WAAoEC,EAApE,MAAgFC,EAAhF,SAAuFC,GAAY,EAC3Gr7B,QACAllF,KAAKwgH,SAAW,CACZN,2BAAwD,IAA1BA,GAA+CA,EAC7E/B,YAAaoC,EACbD,MAAAA,EACAH,wBAAkD,IAAvBA,EAAqC,IAAYrxG,OAAOqxG,GACnFC,sBAAAA,GAGJpgH,KAAK87G,aAAe,IAAI/Z,GAAAA,QAAAA,WAAmBse,GAC3CrgH,KAAKygH,eAAiBJ,EAAWK,WAAW,QAAUL,EAAWK,WAAW,QAG5E1gH,KAAK87G,aAAa6E,WAAa,EAE/B3gH,KAAK4gH,iBAAmB,IAAIC,GAC5B7gH,KAAK4gH,iBAAiBxD,cAAcp9G,KAAMA,KAAK87G,cAE/C97G,KAAK8gH,YAAc,IAAIlF,GAAW57G,KAAK87G,cAcvC97G,KAAK+gH,aAAe,GAIpB/gH,KAAKghH,oBACD,OACA,IAAIjD,GAAqB,CACrBE,+BAAgC,IAAMj+G,KAAK49G,0BAC3CM,wBAAyB,IAAMl+G,KAAKihH,gCACpC9C,YAAaoC,KAIrBvgH,KAAKkhH,uBAAwB,EAQ7BxD,gBACA,MAAMyD,EAAYnhH,KAAK87G,cAAgB97G,KAAK87G,aAAasF,QAAUphH,KAAK87G,aAAasF,OAAOC,OAE5F,OAAQrhH,KAAK0kG,UAAY3C,GAAAA,QAAAA,OAAAA,WAA4B/hG,KAAK0kG,UAAY3C,GAAAA,QAAAA,OAAAA,aAC7D/hG,KAAKshH,kBAAqBH,GAAaA,EAAU34E,aAAe+4E,UAAUC,MAQnFzH,YACA,OAAO/5G,KAAK87G,aAAa/B,MAQzB0H,oBACA,OAA2C,IAApCzhH,KAAK87G,aAAa2F,cAQzBC,aACA,OAAO1hH,KAAK87G,aAAa4F,OAQzBJ,uBACA,OAAOthH,KAAKygH,eAQZtd,UACA,OAAOnjG,KAAK87G,aAAa3Y,IAQzBwe,0BACA,OAAO3hH,KAAK87G,aAAasF,QAAUphH,KAAK87G,aAAasF,OAAOO,oBAQ5Dp9G,aACA,OAAOvE,KAAK87G,aAAav3G,OAQzBxE,cACA,OAAOC,KAAK87G,aAAa/7G,QAMzB6hH,iBAAa,MACb,OAAO,UAAA5hH,KAAKwgH,SAASrC,mBAAd,eAA2BuD,SAAU1hH,KAAK0hH,OAQjD3E,cACA,OAAO/8G,KAAK87G,aAAaiB,QAOzBuD,UAAMn5G,GACNnH,KAAKwgH,SAASF,MAAQn5G,EAGlBnH,KAAKkhH,uBACLlhH,KAAK6hH,yBAST5yB,aACA,OAAOjvF,KAAK0kG,QAUhBsc,oBAAoBx0G,EAAMs1G,GACtB9hH,KAAKwM,GAAQs1G,EACbA,EAAOl4E,KAAK5pC,MAQhBy4B,aACIz4B,KAAK87G,aAAarjF,cAAc,WAUpCspF,OAAO5e,EAAK6e,EAAKC,EAAKrlG,GAAmB,2BAANnY,EAAM,iCAANA,EAAM,kBACrCzE,KAAK87G,aAAaiG,OAAO5e,EAAK6e,EAAKC,EAAKjiH,KAAKkiH,qBAAqBthH,KAAKZ,KAAM4c,MAAcnY,GAS/F6tF,QAAQ6Q,EAAKgf,EAAMvlG,GAAmB,2BAANnY,EAAM,iCAANA,EAAM,kBAClCzE,KAAK87G,aAAaxpB,QAAQ6Q,EAAKgf,EAAMniH,KAAKkiH,qBAAqBthH,KAAKZ,KAAM4c,MAAcnY,GAc5Fy9G,qBAAqBE,EAAgBnzB,GACjCjvF,KAAK0kG,QAAUzV,EAEf,IAAIozB,GAAgB,EAE2D,MAwB/E,GAxBIpzB,IAAW8S,GAAAA,QAAAA,OAAAA,WAA4B9S,IAAW8S,GAAAA,QAAAA,OAAAA,UAClD/hG,KAAKsiH,2BAIDtiH,KAAKygH,gBAAkBzgH,KAAKkhH,uBAC5BlhH,KAAKuiH,0BAETviH,KAAKkhH,uBAAwB,EAE7BlhH,KAAK6hH,yBACL7hH,KAAKwiH,sBACLxiH,KAAK8gH,YAAY7zC,SACjBjtE,KAAK6+G,KAAKM,eAAc,UAAAn/G,KAAKwgH,SAASrC,mBAAd,eAA2BuD,SAAU1hH,KAAK0hH,SAC3DzyB,IAAW8S,GAAAA,QAAAA,OAAAA,eAClB/hG,KAAK6+G,KAAKU,eAGV8C,EAAgBriH,KAAKyiH,yBAChBJ,GACD9/G,aAAavC,KAAK0iH,gBAIrBL,EAAe,4BA7BwB59G,EA6BxB,iCA7BwBA,EA6BxB,kBAChB29G,EAAenzB,KAAWxqF,GAC1BzE,KAAKwzF,aAAa37D,KAAKioF,GAAe38B,OAAO48B,oBAAqB9wB,IAS1E0zB,oBACI,IAAK,MAAM7gE,KAAY9hD,KAAK+gH,aACxBj/D,EAAS7X,OAAO,IAAIjmC,MAAM,eAE9BhE,KAAK+gH,aAAe,GAQxB6B,iBACQ5iH,KAAK87G,cAAgB97G,KAAK87G,aAAasF,SACvCphH,KAAK87G,aAAasF,OAAOyB,eACzB7iH,KAAK87G,aAAasF,OAAO0B,SAAS,OAS1CjuB,aACI70F,KAAK8gH,YAAY7zC,SACjB1qE,aAAavC,KAAK0iH,cAClB1iH,KAAK2iH,oBACL3iH,KAAK87G,aAAajnB,cAAc,WAQpCpyF,QACIzC,KAAK87G,aAAar5G,SAAS,WAQ/Bm7G,0BACI,OAAO59G,KAAK4gH,iBAAiBhD,0BAQjCD,uBACI,OAAO39G,KAAK4gH,iBAAiBjD,uBAQjC2E,2BACI,IAAKtiH,KAAKwgH,SAASN,sBAEf,OAGJ,MAAM,iBAAEtD,GAAqB58G,KAAK87G,aAE7B97G,KAAKshH,iBAEE1E,EAEAA,EAAiB36F,cAEjB26F,EAAiBE,mBACzBv4G,GAAOiH,KAAK,uCACZoxG,EAAiBmG,QAAoB,IAHrCx+G,GAAO2T,KAAK,sEAFZ3T,GAAO2T,KAAK,+EAFZ3T,GAAO2T,KAAK,yDAiBpB2pG,yBACI,MAAM,mBAAE1B,GAAuBngH,KAAKwgH,SAEpC,GAAIxgH,KAAKygH,gBAAkBN,EAAqB,EAAG,CAC/CngH,KAAK0iH,cAAgBn+G,GAAOiH,KAAM,kCAAiC20G,OACnE59G,aAAavC,KAAK0iH,cAElB,MAAMM,EAAgC7C,EAAmD,GAAhBl2G,KAAKE,SAAgB,IAE9F5F,GAAOynF,MAAO,2CAA0Cg3B,OAExDhjH,KAAK0iH,aAAelgH,YAChB,IAAMxC,KAAKuiH,0BACN3hE,MAAK,IAAM5gD,KAAK6hH,4BACrBmB,IAUZT,0BACI,MAAM,MAAEjC,EAAF,sBAASF,GAA0BpgH,KAAKwgH,SACxCr4E,EAAMi4E,GACNpgH,KAAK+8G,QAAQtsG,QAAQ,SAAU,YAAYA,QAAQ,QAAS,WAElE,OAAOwyG,MAAM96E,GACRyY,MAAKk6D,IAGF,IAAKwF,EACD,OAGJ,MAAM4C,EAAgBpI,EAASqI,QAAQn+F,IAAI,iBAEvCk+F,IAAkB5C,IAClB/7G,GAAOlD,MACF,oCAAmCi/G,QAAY4C,KACpDljH,KAAKwzF,aAAa37D,KAAKioF,GAAe38B,OAAO68B,wBAGpDh8D,OAAM3iD,IACHkD,GAAOlD,MAAO,wCAAuC8mC,IAAO,CAAE9mC,MAAAA,OAU1EmhH,sBACI,IAAK,MAAM1gE,KAAY9hD,KAAK+gH,aACxB,GAAIj/D,EAASi9D,GAAI,CACbx8G,aAAau/C,EAASgW,SAEtB,MAAMsrD,EAAWj+G,KAAK8nD,MAAQnL,EAAS1/C,MAEvCpC,KAAKqjH,OACDvhE,EAASi9D,IACTzlF,GAAUwoB,EAAS9X,QAAQ1Q,KAC3Bj4B,GAASygD,EAAS7X,OAAO5oC,IACzB+hH,GAIZpjH,KAAK+gH,aAAe,GASxBuC,KAAKC,GACD,IAAKvjH,KAAK09G,UACN,MAAM,IAAI15G,MAAM,iBAEpBhE,KAAK87G,aAAawH,KAAKC,GAa3BF,OAAOh0E,EAAMzyB,EAAU4mG,EAAS1rD,GAC5B,GAAK93D,KAAK09G,UAMV,OAAO19G,KAAK87G,aAAauH,OAAOh0E,EAAMzyB,EAAU4mG,EAAS1rD,GALrD0rD,EAAQ,iBAgBhBtE,QAAQH,EAAD,GAAkB,IAAb,QAAEjnD,GAAW,EACrB,OAAO,IAAI/tB,SAAQ,CAACC,EAASC,KACzB,GAAIjqC,KAAK09G,UACL19G,KAAKqjH,OACDtE,GACAzlF,GAAU0Q,EAAQ1Q,KAClBj4B,GAAS4oC,EAAO5oC,IAChBy2D,OACD,CACH,MAAMhW,EAAW,CACbi9D,GAAAA,EACA/0E,QAAAA,EACAC,OAAAA,EACA7nC,MAAO+C,KAAK8nD,MACZ6K,QAASt1D,YAAW,KAEhBs/C,EAASi9D,QAAKhzG,EAGdk+B,OAAOl+B,KACR+rD,IAGP93D,KAAK+gH,aAAa7+G,KAAK4/C,OAUnCm/D,gCACQjhH,KAAKshH,mBACL/8G,GAAO2T,KAAK,yDACZlY,KAAK4iH,kBAebnI,aAAaprE,EAAMzyB,EAAU4mG,EAAS1rD,GAC7B93D,KAAK09G,UAKV19G,KAAK87G,aAAarB,aAAaprE,EAAMzyB,EAAU4mG,EAAS1rD,GAJpD0rD,EAAQ,iBAYhBC,wBACI,IAAKp/B,UAAUq/B,YAAc1jH,KAAK87G,aAAa2F,gBAAkBzhH,KAAK87G,aAAa4B,UAC/E,OAAO,EAGX19G,KAAK87G,aAAa6H,qBAAqB5hB,GAAAA,QAAAA,OAAAA,eACvC/hG,KAAK87G,aAAa2F,eAAgB,EAElC,MAAMv6D,EAAOlnD,KAAK87G,aAAasF,OAAOwC,aACjCtuG,MAAM,CACH1N,KAAM,cAERi8G,GAAOC,EAAAA,GAAAA,OAAM,CACf1vG,MAAO2tF,GAAAA,QAAAA,GAAAA,OACPn6F,KAAM,gBAGVs/C,EAAK68D,MAAMF,EAAKG,QAEhB,MAAMtK,EAAMr1B,UAAUq/B,YACoB,IAAtC1jH,KAAK+8G,QAAQ15G,QAAQ,YAAsB,SAAQrD,KAAK+8G,UAAY/8G,KAAK+8G,QACzEhb,GAAAA,QAAAA,UAAkB76C,EAAK88D,SAO3B,OALAz/G,GAAOiH,KAAM,wCAAuCkuG,KAEpD15G,KAAK87G,aAAasF,OAAO6C,oBACzBjkH,KAAK87G,aAAaoI,iBAEX,EAWXzB,yBACI,MAAM,iBAAE7F,GAAqB58G,KAAK87G,aAGlC,SAFoBc,IAAoBA,EAAiBE,mBAGrD98G,KAAK8gH,YAAY5E,WAEV,KCxnBZ,IAAKiI,aAAAA,GAAAA,EAAAA,GAAAA,KAAAA,EAAAA,IAAAA,OAAAA,KAAAA,GAAAA,KAaL,MAAMC,GAAKD,GAAyBC,GAC9BC,GAAMF,GAAyBE,ICRtC9/G,IAAS2B,EAAAA,EAAAA,2CAKA,MAAMo+G,GAOjBlrG,YAAYmoF,GACRvhG,KAAKukH,MAAQhjB,EAAK7E,KAElB18F,KAAKwkH,UAAYjjB,EAEjBvhG,KAAKykH,yBAA2B,CAC5B,CAAC3vB,GAAUqH,QAAQ,EACnB,CAACrH,GAAU2G,QAAQ,GAGvBz7F,KAAK0kH,gBAAkB,GACvB1kH,KAAK2kH,gBAAkB,GAEvB3kH,KAAK4kH,WAAa5kH,KAAK4kH,WAAWhkH,KAAKZ,MACvCA,KAAKukH,MAAM3sF,YAAYqF,GAAW,WAAXA,uBAAmCj9B,KAAK4kH,YAMnEt6B,UACItqF,KAAKukH,MAAMp6E,eAAelN,GAAW,WAAXA,uBAAmCj9B,KAAK4kH,YAQtE3iG,cACI,OAAOqlE,QAAQtnF,KAAKukH,MAAMM,8BAM9B9B,OAAOl3E,EAAOo3C,GACV,IAAKjjF,KAAKiiB,gBAAkBjiB,KAAKwkH,UAAUxgB,cAIvC,YAHAz/F,GAAOlD,MAAO,iBAAgBwqC,6BAAiC7rC,KAAKiiB,6CACpDjiB,KAAKwkH,UAAUxgB,iBAKnC,GAAIn4D,IAAU7rC,KAAKykH,yBAAyBxhC,GAGxC,YAFA1+E,GAAO2T,KAAM,+BAA8B2zB,mBAAuBo3C,KAMtE,MAAM1hF,GAAMujH,EAAAA,GAAAA,MAAK,CAAE7F,GAAIj/G,KAAKukH,MAAMM,+BAElCtjH,EAAI4L,EAAE,gBAAiB,CACnB41G,OAAQl3E,EACRo3C,UAAAA,IACD8hC,KAEH/kH,KAAKukH,MAAMzhB,WAAWwgB,KAAK/hH,GAM/ByjH,QAAQ/hC,EAAWkgB,GACf,IAAKnjG,KAAKiiB,gBAAkBjiB,KAAKwkH,UAAUxgB,cAIvC,YAHAz/F,GAAOlD,MAAO,6CAA4CrB,KAAKiiB,6CAC/CjiB,KAAKwkH,UAAUxgB,iBAMnC,MAAMziG,GAAMujH,EAAAA,GAAAA,MAAK,CAAE7F,GAAIj/G,KAAKukH,MAAMM,+BAElCtjH,EAAI4L,EAAE,gBAAiB,CACnB81E,UAAAA,EACAgiC,eAAgB9hB,IAAO4hB,KAE3B/kH,KAAKukH,MAAMzhB,WAAWwgB,KAAK/hH,GAM/B0oC,OAAOg5C,EAAWkgB,GACd,IAAKnjG,KAAKiiB,gBAAkBjiB,KAAKwkH,UAAUxgB,cAIvC,YAHAz/F,GAAOlD,MAAO,4CAA2CrB,KAAKiiB,6CAC9CjiB,KAAKwkH,UAAUxgB,iBAMnC,MAAMziG,GAAMujH,EAAAA,GAAAA,MAAK,CAAE7F,GAAIj/G,KAAKukH,MAAMM,+BAElCtjH,EAAI4L,EAAE,gBAAiB,CACnB81E,UAAAA,EACAiiC,eAAgB/hB,IACjB4hB,KAEH/kH,KAAKukH,MAAMzhB,WAAWwgB,KAAK/hH,GAQ/BqjH,WAAWz2G,GACP,MAAM,QAAEg3G,EAASliC,UAAWt7E,EAAtB,QAA6B8+F,EAA7B,SAAsC2e,EAAtC,MAAgDjjB,EAAOkjB,WAAYC,GAAkBn3G,EAE3F,GAAIm3G,EAAe,CACf,MAAMC,EAAU59G,IAAUmtF,GAAUqH,MAC9Bn8F,KAAK0kH,gBACL1kH,KAAK2kH,gBACLa,EAAU9gH,MAAMgD,QAAQ49G,EAAc39G,IAAU29G,EAAc39G,GAAS,GAEzEw9G,EACAI,EAAQx+G,QAAO2J,IAAM80G,EAAQ/H,SAAS/sG,KACjCnQ,SAAQ4iG,GAAOnjG,KAAKukH,MAAM/wB,aACtB37D,KAAKoF,GAAW,WAAXA,mCAA+Ct1B,EAAOw7F,KAEpEqiB,EAAQz+G,QAAO2J,IAAM60G,EAAQ9H,SAAS/sG,KACjCnQ,SAAQ4iG,GAAOnjG,KAAKukH,MAAM/wB,aACtB37D,KAAKoF,GAAW,WAAXA,mCAA+Ct1B,EAAOw7F,KAGpEx7F,IAAUmtF,GAAUqH,MACpBn8F,KAAK0kH,gBAAkBc,EAEvBxlH,KAAK2kH,gBAAkBa,YAERz5G,IAAZ06F,GAAyBzmG,KAAKykH,yBAAyB98G,KAAW8+F,GACzEzmG,KAAKykH,yBAAyB98G,GAAS8+F,EAEvCzmG,KAAKukH,MAAM/wB,aAAa37D,KAAKoF,GAAW,WAAXA,sBAAkCwpE,EAAS9+F,EAAOw6F,IACxEgjB,EACPnlH,KAAKukH,MAAM/wB,aAAa37D,KAAKoF,GAAW,WAAXA,uBAAmCt1B,GACzDy9G,GACPplH,KAAKukH,MAAM/wB,aAAa37D,KAAKoF,GAAW,WAAXA,uBAAmCt1B,ICzJ5E,MAAM89G,GAAc,0BACdC,GAAwB,CAC1BC,IAAM,GAAEF,SACRG,OAAS,GAAEH,YACXI,aAAe,GAAEJ,mBAEfK,GACa,GAAEL,kBADfK,GAEO,GAAEL,YAGTlhH,IAAS2B,EAAAA,EAAAA,4CAKA,MAAM6/G,GAOjB3sG,YAAYmoF,GACRvhG,KAAKuhG,KAAOA,EAEZvhG,KAAKgmH,gBAAkBhmH,KAAKgmH,gBAAgBplH,KAAKZ,MACjDA,KAAKuhG,KAAK7E,KAAK9kE,YAAYqF,GAAW,WAAXA,qBAAiCj9B,KAAKgmH,iBAEjEhmH,KAAKimH,OAAS,GAMlB37B,UACItqF,KAAKuhG,KAAK7E,KAAKvyD,eAAelN,GAAW,WAAXA,qBAAiCj9B,KAAKgmH,iBAQxEE,mBAAmBC,GACf,IAAKnmH,KAAKiiB,gBAAkBjiB,KAAKuhG,KAAKyC,cAIlC,YAHAz/F,GAAOlD,MAAO,2CAA0CrB,KAAKiiB,6CAC7CjiB,KAAKuhG,KAAKyC,iBAK9B,MAAMhpF,EAAU,CACZpT,KAAM89G,GAAsBC,IAC5BQ,QAAAA,GAGJnmH,KAAKk1G,aAAal6F,GAQtBorG,mBAAmBC,GACf,IAAKrmH,KAAKiiB,gBAAkBjiB,KAAKuhG,KAAKyC,cAIlC,YAHAz/F,GAAOlD,MAAO,2CAA0CrB,KAAKiiB,6CAC7CjiB,KAAKuhG,KAAKyC,iBAK9B,MAAMhpF,EAAU,CACZpT,KAAM89G,GAAsBE,OAC5BS,gBAAAA,GAGJrmH,KAAKk1G,aAAal6F,GAStBsrG,sBAAsBC,EAAgB1mB,GAClC,IAAK7/F,KAAKiiB,gBAAkBjiB,KAAKuhG,KAAKyC,cAIlC,YAHAz/F,GAAOlD,MAAO,+CAA8CrB,KAAKiiB,6CACjDjiB,KAAKuhG,KAAKyC,iBAK9B,MAAMhpF,EAAU,CACZpT,KAAM89G,GAAsBG,aAC5BU,eAAAA,EACA1mB,QAAAA,GAGJ7/F,KAAKk1G,aAAal6F,GAMtBiH,cACI,OAAOqlE,QAAQtnF,KAAKwmH,uBAQxBA,sBACI,OAAOxmH,KAAKuhG,KAAK7E,KAAK+pB,8BAQ1BC,mBAAmBC,GACf3mH,KAAK4mH,gBAAkBD,EAQ3BA,iBACI,OAAO3mH,KAAK4mH,gBAShBC,gBAAgB1jB,GACZnjG,KAAK8mH,aAAe3jB,EAQxB4jB,iBACI,OAAO/mH,KAAK8mH,aAQhBd,gBAAgBrhB,GACZ,OAAQA,EAAQrsE,OAChB,KAAKwtF,GACD9lH,KAAKuhG,KAAK/N,aAAa37D,KAAKoF,GAAW,WAAXA,4BAAwC0nE,EAAQ9E,SAC5E,MACJ,KAAKimB,GACD9lH,KAAKimH,OAASthB,EAAQqV,MACtBh6G,KAAKuhG,KAAK/N,aAAa37D,KAAKoF,GAAW,WAAXA,uBAAmC0nE,IAWvEuQ,aAAal6F,GACT,MAAMzZ,GAAMujH,EAAAA,GAAAA,MAAK,CAAE7F,GAAIj/G,KAAKwmH,wBAE5BjlH,EAAI4L,EAAE,iBAAkB6N,GAAS+pG,KAEjC/kH,KAAKuhG,KAAK7E,KAAKoG,WAAWwgB,KAAK/hH,ICzLvC,MAAMgD,IAAS2B,EAAAA,EAAAA,oCAOT8gH,GAAgB,QAMP,MAAMC,GAOjB7tG,YAAYmoF,GACRvhG,KAAK08F,KAAO6E,EAAK7E,KACjB18F,KAAKknH,SAAW3lB,EAEhB,MAAM4lB,EAAqBnnH,KAAKonH,oBAAoBxmH,KAAKZ,MAEzDA,KAAKknH,SAAS76E,iBACVpP,GAAW,WAAXA,mBACAkqF,GAEJnnH,KAAKknH,SAAS76E,iBACVpP,GAAW,WAAXA,yBACAkqF,GAEJnnH,KAAKknH,SAAS76E,iBACVpP,GAAW,WAAXA,iCACAkmE,IACInjG,KAAKqnH,aAAelkB,KAShClhF,cACI,OAAOjiB,KAAK08F,KAAK4qB,eAQrBvE,SACI,OAAK/iH,KAAKiiB,cAIH,IAAI8nB,SAAQ,CAACC,EAASC,KACzBjqC,KAAKknH,SAASK,gBAAe,EAAMv9E,EAASC,MAJrCF,QAAQE,OAAO,IAAIjmC,MAAM,yBAaxCu9C,UACSvhD,KAAKiiB,eAAkBjiB,KAAKknH,SAASljB,eAC9BhkG,KAAKwnH,WAAcxnH,KAAKknH,SAASO,oBAI7CznH,KAAKknH,SAASK,gBAAe,GASjCtQ,YAAYj8F,GACJhb,KAAKwnH,WACLxnH,KAAKwnH,UAAUvQ,YAAY71G,KAAKF,UAAU8Z,GAAU,gBAW5D0sG,mBAAmBriH,EAAI2V,GACfhb,KAAKwnH,WACLxnH,KAAKwnH,UAAUE,mBAAmBriH,EAAIjE,KAAKF,UAAU8Z,GAAU,gBAUvE2sG,aACI,GAAI3nH,KAAKwnH,UACL,OAAOzlB,GAAAA,QAAAA,mBAA2B/hG,KAAKwnH,UAAUI,WAWzDC,mBAAmB/8E,GACf,GAAI9qC,KAAKwnH,UAAW,CAChB,MAAMnvF,EAAU,CAACmgE,EAAex9E,KAC5B8vB,EAAS9vB,EAAS+mF,GAAAA,QAAAA,mBAA2BvJ,KAKjD,OAFAx4F,KAAKwnH,UAAUj9E,GAAGtN,GAAW,WAAXA,sBAAkC5E,GAE7CA,GAUfyvF,qBAAqBzvF,GACbr4B,KAAKwnH,WACLxnH,KAAKwnH,UAAUn6E,IAAIpQ,GAAW,WAAXA,sBAAkC5E,GAS7D0vF,QACI,OAAI/nH,KAAKwnH,UACExnH,KAAKwnH,UAAUO,QACjBnnE,MAAK,KACF5gD,KAAKwnH,eAAYz7G,EACjBxH,GAAOiH,KAAK,uBAEfw4C,OAAM,SAGRja,QAAQE,OACP,IAAIjmC,MAAM,oCAQtBgkH,gBAAgB7kB,GACZnjG,KAAKqnH,aAAelkB,EAOxBikB,sBACSpnH,KAAKiiB,eAIUjiB,KAAKknH,SAASe,QAAUjoH,KAAKknH,SAASljB,eAEvChkG,KAAKknH,SAASO,qBAAuBznH,KAAKwnH,WAEzDxnH,KAAKuJ,OACAq3C,MAAK,IAAMr8C,GAAOiH,KAAK,uBACvBw4C,OAAMj3C,GAAKxI,GAAOlD,MAAM,uBAAwB0L,KAW7DxD,KAAKyiG,EAAakc,GACd,MAAMlkB,EAAchkG,KAAKknH,SAASe,QAAUjoH,KAAKknH,SAASljB,cAE1D,IAAKhkG,KAAKqnH,aACN,OAAOt9E,QAAQE,OAAO,IAAIjmC,MAAM,kDAGpC,MAAMyzB,EAAWsqE,GAAAA,QAAAA,eAAuB/hG,KAAKqnH,cACvCc,EAAepmB,GAAAA,QAAAA,iBAAyB/hG,KAAKqnH,cAuHnD,OArHArnH,KAAKwnH,UAAYxnH,KAAK08F,KAAK0rB,WACvB3wF,EAAU,CACN0wF,aAAAA,EACAE,kBAAkB,EAClBC,cAAc,EACdC,aAAa,IAIjBvc,GAEAhsG,KAAKwnH,UAAU7M,uBAAuB,OAAQ,CAC1C96F,WAAY,CAAEzL,MAAO,mCACrBjN,MAAO6kG,IAIXhI,GACAhkG,KAAKwnH,UAAU5iB,oBAAoBoiB,IAAe,CAAC/zG,EAAM4rF,KACrD7+F,KAAKknH,SAAS1zB,aAAa37D,KAAKoF,GAAW,WAAXA,yBAAqC4hE,EAAM,CAAEqpB,MAAOj1G,EAAK9L,WAE7FnH,KAAKwnH,UAAUn7E,iBACXpP,GAAW,WAAXA,mBAEA,CAAC4hE,EAAM2pB,EAAMj0C,EAAMk0C,EAAgBxc,EAAShd,EAAQid,EAAUwc,EAASvlB,KAEnE,IAAI/iG,OAAOkJ,OAAOtJ,KAAKknH,SAASyB,SAAStgH,MAAKlE,GAAKA,EAAEg/F,MAAQA,IAA7D,CAKA,IAAK,MAAM5B,KAAQnhG,OAAOkJ,OAAOtJ,KAAKknH,SAAS0B,mBAAmB3C,QAC9D,GAAI7lH,OAAOkJ,OAAOi4F,EAAKiJ,cAAcniG,MAAK2E,GAAKA,EAAEm2F,MAAQA,IACrD,OAMRnjG,KAAKknH,SAAS1zB,aAAa37D,KACvBoF,GAAW,WAAXA,wBACA8kE,GAAAA,QAAAA,mBAA2BlD,GAC3B2pB,EACAtc,EAAWA,EAAS2c,YAAS98G,OAGzC/L,KAAKwnH,UAAUn7E,iBACXpP,GAAW,WAAXA,iBAA4B4hE,IAGxB7+F,KAAKknH,SAAS1zB,aAAa37D,KACvBoF,GAAW,WAAXA,sBACA8kE,GAAAA,QAAAA,mBAA2BlD,OAGvC7+F,KAAKwnH,UAAUn7E,iBACXpP,GAAW,WAAXA,eACA,KAEI78B,OAAOC,KAAKL,KAAKwnH,UAAUmB,SACtBpoH,SAAQyK,GAAKhL,KAAKknH,SAAS1zB,aAAa37D,KACrCoF,GAAW,WAAXA,sBAAkC8kE,GAAAA,QAAAA,mBAA2B/2F,MAErEhL,KAAKwnH,UAAUsB,QAEf9oH,KAAKwnH,eAAYz7G,EACjBxH,GAAOiH,KAAK,oCAIpBxL,KAAKwnH,UAAUn7E,iBAAiBpP,GAAW,WAAXA,QAAmB8rF,IAC/C,GAAIA,EAKA,OAJA/oH,KAAKknH,SAAS1zB,aAAa37D,KAAKoF,GAAW,WAAXA,wBAEhCj9B,KAAKwnH,UAAUsB,WASvB9oH,KAAKknH,SAAS76E,iBACVpP,GAAW,WAAXA,yBACA,CAAC4iE,EAAShB,EAAM0F,EAAKykB,KACjBzkH,GAAOynF,MAAO,6BAA4B6T,KAAWhB,KAAQ0F,KACzD1E,IAAY7/F,KAAKknH,SAASjkB,SAE1BjjG,KAAKknH,SAAS39G,KAAKy/G,MAG/BhpH,KAAKwnH,UAAUn7E,iBACXpP,GAAW,WAAXA,eACA,CAAC1E,EAAQ4qE,KAGDA,EACAnjG,KAAKknH,SAAS39G,QAKlBvJ,KAAKwnH,UAAUsB,QAEf9oH,KAAKknH,SAAS1zB,aAAa37D,KAAKoF,GAAW,WAAXA,cAA0B1E,OAKlEv4B,KAAKknH,SAAS76E,iBACVpP,GAAW,WAAXA,YACA,KACIj9B,KAAK+nH,YAIV,IAAIh+E,SAAQ,CAACC,EAASC,KACzBjqC,KAAKwnH,UAAUn7E,iBAAiBpP,GAAW,WAAXA,YAAuB,KACnD+M,IAGIk+E,IAAUlkB,GACVhkG,KAAKwnH,UAAU7M,uBAAuBqM,GAAe,CAAE7/G,MAAO+gH,KACvDloH,KAAKwnH,UAAU/M,kBAG9Bz6G,KAAKwnH,UAAUn7E,iBAAiBpP,GAAW,WAAXA,gBAA4BgN,GAC5DjqC,KAAKwnH,UAAUn7E,iBAAiBpP,GAAW,WAAXA,+BAA2CgN,GAC3EjqC,KAAKwnH,UAAUn7E,iBAAiBpP,GAAW,WAAXA,mBAA+BgN,GAE/DjqC,KAAKwnH,UAAUj+G,UASvB0/G,WAAW5jH,GACP,IAAKrF,KAAKiiB,gBAAkBjiB,KAAKknH,SAASljB,cACtC,OAGJ,MAAMb,EAAM/iG,OAAOC,KAAKL,KAAKwnH,UAAUmB,SAClCtgH,MAAK2C,GAAK+2F,GAAAA,QAAAA,mBAA2B/2F,KAAO3F,IAE7C89F,EACAnjG,KAAKwnH,UAAU0B,KAAK/lB,GAEpB5+F,GAAOlD,MAAO,wBAAuBgE,oBAQ7C8jH,cAAc9jH,GACV,IAAKrF,KAAKiiB,gBAAkBjiB,KAAKknH,SAASljB,cACtC,OAKJ,IAAIolB,EAAcppH,KAAKknH,SAASjkB,QAE5BjjG,KAAKknH,SAAS0B,mBAAmBjC,mBACjCyC,EAAcppH,KAAKknH,SAAS0B,mBAAmB7B,kBAGnD,MAAMsC,EAAgBjpH,OAAOC,KAAKL,KAAKwnH,UAAUmB,SAC5CtgH,MAAK2C,GAAK+2F,GAAAA,QAAAA,mBAA2B/2F,KAAO3F,IAEjD,GAAIgkH,EAAe,CACf,MAAMlmB,EAAMnjG,KAAKwnH,UAAUmB,QAAQU,GAAelmB,IAC5CmmB,GACAxE,EAAAA,GAAAA,MAAK,CAAE7F,GAAImK,IACRj8G,EAAE,IAAK,CAAEiH,MAAO,wCAChBjH,EAAE,SAAU,CAAE8xG,GAAI9b,IAE3BnjG,KAAK08F,KAAKoG,WAAWugB,OAAOiG,GACxB,SACAv8G,IACIxI,GAAOlD,MAAO,4BAA2B8hG,IAAOp2F,WAGxDxI,GAAOlD,MAAO,wBAAuBgoH,8CCjZjD,MAAM9kH,IAAS2B,EAAAA,EAAAA,2CAIf,IAAIqjH,GAEAC,GAKJ,UAKI7kC,SAAUM,GAQVr7C,KAAK6/E,GACDzpH,KAAK2kF,SAAW8kC,GAAmBxkC,IAOnCykC,wBASA,OARKH,KACDA,GAAqBvpH,KAAK2kF,SAASC,QAAQ,qBACtC2kC,KACDA,GAwDhB,WACI,MAAM/vC,EAAWmwC,KAAAA,mBAIjB,OAFAplH,GAAOD,IAAI,0BAA2Bk1E,GAE/BA,EA7D0BowC,GACrB5pH,KAAK2kF,SAASG,QAAQ,oBAAqBykC,MAI5CA,IAOPM,gBACA,IAAKL,GAAY,CACb,MAAMM,EAAQ9pH,KAAK2kF,SAASC,QAAQ,aAEpC4kC,GAAaM,GAAS9pH,KAAK2kF,SAASC,QAAQ,eAExCklC,EACA9pH,KAAK2kF,SAASG,QAAQ,cAAeglC,GAC7BN,KACRA,GA+ChB,WACI,MAAMO,EAWCC,KAAQA,KAAQA,KAAQA,KAP/B,OAFAzlH,GAAOD,IAAI,eAAgBylH,GAEpBA,EApDkBE,GACbjqH,KAAK2kF,SAASG,QAAQ,cAAe0kC,KAI7C,OAAOA,IAOPrwC,gBAGA,OAAOn5E,KAAK2kF,SAASC,QAAQ,cAO7BzL,cAAUA,GACNA,EACAn5E,KAAK2kF,SAASG,QAAQ,YAAa3L,GAEnCn5E,KAAK2kF,SAASK,WAAW,eAuCrC,SAASglC,KACL,MAAQ,GAAE//G,KAAKE,SAAS+W,SAAS,eAAe7c,OAAO,EAAG,GCxH9D,MAAM04B,GACAvD,EAAQ,MACNyD,WAAUA,IAAKzD,EAAQ,KACzBhB,GAAuBgB,EAAQ,IAE/Bj1B,IAAS2B,EAAAA,EAAAA,wCAMf,SAASgkH,GAAsBC,GAC3B,IAAIloH,EAAQ,EAEZ,OAAO,SAAS+4C,GAEZ,GAAIA,EAGA,YAFA/4C,EAAQ,GAMZ,MAAM61D,EAAU7tD,KAAK2wB,IAAI,EAAG34B,EAAQ,GAIpC,OAFAA,GAAS,EAEF61D,EAAUqyD,GAaV,SAASC,GAAU3yF,EAAUilE,EAAM5yD,EAAS/pC,GAuBvD,SAAS+qC,EAASxS,GACd,GAAIA,EAAM7hB,MAAQ6hB,EAAM7hB,KAAK0iE,UAAW,CACpC,GAAI7gD,EAAM0Q,SAAW1mC,OAAO0M,SAASg6B,OAKjC,YAJAzkC,GAAO2T,KACF,6CACGogB,EAAM0Q,UAIlBqhF,GAASlxC,UAAY7gD,EAAM7hB,KAAK0iE,WA/BxCn5E,KAAKy3B,SAAWA,EAChBz3B,KAAKsqH,YAAc5tB,EACnB18F,KAAKuqH,eAAiBL,GAAsB,KAC5ClqH,KAAKwqH,oBAAsBN,GAAsB,KAGjDlqH,KAAKyqH,qBAAsB,EAC3BzqH,KAAKD,QAAUA,EAIfC,KAAK0qH,mBAAoB,EAEzB1qH,KAAKwzF,aAAe1pD,EAEpB9pC,KAAK8iG,WAAa9iG,KAAKsqH,YAAYxnB,WAuB/BxgG,OAAO+pC,iBACP/pC,OAAO+pC,iBAAiB,UAAWvB,GAAU,GAE7CxoC,OAAOq0C,YAAY,YAAa7L,GAMxCs/E,GAAUnpH,UAAU0pH,sBAAwB,WACxC,OAAO3qH,KAAKyqH,qBAGhBL,GAAUnpH,UAAU2pH,oBAAsB,WACtC,OAAO5qH,KAAK0qH,mBAGhBN,GAAUnpH,UAAU4pH,gBAAkB,SAAS1nB,GAG1B,UAFApB,GAAAA,QAAAA,mBAA2BoB,KAGxC5+F,GAAOiH,KACH,gDACJxL,KAAKwzF,aAAa37D,KAAKoF,GAAWw9C,cAI1C2vC,GAAUnpH,UAAU6pH,gBAAkB,SAASC,GACtC/qH,KAAKgrH,eACNhrH,KAAKgrH,aAAeD,EACpBxmH,GAAOiH,KAAM,sBAAqBxL,KAAKgrH,kBAI/CZ,GAAUnpH,UAAUgqH,gBAAkB,WAClC,OAAOjrH,KAAKgrH,cAGhBZ,GAAUnpH,UAAUiqH,kBAAoB,WAEpC,IAAIC,EAAiBnrH,KAAKD,QAAQ+iG,WAAWsoB,MAAMrpF,MAQnD,OAJKopF,IACDA,EAAkB,SAAQnrH,KAAKD,QAAQ+iG,WAAWsoB,MAAM1J,UAGrDyJ,GAGXf,GAAUnpH,UAAUoqH,mBAAqB,WAAW,UAEhD,MAAMh8E,GAAO2vE,EAAAA,GAAAA,KAAI,CAAEC,GAAIj/G,KAAKkrH,oBACxBtjH,KAAM,SAGJ,UAAEuxE,GAAckxC,GAChBiB,EAAajB,GAASR,UACtBp8G,EAASzN,KAAKD,QAAQ2+F,WAE5Bn6F,GAAOiH,KAAM,eAAc2tE,kBAA0BmyC,KAErDj8E,EAAKliC,EAAE,aAAc,CACjBiH,MAAO,kCACPmtF,KAAMvhG,KAAKy3B,SACX,cAAe6zF,IAGfnyC,GACA9pC,EAAK/5B,MAAM,CAAE,aAAc6jE,IAG/B9pC,EAAKliC,EACD,WAAY,CACRX,KAAM,aACNrF,MAAOmgF,QAAQ75E,EAAO89G,cACvBxG,UAEyBh5G,IAA5B0B,EAAO+9G,kBACPn8E,EAAKliC,EACD,WAAY,CACRX,KAAM,mBACNrF,MAAOsG,EAAO+9G,mBACfzG,KAEPt3G,EAAOg+G,cACPp8E,EAAKliC,EACD,WAAY,CACRX,KAAM,eACNrF,MAAOsG,EAAOg+G,eACf1G,KAEPt3G,EAAOi+G,YACPr8E,EAAKliC,EACD,WAAY,CACRX,KAAM,aACNrF,MAAOsG,EAAOi+G,aACf3G,UAGqCh5G,IAA5C/L,KAAKD,QAAQ2+F,WAAWoG,iBACxBz1D,EAAKliC,EACD,WAAY,CACRX,KAAM,kBACNrF,MAAOnH,KAAKD,QAAQ2+F,WAAWoG,kBAChCigB,UAEqCh5G,IAA5C/L,KAAKD,QAAQ2+F,WAAWqG,iBACxB11D,EAAKliC,EACD,WAAY,CACRX,KAAM,kBACNrF,MAAOnH,KAAKD,QAAQ2+F,WAAWqG,kBAChCggB,KASX,MAAM4G,EAAe,oBAAG3rH,KAAKD,QAAQ2+F,kBAAhB,iBAAG,EAAyBlB,iBAA5B,aAAG,EAAoCmuB,uBAAvC,SAEhBA,GACDt8E,EAAKliC,EACD,WAAY,CACRX,KAAM,kBACNrF,MAAOwkH,IACR5G,KAGX,MAAM,YAAE92B,EAAF,gBAAeC,EAAf,0BAAgC4O,EAAhC,gBAA2DD,GAAoB78F,KAAKD,QAAQ2+F,WAC5FktB,GAAqB39B,IAAgBC,IAAoB2O,IAK1B,IAA9BC,EAYP,OATI8uB,GACAv8E,EAAKliC,EACD,WAAY,CACRX,KAAM,mBACNrF,OAAQykH,IACT7G,KAEX11E,EAAK01E,KAEE11E,GAIX+6E,GAAUnpH,UAAU4qH,eAAiB,SAASC,GAE1C,MAAM3yC,EAAY5a,IAAAA,CAAEutD,GAAUzjH,KAAK,cAAcqN,KAAK,cAElDyjE,IACA50E,GAAOiH,KAAM,wBAAuB2tE,KACpCkxC,GAASlxC,UAAYA,IAI7BixC,GAAUnpH,UAAU8qH,mBAAqB,SAASD,GAE9C9rH,KAAK8qH,gBAAgBvsD,IAAAA,CAAEutD,GAAUzjH,KAAK,cAAcqN,KAAK,aAEzD,MAAMs2G,EACAztD,IAAAA,CAAEutD,GAAUzjH,KACV,6DAC+C3G,OAAS,EAEhE6C,GAAOiH,KAAM,2BAA0BwgH,KAEvChsH,KAAKyqH,oBAAsBlsD,IAAAA,CAAEutD,GAAUzjH,KACnC,2DACiD3G,OAAS,EAE9D6C,GAAOiH,KACF,oCAAmCxL,KAAKyqH,uBAExCzqH,KAAKyqH,qBAENzqH,KAAK6rH,eAAeC,GAIxB,MAAMxnB,EAAe/lC,IAAAA,CAAEutD,GAAUzjH,KAAK,eAAeqN,KAAK,YAE1D1V,KAAKwzF,aAAa37D,KAAKkF,GAAqBC,iBACxCgvF,EAAuB1nB,GAGvB/lC,IAAAA,CAAEutD,GAAUzjH,KACZ,gEACkD3G,SAClD1B,KAAK0qH,mBAAoB,GAG7BnmH,GAAOiH,KAAM,yBAAwBxL,KAAK0qH,sBAa9CN,GAAUnpH,UAAUgrH,wBAA0B,WAC1C,OAAO,IAAIliF,SAAQC,IAEfhqC,KAAK8qH,gBAAgB9qH,KAAKD,QAAQ+iG,WAAWkoB,cAG7ChrH,KAAK8iG,WAAWugB,OACZrjH,KAAKqrH,sBACL/xF,GAAUt5B,KAAKksH,gCAAgC5yF,EAAQ0Q,KACvD3oC,GAASrB,KAAKmsH,8BAA8B9qH,EAAO2oC,KAMvDhqC,KAAK8iG,WAAWrgG,YAaxB2nH,GAAUnpH,UAAUkrH,8BAAgC,SAAS9qH,EAAOub,GAGhE,MAAMwvG,EACA7tD,IAAAA,CAAEl9D,GAAOgH,KAAK,0BAA0B3G,QACnC68D,IAAAA,CAAEl9D,GAAOgH,KAAK,yBAAyB3G,OAMlD,GAJI0qH,IACA7nH,GAAOiH,KAAK,+BACZ6+G,GAASlxC,eAAYptE,GAErBwyD,IAAAA,CAAEl9D,GAAOgH,KAAK,4BAA4B3G,OAG1C,YAFA1B,KAAKwzF,aAAa37D,KAAKoF,GAAWy9C,mBAMtC,MAAM2xC,EAAiB9tD,IAAAA,CAAEl9D,GAAOgH,KAAK,4BAErC,GAAIgkH,EAAe3qH,OAAQ,CAEvB,MAAM4qH,EAAYD,EAAe32G,KAAK,cAChC62G,EAAgBhuD,IAAAA,CAAEl9D,GAAOgH,KAAK,eACpC,IAAImkH,EAUJ,OARID,IACAC,EAAWD,EAAcvqH,aAE7BhC,KAAKwzF,aAAa37D,KACdoF,GAAW+9C,kBACXsxC,EACAE,GAMR,GAAIjuD,IAAAA,CAAEl9D,GAAOgH,KAAK,yBAAyB3G,OAWvC,OAVA6C,GAAO2T,KAAK,uCAAwC7W,GACnC0gG,GAAAA,QAAAA,iBAAyB1gG,EAAMmhB,aAAa,SAE5CxiB,KAAKD,QAAQ+iG,WAAWsoB,MAAMqB,kBAG3CzsH,KAAKyqH,qBAAsB,QAE/BzqH,KAAKwzF,aAAa37D,KAAKoF,GAAW68C,yBAItC,MAAM4yC,EAAS1sH,KAAKwqH,sBACdlL,EAAU,4BAA2BoN,IAE3Cl0F,GAAqBE,iBAAiB,IAAI10B,MAAMs7G,IAChD/6G,GAAOlD,MAAMi+G,EAAQj+G,GAGrB,MAAM8pH,EAAiBnrH,KAAKkrH,oBACtByB,EAAWD,EAAS,IAKrBN,GACDpsH,KAAKwzF,aAAa37D,KACdoF,GAAWu9C,mBACX2wC,EACAwB,GAIR3sH,KAAKuqH,gBAAe,GACpBjoH,OAAOE,YACH,IAAMxC,KAAKisH,0BAA0BrrE,KAAKhkC,IAC1C8vG,IAYRtC,GAAUnpH,UAAUirH,gCAAkC,SAC9C5yF,EACA1c,GAQJ,GANA5c,KAAK+rH,mBAAmBzyF,GAGxBt5B,KAAKwqH,qBAAoB,GAG0B,SAA/CjsD,IAAAA,CAAEjlC,GAAQjxB,KAAK,cAAcqN,KAAK,SAElC1V,KAAKuqH,gBAAe,GAGpB3tG,QACG,CACH,MAAM8vG,EAAS1sH,KAAKuqH,iBAEpBhmH,GAAOiH,KAAM,4BAA2BkhH,KACxCpqH,OAAOE,YACH,IAAMxC,KAAKisH,0BAA0BrrE,KAAKhkC,IAC1C8vG,KAIZtC,GAAUnpH,UAAU2rH,aAAe,WAC/B,OAAO,IAAI7iF,SAAQ,CAACC,EAASC,KACzBjqC,KAAK8iG,WAAWugB,OACZrjH,KAAKqrH,sBACL/xF,IACIt5B,KAAK6rH,eAAevyF,GACpB0Q,OAEJ6iF,GAAW5iF,EAAO,CACd5oC,MAAOk9D,IAAAA,CAAEsuD,GAASxkH,KAAK,mBAClB8jB,KAAK,WACVnR,QAASujD,IAAAA,CAAEsuD,GAASxkH,KAAK,iBACpBrG,eAMrBooH,GAAUnpH,UAAU6rH,YAAc,SAASC,EAAaC,GACpDhtH,KAAKitH,cAAyB,EAAOF,EAAaC,IAUtD5C,GAAUnpH,UAAUgsH,aAAe,SAASC,EAAOC,EAAOC,GACtD,MAAMrO,GAAKC,EAAAA,GAAAA,KAAI,CAAEC,GAAIj/G,KAAKkrH,oBACtBtjH,KAAM,QACJ0N,EAAQ,CACVlB,MAAO,kCACPmtF,KAAMvhG,KAAKy3B,SACX,cAAe4yF,GAASR,WAE5B,IAAIl8G,EAAM,WAeV,SAASw/E,EAAYmyB,EAAQ72E,GACzBjQ,GAAqBE,iBAAiB,IAAI10B,MAAMs7G,IAChD/6G,GAAOlD,MAAMi+G,EAAQ72E,GACrB2kF,EAAU3kF,GAhBVykF,IACA53G,EAAM43G,OAAQ,EACdv/G,EAAO,SAAQA,KAEnBoxG,EAAG5xG,EAAE,YAAamI,GAclBtV,KAAK8iG,WAAWugB,OACZtE,GACAzlF,IAEI,IAAI6O,EAAMo2B,IAAAA,CAAEjlC,GAAQjxB,KAAK,aAAaqN,KAAK,OAE3CyyB,EAAMklF,mBAAmBllF,GACrBA,GACA5jC,GAAOiH,KAAM,OAAMmC,MAAQw6B,KAC3BglF,EAAMhlF,IAENglD,EAAa,iBAAgBx/E,mBAAsB2rB,KAG3D6zD,EAAYvsF,UAAKmL,EAAY,OAAM4B,aAI3Cy8G,GAAUnpH,UAAUqsH,iBAAmB,SAASP,EAAaC,GACzDhtH,KAAKitH,cAAyB,EAAMF,EAAaC,IAGrD5C,GAAUnpH,UAAUssH,OAAS,SAAS3wG,GAClC,MAAMmiG,GAAKC,EAAAA,GAAAA,KAAI,CAAEC,GAAIj/G,KAAKkrH,oBACtBtjH,KAAM,SACJ,UAAEuxE,GAAckxC,GAEjBlxC,GAKL4lC,EAAG5xG,EAAE,SAAU,CACXiH,MAAO,kCACP,aAAc+kE,IAElBn5E,KAAK8iG,WAAWugB,OACZtE,GACAzlF,IAEI,IAAIk0F,EAAYjvD,IAAAA,CAAEjlC,GAAQjxB,KAAK,UAAUqN,KAAK,cAE1C83G,IACAA,EAAYH,mBAAmBG,IAEnCjpH,GAAOiH,KAAM,oBAAmBgiH,IAAal0F,GAC7C+wF,GAASlxC,eAAYptE,EACrB6Q,EAAS4wG,MAEbnsH,IACI,MAAMi+G,EAAS,eAEf9mF,GAAqBE,iBAAiB,IAAI10B,MAAMs7G,IAChD/6G,GAAOlD,MAAMi+G,EAAQj+G,OAzBzBub,KC1fR,MAAMrY,IAAS2B,EAAAA,EAAAA,uCAEFkI,GAAS,CAClBq/G,YAAYC,EAAYvkE,GACpB,IAAK,MAAM9rC,KAAS3Y,MAAMm6F,KAAK6uB,EAAWvuE,UAAW,CACjD,MAAMlsC,EAAO,CACT4M,WAAY,GACZs/B,SAAU,GACVjpC,QAASmH,EAAMnH,SAGnB,IAAK,MAAMR,KAAQhR,MAAMm6F,KAAKxhF,EAAMwC,YAChC5M,EAAK4M,WAAWnK,EAAKlJ,MAAQkJ,EAAKvO,MAEtC,MAAMnF,EAAO+/F,GAAAA,QAAAA,QAAgB1kF,GAEzBrb,IAIAiR,EAAK9L,MAAQ46F,GAAAA,QAAAA,YAAoB//F,IAErCmnD,EAAMjnD,KAAK+Q,GACXjT,KAAKytH,YAAYpwG,EAAOpK,EAAKksC,YAGrCwuE,YAAYxkE,EAAOykE,GACf,IAAK,IAAIpsH,EAAI,EAAGA,EAAI2nD,EAAMznD,OAAQF,IAAK,CACnC,MAAMyR,EAAOk2C,EAAM3nD,GAEfyR,IACA26G,EAAOzgH,EAAE8F,EAAKiD,QAASjD,EAAK4M,YACxB5M,EAAK9L,OACLymH,EAAO5oH,EAAEiO,EAAK9L,OAEd8L,EAAKksC,UACLn/C,KAAK2tH,YAAY16G,EAAKksC,SAAUyuE,GAEpCA,EAAO7I,SAchB,SAAS8I,GAA2BhK,EAAM/jG,GAC7C,MAAM45F,EAAM,GAEZ,IAAK,IAAIl4G,EAAI,EAAGA,EAAIqiH,EAAKniH,OAAQF,IACzBqiH,EAAKriH,GAAG0U,UAAY4J,GACpB45F,EAAIx3G,KAAK2hH,EAAKriH,IAItB,OAAOk4G,EAWX,MAAMoU,GAAuB,CAAE,QAAS,QAAS,UAKlC,MAAMC,WAAiBpe,GAmBlCv2F,YAAY0pF,EAAYK,EAAKtoD,EAAUmzE,EAAMjuH,GACzCmlF,QACAllF,KAAK08F,KAAOsxB,EACZhuH,KAAK8iG,WAAaA,EAClB9iG,KAAKijG,QAAUlB,GAAAA,QAAAA,kBAA0BoB,GACzCnjG,KAAK4nH,UAAYzkB,EACjBnjG,KAAK66C,SAAWA,EAChB76C,KAAKiuH,oBAAqB,EAC1B1pH,GAAOiH,KAAM,iBAAgBxL,KAAK4nH,aAClC5nH,KAAK2oH,QAAU,GACf3oH,KAAKkuH,QAAU,GACfluH,KAAKmuH,aAAe,GACpBnuH,KAAKouH,qBAAuB,GAC5BpuH,KAAKioH,QAAS,EACdjoH,KAAKquH,mBAAoB,EACzBruH,KAAKu0E,KAAO,KACZv0E,KAAKsuH,YAAc,KACnBtuH,KAAKuuH,mBAAoB,EACzBvuH,KAAKD,QAAUA,GAAW,GAC1BC,KAAKwuH,UACC,IAAIpE,GAAUpqH,KAAKijG,QAASjjG,KAAK08F,KAAM18F,KAAKwzF,aAAc,CACxDsP,WAAY9iG,KAAK08F,KAAK38F,QACtB2+F,WAAY1+F,KAAKD,gBAEe,IAA7BC,KAAKD,QAAQwoH,aAA+BvoH,KAAKD,QAAQwoH,eAChEvoH,KAAKyuH,MAAQ,IAAIxH,GAAMjnH,OAE3BA,KAAK0uH,aAAe,IAAIpK,GAAatkH,MACrCA,KAAK2uH,cAAgB,IAAI5I,GAAc/lH,MACvCA,KAAK4uH,gBAAgB7uH,GACrBC,KAAK6uH,cAAgB,GACrB7uH,KAAK8uH,YAAc,KACnB9uH,KAAK+uH,SAAW,KAChB/uH,KAAK4iG,gBAAkB,GACvB5iG,KAAKgvH,4BAA8B,KAEnChvH,KAAKmhD,QAAS,EACdnhD,KAAKivH,oBAAsB9K,GAQ/ByK,kBAA8B,IAAd7uH,EAAc,uDAAJ,GACtBC,KAAKkuH,QAAQjP,GAAKj/G,KAAK4nH,UACvB5nH,KAAKkuH,QAAQgB,IAAM,iCACnBlvH,KAAKkuH,QAAQ/kE,MAAQ,GAEjBppD,EAAQovH,SACRnvH,KAAKkuH,QAAQ/kE,MAAMjnD,KAAK,CACpB,QAAW,WACX,MAASnC,EAAQovH,UAIzBnvH,KAAKovH,mBAAqBjqH,KAAK8nD,MASnC1jD,KAAKsxC,EAAUozE,GAIX,OAHAjuH,KAAK66C,SAAWA,EAChB76C,KAAKiuH,mBAAqBA,EAEnB,IAAIlkF,SAAQC,IACfhqC,KAAKD,QAAQuoH,cACN/jH,GAAOiH,KAAM,iCAAgCxL,KAAKijG,YAGnDjjG,KAAKD,QAAQuoH,aACTv+E,QAAQC,UACRhqC,KAAKwuH,UAAUvC,2BAEjBrrE,MAAK,KACT5gD,KAAKy6G,cAAa,GAClBz6G,KAAKouH,qBAAqBlsH,KACtBlC,KAAK8iG,WAAWz2D,iBACZyzE,GAAe38B,OAAO48B,oBACtB//G,KAAKqvH,oBAAoBzuH,KAAKZ,QAEtCgqC,UASZywE,aAAa6U,GACT,MAAMrQ,EAAKj/G,KAAKkuH,QAAQjP,GAExB,IAAKj/G,KAAK8iG,aAAe9iG,KAAK8iG,WAAW4a,YAAcuB,IAAQj/G,KAAKioH,SAAWqH,EAE3E,OAGJ,MAAMzL,GAAOC,EAAAA,GAAAA,OAAM,CAAE7E,GAAAA,IAOjBqQ,IACItvH,KAAKiuH,oBACLpK,EAAK12G,EAAE,eAAe43G,KAG1BlB,EAAK12G,EAAE,IAAK,CAAEiH,MAAOpU,KAAKkuH,QAAQgB,MAE9BlvH,KAAK66C,UACLgpE,EAAK12G,EAAE,YAAYnI,EAAEhF,KAAK66C,UAAUkqE,KAEpC/kH,KAAKD,QAAQwvH,WACb1L,EAAK12G,EAAE,aAAanI,EAAEhF,KAAKD,QAAQwvH,WAAWxK,KAGlDlB,EAAKkB,MAGT32G,GAAOu/G,YAAY3tH,KAAKkuH,QAAQ/kE,MAAO06D,GAGvC7jH,KAAKwvH,iBAAmBrqH,KAAK8nD,MAE7BjtD,KAAK8iG,WAAWwgB,KAAKO,GACjByL,GAKAtvH,KAAK8iG,WAAWrgG,QAQxBugG,UACIz+F,GAAOD,IAAI,WAAYtE,KAAK4nH,WAC5B,MAAM/D,GAAOC,EAAAA,GAAAA,OAAM,CAAE7E,GAAIj/G,KAAK4nH,UAC1BhgH,KAAM,gBAEV5H,KAAKkuH,QAAQxsH,OAAS,GAerB1B,KAAK8iG,WAAWwe,kBAAoBthH,KAAK8iG,WAAWrgG,QACrDzC,KAAK8iG,WAAWwgB,KAAKO,GACrB7jH,KAAK8iG,WAAWrgG,QAMpBgtH,gBAGI,MAAMC,GACA1Q,EAAAA,GAAAA,KAAI,CACFp3G,KAAM,MACNq3G,GAAIj/G,KAAKijG,UAER91F,EAAE,QAAS,CAAEiH,MAAO2tF,GAAAA,QAAAA,GAAAA,aAE7B/hG,KAAK8iG,WAAWugB,OAAOqM,GAASp2F,IAC5B,MAAM6nB,EAGM,IAFNod,IAAAA,CAAEjlC,GAAQjxB,KAAK,+CACZ3G,OAGLy/C,IAAWnhD,KAAKmhD,SAChBnhD,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,iBAA6BkkB,GACpDnhD,KAAKmhD,OAASA,GAGlB,MAAMwuE,EACApxD,IAAAA,CAAEjlC,GAAQjxB,KAAK,qEAEjBsnH,EAAejuH,OACf1B,KAAK4vH,aAAaD,EAAe3tH,QAEjCuC,GAAO2T,KAAK,8BAGhB,MAAM23G,EAAiF,IAAnEtxD,IAAAA,CAAEjlC,GAAQjxB,KAAK,yCAAyC3G,OAEtEouH,EACAvxD,IAAAA,CAAEjlC,GAAQjxB,KAAK,qEAEjBrI,KAAKyuH,OACLzuH,KAAKyuH,MAAMzG,gBAAgB8H,GAAkBA,EAAepuH,OAASouH,EAAe9tH,YAAS+J,GAGjG,MAAMgkH,EACAxxD,IAAAA,CAAEjlC,GAAQjxB,KAAK,sEACfs+G,EAAiBr/B,QAAQyoC,MAAAA,OAAD,EAACA,EAAiB/tH,QAEhDhC,KAAK2uH,cAAcjI,mBAAmBC,GAEtC,MAAMqJ,EACAzxD,IAAAA,CAAEjlC,GAAQjxB,KAAK,8EAEjB2nH,MAAAA,GAAAA,EAAuBtuH,QACvB1B,KAAK2uH,cAAc9H,gBAAgBmJ,EAAsBhuH,QAGzD6tH,IAAgB7vH,KAAKynH,qBACrBznH,KAAKynH,mBAAqBoI,EAC1B7vH,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,yBAAqC4yF,OAGjExuH,IACCm3B,KAAAA,iBAAsCn3B,GACtCkD,GAAOlD,MAAM,4BAA6BA,MAUlDuuH,aAAaK,GACLjwH,KAAKiwH,YAAcA,IACfjwH,KAAKiwH,WACL1rH,GAAO2T,KAAM,2BAA0BlY,KAAKiwH,gBAAgBA,KAEhEjwH,KAAKiwH,UAAYA,EACjBjwH,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,eAA2BgzF,IAO1DC,yBAGI,GAAIlwH,KAAKD,QAAQsoH,iBACb,OAGJ,MAAM8H,GAAUnR,EAAAA,GAAAA,KAAI,CAAEp3G,KAAM,MACxBq3G,GAAIj/G,KAAKijG,UACR91F,EAAE,QAAS,CAAEiH,MAAO,yCACpBjH,EAAE,IAAK,CAAEiH,MAAO,gBACbxM,KAAM,WAEd5H,KAAK8iG,WAAWugB,OAAO8M,GAASC,IAC5B,IAAK7xD,IAAAA,CAAE6xD,GAAM/nH,KACL,qEACwC3G,OAAQ,CACpD,MAAM49G,EAAS,oCAKf,OAHA9mF,KAAAA,iBAAsC,IAAIx0B,MAAMs7G,SAChD/6G,GAAOlD,MAAMi+G,GAKjB,MAAM+Q,GAAarR,EAAAA,GAAAA,KAAI,CAAEC,GAAIj/G,KAAKijG,QAC9Br7F,KAAM,QACLuF,EAAE,QAAS,CAAEiH,MAAO,yCAEzBi8G,EAAWljH,EAAE,IAAK,CAAEiH,MAAO,gBACvBxM,KAAM,WAEVyoH,EAAWljH,EAAE,QAAS,CAAE,IAAO,cAC1BA,EAAE,SACFnI,EAAE,6CAA6C+/G,KAAKA,KAEzDsL,EAAWljH,EAAE,QAAS,CAAE,IAAO,yBAC1BA,EAAE,SAASnI,EAAE,UAAU+/G,KAAKA,KAEjC/kH,KAAK8iG,WAAWugB,OAAOgN,MAExBhvH,IACCm3B,KAAAA,iBAAsCn3B,GACtCkD,GAAOlD,MAAM,0CAA2CA,MAShEguH,oBAAoBpgC,GAEZA,IAAW6wB,GAAeG,OAAOqQ,WACjCtwH,KAAKy6G,eAQb8V,WAAW1M,GACP,MAAMhlB,EAAOglB,EAAKrhG,aAAa,QACzBguG,EAAS,GACTC,EAAW5M,EAAKz/F,qBAAqB,UAAU,GAEjDqsG,IACAD,EAAOvhC,OAASwhC,EAASn4E,aAAe,IAE5C,IAAIo4E,GAAkB,EAClBC,GAAmB,EACvB,MAAMC,EACA/M,EAAKx/F,uBACH,sCAAuC,KAAK,GAC9CwsG,EACAD,GAAYA,EAASxsG,qBAAqB,QAAQ,GAExDosG,EAAOM,qBACDjN,EAAKz/F,qBAAqB,eAAe1iB,OAE/C8uH,EAAOO,YACDF,GAAeA,EAAYruG,aAAa,eAC9CguG,EAAOj8C,KAAOs8C,GAAeA,EAAYruG,aAAa,QAGtD,MAAM2gF,EAAM0tB,GAAeA,EAAYruG,aAAa,OAEpDguG,EAAOrtB,IAAMA,EACbqtB,EAAOQ,QACD7tB,GAA+D,IAAxDA,EAAI9/F,QAAS,GAAErD,KAAKwuH,UAAUvD,sBAC3CuF,EAAO/H,eACDtlB,GAAOA,EAAI9/F,QAAQ,KAAO,GACrBrD,KAAKD,QAAQkxH,eACR9tB,EAAIhzF,UAAUgzF,EAAI9/F,QAAQ,KAAO,EAAG8/F,EAAI9/F,QAAQ,MAEhErD,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,kBAA8B,CACjDi0F,iBAAkBV,EAAO/H,eACzB0I,SAAUtN,IAGd,MAAMuN,EAAMvN,EAAK5T,cAAc,KAE3BmhB,GACAA,EAAIp0G,SAGR,MAAMmsC,EAAQ,GAEd/6C,GAAOq/G,YAAY5J,EAAM16D,GACzBnpD,KAAK6uH,cAAchwB,GAAQ11C,EAI3B,MAAMkoE,EAA6Bp+G,IAC/B,MAAMi5F,EAAW,GACXolB,EAAWr+G,EAAKksC,SAAS92C,MAAK8E,GAAmB,SAAdA,EAAE+I,UAE3C,GAAIo7G,EAAU,CACVplB,EAAS4B,KAAO,GAChB,MAAMyjB,EAAO,CAAE,KAAM,OAAQ,UAEzBvxH,KAAKD,QAAQyxH,kCACbD,EAAKrvH,KAAK,wBAGd,IAAK,MAAM80C,KAAOu6E,EAAM,CACpB,MAAMl0G,EACAi0G,EAASnyE,SAAS92C,MAAK8E,GAAKA,EAAE+I,UAAY8gC,IAE5C35B,IACA6uF,EAAS4B,KAAK92D,GAAO35B,EAAMlW,QAIvC,MAAMsqH,EAAYx+G,EAAKksC,SAAS92C,MAAK8E,GAAmB,UAAdA,EAAE+I,UAM5C,OAJIu7G,IACAvlB,EAAS5jG,MAAQmpH,EAAUtqH,OAGxB+kG,GAGX,IAAK,IAAI1qG,EAAI,EAAGA,EAAI2nD,EAAMznD,OAAQF,IAAK,CACnC,MAAMyR,EAAOk2C,EAAM3nD,GAEnB,OAAQyR,EAAKiD,SACb,IAAK,MAAO,CACR,MAAM,WAAE2J,GAAe5M,EAEvB,IAAK4M,EACD,MAEJ,MAAM,KAAEjY,GAASiY,EAEjB2wG,EAAO9H,QAAU9gH,EACjB,MAEJ,IAAK,OACD4oH,EAAOhI,KAAOv1G,EAAK9L,MACnB,MACJ,IAAK,SACDqpH,EAAOnrH,GAAK4N,EAAK9L,MACjB,MACJ,IAAK,WACDqpH,EAAOvkB,QAAUh5F,EAAK9L,MACtB,MACJ,IAAK,WACDqpH,EAAOtkB,SAAWmlB,EAA2Bp+G,GAC7C,MACJ,IAAK,WACDu9G,EAAO5uB,SAAW5hG,KAAK0xH,iBAAiBz+G,GACxC,MAEJ,IAAK,OAAQ,CACT,MAAM,WAAE4M,GAAe5M,EAEvB,IAAK4M,EACD,MAEJ,MAAM,KAAErT,GAASqT,EAEJ,YAATrT,IACAgkH,EAAOv/G,QAAU4O,EAAW1Y,OAEhC,QAKR,IAAKnH,KAAKioH,SAAWjoH,KAAKquH,kBAAmB,CACzC,MAAMphE,EAAMjtD,KAAK4iG,gBAAgB,oBAAsBtgG,OAAOijG,YAAYt4C,MAE1E1oD,GAAOD,IAAI,6BAA8B2oD,GAEzCjtD,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,sBACvBj9B,KAAKquH,mBAAoB,EAG7B,GAAIxvB,IAAS7+F,KAAK4nH,UAAW,CACzB,MAAMzZ,EACuB,UAAvBqiB,EAAOO,YAA0BP,EAAOj8C,KAAO,OAQrD,GANIv0E,KAAKu0E,OAAS45B,IACdnuG,KAAKu0E,KAAO45B,EACZnuG,KAAKwzF,aAAa37D,KACdoF,GAAW,WAAXA,mBACAj9B,KAAKu0E,QAERv0E,KAAKioH,OAAQ,CACdjoH,KAAKioH,QAAS,EACd,MAAMh7D,EAAMjtD,KAAK4iG,gBAAgB,cAC3BtgG,OAAOijG,YAAYt4C,MAEzB1oD,GAAOD,IAAI,uBAAwB2oD,GAG/BjtD,KAAK66C,WACL76C,KAAKmhD,QAAS,GAMdnhD,KAAKovH,oBAAsBpvH,KAAKwvH,kBAChCxvH,KAAKy6G,eAGTz6G,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,aAItBj9B,KAAKD,QAAQsoH,kBAAoBroH,KAAKyvH,sBAExC,QAAY1jH,IAARo3F,EACP5+F,GAAOiH,KAAK,2CACT,QAA2BO,IAAvB/L,KAAK2oH,QAAQ9pB,GAEpB7+F,KAAK2oH,QAAQ9pB,GAAQ2xB,EACrBjsH,GAAOD,IAAI,UAAWu6F,EAAM2xB,GAC5BE,OAAoC3kH,IAAlBykH,EAAOvhC,OACzB0hC,OAAsC5kH,IAAnBykH,EAAOv/G,QACtBu/G,EAAOQ,QACPhxH,KAAK2xH,WAAW9yB,EAAM2xB,EAAO5uB,WAK7B5hG,KAAKwzF,aAAa37D,KACdoF,GAAW,WAAXA,kBACA4hE,EACA2xB,EAAOhI,KACPgI,EAAOj8C,KACPi8C,EAAO/H,eACP+H,EAAOvkB,QACPukB,EAAOvhC,OACPuhC,EAAOtkB,SACPskB,EAAO9H,QACP8H,EAAOrtB,IACPqtB,EAAO5uB,SACP4uB,EAAOM,sBAIXJ,GAAkB,OAEnB,CAGH,MAAMkB,EAAe5xH,KAAK2oH,QAAQ9pB,GAE9B+yB,EAAar9C,OAASi8C,EAAOj8C,OAC7Bq9C,EAAar9C,KAAOi8C,EAAOj8C,KAC3Bv0E,KAAKwzF,aAAa37D,KACdoF,GAAW,WAAXA,iBAA6B4hE,EAAM2xB,EAAOj8C,OAI9Cq9C,EAAab,cAAgBP,EAAOO,cACpCa,EAAab,YAAcP,EAAOO,aAIlCa,EAAalJ,UAAY8H,EAAO9H,UAChCkJ,EAAalJ,QAAU8H,EAAO9H,QAC9B1oH,KAAKwzF,aAAa37D,KACdoF,GAAW,WAAXA,4BACA4hE,EACA2xB,EAAO9H,UAGX8H,EAAOQ,UAePY,EAAaZ,SAAU,EACvBhxH,KAAK2xH,WAAW9yB,EAAM2xB,EAAO5uB,WAI7B4uB,EAAOxkB,cACP4lB,EAAa5lB,YAAcwkB,EAAOxkB,aAIlC4lB,EAAa3iC,SAAWuhC,EAAOvhC,SAC/ByhC,GAAkB,EAClBkB,EAAa3iC,OAASuhC,EAAOvhC,QAG7B2iC,EAAa3gH,UAAYu/G,EAAOv/G,UAChC0/G,GAAmB,EACnBiB,EAAa3gH,QAAUu/G,EAAOv/G,SAG7B8lG,IAAAA,CAAQ6a,EAAahwB,SAAU4uB,EAAO5uB,YACvCgwB,EAAahwB,SAAW4uB,EAAO5uB,SAC/B5hG,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,6BAAyC4hE,EAAM2xB,EAAO5uB,WAMrF,IAAK,IAAIpgG,EAAI,EAAGA,EAAI2nD,EAAMznD,OAAQF,IAAK,CACnC,MAAMyR,EAAOk2C,EAAM3nD,GAEnB,OAAQyR,EAAKiD,SACb,IAAK,OACD,IAAKs6G,EAAOQ,QAAS,CACjB,MAAMhlB,EACAhsG,KAAK08F,KAAK38F,QAAQ8xH,YACd9vB,GAAAA,QAAAA,mBAA2BlD,GAC3B2xB,EAAOhI,KAEjBxoH,KAAKwzF,aAAa37D,KACdoF,GAAW,WAAXA,qBACA4hE,EACAmN,GAER,MACJ,IAAK,qBACGwkB,EAAOQ,UAAYhxH,KAAKuuH,oBACxBvuH,KAAKuuH,mBAAoB,EACzBvuH,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,cAE3B,MACJ,IAAK,wBACD,GAAIuzF,EAAOQ,QAAS,CAChB,MAAMrmC,EAAa,GAEnB,IAAK,IAAI3/E,EAAI,EAAGA,EAAIiI,EAAKksC,SAASz9C,OAAQsJ,IAAK,CAC3C,MAAM,WAAE6U,GAAe5M,EAAKksC,SAASn0C,GAEjC6U,GAAcA,EAAW3R,MACzBy8E,EAAW9qE,EAAW3R,KAAO2R,EAAW1Y,OAIhDnH,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,8BAA0C0tD,QAIjB,IAArC3qF,KAAK8xH,8BACZ9xH,KAAK8xH,4BAA0E,SAA5CnnC,EAAW,6BAC9CpmF,GAAOiH,KAAM,yCAAwCxL,KAAK+xH,iCAGlE,MACJ,IAAK,uBAAwB,CACzB,MAAM,WAAElyG,GAAe5M,EAEvB,IAAK4M,EACD,MAGJ,MAAM,OAAEovE,GAAWpvE,EAEfovE,GAAUA,IAAWjvF,KAAKivH,sBAC1BjvH,KAAKivH,oBAAsBhgC,EAC3BjvF,KAAKwzF,aAAa37D,KACdoF,GAAW,WAAXA,6BACAgyD,IAKR,MAEJ,IAAK,eAAgB,CACjB,MAAM+iC,EAAM/+G,EAAK4M,WAEjB,IAAKmyG,EACD,MAEJhyH,KAAK8uH,YAAckD,EAAIC,OAAS,KAChCjyH,KAAK+uH,SAAWiD,EAAIE,KAAO,KAC3BlyH,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,sBACvB,MAEJ,QACIj9B,KAAKmyH,YAAYl/G,EAAM4rF,IAK3B6xB,GACA1wH,KAAKwzF,aAAa37D,KACdoF,GAAW,WAAXA,gBACA4hE,EACA2xB,EAAOvhC,QAGX0hC,GACApsH,GAAOiH,KAAM,wBAAuB23F,MAAQqtB,EAAOv/G,WAU3DygH,iBAAiBz+G,GACb,MAAM2uF,EAAW,IAAIt7B,IAErB,IAAK,IAAIt7D,EAAI,EAAGA,EAAIiI,EAAKksC,SAASz9C,OAAQsJ,IAAK,CAC3C,MAAM,WAAE6U,GAAe5M,EAAKksC,SAASn0C,GAEjC6U,GAAcA,EAAWuyG,KACzBxwB,EAASjiD,IAAI9/B,EAAWuyG,KAIhC,OAAOxwB,EAQX+vB,WAAW9yB,EAAM+C,GACb5hG,KAAKsuH,YAAczvB,EACnB7+F,KAAKqyH,cAAgBzwB,EAOzB4B,+BAA+B14D,GAC3B9qC,KAAKgvH,4BAA8BlkF,EAOvCinF,6BACI,OAAO/xH,KAAK8xH,4BAQhBK,YAAYl/G,EAAM4rF,GAGd,IACI,IAAIyzB,EAActyH,KAAKmuH,aAAal7G,EAAKiD,SAErCjD,EAAKiD,QAAQwqG,WAAW,wBACxB4R,EAAc,CAAEtyH,KAAKgvH,8BAGrBsD,GACAA,EAAY/xH,SAAQ83B,IAChBA,EAAQplB,EAAM8uF,GAAAA,QAAAA,mBAA2BlD,GAAOA,MAG1D,MAAO9xF,GACLyrB,KAAAA,iBAAsCzrB,GACtCxI,GAAOlD,MAAO,oBAAmB4R,EAAKiD,gBAAiBnJ,IAS/DkqG,YAAYj8F,EAASu3G,GACjB,MAAMhxH,GAAMujH,EAAAA,GAAAA,MAAK,CAAE7F,GAAIj/G,KAAKijG,QACxBr7F,KAAM,cAKU,SAAhB2qH,EACAhxH,EAAI4L,EAAEolH,EAAa,GAAIv3G,GAEvBzZ,EAAI4L,EAAEolH,EAAa,CAAEn+G,MAAO,4BAA8B4G,GAG9Dhb,KAAK8iG,WAAWwgB,KAAK/hH,GACrBvB,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,qBAAiCjiB,GAU5D0sG,mBAAmBriH,EAAI2V,EAASu3G,GAC5B,MAAMhxH,GAAMujH,EAAAA,GAAAA,MAAK,CAAE7F,GAAK,GAAEj/G,KAAKijG,WAAW59F,IACtCuC,KAAM,SAKU,SAAhB2qH,EACAhxH,EAAI4L,EAAEolH,EAAav3G,GAAS+pG,KAE5BxjH,EAAI4L,EAAEolH,EAAa,CAAEn+G,MAAO,4BAA8B4G,GACrD+pG,KAGT/kH,KAAK8iG,WAAWwgB,KAAK/hH,GACrBvB,KAAKwzF,aAAa37D,KACdoF,GAAW,WAAXA,6BAAyCjiB,GAQjDw3G,WAAWrM,GACP,MAAM5kH,GAAMujH,EAAAA,GAAAA,MAAK,CAAE7F,GAAIj/G,KAAKijG,QACxBr7F,KAAM,cAEVrG,EAAI4L,EAAE,UAAWg5G,GACjBnmH,KAAK8iG,WAAWwgB,KAAK/hH,GASzBkxH,kBAAkBtvB,EAAKuvB,UACZ1yH,KAAK6uH,cAAc1rB,GAEtBuvB,IAIJ1yH,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,gBAA4BkmE,GAEnDnjG,KAAKwuH,UAAU3D,gBAAgB1nB,IAQnCwvB,sBAAsB9O,EAAMhlB,GAExB,GAAItgC,IAAAA,CAAEslD,GAAMx7G,KAAK,8CAA8C3G,OAC3D,OAAO,EAIX,MAAMkxH,EAAgBr0D,IAAAA,CAAEslD,GAAMx7G,KAAK,2DAEnC,GAAIuqH,EAAclxH,OAAQ,CACtB,IAAI62B,EACJ,MAAMs6F,EACAt0D,IAAAA,CAAEslD,GAAMx7G,KACN,kEAUR,OAPIwqH,EAAanxH,SACb62B,EAASs6F,EAAa7wH,QAG1BhC,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,cAA0B1E,EAAQq6F,EAAcl9G,KAAK,QAC5E1V,KAAK8iG,WAAWC,KAAKC,QAAQhjG,KAAKijG,UAE3B,EAIX,MAAM8lB,EACAxqD,IAAAA,CAAEslD,GACCx7G,KACG,sEAEH3G,OACHoxH,EACAv0D,IAAAA,CAAEslD,GACCx7G,KACG,sEAEH3G,OACHqxH,EAAc3yH,OAAOC,KAAKL,KAAK2oH,SAC/BmI,EAAuBvyD,IAAAA,CAAEslD,GAAMx7G,KAAK,eAAe3G,OAEzD,GAAIoxH,EAAQ,CACR,MAAME,EACAz0D,IAAAA,CAAEslD,GACHx7G,KAAK,8DACV,IAAI4qH,EAMA16F,EAJAy6F,EAAYtxH,SACZuxH,EAAYD,EAAYt9G,KAAK,SAIjC,MAAMm9G,EACAt0D,IAAAA,CAAEslD,GAAMx7G,KACV,+DAGAwqH,EAAanxH,SACb62B,EAASs6F,EAAa7wH,QAM1BhC,KAAKwzF,aAAa37D,KACdoF,GAAW,WAAXA,OACA8rF,EACAkK,EACAlxB,GAAAA,QAAAA,mBAA2BlD,GAC3BtmE,EACAu4F,GAGJ/H,GAIAgK,EAAYxyH,SAAQ4iG,IAChB,MAAMqtB,EAASxwH,KAAK2oH,QAAQxlB,UAErBnjG,KAAK2oH,QAAQxlB,GACpBnjG,KAAKyyH,kBAAkBtvB,EAAKqtB,EAAOQ,YAEvChxH,KAAK8iG,WAAWC,KAAKC,QAAQhjG,KAAKijG,SAI7B6vB,GACD9yH,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,mBAGpBj9B,KAAK2oH,QAAQ9pB,GACpB7+F,KAAKyyH,kBAAkB5zB,GAAM,IASrCq0B,UAAU3xH,EAAKs9F,GACX,MAAMj3F,EAAOrG,EAAIihB,aAAa,QAE9B,GAAa,UAAT5a,EAAkB,CAClB,MAAMurH,EAAmB50D,IAAAA,CAAEh9D,GAAK8G,KAAK,wBAAwBrG,OAE7D,GAAImxH,EAAiBzxH,OAGjB,OAFA1B,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,wBAAoCk2F,IAEpD,EAEX,MAAM3G,EAAWjuD,IAAAA,CAAEh9D,GAAK8G,KAAK,eAAerG,OAI5C,OAFAhC,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,oBAAgCuvF,IAEhD,EAGX,MAAMjoB,EAAMhmC,IAAAA,CAAEh9D,GAAK8G,KAAK,SAASrG,OAC3BmkH,EAAU5nD,IAAAA,CAAEh9D,GAAK8G,KAAK,YAE5B,GAAI89G,EAAQzkH,OAAQ,CAChB,MAAM0xH,EAAcjN,EAAQnkH,QAExBoxH,GAA+B,KAAhBA,KACfpzH,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,gBAA4Bm2F,GACnD7uH,GAAOD,IAAK,yBAAwB8uH,MAK5C,IAAIC,EAAQ90D,IAAAA,CAAEh9D,GAAK8G,KAAK,UAAUqN,KAAK,SAEvC,IAAK29G,IAEDA,EAAQ90D,IAAAA,CAAEh9D,GAAK8G,KAAK,6BAA6BqN,KAAK,SAElD29G,GAAO,CAEP,MAAMC,EACAD,EAAMjvH,MAAM,2CAElBivH,EAAS,GAAEC,EAAU,MAAMA,EAAU,MAAMA,EAAU,MAI7D,GAAIz0B,IAAS7+F,KAAKijG,QAAS,CACvB,IAAIswB,EAEJ,GAAIh1D,IAAAA,CAAEh9D,GAAK8G,KAAK,sEAAsE3G,OAClF1B,KAAKyvH,qBACF,IAAK8D,EAASh1D,IAAAA,CAAEh9D,GAAK8G,KAAK,4DAClBkrH,EAAO7xH,OAAQ,CAC1B,MAAM8xH,EAAiBj1D,IAAAA,CAAEh9D,GAAK8G,KAAK,4DACnC,IAAIwyC,EAEA24E,GAAkBA,EAAe9xH,SACjCm5C,EAAW24E,EAAexxH,QAG9BhC,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,wBACnB4hE,EAAM00B,EAAO79G,KAAK,QAAS6uF,EAAK1pD,IAI5C,MAAM44E,EAAcl1D,IAAAA,CAAEh9D,GAAK8G,KAAK,iBAAiBrG,OAEjD,GAAIyxH,EAAa,CACb,MAAMC,EAAa1zH,KAAK08F,KAAKi3B,sBAAsBF,GAKnD,GAAIC,QAAwB3nH,IAAVsnH,EAId,YAHArzH,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,sBACnB4hE,EAAM60B,GAMdnvB,IACa,SAAT38F,EACA5H,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,yBACf4hE,EAAM0F,EAAKvkG,KAAK4nH,UAAWyL,GACnB,cAATzrH,GACP5H,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,iBACf4hE,EAAM0F,EAAKvkG,KAAK4nH,UAAWyL,IAU/CO,gBAAgB/P,EAAMhlB,GAClB,GAAItgC,IAAAA,CAAEslD,GACGx7G,KACG,mFAGH3G,OACL6C,GAAOD,IAAI,uBAAwBu6F,GACnC7+F,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,wBACpB,GAAIshC,IAAAA,CAAEslD,GACJx7G,KACG,kFAGH3G,OACYqgG,GAAAA,QAAAA,iBAAyB8hB,EAAKrhG,aAAa,SAE3CxiB,KAAK08F,KAAK38F,QAAQqrH,MAAMqB,gBAKrCzsH,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,kBAGvB14B,GAAO2T,KAAK,eAAgB2rG,GAC5B7jH,KAAKwzF,aAAa37D,KACdoF,GAAW,WAAXA,sCAEL,GAAIshC,IAAAA,CAAEslD,GAAMx7G,KAAK,8BAA8B3G,OAClD6C,GAAO2T,KAAK,oDACR2rG,GACJ7jH,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,sBACvBj9B,KAAK8iG,WAAWC,KAAKC,QAAQhjG,KAAKijG,cAC/B,GAAI1kC,IAAAA,CAAEslD,GACRx7G,KACG,0FAEkD3G,OAAQ,CAG9D,MAAMmyH,EAAgBt1D,IAAAA,CAAEslD,GAAMx7G,KAAK,iCACnC,IAAIg/G,EAEJ,GAAIwM,EAAcnyH,OACd2lH,EAAewM,EAAc7xH,WAC1B,CAGH,MAAM8xH,EAAmBv1D,IAAAA,CAAEslD,GAAMx7G,KAAK,cAElCyrH,EAAiBpyH,SACjB2lH,EAAeyM,EAAiB9xH,QAIxChC,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,gCAA4CoqF,QAEnE9iH,GAAO2T,KAAK,eAAgB2rG,GAC5B7jH,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,oBAS/B82F,eAAe5wB,EAAK4tB,GAChB,MAAMiD,GAAUhV,EAAAA,GAAAA,KAAI,CAChBC,GAAIj/G,KAAKijG,QACTr7F,KAAM,QAETuF,EAAE,QAAS,CAAEiH,MAAO,yCACpBjH,EAAE,OAAQ,CACP4jH,YAAAA,EACAvI,KAAMzmB,GAAAA,QAAAA,mBAA2BoB,KAEpCh2F,EAAE,UAAUnI,EAAG,yCAAwC+rH,OACvDhM,KAAKA,KAAKA,KAEX/kH,KAAK8iG,WAAWugB,OACZ2Q,GACA16F,GAAU/0B,GAAOD,IAAI,4CAA6C6+F,EAAK,KAAM4tB,EAAaz3F,KAC1Fj4B,GAASkD,GAAOD,IAAI,yCAA0CjD,KAQtE6nH,KAAK/lB,GAAuC,IAAlC5qE,EAAkC,uDAAzB,wBACf,MAAM07F,GAASjV,EAAAA,GAAAA,KAAI,CAAEC,GAAIj/G,KAAKijG,QAC1Br7F,KAAM,QACLuF,EAAE,QAAS,CAAEiH,MAAO,yCACpBjH,EAAE,OAAQ,CAAEq7G,KAAMzmB,GAAAA,QAAAA,mBAA2BoB,GAC1C5uB,KAAM,SACTpnE,EAAE,UAAUnI,EAAEuzB,GAAQwsF,KAAKA,KAAKA,KAErC/kH,KAAK8iG,WAAWugB,OACZ4Q,GACA36F,GAAU/0B,GAAOD,IAAI,8BAA+B6+F,EAAK7pE,KACzDj4B,GAASkD,GAAOD,IAAI,2BAA4BjD,KAYxD6yH,SAAShmH,EAAKimH,EAAWC,EAASC,GAE9Br0H,KAAK8iG,WAAWugB,QACZrE,EAAAA,GAAAA,KAAI,CACAC,GAAIj/G,KAAKijG,QACTr7F,KAAM,QAELuF,EAAE,QAAS,CAAEiH,MAAO,0CACzBslG,IACI,GAAIn7C,IAAAA,CAAEm7C,GACGrxG,KACG,0EAEH3G,OAAQ,CACb,MAAM4yH,GACAtV,EAAAA,GAAAA,KAAI,CACFC,GAAIj/G,KAAKijG,QACTr7F,KAAM,QAELuF,EAAE,QAAS,CACRiH,MAAO,yCAGnBkgH,EAAWnnH,EAAE,IAAK,CACdiH,MAAO,gBACPxM,KAAM,WAEV0sH,EACKnnH,EAAE,QAAS,CAAE,IAAO,cACpBA,EAAE,SACFnI,EAAE,6CACF+/G,KACAA,KACLuP,EACKnnH,EAAE,QAAS,CAAE,IAAO,8BACpBA,EAAE,SACFnI,EAAEkJ,GACF62G,KACAA,KACLuP,EACKnnH,EAAE,QACE,CAAE,IAAO,yCACbA,EAAE,SACFnI,EAAU,OAARkJ,GAA+B,IAAfA,EAAIxM,OAAe,IAAM,KAC3CqjH,KACAA,KAGD/kH,KAAKynH,oBACL6M,EACKnnH,EAAE,QAAS,CAAE,IAAO,+BACpBA,EAAE,SACFnI,EAAE,QACF+/G,KACAA,KAKTuP,EACKnnH,EAAE,QAAS,CAAE,IAAO,yBACpBA,EAAE,SACFnI,EAAE,UACF+/G,KACAA,KAEL/kH,KAAK8iG,WAAWugB,OACZiR,GACA,KAIIt0H,KAAK66C,SAAW3sC,EAChBimH,MAEJC,QAEJC,MAGRD,GAYR7M,eAAe9gB,EAAS0tB,EAAWC,GAC3B3tB,GAAWrmG,OAAOkJ,OAAOtJ,KAAK2oH,SAAS5hH,QAAO5C,IAAMA,EAAE6sH,UAAStvH,QAI/DtB,OAAOkJ,OAAOtJ,KAAK2oH,SAASpoH,SAAQ4D,IAC5BA,EAAEg/F,MAAQ2qB,GAAqBrQ,SAASt5G,EAAE4sH,cAC1C/wH,KAAK08F,KAAKoG,WAAWugB,QACjBrE,EAAAA,GAAAA,KAAI,CACAC,GAAIj/G,KAAKijG,QACTr7F,KAAM,QACTuF,EAAE,QAAS,CACRiH,MAAO,yCACVjH,EAAE,OAAQ,CACP,YAAe,SACf,IAAOhJ,EAAEg/F,MACV4hB,KAAKA,SAKxB,MAAMhrF,EAAgBq6F,GAAoB,SAE1Cp0H,KAAK08F,KAAKoG,WAAWugB,QACjBrE,EAAAA,GAAAA,KAAI,CACAC,GAAIj/G,KAAKijG,QACTr7F,KAAM,QACPuF,EAAE,QAAS,CAAEiH,MAAO,0CACvBslG,IACI,GAAIn7C,IAAAA,CAAEm7C,GAAKrxG,KAAK,2EAA2E3G,OAAQ,CAC/F,MAAM6yH,GACAvV,EAAAA,GAAAA,KAAI,CACFC,GAAIj/G,KAAKijG,QACTr7F,KAAM,QACPuF,EAAE,QAAS,CAAEiH,MAAO,yCAE3BmgH,EAAapnH,EAAE,IAAK,CAChBiH,MAAO,gBACPxM,KAAM,WAEV2sH,EACKpnH,EAAE,QAAS,CAAE,IAAO,cACpBA,EAAE,SACFnI,EAAE,6CACF+/G,KACAA,KACLwP,EACKpnH,EAAE,QAAS,CAAE,IAAO,+BACpBA,EAAE,SACFnI,EAAEyhG,EAAU,OAAS,SACrBse,KACAA,KAGD/kH,KAAKmhD,QACLozE,EACKpnH,EAAE,QACC,CAAE,IAAO,yCACZA,EAAE,SACFnI,EAAE,KACF+/G,KACAA,KAGT/kH,KAAK08F,KAAKoG,WAAWugB,OAAOkR,EAAcJ,EAAWp6F,QAErDA,EAAc,IAAI/1B,MAAM,+CAGhC+1B,GAaRy6F,cAActmH,EAAK5E,GACf,OAAOtJ,KAAK26G,uBAAuBzsG,EAAK5E,GAU5CqxG,uBAAuBzsG,EAAK5E,GACxBA,EAAO4M,QAAUhI,EAEjB,MAAMumH,EAAgBz0H,KAAKkuH,QAAQ/kE,MAAMpiD,QAAOkM,GAAQ/E,IAAQ+E,EAAKiD,UAGrE,QAA6B,IAAzBu+G,EAAc/yH,QAAgBq1G,IAAAA,CAAQ0d,EAAc,GAAInrH,KAI5DtJ,KAAK06G,mBAAmBxsG,GACxBlO,KAAKkuH,QAAQ/kE,MAAMjnD,KAAKoH,GACxBtJ,KAAKovH,mBAAqBjqH,KAAK8nD,MAExB,IASXynE,gBAAgBxmH,GACZ,OAAOlO,KAAKkuH,QAAQ/kE,MAAM9gD,MAAK4K,GAAQ/E,IAAQ+E,EAAKiD,UAOxDwkG,mBAAmBxsG,GACf,MAAMi7C,EAAQnpD,KAAKkuH,QAAQ/kE,MAAMpiD,QAAOkM,GAAQ/E,IAAQ+E,EAAKiD,UAE7DlW,KAAKkuH,QAAQ/kE,MAAQA,EACrBnpD,KAAKovH,mBAAqBjqH,KAAK8nD,MAQnC23C,oBAAoBp4F,EAAM6rB,GACtB,GAAuB,mBAAZA,EACP,MAAM,IAAIr0B,MAAM,+BAEpB,IAAIsuH,EAActyH,KAAKmuH,aAAa3hH,GAE/B8lH,IACDtyH,KAAKmuH,aAAa3hH,GAAQ8lH,EAAc,KAEN,IAAlCA,EAAYjvH,QAAQg1B,GACpBi6F,EAAYpwH,KAAKm2B,GAEjB9zB,GAAO2T,KACF,sDAAqD1L,KASlEmoH,uBAAuBnoH,EAAM6rB,GACzB,MAAMi6F,EAActyH,KAAKmuH,aAAa3hH,GAChCooH,EAAatC,EAAcA,EAAYjvH,QAAQg1B,IAAY,GAG7C,IAAhBu8F,EACAtC,EAAY9uH,OAAOoxH,EAAY,GAE/BrwH,GAAO2T,KAAM,gBAAe1L,wBAYpCwkH,QAAQ6D,GACJ,MAAMrE,EAASxwH,KAAK2oH,QAAQkM,GAE5B,OAAIrE,EACOA,EAAOQ,QAGX,KAMXhtB,cACI,MAAqB,cAAdhkG,KAAKu0E,KAOhBugD,cAAcC,GACV,OAAI/0H,KAAK2oH,QAAQoM,GACN/0H,KAAK2oH,QAAQoM,GAASxgD,KAG1B,KAOXygD,uBAAuB9lC,GACnB,MAAM+lC,EAAoB,aAG1B,QAAI/lC,IAASlvF,KAAK00H,gBAAgBO,KAI3Bj1H,KAAK26G,uBACRsa,EACA,CACI9tH,MAAO+nF,EAAKhuE,aAQxBg0G,uBAAuBhmC,GACnB,MAAMimC,EAAoB,aAG1B,QAAIjmC,IAASlvF,KAAK00H,gBAAgBS,KAI3Bn1H,KAAK26G,uBACRwa,EACA,CACIhuH,MAAO+nF,EAAKhuE,aAexBk0G,qBAAqBvrB,EAAY5mB,GAE7B,MAAM4gC,EAAO7jH,KAAK6uH,cAAe,GAAE7uH,KAAKijG,WAAW4G,KAEnD,IAAKga,EAED,OAAO,KAEX,MAAMptG,EAAO,CACTmpF,OAAO,EACP6F,UAAW3oE,GAAU,UAAVA,QAEf,IAAIu4F,EAAY,KAEhB,GAAIpyC,IAAc6R,GAAUqH,MACxBk5B,EAAYxH,GAA2BhK,EAAM,kBAC1C,IAAI5gC,IAAc6R,GAAU2G,MAc/B,OAFAl3F,GAAOlD,MAAO,2BAA0B4hF,KAEjC,KAd+B,CACtCoyC,EAAYxH,GAA2BhK,EAAM,cAC7C,MAAMyR,EAAgBzH,GAA2BhK,EAAM,+BACjD0R,EAAgB1H,GAA2BhK,EAAM,aAEnD0R,EAAc7zH,OAAS,IACvB+U,EAAKgvF,UAAY8vB,EAAc,GAAGpuH,OAElCmuH,EAAc5zH,OAAS,IACvB+U,EAAK++G,UAAYF,EAAc,GAAGnuH,QAY1C,OAJIkuH,EAAU3zH,OAAS,IACnB+U,EAAKmpF,MAA+B,SAAvBy1B,EAAU,GAAGluH,OAGvBsP,EAQXg/G,gBAAgBC,GACZ,OAAO11H,KAAK6uH,cAAe,GAAE7uH,KAAKijG,WAAWyyB,KAMjDC,wBACI,QAAI31H,KAAKwuH,WACExuH,KAAKwuH,UAAU5D,sBAU9BgL,KAAKnkC,GACD,OAAOzxF,KAAK8iG,WAAW+yB,KAAKD,KAAKnkC,EAAQ,aACrCsQ,GAAAA,QAAAA,kBAA0B/hG,KAAK4nH,WAAY5nH,KAAK66C,SAChD76C,KAAKsuH,aAMbwH,SACI,OAAO91H,KAAK8iG,WAAW+yB,KAAKC,SAOhCC,WACI,OAAO/1H,KAAKyuH,MAMhBuH,kBACI,OAAOh2H,KAAK0uH,aAMhB9F,mBACI,OAAO5oH,KAAK2uH,cAMhBsH,iBACI,OAAOj2H,KAAK8uH,YAMhBoH,cACI,OAAOl2H,KAAK+uH,SAQhBoH,eACI,OAAOn2H,KAAKiwH,UAShBmG,gBAAgBjzB,EAAKjU,EAAMjM,GACvB1+E,GAAOiH,KAAK,WAAY0jF,EAAMiU,GAC9B,MAAMkzB,GAAYrX,EAAAA,GAAAA,KACd,CAAEC,GAAIj/G,KAAKsuH,YACP1mH,KAAM,QACTuF,EAAE,OAAQ,CACPiH,MAAQ,4BAA2B6uE,IACnCkgB,IAAAA,IAEHn+F,EAAEkqF,EAAKhuE,YACP6jG,KAEL/kH,KAAK8iG,WAAWugB,OACZgT,GACA/8F,GAAU/0B,GAAOD,IAAI,WAAYg1B,KACjCj4B,GAASkD,GAAOD,IAAI,iBAAkBjD,KAO9Ci1H,OAAOvX,GAGH,GAFaA,EAAGv8F,aAAa,UAEhBxiB,KAAKsuH,YAGd,YAFA/pH,GAAO2T,KAAK,oCAIhB,MAAMg3E,EAAO3wB,IAAAA,CAAEwgD,GAAI12G,KAAK,QAEpB6mF,EAAKxtF,QAA0B,SAAhBwtF,EAAKltF,OACpBhC,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,qBAAiCiyD,EAAKx5E,KAAK,UAKlEnR,GAAO2T,KAAK,sFASpBq+G,YAAYxX,GAGR,GAFaA,EAAGv8F,aAAa,UAEhBxiB,KAAKsuH,YAGd,YAFA/pH,GAAO2T,KAAK,oCAIhB,MAAMg3E,EAAO3wB,IAAAA,CAAEwgD,GAAI12G,KAAK,QAEpB6mF,EAAKxtF,QAA0B,SAAhBwtF,EAAKltF,OACpBhC,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,qBAAiCiyD,EAAKx5E,KAAK,UAKlEnR,GAAO2T,KAAK,sFAQpB4wG,QACI9oH,KAAKouH,qBAAqB7tH,SAAQyc,GAAUA,MAC5Chd,KAAKouH,qBAAuB,GAE5BpuH,KAAKioH,QAAS,EACdjoH,KAAKquH,mBAAoB,EAS7BtG,QAAQ,aACJ/nH,KAAK0uH,aAAapkC,UAClBtqF,KAAK2uH,cAAcrkC,UAEnB,MAAM8pB,EAAW,GA0BjB,OAxBA,UAAAp0G,KAAKyuH,aAAL,eAAYjH,YAAapT,EAASlyG,KAAKlC,KAAKyuH,MAAM1G,SAElD3T,EAASlyG,KAAK,IAAI6nC,SAAQ,CAACC,EAASC,KAChC,IAAI6tB,GAAW,EAEf,MAAM0+D,EAAY,WAAsB,IAArBC,EAAqB,wDACpC,EAAKjjC,aAAarpD,eAAelN,GAAW,WAAXA,SAAqBu5F,GACtDj0H,aAAau1D,GACT2+D,GAEA,EAAK3zB,WAAWC,KAAKC,QAAQ,EAAKC,SAClCh5D,EAAO,IAAIjmC,MAAM,sEAEjBgmC,KAIR8tB,EAAUt1D,YAAW,IAAMg0H,GAAU,IAAO,KAE5Cx2H,KAAK8oH,QACL9oH,KAAKwzF,aAAajpD,GAAGtN,GAAW,WAAXA,SAAqBu5F,GAC1Cx2H,KAAKgjG,cAGFj5D,QAAQyqE,WAAWJ,IC5zDlC,MAAM7vG,IAAS2B,EAAAA,EAAAA,2CAKA,MAAMwwH,WAA4B5Y,GAK7C1kG,YAAYsjF,GACRxX,QACAllF,KAAK08F,KAAOA,EACZ18F,KAAKg6G,MAAQ,GAOjBpwE,KAAKk5D,GACD5d,MAAMt7C,KAAKk5D,GAGX9iG,KAAK8iG,WAAWrqE,WAAWz4B,KAAKuwH,WAAW3vH,KAAKZ,MAAO,KACnD,WAAY,KAAM,KAAM,KAAM,MAClCA,KAAK8iG,WAAWrqE,WAAWz4B,KAAK2yH,sBAAsB/xH,KAAKZ,MACvD,KAAM,WAAY,cAAe,MACrCA,KAAK8iG,WAAWrqE,WAAWz4B,KAAK4zH,gBAAgBhzH,KAAKZ,MAAO,KACxD,WAAY,QAAS,MACzBA,KAAK8iG,WAAWrqE,WAAWz4B,KAAKkzH,UAAUtyH,KAAKZ,MAAO,KAClD,UAAW,KAAM,MACrBA,KAAK8iG,WAAWrqE,WAAWz4B,KAAKs2H,OAAO11H,KAAKZ,MACxC,iCAAkC,KAAM,MAAO,KAAM,MACzDA,KAAK8iG,WAAWrqE,WAAWz4B,KAAKu2H,YAAY31H,KAAKZ,MAC7C,iCAAkC,KAAM,MAAO,KAAM,MAS7DooH,WAAWjlB,EAAKtoD,EAAU96C,GACtB,MAAM8/F,EAAUkC,GAAAA,QAAAA,kBAA0BoB,GAE1C,GAAInjG,KAAK22H,cAAc92B,GAAU,CAC7B,MAAMyf,EAAS,+BAGf,MADA/6G,GAAOlD,MAAMi+G,GACP,IAAIt7G,MAAMs7G,GAOpB,OALAt/G,KAAKg6G,MAAMna,GAAW,IAAIkuB,GAAS/tH,KAAK8iG,WAAYK,EAChDtoD,EAAU76C,KAAK08F,KAAM38F,GACzBC,KAAKwzF,aAAa37D,KACdoF,GAAW,WAAXA,gBAA4Bj9B,KAAKg6G,MAAMna,IAEpC7/F,KAAKg6G,MAAMna,GAStB82B,cAAc92B,GACV,OAAOA,KAAW7/F,KAAKg6G,MAO3BhX,QAAQG,GACJnjG,KAAKwzF,aAAa37D,KACdoF,GAAW,WAAXA,kBAA8Bj9B,KAAKg6G,MAAM7W,WACtCnjG,KAAKg6G,MAAM7W,GAOtBotB,WAAW1M,GACP,MAAMhlB,EAAOglB,EAAKrhG,aAAa,QAG/B,GAAIqhG,EAAKrhG,aAAa,QAClB,OAAO,EAGX,MAAM++E,EAAOvhG,KAAKg6G,MAAMjY,GAAAA,QAAAA,kBAA0BlD,IAElD,OAAK0C,IAKDhjC,IAAAA,CAAEslD,GAAMx7G,KAAK,sEACY3G,QACzB6/F,EAAK2uB,yBAGT3uB,EAAKgvB,WAAW1M,IAET,GAOX8O,sBAAsB9O,GAClB,MAAMhlB,EAAOglB,EAAKrhG,aAAa,QACzB++E,EAAOvhG,KAAKg6G,MAAMjY,GAAAA,QAAAA,kBAA0BlD,IAElD,OAAK0C,IAILA,EAAKoxB,sBAAsB9O,EAAMhlB,IAE1B,GAOX+0B,gBAAgB/P,GACZ,MAAMhlB,EAAOglB,EAAKrhG,aAAa,QACzB++E,EAAOvhG,KAAKg6G,MAAMjY,GAAAA,QAAAA,kBAA0BlD,IAElD,OAAK0C,IAILA,EAAKqyB,gBAAgB/P,EAAMhlB,IAEpB,GAOXq0B,UAAU3xH,GAEN,MAAMs9F,EAAOt9F,EAAIihB,aAAa,QACxB++E,EAAOvhG,KAAKg6G,MAAMjY,GAAAA,QAAAA,kBAA0BlD,IAElD,OAAK0C,IAILA,EAAK2xB,UAAU3xH,EAAKs9F,IAEb,GAOXy3B,OAAOvX,GACH,MAAMlgB,EAAOkgB,EAAGv8F,aAAa,QACvB++E,EAAOvhG,KAAKg6G,MAAMjY,GAAAA,QAAAA,kBAA0BlD,IAGlD,OAAK0C,IAILA,EAAK+0B,OAAOvX,IAEL,GAOXwX,YAAYxX,GACR,MAAMlgB,EAAOkgB,EAAGv8F,aAAa,QACvB++E,EAAOvhG,KAAKg6G,MAAMjY,GAAAA,QAAAA,kBAA0BlD,IAGlD,OAAK0C,IAILA,EAAKg1B,YAAYxX,IAEV,IC1Mf,MAAMx6G,IAAS2B,EAAAA,EAAAA,WAAU,gBAsCzB,OAjCA,MAMI0jC,KAAKU,GACDtqC,KAAK42H,qBAAuBtvC,QAAQh9C,EAAMusF,qBAC1C72H,KAAK82H,0BAA4BxvC,QAAQh9C,EAAMysF,0BAE/CxyH,GAAOiH,KAAM,0BAAyBxL,KAAK42H,sDACJ52H,KAAK82H,6BAQhDE,8BACI,OAAOh3H,KAAK42H,sBAAwB52H,KAAK82H,0BAQ7CG,+BACI,OAAOj3H,KAAK42H,uBC7BdryH,IAAS2B,EAAAA,EAAAA,oDAQf,SAASgxH,GAAuBhyE,EAAOiyE,GACnC,MAAMlkH,GAAOmkH,EAAAA,GAAAA,QAAO,SAAU,CAC1BhjH,MAAO,kCACPxN,KAAMuwH,EAAkBtqH,EACxBL,KAAM6qH,GAAAA,+BAA8CF,EAAkBtmH,OAAI9E,IAc9E,OAXIorH,EAAkBhzH,GAClB8O,EAAK9F,EAAE,YAAa,CAChBX,KAAM,OACNrF,MAAOgwH,EAAkBhzH,IAC1B4gH,KAEP9xG,EAAK9F,EAAE,YAAa,CAChBiH,MAAO,2BACP8wC,MAAAA,IACD6/D,KAEI9xG,EAAKA,KAQhB,SAASqkH,GAA0BC,GAC/B,MAAMtkH,GAAOmkH,EAAAA,GAAAA,QAAO,aAAc,CAC9BhjH,MAAO,kCACP7L,WAwDeoF,EAxDU4pH,EAAqB,GAyDtC,MAAR5pH,EACO,MACQ,MAARA,EACA,MAGJ,QAPX,IAAuBA,EArDnB,IAAK,IAAInM,EAAI,EAAGA,EAAI+1H,EAAqB71H,OAAQF,IAC7CyR,EAAK9F,EAAE,SAAU,CACbiH,MAAO,kCACPxN,KAAM2wH,EAAqB/1H,KAC5BujH,KAGP,OAAO9xG,EAAKA,KAUhB,SAASukH,GAA2BzY,EAAI97B,GACpC,MAAMw0C,EAASl5D,IAAAA,CAAEwgD,GAAI12G,KAAK,UAAU,GACpC,IACIytE,EADA7mE,EAAUsvD,IAAAA,CAAEk5D,GAAQpvH,KAAM,iBAAgB46E,OAyB9C,OAtBIh0E,EAAQvN,OACRuN,EAAUA,EAAQ,IAGlBA,GAAUmoH,EAAAA,GAAAA,QAAO,UAAW,CACxB5qH,KAAMy2E,IACPhwE,KACHwkH,EAAO5jH,YAAY5E,IAGvB6mE,EAAcvX,IAAAA,CAAEtvD,GAAS5G,KAAK,eAE1BytE,EAAYp0E,OACZo0E,EAAcA,EAAY,IAE1BA,GAAcshD,EAAAA,GAAAA,QAAO,cAAe,CAChChjH,MAAO,6BACPzM,MAAOs7E,IACRhwE,KACHhE,EAAQ4E,YAAYiiE,IAGjBA,EA+BJ,SAAS4hD,GAAsB3Y,EAAI4Y,GAAgB,MACtD,IAAI/gB,EAEJ,IACIA,EAAOx1G,KAAKwJ,MAAM+sH,EAAer/E,aACnC,MAAOj3C,GAGL,OAFAkD,GAAOlD,MAAO,sDAAqDs2H,EAAer/E,eAE3E,KAGX,GAAI,UAACs+D,SAAD,QAAC,EAAM9rG,QAEP,OAAO,KAIX,MAAM8sH,EAAsBJ,GAA2BzY,EAAIjqB,GAAUqH,OAC/D07B,EAAsBL,GAA2BzY,EAAIjqB,GAAU2G,OAC/D5yF,EAAU,IAAIw9D,IAEpB,IAAK,MAAMnhB,KAAS0xD,EAAK9rG,QACrB,GAAI8rG,EAAK9rG,QAAQ2N,eAAeysC,GAAQ,CACpC,MAAMp+C,EAAQ,GACRgxH,EAAelhB,EAAK9rG,QAAQo6C,GAI5B6yE,GAAeD,MAAAA,OAAA,EAAAA,EAAcp2H,SAAUo2H,EAAa,GACpDE,GAAkBF,MAAAA,OAAA,EAAAA,EAAcp2H,QAAS,GAAKo2H,EAAa,GAC3DG,GAAeH,MAAAA,OAAA,EAAAA,EAAcp2H,QAAS,GAAKo2H,EAAa,GACxDI,GAAkBJ,MAAAA,OAAA,EAAAA,EAAcp2H,QAAS,GAAKo2H,EAAa,GAEjE,GAAIC,MAAAA,GAAAA,EAAcr2H,OACd,IAAK,IAAIF,EAAI,EAAGA,EAAIu2H,EAAar2H,OAAQF,IAAK,OAC1Cq2H,EAAoBhkH,YAAYqjH,GAAuBhyE,EAAO6yE,EAAav2H,KAC3EsF,EAAM5E,KAAN,UAAW61H,EAAav2H,UAAxB,aAAW,EAAiBqL,GAIpC,GAAImrH,MAAAA,GAAAA,EAAiBt2H,OACjB,IAAK,IAAIF,EAAI,EAAGA,EAAIw2H,EAAgBt2H,OAAQF,IACxCq2H,EAAoBhkH,YAAYyjH,GAA0BU,EAAgBx2H,KAGlF,GAAIy2H,MAAAA,GAAAA,EAAcv2H,OACd,IAAK,IAAIF,EAAI,EAAGA,EAAIy2H,EAAav2H,OAAQF,IAAK,OAC1Co2H,EAAoB/jH,YAAYqjH,GAAuBhyE,EAAO+yE,EAAaz2H,KAC3EsF,EAAM5E,KAAN,UAAW+1H,EAAaz2H,UAAxB,aAAW,EAAiBqL,GAIpC,GAAIqrH,MAAAA,GAAAA,EAAiBx2H,OACjB,IAAK,IAAIF,EAAI,EAAGA,EAAI02H,EAAgBx2H,OAAQF,IACxCo2H,EAAoB/jH,YAAYyjH,GAA0BY,EAAgB12H,KAGlFqH,EAAQqc,IAAIggC,EAAOp+C,GAI3B,OAAO+B,ECnLJ,MA4BP,GA5B6B,CAIzBsvH,KAAM,OAKNC,KAAM,OAKNC,OAAQ,SAKRC,IAAK,MAKLC,IAAK,OCFT,GAtB8B,CAI1BlxB,SAAU,WAKVmxB,SAAU,WAKVC,SAAU,WAKVC,SAAU,YClBRn0H,GAASi1B,EAAAA,IAAAA,2CAUTm/F,GAAiB,CAQnBC,aAAc,KAQdhvF,OAAmB,IAAd7pC,EAAc,uDAAJ,GACXC,KAAKD,QAAUA,EACfC,KAAK44H,aAAe54H,KAAK64H,4BAEpB74H,KAAK44H,cACNr0H,GAAOiH,KAAK,6BAWpBqtH,4BACI,OAAItzF,GAAQihD,SACD,CAAC2tC,EAAW2E,KACfx2H,OAAOy2H,YAAYC,oBACf7E,GACA,CAAC9yH,EAAOo/E,KACJ,IAAIw4C,EAmBAA,EADA53H,GAAwB,sBAAfA,EAAMmL,KACF,IAAI8zE,GACbd,IAGS,IAAIc,GACbj/E,EAAOo/E,EAAa,CAAE,YAER,mBAAdq4C,GACDA,EAAUG,OAGtB1zF,GAAQkhD,aACRzmF,KAAKk5H,uBACL3zF,GAAQmhD,iBAAmBnhD,GAAQ4jD,0BACnCnpF,KAAKm5H,kCACL5zF,GAAQ4jD,0BACRnpF,KAAKo5H,iCAEhB70H,GAAOD,IAAI,mCAAoCihC,GAAQ2gD,WAEhD,OAQXmzC,uBACI,MAAM,aAAEC,GAAiBt5H,KAAKD,QAQ9B,OAPcu5H,MAAAA,IAAAA,EAAcC,QAAS,CACjCC,iBAAiB,EACjBC,aAAc,EACdC,kBAAkB,EAClBC,kBAAkB,IAW1B13G,cACI,OAA6B,OAAtBjiB,KAAK44H,cAShBM,uBAAuB/E,EAAW2E,GAAW,WACzC,GAAIx2H,OAAOs3H,yBAA2Bt3H,OAAOs3H,wBAAwBC,kBAAmB,CACpF,MAAM,wBAAEC,EAAF,sBAA2BC,GAA0B/5H,KAAKD,QAEhEuC,OAAOs3H,wBAAwBC,kBAC3B,CACIE,sBAAuBA,GAAyB,CAAE,SAAU,YAEhE,SAACC,EAAUC,GAAyC,IAA7BC,EAA6B,wDAChD,GAAIF,EAAU,SACV,IAAIG,GAAmB,EAEvB,GAAID,EAAkB,CAClBC,EAAmB,GACnB,MAAMC,EAAsB,EAAKf,uBAEE,kBAAxBe,IACPD,EAAmB,CACfE,SAAUD,IAUC,WAAfH,IACAE,EAAiBr5C,UAAY,CACzBw5C,kBAAmB,YAK/B,MAAM75C,EAAc,CAChBqY,MAAOqhC,EACPv5C,MAAO,CACHE,UAAW,CACPw5C,kBAAmB,UACnBC,oBAAqBP,EACrBQ,aAAY,UAAEV,MAAAA,OAAF,EAAEA,EAAyBhhG,WAA3B,QA9JX,EA+JD2hG,aAAY,UAAEX,MAAAA,OAAF,EAAEA,EAAyBziG,WAA3B,QA/JX,EAgKD46B,SAAU3vD,OAAOo4H,OAAO99F,MACxB+9F,UAAWr4H,OAAOo4H,OAAO79F,UAMrCwnD,UAAUkD,aAAaC,aAAa/G,GAC/B7/B,MAAKxwC,GAAU+jH,EAAU,CACtB/jH,OAAAA,EACAwqH,SAAUZ,EACVa,WAAYZ,KACZnB,QAKRA,EAAU,IAAIx4C,GAAgBd,QAGtC/2C,GAAOqwF,EAAU,IAAIx4C,GACjBd,GACA/2C,WAIRqwF,EAAU,IAAIx4C,GAAgBd,MAUtC45C,gCAAgCx8G,EAAUmd,GACtC,IAAIqvD,EAGAA,EADA/E,UAAU+E,gBACQ/E,UAAU+E,gBAAgBxoF,KAAKyjF,WAG/BA,UAAUkD,aAAa6B,gBAAgBxoF,KAAKyjF,UAAUkD,cAG5E,MAAM,wBAAEuyC,GAA4B95H,KAAKD,QACnC6gF,EAA2C,iBAA5Bk5C,GAAuC,CAAE1+B,UAAW0+B,GACnEhhC,EAAQ94F,KAAKq5H,uBAGnBz4C,EAAMwa,kBAAoBxa,EAAMwa,UAAUtiE,IAE1C,MAAM2nD,EAAc,CAChBG,MAAAA,EACAkY,MAAAA,EACAgiC,OAAQ,UAGZv2H,GAAOiH,KAAK,2CAA4Ci1E,GAExD2I,EAAgB3I,GACX7/B,MAAKxwC,IACFwM,EAAS,CACLxM,OAAAA,EACAwqH,SAAUxqH,EAAO/K,QAGxB2+C,OAAM3iD,IACH,MAAM05H,EAAe,CACjBC,UAAW35H,GAASA,EAAMmL,KAC1BggH,SAAUnrH,GAASA,EAAM2Z,QACzBigH,WAAY55H,GAASA,EAAM4C,OAG/BM,GAAOlD,MAAM,wBAAyBo/E,EAAas6C,GAE/CA,EAAavO,WAAmE,IAAvDuO,EAAavO,SAASnpH,QAAQ,oBAGvD02B,EAAc,IAAIumD,GAAgBd,KAKtCzlD,EAAc,IAAIumD,GAAgBd,SAU9C25C,kCAAkCv8G,EAAUmd,GACxCx1B,GAAOiH,KAAK,4CAEZ64E,UAAUkD,aAAa6B,gBAAgB,CAAExI,OAAO,IAC3ChgC,MAAKxwC,IACFwM,EAAS,CACLxM,OAAAA,EACAwqH,SAAUxqH,EAAO/K,QAExB2+C,OAAM,KACHjqB,EAAc,IAAIumD,GAAgBd,SAW9C07C,2BAA2BC,GACvB52H,GAAOiH,KAAM,uCAAsC2vH,KAEnDn7H,KAAKD,QAAQ+5H,wBAA0B,CACnChhG,IAxRyB,EAyRzBzB,IAAK8jG,KAKjB,yCCvSA,MAAM52H,IAAS2B,EAAAA,EAAAA,qCAOTk1H,GAAU,CACZC,mBAAmBr5H,GAIRA,EAAOA,EAAKyO,QAAQ,iBAAkB,IAAMzO,EAEvDs5H,UAAUC,EAAWC,GACjB,IACI9lD,EAAKzD,EADLx7D,EAAO,KAeX,OAZKw7D,EAAQmpD,GAAQK,SAASF,EAAW,eAAgBC,MAC7C9lD,EACE0lD,GAAQK,SACNF,EACA,aACAC,MACZ/kH,EAAO,CACHw7D,MAAOmpD,GAAQM,cAAczpD,GAC7ByD,IAAK0lD,GAAQO,YAAYjmD,KAI1Bj/D,GAEXilH,cAAc53H,GACHA,EAAKqM,UAAU,IAE1ByrH,cAAcC,GACF,eAAcA,IAE1BF,YAAY73H,GACDA,EAAKqM,UAAU,IAE1B2rH,YAAYpmD,GACA,aAAYA,IAExBqmD,SAASj4H,GACEA,EAAKqM,UAAU,GAS1B6rH,mBAAmBC,GACf,MAAMC,EAAWD,EAAU5zH,MAAKvE,GAAQA,EAAKT,QAAQ,UAAY,IAEjE,IAAK64H,EACD,OAGJ,MAAM3vH,EAAI2vH,EAAS/rH,UAAU+rH,EAAS74H,QAAQ,UAAY,GAE1D,OAAO+3H,GAAQC,mBAAmB9uH,IAEtCgsE,WAAWz0E,GACP,MAAM2S,EAAO,GACPvL,EAAQpH,EAAKqM,UAAU,GAAGjM,MAAM,KAUtC,OARAuS,EAAK9O,MAAQuD,EAAMiiC,QACnB12B,EAAKxG,KAAO/E,EAAMiiC,QAClB12B,EAAK25B,MAAQllC,EAAMiiC,QACa,KAA5BjiC,EAAMA,EAAMxJ,OAAS,IACrBwJ,EAAM+rB,MAEVxgB,EAAKiiE,IAAMxtE,EAEJuL,GAEX0lH,WAAWhmD,GAEF,KAAIA,EAAMxuE,SAASwuE,EAAMlmE,QAAQkmE,EAAM/lC,SACpC+lC,EAAMuC,IAAInvE,KAAK,OAE3B6yH,YAAYt4H,GACR,MAAM2S,EAAO,GACb,IAAIvL,EAAQpH,EAAKqM,UAAU,GAAGjM,MAAM,KAQpC,OANAuS,EAAKpR,GAAK6F,EAAMiiC,QAChBjiC,EAAQA,EAAM,GAAGhH,MAAM,KACvBuS,EAAKjK,KAAOtB,EAAMiiC,QAClB12B,EAAK4lH,UAAYnxH,EAAMiiC,QACvB12B,EAAK+7D,SAAWtnE,EAAMxJ,OAASwJ,EAAMiiC,QAAU,IAExC12B,GAQX6lH,aAAax4H,GACT,MAAMoH,EAAQpH,EAAKqM,UAAU,IAAIjM,MAAM,KAQvC,MAAO,CAPUgH,EAAM,GACNA,EAAM,GAGHA,EAAMxJ,OAAS,EAAIwJ,EAAM,GAAK,OAKtDqxH,cAAcz4H,GACHA,EAAKqM,UAAU,IAE1BqsH,YAAYnrH,GACR,IAAIvN,EACG,YAAWuN,EAAGmR,aAAa,SAASnR,EAAGmR,aAAa,WACnDnR,EAAGmR,aAAa,eAOxB,OALInR,EAAGmR,aAAa,aACmB,MAAhCnR,EAAGmR,aAAa,cACnB1e,GAAS,IAAGuN,EAAGmR,aAAa,eAGzB1e,GAEX24H,YAAY34H,GACR,MAAM2S,EAAO,GACPvL,EAAQpH,EAAKqM,UAAU,GAAGjM,MAAM,KAStC,OAPAuS,EAAKugC,IAAM9rC,EAAMiiC,QACjB12B,EAAK,gBAAkBvL,EAAMiiC,QAC7B12B,EAAK,cAAgBvL,EAAMiiC,QACvBjiC,EAAMxJ,SACN+U,EAAK,kBAAoBvL,EAAM3B,KAAK,MAGjCkN,GAEX09D,iBAAiBrwE,GACb,MAAM2S,EAAO,GACPvL,EAAQpH,EAAKqM,UAAU,IAAIjM,MAAM,KAMvC,OAJAuS,EAAKkkB,KAAOzvB,EAAMiiC,QAClB12B,EAAKimH,YAAcxxH,EAAMiiC,QAGlB12B,GAEXw8D,UAAUnvE,GACN,MAAM2S,EAAO,GACb,IAAIvL,EAAQpH,EAAKI,MAAM,KAEvBgH,EAAMiiC,QACNjiC,EAAQA,EAAM3B,KAAK,KAAKrF,MAAM,KAC9B,IAAK,IAAI1C,EAAI,EAAGA,EAAI0J,EAAMxJ,OAAQF,IAAK,CACnC,IAAI0M,EAAMhD,EAAM1J,GAAG0C,MAAM,KAAK,GAE9B,KAAOgK,EAAIxM,QAAqB,MAAXwM,EAAI,IACrBA,EAAMA,EAAIiC,UAAU,GAExB,MAAMhJ,EAAQ+D,EAAM1J,GAAG0C,MAAM,KAAK,GAE9BgK,GAAO/G,EACPsP,EAAKvU,KAAK,CAAEsK,KAAM0B,EACd/G,MAAAA,IACG+G,GAEPuI,EAAKvU,KAAK,CAAEsK,KAAM,GACdrF,MAAO+G,IAInB,OAAOuI,GAEXkmH,kBAAkB74H,GACd,MAAM4tE,EAAY,GACZziC,EAAQnrC,EAAKI,MAAM,KAEzBwtE,EAAUC,WAAa1iC,EAAM,GAAG9+B,UAAU,IAC1CuhE,EAAU3hE,UAAYk/B,EAAM,GAC5ByiC,EAAUE,SAAW3iC,EAAM,GAAG9X,cAC9Bu6C,EAAUG,SAAW5iC,EAAM,GAC3ByiC,EAAU1hE,GAAKi/B,EAAM,GACrByiC,EAAUzhE,KAAOg/B,EAAM,GAGvByiC,EAAU9pE,KAAOqnC,EAAM,GACvByiC,EAAU5jE,WAAa,EACvB,IAAK,IAAItM,EAAI,EAAGA,EAAIytC,EAAMvtC,OAAQF,GAAK,EACnC,OAAQytC,EAAMztC,IACd,IAAK,QACDkwE,EAAU,YAAcziC,EAAMztC,EAAI,GAClC,MACJ,IAAK,QACDkwE,EAAU,YAAcziC,EAAMztC,EAAI,GAClC,MACJ,IAAK,aACDkwE,EAAU5jE,WAAamhC,EAAMztC,EAAI,GACjC,MACJ,IAAK,UACDkwE,EAAU7jE,QAAUohC,EAAMztC,EAAI,GAC9B,MACJ,QACI+C,GAAOynF,MACF,sCACG/8C,EAAMztC,UAAUytC,EAAMztC,EAAI,OAS1C,OANAkwE,EAAUkrD,QAAU,IAIpBlrD,EAAUrsE,GAAK4E,KAAKE,SAAS+W,SAAS,IAAI7c,OAAO,EAAG,IAE7CqtE,GAEXmrD,kBAAkBC,GACd,IAAIh5H,EAAO,CACN,eAAcg5H,EAAKnrD,aACpBmrD,EAAK/sH,UACL+sH,EAAKlrD,SACLkrD,EAAKjrD,SACLirD,EAAK9sH,GACL8sH,EAAK7sH,KACL,MACA6sH,EAAKl1H,MACP2B,KAAK,KAGP,OADAzF,GAAQ,IACAg5H,EAAKl1H,MACb,IAAK,QACL,IAAK,QACL,IAAK,QACGk1H,EAAKC,gBAAgB,aACdD,EAAKC,gBAAgB,cAC5Bj5H,GAAQ,QACRA,GAAQ,IACRA,GAAQg5H,EAAK,YACbh5H,GAAQ,IACRA,GAAQ,QACRA,GAAQ,IACRA,GAAQg5H,EAAK,YACbh5H,GAAQ,KAchB,OAVIg5H,EAAKC,gBAAgB,aACrBj5H,GAAQ,UACRA,GAAQ,IACRA,GAAQg5H,EAAKjvH,QACb/J,GAAQ,KAEZA,GAAQ,aACRA,GAAQ,IACRA,GAAQg5H,EAAKC,gBAAgB,cAAgBD,EAAKhvH,WAAa,IAExDhK,GAEXk5H,UAAUl1H,GAIN,MAAM2O,EAAO,IAAI4vD,IACXoN,EAAQ3rE,EAAK5D,MAAM,QAEzB,IAAK,IAAI1C,EAAI,EAAGA,EAAIiyE,EAAM/xE,OAAQF,IAC9B,GAAiC,YAA7BiyE,EAAMjyE,GAAG2O,UAAU,EAAG,GAAkB,CAExC,MAAMvJ,EAAO6sE,EAAMjyE,GAAG0C,MAAM,WAAW,GAAGA,MAAM,KAAK,GAEhDuS,EAAKuO,IAAIpe,IACV6P,EAAKyO,IAAIte,EAAM,IAGnB6P,EAAKuO,IAAIpe,GAAM1E,KAAKuxE,EAAMjyE,IAIlC,OAAOiV,GASXwmH,oBAAoBhB,GAChB,MAAMiB,EAAiBjB,EAAU5zH,MAAK80H,GAAeA,EAAY95H,QAAQ,UAAY,IAGrF,OAAO65H,MAAAA,OAAP,EAAOA,EAAgB/sH,UAAU+sH,EAAe75H,QAAQ,UAAY,IAExE+5H,YAAYt5H,GACR,MAAMoH,EAAQpH,EAAKO,OAAO,IAAIH,MAAM,KAC9BuS,EAAO,GAMb,OAJAA,EAAK0C,GAAKjO,EAAMiiC,QAChB12B,EAAK7O,KAAOsD,EAAMiiC,QAClB12B,EAAK48D,OAASnoE,EAEPuL,GAEXo8D,YAAY/uE,GACR,MAAMoH,EAAQpH,EAAKO,OAAO,GAAGH,MAAM,KAC7BuS,EAAO,GAYb,OAVAA,EAAKtP,MAAQ+D,EAAMiiC,SACc,IAA7B12B,EAAKtP,MAAM9D,QAAQ,KACnBoT,EAAKrK,UAAY,QAEjBqK,EAAKrK,UAAYqK,EAAKtP,MAAM9C,OAAOoS,EAAKtP,MAAM9D,QAAQ,KAAO,GAC7DoT,EAAKtP,MAAQsP,EAAKtP,MAAM9C,OAAO,EAAGoS,EAAKtP,MAAM9D,QAAQ,OAEzDoT,EAAKxE,IAAM/G,EAAMiiC,QACjB12B,EAAK48D,OAASnoE,EAEPuL,GAEXglH,SAAS4B,EAAUC,EAAQhpD,GACvB,IAAIb,EAAQ4pD,EAASn5H,MAAM,QAE3B,IAAK,IAAI1C,EAAI,EAAGA,EAAIiyE,EAAM/xE,OAAQF,IAC9B,GAAIiyE,EAAMjyE,GAAG2O,UAAU,EAAGmtH,EAAO57H,UAAY47H,EACzC,OAAO7pD,EAAMjyE,GAGrB,IAAK8yE,EACD,OAAO,EAIXb,EAAQa,EAAYpwE,MAAM,QAC1B,IAAK,IAAI8G,EAAI,EAAGA,EAAIyoE,EAAM/xE,OAAQsJ,IAC9B,GAAIyoE,EAAMzoE,GAAGmF,UAAU,EAAGmtH,EAAO57H,UAAY47H,EACzC,OAAO7pD,EAAMzoE,GAIrB,OAAO,GAEXuyH,UAAUF,EAAUC,EAAQhpD,GACxB,IAAIb,EAAQ4pD,EAASn5H,MAAM,QAC3B,MAAMs5H,EAAU,GAEhB,IAAK,IAAIh8H,EAAI,EAAGA,EAAIiyE,EAAM/xE,OAAQF,IAC1BiyE,EAAMjyE,GAAG2O,UAAU,EAAGmtH,EAAO57H,UAAY47H,GACzCE,EAAQt7H,KAAKuxE,EAAMjyE,IAG3B,GAAIg8H,EAAQ97H,SAAW4yE,EACnB,OAAOkpD,EAIX/pD,EAAQa,EAAYpwE,MAAM,QAC1B,IAAK,IAAI8G,EAAI,EAAGA,EAAIyoE,EAAM/xE,OAAQsJ,IAC1ByoE,EAAMzoE,GAAGmF,UAAU,EAAGmtH,EAAO57H,UAAY47H,GACzCE,EAAQt7H,KAAKuxE,EAAMzoE,IAI3B,OAAOwyH,GAEXC,kBAAkB35H,GAKd,GAAmC,IAA/BA,EAAKT,QAAQ,cAEbS,EAAQ,KAAIA,SACT,GAA8B,iBAA1BA,EAAKqM,UAAU,EAAG,IAMzB,OALA5L,GAAO2T,KACH,kEAEJ3T,GAAO2T,KAAKpU,GAEL,KAE6B,SAApCA,EAAKqM,UAAUrM,EAAKpC,OAAS,KAE7BoC,EAAOA,EAAKqM,UAAU,EAAGrM,EAAKpC,OAAS,IAE3C,MAAMgwE,EAAY,GACZziC,EAAQnrC,EAAKI,MAAM,KAEzB,GAAiB,QAAb+qC,EAAM,GAIN,OAHA1qC,GAAO2T,KAAK,uCACZ3T,GAAO2T,KAAKpU,GAEL,KAEX4tE,EAAUC,WAAa1iC,EAAM,GAAG9+B,UAAU,IAC1CuhE,EAAU3hE,UAAYk/B,EAAM,GAC5ByiC,EAAUE,SAAW3iC,EAAM,GAAG9X,cAC9Bu6C,EAAUG,SAAW5iC,EAAM,GAC3ByiC,EAAU1hE,GAAKi/B,EAAM,GACrByiC,EAAUzhE,KAAOg/B,EAAM,GAGvByiC,EAAU9pE,KAAOqnC,EAAM,GAEvByiC,EAAU5jE,WAAa,IACvB,IAAK,IAAItM,EAAI,EAAGA,EAAIytC,EAAMvtC,OAAQF,GAAK,EACnC,OAAQytC,EAAMztC,IACd,IAAK,QACDkwE,EAAU,YAAcziC,EAAMztC,EAAI,GAClC,MACJ,IAAK,QACDkwE,EAAU,YAAcziC,EAAMztC,EAAI,GAClC,MACJ,IAAK,aACDkwE,EAAU5jE,WAAamhC,EAAMztC,EAAI,GACjC,MACJ,IAAK,UACDkwE,EAAU7jE,QAAUohC,EAAMztC,EAAI,GAC9B,MACJ,QACI+C,GAAOynF,MAAO,oBAAmB/8C,EAAMztC,UAAUytC,EAAMztC,EAAI,OASnE,OANAkwE,EAAUkrD,QAAU,IAIpBlrD,EAAUrsE,GAAK4E,KAAKE,SAAS+W,SAAS,IAAI7c,OAAO,EAAG,IAE7CqtE,GAEXgsD,oBAAoBZ,GAChB,IAAIh5H,EAAO,eAEXA,GAAQg5H,EAAKt6G,aAAa,cAC1B1e,GAAQ,IACRA,GAAQg5H,EAAKt6G,aAAa,aAC1B1e,GAAQ,IAER,IAAI8tE,EAAWkrD,EAAKt6G,aAAa,YAmBjC,OAfI+iB,GAAQ8gD,aAA0C,WAA3BzU,EAASz6C,gBAChCy6C,EAAW,OAGf9tE,GAAQ8tE,EACR9tE,GAAQ,IACRA,GAAQg5H,EAAKt6G,aAAa,YAC1B1e,GAAQ,IACRA,GAAQg5H,EAAKt6G,aAAa,MAC1B1e,GAAQ,IACRA,GAAQg5H,EAAKt6G,aAAa,QAC1B1e,GAAQ,IACRA,GAAQ,MACRA,GAAS,IAAGg5H,EAAKt6G,aAAa,UAC9B1e,GAAQ,IACAg5H,EAAKt6G,aAAa,SAC1B,IAAK,QACL,IAAK,QACL,IAAK,QACGs6G,EAAKt6G,aAAa,aACXs6G,EAAKt6G,aAAa,cACzB1e,GAAQ,QACRA,GAAQ,IACRA,GAAQg5H,EAAKt6G,aAAa,YAC1B1e,GAAQ,IACRA,GAAQ,QACRA,GAAQ,IACRA,GAAQg5H,EAAKt6G,aAAa,YAC1B1e,GAAQ,KAchB,MAV+B,QAA3B8tE,EAASz6C,gBACTrzB,GAAQ,UACRA,GAAQ,IACRA,GAAQg5H,EAAKt6G,aAAa,WAC1B1e,GAAQ,KAEZA,GAAQ,aACRA,GAAQ,IACRA,GAAQg5H,EAAKt6G,aAAa,eAAiB,IAEnC,GAAE1e,SAQd65H,sBAAsBC,GAClB,MAAMvzH,EAAWuzH,EAAW92H,MACvBI,KAAIF,GAAYA,EAAS3B,KACzB0B,QAAO,CAACH,EAAM0D,EAAOC,IAAUA,EAAMlH,QAAQuD,KAAU0D,IACvD5I,OACC8I,EACCozH,EAAWx1H,YAAcw1H,EAAWx1H,WAAW1G,QAAW,EAEjE,GAAI2I,EAAW,GAAmB,IAAdG,EAEhB,OAEJ,IAAIf,EAAc,KAElB,GAAiB,IAAbY,EACAZ,EAAcm0H,EAAW92H,MAAM,GAAGzB,QAC/B,GAAiB,IAAbgF,EAAgB,CAEvB,MAAMI,EACAmzH,EAAWx1H,WAAWC,MACpBC,GAA6B,QAApBA,EAAMC,YAEnBkC,IACAhB,EAAcgB,EAAS3D,MAAM5C,MAAM,KAAK,SAEzC,GAAImG,GAAY,EAAG,CAEtB,MAAMlC,EACAy1H,EAAWx1H,WAAWC,MACpBC,GAA6B,QAApBA,EAAMC,YAEnBJ,IACAsB,EAActB,EAASrB,MAAM5C,MAAM,KAAK,IAIhD,OAAOuF,GAOXo0H,aAAY,IACD5kG,KAAAA,UAAqB,EAAG,YAYnCvyB,iBAAiBC,EAAOC,EAAMC,GAC1B,IAAK,IAAIrF,EAAI,EAAGA,EAAImF,EAAMG,MAAMpF,SAAUF,EAAG,CACzC,MAAMs8H,EAAWn3H,EAAMG,MAAMtF,GAE7B,GAAIs8H,EAASz4H,KAAOuB,GACbk3H,EAAS72H,YAAcJ,EAC1B,OAAOi3H,EAAS32H,QAa5B42H,gBAAgBC,GACLA,EACFl3H,MACA5C,MAAM,KACNgD,KAAIsB,GAAWC,SAASD,EAAS,MAS1Cy1H,SAAQ,CAACl2H,EAAKH,IACHG,EAAIJ,MAAMU,MAAKlE,GAAKA,EAAEyD,OAASA,IAO1Cs2H,SAASn2H,GACL,MAAMo2H,EACAp2H,EAAI7D,MAAM,MAAM6C,QAAOjD,GAAQA,EAAK48G,WAAW,kBAErD,GAAIyd,EAAWz8H,OAAS,EACpB,OAAOy8H,EAAW,GAAG95H,OAAO,eAAe3C,SAWnD08H,YAAYjoD,EAAOkoD,GACf,IAAKloD,IAAUkoD,EACX,OAGJ,MAAMC,EAAuBnoD,EAAM3mE,IAC9BzI,QAAOyI,GAAOA,EAAImjE,OAASnjE,EAAImjE,MAAMx7C,gBAAkBknG,EAAUlnG,gBACjEjwB,KAAIsI,GAAOA,EAAIm1F,UAEpB,GAAI25B,EAAsB,CAGtB,MAAMC,EACApoD,EAAMjlE,SACPgQ,WACAhd,MAAM,KACNgD,KAAI8F,GAAKvE,SAASuE,EAAG,MAE1B,IAAK,MAAMmM,KAAMmlH,EAAqBh/F,UAAW,CAC7C,MAAMk/F,EAAeD,EAAal7H,QAAQ8V,GAE1ColH,EAAa/6H,OAAOg7H,EAAc,GAClCD,EAAajzF,QAAQnyB,GAEzBg9D,EAAMjlE,SAAWqtH,EAAah1H,KAAK,OAc3Ck1H,WAAW93H,EAAO03H,GAAgC,IAArBK,EAAqB,wDAC9C,IAAK/3H,IAAU03H,EACX,OAGJ,MAAMM,EAAU,GAChB,IAAIC,EAAY,GAChB,MAAMC,EAAqBR,EAAUlnG,gBAAkB2nG,GAAAA,MAAsBJ,EAE7E,IAAK,MAAMlvH,KAAO7I,EAAM6I,IAChBA,EAAImjE,OACDnjE,EAAImjE,MAAMx7C,gBAAkBknG,EAAUlnG,gBACrC0nG,EACAF,EAAQz8H,KAAKsN,EAAIm1F,SAEjBi6B,EAAU18H,KAAKsN,EAAIm1F,UAY/B,GANIk6B,IACAD,EAAYj4H,EAAM8I,KACb1I,QAAOmJ,GAAQyuH,EAAQt7H,QAAQ6M,EAAKy0F,UAAY,GAAKz0F,EAAKzC,OAAOgwG,SAAS,yBAC1Ev2G,KAAIgJ,GAAQA,EAAKy0F,WAGtBi6B,EAAUl9H,OAAS,EAAG,CAGtB,MAAMq9H,EAAUH,EAAU13H,KAAIgJ,GAAS,OAAMA,MACvC8uH,EAASr4H,EAAM8I,KAAK1I,QACtBmJ,IAA0C,IAAlC6uH,EAAQ17H,QAAQ6M,EAAKzC,UAEjCmxH,EAAU18H,QAAQ88H,EAAO93H,KAAIgJ,GAAQA,EAAKy0F,WAK1C,MAIMs6B,EAJSt4H,EAAMuK,SAChBgQ,WACAhd,MAAM,KACNgD,IAAI4H,QACc/H,QAAOoS,IAAiC,IAA3BylH,EAAUv7H,QAAQ8V,KAE/B,IAAnB8lH,EAAQv9H,QAERiF,EAAMsJ,KAAO,EACbtJ,EAAMyF,UAAY8yH,GAAAA,SAClBv4H,EAAMuK,SAAW,KAEjBvK,EAAMuK,SAAW+tH,EAAQ11H,KAAK,KAGlC5C,EAAM6I,IAAM7I,EAAM6I,IAAIzI,QAClBmJ,IAA2C,IAAnC+uH,EAAQ57H,QAAQ6M,EAAKy0F,WACjCh+F,EAAM8I,KAAO9I,EAAM8I,KAAK1I,QACpBmJ,IAA2C,IAAnC+uH,EAAQ57H,QAAQ6M,EAAKy0F,WAC7Bh+F,EAAMw4H,SACNx4H,EAAMw4H,OAASx4H,EAAMw4H,OAAOp4H,QACxBmJ,IAA2C,IAAnC+uH,EAAQ57H,QAAQ6M,EAAKy0F,eAMjD,MCzrBe,SAASy6B,GAAIr3H,GACxB,MAAMJ,EAAQI,EAAI7D,MAAM,UAExB,IAAK,IAAI1C,EAAI,EAAGE,EAASiG,EAAMjG,OAAQF,EAAIE,EAAQF,IAAK,CACpD,IAAI69H,EAAU,KAAI13H,EAAMnG,KAEpBA,IAAME,EAAS,IACf29H,GAAU,QAEd13H,EAAMnG,GAAK69H,EAEf,MAAM73H,EAAW,GAAEG,EAAMwlC,cAEzBntC,KAAK2H,MAAQA,EACb3H,KAAKukD,IAAM/8C,EAAUG,EAAM4B,KAAK,IAChCvJ,KAAKwH,QAAUA,ECpBnB,SAAS83H,GAAYC,EAAQC,GAEzB,IAAKA,EACD,OAAO,EAIX,GAAID,EAAO79H,SAAW89H,EAAO99H,OACzB,OAAO,EAGX,IAAK,IAAIF,EAAI,EAAGyD,EAAIs6H,EAAO79H,OAAQF,EAAIyD,EAAGzD,IAEtC,GAAI+9H,EAAO/9H,aAAckD,OAAS86H,EAAOh+H,aAAckD,OAEnD,IAAK66H,EAAO/9H,GAAGi+H,OAAOD,EAAOh+H,IACzB,OAAO,OAER,GAAI+9H,EAAO/9H,KAAOg+H,EAAOh+H,GAG5B,OAAO,EAIf,OAAO,EAQI,SAASk+H,GAAUC,EAAOC,GAGrC,GAFA5/H,KAAK2/H,MAAQA,EACb3/H,KAAK4/H,SAAWA,GACXD,EACD,MAAM,IAAI37H,MAAM,yBACb,IAAK47H,EACR,MAAM,IAAI57H,MAAM,4BDVxBo7H,GAAIn+H,UAAU4+H,SAAU,EAMxBT,GAAIn+H,UAAU6+H,qBAAsB,EAMpCV,GAAIn+H,UAAU8+H,qBAAsB,EAQpCX,GAAIn+H,UAAU++H,0BAA4B,SAAS/8C,GAC/C,MAAM/O,EAAMl0E,KAAK2H,MAAMjG,OACjBqG,EAAMzB,GAAAA,MAAgBtG,KAAKukD,KAC3B4xB,EAAQ8pD,IAAAA,CAAUl4H,EAAIJ,MAAMU,MAAKlE,GAAKA,EAAEyD,OAASq7E,KAGvD9M,EAAMjC,IAAMA,EACZiC,EAAM/pE,UAAY8yH,GAAAA,SAGlB/oD,EAAMrsE,UAAOiC,EACboqE,EAAMrvE,WAAQiF,EACdoqE,EAAM/tE,gBAAa2D,EAEnBhE,EAAIJ,MAAQI,EAAIJ,MAAM5C,OAAOoxE,GAG7BpuE,EAAI8sC,OAAOt0C,SAAQ+H,IACf,GAAmB,WAAfA,EAAMV,KAAmB,CACzB,MAAMs4H,EAAO53H,EAAM43H,KAAKh8H,MAAM,KAE9Bg8H,EAAKh+H,KAAKgyE,GACV5rE,EAAM43H,KAAOA,EAAK32H,KAAK,SAG/BvJ,KAAKukD,IAAMj+C,GAAAA,MAAgByB,IAM/Bq3H,GAAIn+H,UAAUk/H,gBAAkB,WAC5B,MAAMC,EAAa,GAEnB,IAAK,IAAIC,EAAa,EAAGA,EAAargI,KAAK2H,MAAMjG,OAAQ2+H,IAAc,CACnE,MAGM14H,EAAQ,CACV04H,WAAAA,EACAnsD,IAJEknD,GAAAA,SACEA,GAAAA,SAAiBp7H,KAAK2H,MAAM04H,GAAa,WAI7Cv5H,MAAO,GACPsB,WAAY,IAGhBg4H,EAAWC,GAAc14H,EAEzByzH,GAAAA,UAAkBp7H,KAAK2H,MAAM04H,GAAa,WAAW9/H,SAAQuD,IACzD,MAAMw8H,EAAWx8H,EAAKqM,UAAU,GAAGjM,MAAM,KAAK,GAIzCyD,EAAMb,MAAMw5H,KACb34H,EAAMb,MAAMw5H,GAAY,CACpB15H,KAAM05H,EACN7sD,MAAO,KAGf9rE,EAAMb,MAAMw5H,GAAU7sD,MAAMvxE,KAAK4B,MAErCs3H,GAAAA,UAAkBp7H,KAAK2H,MAAM04H,GAAa,iBAAiB9/H,SAAQuD,IAC/D,MAAMg2C,EAAMh2C,EAAKT,QAAQ,KACnBkF,EAAYzE,EAAKO,OAAO,EAAGy1C,GAAKz1C,OAAO,IACvCyC,EAAQhD,EAAKO,OAAO,GAAKkE,EAAU7G,QAAQwC,MAAM,KAEnD4C,EAAMpF,QACNiG,EAAMS,WAAWlG,KAAK,CAClBqG,UAAAA,EACAzB,MAAAA,OAMhB,OAAOs5H,GAQXhB,GAAIn+H,UAAUs/H,aAAe,SAAS35H,GAElC,MAAM45H,EAASxgI,KAAKmgI,kBACpB,IAAI7mG,GAAS,EAWb,OATAl5B,OAAOC,KAAKmgI,GAAQjgI,SAAQ8/H,IACpB/mG,GAGAknG,EAAOH,GAAYv5H,MAAMF,KACzB0yB,GAAS,MAIVA,GAIX8lG,GAAIn+H,UAAUw/H,SAAW,SAASpxF,EAAMqxF,GAEpCtF,GAAAA,UAAkBp7H,KAAKwH,QAAS,YAAYjH,SAAQuD,IAChD,MAAMoH,EAAQpH,EAAKI,MAAM,KACnBqE,EAAY2C,EAAMiiC,QAAQ9oC,OAAO,GAEvCgrC,EAAKliC,EAAE,QAAS,CAAEiH,MAAO,kCACrB7L,UAAAA,IACJ,IAAK,IAAIyC,EAAI,EAAGA,EAAIE,EAAMxJ,OAAQsJ,IAC9BqkC,EAAKliC,EAAE,UAAW,CAAEX,KAAMtB,EAAMF,KAAM+5G,KAE1C11E,EAAK01E,QAGT,IAAK,IAAIvjH,EAAI,EAAGA,EAAIxB,KAAK2H,MAAMjG,OAAQF,IAAK,CACxC,MAAM20E,EAAQilD,GAAAA,WAAmBp7H,KAAK2H,MAAMnG,GAAG0C,MAAM,QAAQ,IAE7D,GAAsB,UAAhBiyE,EAAMxuE,OACa,UAAhBwuE,EAAMxuE,OACU,gBAAhBwuE,EAAMxuE,MACX,SAGJ,IAAIf,EACJ,MAAM+5H,EAAYvF,GAAAA,SAAiBp7H,KAAK2H,MAAMnG,GAAI,WAG9CoF,IADA+5H,GACOA,EAAUxwH,UAAU,GAAGjM,MAAM,KAAK,GAK7CmrC,EAAKliC,EAAE,UAAW,CAAEyzH,QAASF,EACzBl0H,KAAM2pE,EAAMxuE,QAChB,MAAMk5H,EAAWzF,GAAAA,SAAiBp7H,KAAK2H,MAAMnG,GAAI,UAEjD,GAAIq/H,EAAU,CAEV,MAAM3sD,EAAMknD,GAAAA,SAAiByF,GAE7BxxF,EAAK/5B,MAAM,CAAE9I,KAAM0nE,IAGvB,GAAoB,UAAhBiC,EAAMxuE,OAAqC,UAAhBwuE,EAAMxuE,MAAmB,CACpD0nC,EAAKliC,EAAE,cACH,CAAEiH,MAAO,6BACLzM,MAAOwuE,EAAMxuE,QACjBf,GACAyoC,EAAK/5B,MAAM,CAAE1O,KAAAA,IAEjB,IAAK,IAAIoE,EAAI,EAAGA,EAAImrE,EAAMuC,IAAIh3E,OAAQsJ,IAAK,CACvC,MAAM81H,EACA1F,GAAAA,SACEp7H,KAAK2H,MAAMnG,GACV,YAAW20E,EAAMuC,IAAI1tE,MAE9BqkC,EAAKliC,EAAE,eAAgBiuH,GAAAA,YAAoB0F,IAI3C,MAAMC,EACA3F,GAAAA,SACEp7H,KAAK2H,MAAMnG,GACV,UAAS20E,EAAMuC,IAAI1tE,MAE5B,GAAI+1H,EAAW,CACX,MAAMC,EAAiB5F,GAAAA,UAAkB2F,GAGzC,IAAK,IAAI1qG,EAAI,EAAGA,EAAI2qG,EAAet/H,OAAQ20B,IACvCgZ,EAAKliC,EAAE,YAAa6zH,EAAe3qG,IAAI0uF,KAK/C/kH,KAAKihI,eAAez/H,EAAG6tC,EAAM8mC,EAAMuC,IAAI1tE,IAEvCqkC,EAAK01E,KAGT,GAAIn+G,EAAM,CACN,MAAMiC,EAAUuyH,GAAAA,UAAkBp7H,KAAK2H,MAAMnG,IAE7C,IAAK,MAAQ0/H,EAAeC,KAAoBt4H,EAAS,CACrD,MAAMu4H,EAAahG,GAAAA,oBAA4B+F,GAE/C9xF,EAAKliC,EAAE,SAAU,CACbvG,KAAMs6H,EACN10H,KAAM6qH,GAAAA,+BAA8C+J,OAAar1H,EACjEqI,MAAO,oCAGX,MAAMtK,EAAOsxH,GAAAA,mBAA2B+F,GAGpCr3H,IACAulC,EAAKliC,EAAE,aACPkiC,EAAK/5B,MAAM,CAAE9I,KAAM,SACnB6iC,EAAK/5B,MAAM,CAAEnO,MAAO2C,IACpBulC,EAAK01E,MAGT11E,EAAK01E,KAKHqW,GAAAA,UAAkBp7H,KAAK2H,MAAMnG,GAAI,iBAExBjB,SAAQuD,IACnB,MAAMg2C,EAAMh2C,EAAKT,QAAQ,KACnBkF,EAAYzE,EAAKO,OAAO,EAAGy1C,GAAKz1C,OAAO,IACvCyC,EAAQhD,EAAKO,OAAO,GAAKkE,EAAU7G,QAAQwC,MAAM,KAEnD4C,EAAMpF,SACN2tC,EAAKliC,EAAE,aAAc,CAAE5E,UAAAA,EACnB6L,MAAO,oCACXtN,EAAMvG,SAAQsM,GAAKwiC,EAAKliC,EAAE,SAAU,CAAEvG,KAAMiG,IAAKk4G,OACjD11E,EAAK01E,SAKjB,MAAMsc,EAAWjG,GAAAA,UAAkBp7H,KAAK2H,MAAMnG,GAAI,UAElD,GAAI6/H,EAAS3/H,QAAU6jC,GAAQ2jD,uBAAwB,CAGnD,MAAMo4C,EAAOD,EACRn6H,KAAIq6H,GAAWA,EAAQr9H,MAAM,KAAK,KAClCgD,KAAIs6H,GAAWA,EAAQt9H,MAAM,KAAK,KAEvCo9H,EAAK/gI,SAAQ0hH,IACT5yE,EAAKliC,EAAE,SAAU,CACb80G,IAAAA,EACA7tG,MAAO,oCAEXi7B,EAAK01E,QAGHqW,GAAAA,SAAiBp7H,KAAK2H,MAAMnG,GAAI,kBAGlC6tC,EAAKliC,EAAE,YAAa,CAChB5E,UAAW,MACX6L,MAAO,oCAEXktH,EAAK/gI,SAAQ0hH,IACT5yE,EAAKliC,EAAE,SAAU,CAAE80G,IAAAA,IAAO8C,QAE9B11E,EAAK01E,MAITqW,GAAAA,SAAiBp7H,KAAK2H,MAAMnG,GAAI,eAChC6tC,EAAKliC,EAAE,YAAY43G,KAIvB/kH,KAAKihI,eAAez/H,EAAG6tC,EAAM,KAG7B,MAAMoyF,EAAcrG,GAAAA,UAAkBp7H,KAAK2H,MAAMnG,GAAI,aAErD,IAAK,IAAIwJ,EAAI,EAAGA,EAAIy2H,EAAY//H,OAAQsJ,IAAK,CACzC,MAAM02H,EAAStG,GAAAA,YAAoBqG,EAAYz2H,IAS/C,GAPAqkC,EAAKliC,EAAE,aAAc,CACjBiH,MAAO,wCACPnC,IAAKyvH,EAAOzvH,IACZ5M,GAAIq8H,EAAOv6H,QAIXu6H,EAAOjpH,eAAe,aAGtB,OAAQipH,EAAOt1H,WACf,KAAK8yH,GAAAA,SACD7vF,EAAK/5B,MAAM,CAAEqsH,QAAS,cACtB,MACJ,KAAKzC,GAAAA,SACD7vF,EAAK/5B,MAAM,CAAEqsH,QAAS,cACtB,MACJ,KAAKzC,GAAAA,SACD7vF,EAAK/5B,MAAM,CAAEqsH,QAAS,SACtB,MACJ,KAAKzC,GAAAA,SACD7vF,EAAK/5B,MAAM,CAAEqsH,QAAS,SAM9BtyF,EAAK01E,KAET11E,EAAK01E,KAIT/kH,KAAK4hI,kBAAkBpgI,EAAG6tC,GAE1B,MAAMlrC,EAAInE,KAAK2H,MAAMnG,GAEjB45H,GAAAA,SAAiBj3H,EAAI,KAAI+6H,GAAAA,WAA2Bl/H,KAAKwH,SACzD6nC,EAAK/5B,MAAM,CAAEqsH,QAAS,SACfvG,GAAAA,SAAiBj3H,EAAI,KAAI+6H,GAAAA,WAA2Bl/H,KAAKwH,SAChE6nC,EAAK/5B,MAAM,CAAEqsH,QAAS,cACfvG,GAAAA,SAAiBj3H,EAAI,KAAI+6H,GAAAA,WAA2Bl/H,KAAKwH,SAChE6nC,EAAK/5B,MAAM,CAAEqsH,QAAS,cACfvG,GAAAA,SAAiBj3H,EAAI,KAAI+6H,GAAAA,WAA2Bl/H,KAAKwH,UAChE6nC,EAAK/5B,MAAM,CAAEqsH,QAAS,SAKP,MAAfxrD,EAAMlmE,MAAiBmrH,GAAAA,SAAiBj3H,EAAG,gBAAiBnE,KAAKwH,UAEjE6nC,EAAK/5B,MAAM,CAAEqsH,QAAS,aAE1BtyF,EAAK01E,KAIT,OAFA11E,EAAK01E,KAEE11E,GAGX+vF,GAAIn+H,UAAU2gI,kBAAoB,SAASvB,EAAYhxF,GACnDA,EAAKliC,EAAE,aAGP,MAAM00H,EACAzG,GAAAA,SAAiBp7H,KAAK2H,MAAM04H,GAAa,eAAgBrgI,KAAKwH,SAC9Ds6H,EACA1G,GAAAA,SAAiBp7H,KAAK2H,MAAM04H,GAAa,aAAcrgI,KAAKwH,SAElE,GAAIq6H,EAAU,CACV,MAAME,EAAY3G,GAAAA,cAAsByG,GAExCxyF,EAAKliC,EAAE,UAAW,CACdiH,MAAO,yCACPq9E,OAAQswC,EACRnwD,SAAU,uBAIdviC,EAAK/5B,MAAM,CAAE0sH,QAAS,IACtB3yF,EAAK01E,UACF,GAAI+c,EAAS,CAChB,MAAMC,EAAY3G,GAAAA,aAAqB0G,GAEvCzyF,EAAKliC,EAAE,UAAW,CACdiH,MAAO,yCACPq9E,OAAQswC,EAAU,GAClBnwD,SAAUmwD,EAAU,KAIpBA,EAAUrgI,OAAS,EACnB2tC,EAAK/5B,MAAM,CAAE0sH,QAASD,EAAU,KAEhC1yF,EAAK/5B,MAAM,CAAE0sH,QAAS,IAE1B3yF,EAAK01E,KAKHqW,GAAAA,UACEp7H,KAAK2H,MAAM04H,GACX,iBACArgI,KAAKwH,SAEAjH,SAAQuD,IACjB,MAAM44H,EAActB,GAAAA,iBAAyBt3H,GAE7C44H,EAAYtoH,MAAQ,8BACpBi7B,EAAKliC,EAAE,eAAenI,EAAE03H,EAAYA,oBAC7BA,EAAYA,YAEnB,MAAMuF,EACA7G,GAAAA,SACEp7H,KAAK2H,MAAM04H,GACX,WACArgI,KAAKwH,SAETy6H,IACAvF,EAAYxxE,MAAQ+2E,EAAU59H,OAAO,IAEzCgrC,EAAK/5B,MAAMonH,GACXrtF,EAAK01E,QAET,MAAMmd,EAAgB9G,GAAAA,UAAkBp7H,KAAK2H,MAAM04H,GAAargI,KAAKwH,SAEjE06H,IACAA,EAAc9tH,MAAQ,uCACtBi7B,EAAK/5B,MAAM4sH,GAIL9G,GAAAA,UACEp7H,KAAK2H,MAAM04H,GACX,eACArgI,KAAKwH,SAEEjH,SAAQuD,IACnB,MAAM4tE,EAAY0pD,GAAAA,kBAA0Bt3H,GAExC9D,KAAK6/H,UACLnuD,EAAU1hE,GAAK,WAEnB,MAAM4hE,EACAF,GAA2C,iBAAvBA,EAAUE,SAC1BF,EAAUE,SAASz6C,cACnB,GAELn3B,KAAK8/H,sBACe,QAAbluD,GAAmC,WAAbA,IAC1B5xE,KAAK+/H,qBAAoC,QAAbnuD,GAGpCviC,EAAKliC,EAAE,YAAaukE,GAAWqzC,SAGvC11E,EAAK01E,MAITqa,GAAIn+H,UAAUggI,eAAiB,SAASZ,EAAYhxF,EAAM8yF,GAEhD/G,GAAAA,UACEp7H,KAAK2H,MAAM04H,GACV,aAAY8B,KAEf5hI,SAAQuD,IACV,MAAMs+H,EAAWhH,GAAAA,YAAoBt3H,GAEf,YAAlBs+H,EAASx6H,MACTynC,EAAKliC,EAAE,kBAAmB,CACtBiH,MAAO,qCACPjN,MAAOi7H,EAAS/uD,OAAO,KAE3BhkC,EAAK01E,OAEL11E,EAAKliC,EAAE,UAAW,CACdiH,MAAO,qCACPxM,KAAMw6H,EAASx6H,OAEfw6H,EAAS/uD,OAAO3xE,OAAS,GACzB2tC,EAAK/5B,MAAM,CAAE,QAAW8sH,EAAS/uD,OAAO,KAE5ChkC,EAAK01E,UAKjBqa,GAAIn+H,UAAUohI,iBAAmB,SAAShzF,EAAM8yF,GAC5C,IAAIp6H,EAAM,GACV,MAAMu6H,EACAjzF,EAAKhnC,KACH,gEAsBR,OApBIi6H,EAAsB5gI,SACtBqG,GAAO,uBACHu6H,EAAsB5sH,KAAK,SAC3B3N,GAAOu6H,EAAsB5sH,KAAK,SAElC3N,GAAO,IAEXA,GAAO,QAGcsnC,EAAKhnC,KAAK,wDAElB+mC,MAAK,CAAC0R,EAAG6yB,KACtB5rE,GAAQ,aAAYo6H,KAAexuD,EAAGnxD,aAAa,UAC/CmxD,EAAGpwD,aAAa,aAChBxb,GAAQ,IAAG4rE,EAAGnxD,aAAa,cAE/Bza,GAAO,UAGJA,GAIXq3H,GAAIn+H,UAAUshI,WAAa,SAAS9K,GAChC,MAAMt+C,EAAYh0E,KAAK8nD,MAGvBjtD,KAAKukD,IACE,cAAM40B,yCAMb,MAAMtkC,EACA0pB,IAAAA,CAAEk5D,GAAQpvH,KAAK,mDAEjBwsC,EAAOnzC,QACPmzC,EAAOzF,MAAK,CAAC0K,EAAKxxC,KACd,MAAM82C,EACAmf,IAAAA,CAAEj2D,GACCD,KAAK,YACLnB,KAAI,CAAC45C,EAAG7xC,IAAYA,EAAQuT,aAAa,UACzCwC,MAELo6B,EAAS19C,OAAS,IAClB1B,KAAKukD,KACG,WACAj8C,EAAMka,aAAa,cACZla,EAAMka,aAAa,WAC1B48B,EAAS71C,KAAK,eAKlCvJ,KAAKwH,QAAUxH,KAAKukD,IACpBkzE,EAAOpvH,KAAK,YAAY+mC,MAAK,CAAC0R,EAAG7xC,KAC7B,MAAM9K,EAAInE,KAAKwiI,aAAajkE,IAAAA,CAAEtvD,IAE9BjP,KAAK2H,MAAMzF,KAAKiC,MAWpBnE,KAAKukD,IAAMvkD,KAAKwH,QAAUxH,KAAK2H,MAAM4B,KAAK,KAI9C61H,GAAIn+H,UAAUuhI,aAAe,SAASvzH,GAClC,MAAMnH,EAAOmH,EAAQ5G,KAAK,gBACpBjF,EAAY6L,EAAQ5G,KAAK,4DAC/B,IAAIN,EAAM,GACV,MAAM8wE,EAAOz1E,EAAUiF,KACnB,4DAEEV,EAAQ,CAAEA,MAAOG,EAAK4N,KAAK,SAEjC/N,KAAa,KAiEb,OAhEgC,aAA5BsH,EAAQyG,KAAK,aAEb/N,EAAMsI,KAAO,KAEb7M,EAAUiF,KAAK,qDAAqD3G,OACpEiG,EAAMyoC,MAAQyoC,EAAKn3E,OAAS,gBAAkB,oBAE9CiG,EAAMyoC,MAAQ,oBAEdyoC,EAAKn3E,QACLqG,GAAQ,iBAAgBJ,EAAMsI,4CAC9BlI,GAAQ,eAAc8wE,EAAKnjE,KAAK,gBAChC3N,GAAO,kCAEPJ,EAAM+wE,IACA5wE,EACGO,KAAK,iBACLnB,KAAI,CAAC45C,EAAGwxB,IAAgBA,EAAY9vD,aAAa,QACjDwC,MACTjd,GAAQ,GAAEqzH,GAAAA,WAAmBzzH,UAGjCI,GAAO,uBACF8wE,EAAKn3E,SACNqG,GAAO,+BAIP3E,EAAU1B,SACN0B,EAAUsS,KAAK,WACf3N,GAAQ,GAAEqzH,GAAAA,cAAsBh4H,EAAUsS,KAAK,iBAE/CtS,EAAUsS,KAAK,SACf3N,GAAQ,GAAEqzH,GAAAA,YAAoBh4H,EAAUsS,KAAK,eAEjDtS,EAAUiF,KAAK,qDAAqD+mC,MAAK,CAAC0R,EAAG47E,KACzE30H,GAAQ,iBAAgB20H,EAAYl6G,aAAa,UACjDza,GAAQ,IAAGw2D,IAAAA,CAAEm+D,GAAa16H,SAC1B+F,GAAO,OACH20H,EAAYn5G,aAAa,WACzBxb,GAAQ,WAAU20H,EAAYl6G,aAAa,oBAMvDpf,EAAUiF,KAAK,cACV+mC,MAAK,CAAC0R,EAAG4wB,KACN,IAAIE,EAAWF,EAAUlvD,aAAa,YAEtCovD,EAC0B,iBAAbA,EAAwBA,EAASz6C,cAAgB,GAEzDn3B,KAAK8/H,sBACe,QAAbluD,GAAmC,WAAbA,IAC1B5xE,KAAK+/H,qBAAoC,QAAbnuD,IAEzB5xE,KAAK6/H,SACZnuD,EAAUjuD,aAAa,KAAM,WAGjC1b,GAAOqzH,GAAAA,oBAA4B1pD,OAGnCziE,EAAQyG,KAAK,YACrB,IAAK,YACD3N,GAAQ,KAAIm3H,GAAAA,eACZ,MACJ,IAAK,YACDn3H,GAAQ,KAAIm3H,GAAAA,eACZ,MACJ,IAAK,OACDn3H,GAAQ,KAAIm3H,GAAAA,eACZ,MACJ,IAAK,OACDn3H,GAAQ,KAAIm3H,GAAAA,eAGhBn3H,GAAQ,SAAQkH,EAAQyG,KAAK,cAMzB5N,EAAKO,KAAK,aAAa3G,SACvBqG,GAAO,kBAGXD,EAAKO,KAAK,iBAAiB+mC,MAAK,CAAC0R,EAAGwxB,KAChCvqE,GAAQ,GAAEqzH,GAAAA,YAAoB9oD,SAC1B/T,IAAAA,CAAE+T,GAAajqE,KAAK,cAAc3G,SAClCqG,GAAQ,UAASuqE,EAAY9vD,aAAa,SAC1Cza,GACOw2D,IAAAA,CAAE+T,GACAjqE,KAAK,cACLnB,KAAI,CAACu7H,EAAIlvD,KACN,MAAM/mE,EAAO+mE,EAAU/wD,aAAa,QAEpC,OACKhW,EAAQ,GAAEA,KAAU,IACf+mE,EAAU/wD,aAAa,YAEpCwC,MACAzb,KAAK,MACdxB,GAAO,QAIXA,GAAO/H,KAAKqiI,iBAAiB9jE,IAAAA,CAAE+T,GAAcA,EAAY9vD,aAAa,UAI1Eza,GAAO/H,KAAKqiI,iBAAiBv6H,EAAM,KAGnCA,EACKO,KAAK,8DACL+mC,MAAK,CAAC0R,EAAG4hF,KACN36H,GACQ,YAAW26H,EAAOlgH,aAAa,SAC/BkgH,EAAOlgH,aAAa,gBAIpC1a,EACKO,KAAK,wDACL+mC,MAAK,CAAC0R,EAAGk9E,KACN,MAAMz1H,EAAYy1H,EAAUx7G,aAAa,aACnC1b,EACAy3D,IAAAA,CAAEy/D,GACC31H,KAAK,WACLnB,KAAI,CAACu7H,EAAIp2H,IAAWA,EAAOmW,aAAa,UACxCwC,MAELle,EAAMpF,SACNqG,GAAQ,gBAAeQ,KAAazB,EAAMyC,KAAK,eAK3D,IAAIo5H,EAAc,GACdC,EAAiB,GAwCrB,OAtCA96H,EACKO,KAAK,oDACL+mC,MAAK,CAAC0R,EAAGz0C,KACN,MAAMzF,EAAOyF,EAAOmW,aAAa,QACjC,IAAIqgH,GAAe,EACfC,EAAY,GAEhBvkE,IAAAA,CAAElyD,GACGhE,KAAK,cACL+mC,MAAK,CAACqzF,EAAIlvD,KAAc,MACrB,MAAM/mE,EAAO+mE,EAAU/wD,aAAa,QACpC,IAAIrb,EAAQosE,EAAU/wD,aAAa,SAEnCrb,EAAQi0H,GAAAA,mBAA2Bj0H,GACnC27H,GAAc,UAASl8H,KAAQ4F,IAE3BrF,GAASA,EAAMzF,SACfohI,GAAc,IAAG37H,KAGrB27H,GAAa,OAEb,UAAI37H,SAAJ,OAAI,EAAOs2G,SAAS,kBAChBolB,GAAe,MAIvBA,EACAF,GAAeG,EAEfF,GAAkBE,KAM9B/6H,GAAO66H,EAAiBD,EAEjB56H,GC1tBX23H,GAAUz+H,UAAU8hI,YAAc,WAE9B,MAAMC,EAAWhjI,KAAK2/H,MAAMQ,kBACtB8C,EAAejjI,KAAK4/H,SAASO,kBAC7B+C,EAAW,GAoFjB,OAlFA9iI,OAAOC,KAAK4iI,GAAc1iI,SAAQ4iI,IAC9B,MAAMC,EAAUJ,EAASG,GACnBE,EAAcJ,EAAaE,GAE5BC,IAAWC,GAQhBjjI,OAAOC,KAAKgjI,EAAYv8H,OAAOvG,SAAQqG,MACe,IAA9CxG,OAAOC,KAAK+iI,EAAQt8H,OAAOzD,QAAQuD,IAY5By8H,EAAYv8H,MAAMF,GAAM6sE,OACpB2vD,EAAQt8H,MAAMF,GAAM6sE,YAGc1nE,IADvBq3H,EAAQt8H,MAAMF,GAAM6sE,MAAMprE,MAC5CvE,IAAkC,IAA1BA,EAAKT,QAAQ,iBAEoB0I,IADtBs3H,EAAYv8H,MAAMF,GAAM6sE,MAAMprE,MACjDvE,IAAkC,IAA1BA,EAAKT,QAAQ,cAfpB6/H,EAASC,KACVD,EAASC,GAAkB,CACvB9C,WAAYgD,EAAYhD,WACxBnsD,IAAKmvD,EAAYnvD,IACjBptE,MAAO,GACPsB,WAAY,KAGpB86H,EAASC,GAAgBr8H,MAAMF,GAAQy8H,EAAYv8H,MAAMF,OAyBjEy8H,EAAYj7H,WAAW7H,SAAQ+iI,IAG3B,IAAIvpF,GAAU,EAEd,IAAK,IAAIv4C,EAAI,EAAGA,EAAI4hI,EAAQh7H,WAAW1G,OAAQF,IAAK,CAChD,MAAM+hI,EAAcH,EAAQh7H,WAAW5G,GAEvC,GAAI8hI,EAAe/6H,YAAcg7H,EAAYh7H,WACtC+2H,GAAYgE,EAAex8H,MAAOy8H,EAAYz8H,OAAQ,CAEzDizC,GAAU,EACV,OAIHA,IAIImpF,EAASC,KACVD,EAASC,GAAkB,CACvB9C,WAAYgD,EAAYhD,WACxBnsD,IAAKmvD,EAAYnvD,IACjBptE,MAAO,GACPsB,WAAY,KAGpB86H,EAASC,GAAgB/6H,WAAWlG,KAAKohI,QAvE7CJ,EAASC,GAAkBE,KA4E5BH,GAMXxD,GAAUz+H,UAAUw/H,SAAW,SAAS+C,GACpC,MAAMC,EAAgBzjI,KAAK+iI,cAE3B,IAAIW,GAAW,EA4Df,OA1DAtjI,OAAOC,KAAKojI,GAAeljI,SAAQ8/H,IAC/BqD,GAAW,EACX,MAAM/7H,EAAQ87H,EAAcpD,GAE5BmD,EAAOr2H,EAAE,UAAW,CAAEX,KAAM7E,EAAMusE,MAElCsvD,EAAOr2H,EAAE,cACL,CAAEiH,MAAO,6BACLzM,MAAOA,EAAMusE,MAKrB9zE,OAAOC,KAAKsH,EAAMb,OAAOvG,SAAQojI,IAC7B,MAAMC,EAAYj8H,EAAMb,MAAM68H,GACxB1H,EAAY2H,EAAUnwD,MACtB2tD,EAAahG,GAAAA,oBAA4Ba,GAE/CuH,EAAOr2H,EAAE,SAAU,CAAEiH,MAAO,oCAC5BovH,EAAOluH,MAAM,CACT9I,KAAM6qH,GAAAA,+BAA8C+J,OAAar1H,EACjEnF,KAAMg9H,EAAUh9H,OAIpB,MAAMkD,EAAOsxH,GAAAA,mBAA2Ba,GAEpCnyH,IACA05H,EAAOr2H,EAAE,aACTq2H,EAAOluH,MAAM,CAAE9I,KAAM,SACrBg3H,EAAOluH,MAAM,CAAEnO,MAAO2C,IACtB05H,EAAOze,MAGXye,EAAOze,QAIXp9G,EAAMS,WAAW7H,SAAQy9H,IACjBA,EAAUl3H,MAAMpF,SAEhB8hI,EAAOr2H,EAAE,aAAc,CACnB5E,UAAWy1H,EAAUz1H,UACrB6L,MAAO,oCAGX4pH,EAAUl3H,MAAMvG,SAAQqG,IACpB48H,EAAOr2H,EAAE,SAAU,CAAEvG,KAAAA,IAChBm+G,QAETye,EAAOze,SAIfye,EAAOze,KACPye,EAAOze,QAGJ2e,GC5JX,IAAIG,GAA8C,mBAAnBC,gBAAiCA,eAC5DC,GAA0C,mBAAjBC,cAA+BA,aACxDC,GAAiC,iBAAZlhF,SAAoD,mBAArBA,QAAQmhF,SAEhE,SAASC,GAASvvH,GACdpS,WAAWoS,EAAI,GAGnB,SAASo0C,GAAK3C,GACV,MAAO,CAACzxC,KAAOnQ,IAAS4hD,GAAM,IAAMzxC,KAAMnQ,KAe9C,IAAI2/H,GAAiBp7E,GAVjB66E,GACSC,eACFC,GACEC,aACFC,GACElhF,QAAQmhF,SAERC,IAsFb,SAASE,GAAc3jF,EAAS9jC,GAC5B,OAAO8jC,EAAQE,MAAKz5C,IAChBm9H,GAAe1nH,EAAU,KAAMzV,MAChCshC,IACC67F,GAAe1nH,EAAU6rB,GAAOA,EAAIztB,QAAUytB,EAAM,IAAIzkC,MAAMykC,OAItE,SAAS67F,GAAe1nH,EAAUvb,EAAO8F,GACrC,IACIyV,EAASvb,EAAO8F,GAClB,MAAOshC,GACL27F,IAAer3H,IAAO,MAAMA,IAAK07B,IAIzC,SAAS87F,GAAQ3vH,GACb,MAAkC,kBAA3BA,EAAG6pB,OAAOC,aAWrB,SAAS8lG,GAAUC,GACf,GAAuB,mBAAZA,EAAwB,MAAM,IAAIzgI,MAAM,uBACnD,OAAOugI,GAAQE,GAtDXF,GADU5iF,EAuDqB8iF,GArDxB,YAAahgI,GAChB,MAAMmY,EAAWnY,EAAKwyB,MAEtB,OAAOotG,GADS1iF,EAAKjhD,MAAMV,KAAMyE,GACHmY,KAhGlBhI,EAoGC,SAAUnQ,EAAMmY,GACjC,IAAI0c,EACJ,IACIA,EAASqoB,EAAKjhD,MAAMV,KAAMyE,GAC5B,MAAOsI,GACL,OAAO6P,EAAS7P,GAGpB,GAAIusB,GAAiC,mBAAhBA,EAAOsnB,KACxB,OAAOyjF,GAAc/qG,EAAQ1c,GAE7BA,EAAS,KAAM0c,IA9GhB,YAAa70B,GAChB,IAAImY,EAAWnY,EAAKwyB,MACpB,OAAOriB,EAAGhQ,KAAK5E,KAAMyE,EAAMmY,KA+Ie6nH,EAvDlD,IAAkB9iF,EA3FM/sC,EAuJxB,SAAS8vH,GAAUD,EAASE,EAAQF,EAAQ/iI,QACxC,IAAKijI,EAAO,MAAM,IAAI3gI,MAAM,sBAe5B,OAdA,YAAuBS,GACnB,MAA+B,mBAApBA,EAAKkgI,EAAQ,GACbF,EAAQ/jI,MAAMV,KAAMyE,GAGxB,IAAIslC,SAAQ,CAACC,EAASC,KACzBxlC,EAAKkgI,EAAQ,GAAK,CAACl8F,KAAQm8F,KACvB,GAAIn8F,EAAK,OAAOwB,EAAOxB,GACvBuB,EAAQ46F,EAAOljI,OAAS,EAAIkjI,EAASA,EAAO,KAEhDH,EAAQ/jI,MAAMV,KAAMyE,OAOhC,SAASogI,GAAWC,GAChB,OAAO,SAAmB9iF,KAAQ+iF,GAO9B,OANWL,IAAS,SAAU9nH,GAC1B,IAAIquB,EAAOjrC,KACX,OAAO8kI,EAAO9iF,GAAK,CAACptC,EAAIowH,KACpBR,GAAU5vH,GAAIlU,MAAMuqC,EAAM85F,EAAShgI,OAAOigI,MAC3CpoH,OAMf,SAASqoH,GAAUH,EAAQ9rG,EAAK2rC,EAAU/nD,GACtCoc,EAAMA,GAAO,GACb,IAAIyX,EAAU,GACVy0F,EAAU,EACVC,EAAYX,GAAU7/D,GAE1B,OAAOmgE,EAAO9rG,GAAK,CAAC7xB,EAAO25C,EAAGskF,KAC1B,IAAI96H,EAAQ46H,IACZC,EAAUh+H,GAAO,CAACshC,EAAKl8B,KACnBkkC,EAAQnmC,GAASiC,EACjB64H,EAAO38F,SAEZA,IACC7rB,EAAS6rB,EAAKgI,MAItB,SAAS5B,GAAY1nC,GACjB,OAAOA,GACqB,iBAAjBA,EAAMzF,QACbyF,EAAMzF,QAAU,GAChByF,EAAMzF,OAAS,GAAM,EAK7B,MAAM2jI,GAAY,GAElB,SAASx7F,GAAKj1B,GACV,SAAS0wH,KAAY7gI,GACjB,GAAW,OAAPmQ,EAAJ,CACA,IAAI2wH,EAAS3wH,EACbA,EAAK,KACL2wH,EAAO7kI,MAAMV,KAAMyE,IAGvB,OADArE,OAAOqmC,OAAO6+F,EAAS1wH,GAChB0wH,EAgDX,SAASE,GAAS5wH,GACd,OAAO,YAAanQ,GAChB,GAAW,OAAPmQ,EAAa,MAAM,IAAI5Q,MAAM,gCACjC,IAAIuhI,EAAS3wH,EACbA,EAAK,KACL2wH,EAAO7kI,MAAMV,KAAMyE,IAK3B,SAASghI,GAAiBC,EAAWC,EAAOhhE,EAAU/nD,GAClD,IAAIu1B,GAAO,EACPyzF,GAAW,EACXC,GAAW,EACXC,EAAU,EACVhsF,EAAM,EAEV,SAASisF,IAEDD,GAAWH,GAASE,GAAY1zF,IAEpC0zF,GAAW,EACXH,EAAUjoH,OAAOmjC,MAAK,EAAEz5C,MAAAA,EAAOgrC,KAAM6zF,MAEjC,IAAIJ,IAAYzzF,EAAhB,CAEA,GADA0zF,GAAW,EACPG,EAMA,OALA7zF,GAAO,OACH2zF,GAAW,GAEXlpH,EAAS,OAIjBkpH,IACAnhE,EAASx9D,EAAO2yC,EAAKmsF,GACrBnsF,IACAisF,QACD/hF,MAAMkiF,IAGb,SAASD,EAAiBx9F,EAAKnP,GAG3B,GADAwsG,GAAW,GACPF,EACJ,OAAIn9F,EAAYy9F,EAAYz9F,IAEhB,IAARA,GACA0J,GAAO,OACPyzF,GAAW,IAIXtsG,IAAW+rG,IAAclzF,GAAQ2zF,GAAW,GAC5C3zF,GAAO,EAEAv1B,EAAS,YAEpBmpH,IAGJ,SAASG,EAAYz9F,GACbm9F,IACJC,GAAW,EACX1zF,GAAO,EACPv1B,EAAS6rB,IAGbs9F,IAGJ,IAAII,GAAeR,GACR,CAACx3H,EAAKw2D,EAAU/nD,KAEnB,GADAA,EAAWitB,GAAKjtB,GACZ+oH,GAAS,EACT,MAAM,IAAIn5F,WAAW,2CAEzB,IAAKr+B,EACD,OAAOyO,EAAS,MAEpB,GAjN8B,mBAiNTzO,EAjNfswB,OAAOC,aAkNT,OAAO+mG,GAAiBt3H,EAAKw3H,EAAOhhE,EAAU/nD,GAElD,GAjNR,SAAyBzO,GACrB,MAA4C,mBAA9BA,EAAIswB,OAAO2nG,eAgNjBC,CAAgBl4H,GAChB,OAAOs3H,GAAiBt3H,EAAIswB,OAAO2nG,iBAAkBT,EAAOhhE,EAAU/nD,GAE1E,IAAI0pH,EA/FZ,SAAwBC,GACpB,GAAI13F,GAAY03F,GACZ,OAlCR,SAA6BA,GACzB,IAAI/kI,GAAK,EACLC,EAAM8kI,EAAK7kI,OACf,OAAO,WACH,QAASF,EAAIC,EAAM,CAAC0F,MAAOo/H,EAAK/kI,GAAI0M,IAAK1M,GAAK,MA8BvCglI,CAAoBD,GAG/B,IAAIx1F,EAzCR,SAAsBw1F,GAClB,OAAOA,EAAK9nG,OAAOsS,WAAaw1F,EAAK9nG,OAAOsS,YAwC7B01F,CAAYF,GAC3B,OAAOx1F,EA9BX,SAA8BA,GAC1B,IAAIvvC,GAAK,EACT,OAAO,WACH,IAAI0O,EAAO6gC,EAAStzB,OACpB,OAAIvN,EAAKiiC,KACE,MACX3wC,IACO,CAAC2F,MAAO+I,EAAK/I,MAAO+G,IAAK1M,KAuBlBklI,CAAqB31F,GAnB3C,SAA8B5iC,GAC1B,IAAIw4H,EAAQx4H,EAAM/N,OAAOC,KAAK8N,GAAO,GACjC3M,GAAK,EACLC,EAAMklI,EAAMjlI,OAChB,OAAO,SAAS+b,IACZ,IAAIvP,EAAMy4H,IAAQnlI,GAClB,MAAY,cAAR0M,EACOuP,IAEJjc,EAAIC,EAAM,CAAC0F,MAAOgH,EAAID,GAAMA,IAAAA,GAAO,MAUK04H,CAAqBL,GAyFrDM,CAAe14H,GAC1BgkC,GAAO,EACPyzF,GAAW,EACXE,EAAU,EACVgB,GAAU,EAEd,SAASb,EAAiBx9F,EAAKthC,GAC3B,IAAIy+H,EAEJ,GADAE,GAAW,EACPr9F,EACA0J,GAAO,EACPv1B,EAAS6rB,QAER,IAAY,IAARA,EACL0J,GAAO,EACPyzF,GAAW,MAEV,IAAIz+H,IAAUk+H,IAAclzF,GAAQ2zF,GAAW,EAEhD,OADA3zF,GAAO,EACAv1B,EAAS,MAEVkqH,GACNf,KAIR,SAASA,IAEL,IADAe,GAAU,EACHhB,EAAUH,IAAUxzF,GAAM,CAC7B,IAAI9C,EAAOi3F,IACX,GAAa,OAATj3F,EAKA,OAJA8C,GAAO,OACH2zF,GAAW,GACXlpH,EAAS,OAIjBkpH,GAAW,EACXnhE,EAASt1B,EAAKloC,MAAOkoC,EAAKnhC,IAAKs3H,GAASS,IAE5Ca,GAAU,EAGdf,KA6BJgB,GAAgBrC,IAJpB,SAAuB6B,EAAMZ,EAAOhhE,EAAU/nD,GAC1C,OAAOupH,GAAYR,EAAZQ,CAAmBI,EAAM/B,GAAU7/D,GAAW/nD,KAGb,GAG5C,SAASoqH,GAAgBT,EAAM5hE,EAAU/nD,GACrCA,EAAWitB,GAAKjtB,GAChB,IAAItS,EAAQ,EACRy5C,EAAY,GACZ,OAACriD,GAAU6kI,EACXX,GAAW,EAKf,SAASqB,EAAiBx+F,EAAKthC,IACf,IAARshC,IACAm9F,GAAW,IAEE,IAAbA,IACAn9F,EACA7rB,EAAS6rB,KACCsb,IAAcriD,GAAWyF,IAAUk+H,IAC7CzoH,EAAS,OAIjB,IAhBe,IAAXlb,GACAkb,EAAS,MAeNtS,EAAQ5I,EAAQ4I,IACnBq6D,EAAS4hE,EAAKj8H,GAAQA,EAAOk7H,GAASyB,IAK9C,SAASC,GAAeX,EAAM5hE,EAAU/nD,GACpC,OAAOmqH,GAAcR,EAAMz+F,EAAAA,EAAU68B,EAAU/nD,GAqHnD,IAAIuqH,GAAWzC,IALf,SAAgB6B,EAAM5hE,EAAU/nD,GAE5B,OAD2BiyB,GAAY03F,GAAQS,GAAkBE,IACrCX,EAAM/B,GAAU7/D,GAAW/nD,KAG3B,GA0H5BwqH,GAAQ1C,IAHZ,SAAc6B,EAAM5hE,EAAU/nD,GAC1B,OAAOqoH,GAAUkC,GAAUZ,EAAM5hE,EAAU/nD,KAErB,GAyCRioH,GAAUuC,IAuB5B,IAAIC,GAAiB3C,IAHrB,SAAsB6B,EAAM5hE,EAAU/nD,GAClC,OAAOmqH,GAAcR,EAAM,EAAG5hE,EAAU/nD,KAEA,GA6CtBioH,GArBJH,IAHlB,SAAoB6B,EAAM5hE,EAAU/nD,GAChC,OAAOqoH,GAAUoC,GAAgBd,EAAM5hE,EAAU/nD,KAEf,IAuBf6hB,OAAO,mBA4f9B,MAAM6oG,GACFluH,cACIpZ,KAAKyuC,KAAOzuC,KAAKunI,KAAO,KACxBvnI,KAAK0B,OAAS,EAGlB8lI,WAAWv0H,GAQP,OAPIA,EAAKosC,KAAMpsC,EAAKosC,KAAK5hC,KAAOxK,EAAKwK,KAChCzd,KAAKyuC,KAAOx7B,EAAKwK,KAClBxK,EAAKwK,KAAMxK,EAAKwK,KAAK4hC,KAAOpsC,EAAKosC,KAChCr/C,KAAKunI,KAAOt0H,EAAKosC,KAEtBpsC,EAAKosC,KAAOpsC,EAAKwK,KAAO,KACxBzd,KAAK0B,QAAU,EACRuR,EAGXwY,QACI,KAAMzrB,KAAKyuC,MAAMzuC,KAAKmtC,QACtB,OAAOntC,KAGXoxD,YAAYn+C,EAAM4R,GACdA,EAAQw6B,KAAOpsC,EACf4R,EAAQpH,KAAOxK,EAAKwK,KAChBxK,EAAKwK,KAAMxK,EAAKwK,KAAK4hC,KAAOx6B,EAC3B7kB,KAAKunI,KAAO1iH,EACjB5R,EAAKwK,KAAOoH,EACZ7kB,KAAK0B,QAAU,EAGnBigB,aAAa1O,EAAM4R,GACfA,EAAQw6B,KAAOpsC,EAAKosC,KACpBx6B,EAAQpH,KAAOxK,EACXA,EAAKosC,KAAMpsC,EAAKosC,KAAK5hC,KAAOoH,EAC3B7kB,KAAKyuC,KAAO5pB,EACjB5R,EAAKosC,KAAOx6B,EACZ7kB,KAAK0B,QAAU,EAGnB4pC,QAAQr4B,GACAjT,KAAKyuC,KAAMzuC,KAAK2hB,aAAa3hB,KAAKyuC,KAAMx7B,GACvCw0H,GAAWznI,KAAMiT,GAG1B/Q,KAAK+Q,GACGjT,KAAKunI,KAAMvnI,KAAKoxD,YAAYpxD,KAAKunI,KAAMt0H,GACtCw0H,GAAWznI,KAAMiT,GAG1Bk6B,QACI,OAAOntC,KAAKyuC,MAAQzuC,KAAKwnI,WAAWxnI,KAAKyuC,MAG7CxX,MACI,OAAOj3B,KAAKunI,MAAQvnI,KAAKwnI,WAAWxnI,KAAKunI,MAG7Cx4F,UACI,MAAO,IAAI/uC,MAGf,EAAEy+B,OAAOsS,YAEL,IADA,IAAI8E,EAAM71C,KAAKyuC,KACRoH,SACGA,EAAIp/B,KACVo/B,EAAMA,EAAIp4B,KAIlBT,OAAQ0qH,GAEJ,IADA,IAAIC,EAAO3nI,KAAKyuC,KACVk5F,GAAM,CACR,IAAI,KAAClqH,GAAQkqH,EACTD,EAAOC,IACP3nI,KAAKwnI,WAAWG,GAEpBA,EAAOlqH,EAEX,OAAOzd,MAIf,SAASynI,GAAWG,EAAK30H,GACrB20H,EAAIlmI,OAAS,EACbkmI,EAAIn5F,KAAOm5F,EAAIL,KAAOt0H,EAG1B,SAASnS,GAAM+mI,EAAQC,EAAanjC,GAChC,GAAmB,MAAfmjC,EACAA,EAAc,OAEb,GAAmB,IAAhBA,EACJ,MAAM,IAAIt7F,WAAW,gCAGzB,IAAI+jE,EAAUi0B,GAAUqD,GACpBE,EAAa,EACbC,EAAc,GAClB,MAAM78F,EAAS,CACX9pC,MAAO,GACP4mI,MAAO,GACPC,UAAW,GACXC,YAAa,GACb18G,MAAO,IAeX,SAAS4hB,EAAK/U,EAAOD,GACjB,OAAKC,EACAD,OACL8S,EAAO7S,GAAS6S,EAAO7S,GAAOvxB,QAAOqhI,GAAMA,IAAO/vG,KAD7B8S,EAAO7S,GAAS,GADlBl4B,OAAOC,KAAK8qC,GAAQ5qC,SAAQ6nI,GAAMj9F,EAAOi9F,GAAM,KAKtE,SAAS/9E,EAAS/xB,KAAU7zB,GACxB0mC,EAAO7S,GAAO/3B,SAAQ83B,GAAWA,KAAW5zB,KAGhD,IAAI4jI,GAAsB,EAC1B,SAASC,EAAQ7xH,EAAM8xH,EAAeC,EAAe5rH,GACjD,GAAgB,MAAZA,GAAwC,mBAAbA,EAC3B,MAAM,IAAI5Y,MAAM,oCAIpB,IAAI01G,EAAK+uB,EACT,SAASC,EAAiBjgG,KAAQhkC,GAG9B,OAAIgkC,EAAY+/F,EAAgBC,EAAIhgG,GAAOixE,IACvCj1G,EAAK/C,QAAU,EAAUg4G,EAAIj1G,EAAK,SACtCi1G,EAAIj1G,GARRkkI,EAAEC,SAAU,EAWZ,IAAI14H,EAAO,CACPuG,KAAAA,EACAmG,SAAU4rH,EACNE,EACC9rH,GAAY8rH,GAiBrB,GAdIH,EACAI,EAAEE,OAAOv9F,QAAQp7B,GAEjBy4H,EAAEE,OAAO3mI,KAAKgO,GAGbm4H,IACDA,GAAsB,EACtBjE,IAAe,KACXiE,GAAsB,EACtBM,EAAE5lF,cAINylF,IAAkB5rH,EAClB,OAAO,IAAImtB,SAAQ,CAACC,EAASC,KACzByvE,EAAM1vE,EACNy+F,EAAMx+F,KAKlB,SAAS6+F,EAAUC,GACf,OAAO,SAAUtgG,KAAQhkC,GACrBsjI,GAAc,EAEd,IAAK,IAAIvmI,EAAI,EAAGyD,EAAI8jI,EAAMrnI,OAAQF,EAAIyD,EAAGzD,IAAK,CAC1C,IAAI2yF,EAAO40C,EAAMvnI,GAEb8I,EAAQ09H,EAAY3kI,QAAQ8wF,GAClB,IAAV7pF,EACA09H,EAAY76F,QACL7iC,EAAQ,GACf09H,EAAYxkI,OAAO8G,EAAO,GAG9B6pF,EAAKv3E,SAAS6rB,KAAQhkC,GAEX,MAAPgkC,GACA4hB,EAAQ,QAAS5hB,EAAK0rD,EAAK19E,MAI/BsxH,GAAeY,EAAEb,YAAca,EAAE9oE,QACjCxV,EAAQ,eAGRs+E,EAAEK,QACF3+E,EAAQ,SAEZs+E,EAAE5lF,WAIV,SAASkmF,EAAYxyH,GACjB,QAAoB,IAAhBA,EAAK/U,SAAgBinI,EAAEK,SAEvB5E,IAAe,IAAM/5E,EAAQ,WACtB,IAKf,MAAM6+E,EAAe18H,GAAU6rB,IAC3B,IAAKA,EACD,OAAO,IAAI0R,SAAQ,CAACC,EAASC,MA1GrC,SAAe3R,EAAOD,GAClB,MAAM8wG,EAAkB,IAAI1kI,KACxB4oC,EAAI/U,EAAO6wG,GAyGI,EAAC1gG,EAAKhyB,KACb,GAAIgyB,EAAK,OAAOwB,EAAOxB,GACvBuB,EAAQvzB,IA1GhB4hB,IAAW5zB,IAEf0mC,EAAO7S,GAAOp2B,KAAKinI,GAsGXt/F,CAAKr9B,MAMb6gC,EAAI7gC,GArHR,SAAa8rB,EAAOD,GAChB8S,EAAO7S,GAAOp2B,KAAKm2B,GAqHnBkS,CAAG/9B,EAAM6rB,IAIb,IAAI+wG,GAAe,EACfT,EAAI,CACJE,OAAQ,IAAIvB,GACZ,EAAE7oG,OAAOsS,kBACE43F,EAAEE,OAAOpqG,OAAOsS,aAE3B+2F,YAAAA,EACAnjC,QAAAA,EACA9kC,OAAQioE,EAAc,EACtBc,SAAS,EACTt4H,QAAQ,EACRpO,KAAMuU,EAAMmG,GACR,GAAIlY,MAAMgD,QAAQ+O,GAAO,CACrB,GAAIwyH,EAAYxyH,GAAO,OACvB,OAAOA,EAAKvP,KAAImiI,GAASf,EAAQe,GAAO,GAAO,EAAOzsH,KAE1D,OAAO0rH,EAAQ7xH,GAAM,GAAO,EAAOmG,IAEvC0sH,UAAW7yH,EAAMmG,GACb,GAAIlY,MAAMgD,QAAQ+O,GAAO,CACrB,GAAIwyH,EAAYxyH,GAAO,OACvB,OAAOA,EAAKvP,KAAImiI,GAASf,EAAQe,GAAO,GAAO,EAAMzsH,KAEzD,OAAO0rH,EAAQ7xH,GAAM,GAAO,EAAMmG,IAEtC2sH,OACIl8F,IACAs7F,EAAEE,OAAOp9G,SAEb6f,QAAS70B,EAAMmG,GACX,GAAIlY,MAAMgD,QAAQ+O,GAAO,CACrB,GAAIwyH,EAAYxyH,GAAO,OACvB,OAAOA,EAAKvP,KAAImiI,GAASf,EAAQe,GAAO,GAAM,EAAOzsH,KAEzD,OAAO0rH,EAAQ7xH,GAAM,GAAM,EAAOmG,IAEtC4sH,aAAc/yH,EAAMmG,GAChB,GAAIlY,MAAMgD,QAAQ+O,GAAO,CACrB,GAAIwyH,EAAYxyH,GAAO,OACvB,OAAOA,EAAKvP,KAAImiI,GAASf,EAAQe,GAAO,GAAM,EAAMzsH,KAExD,OAAO0rH,EAAQ7xH,GAAM,GAAM,EAAMmG,IAErCI,OAAQ0qH,GACJiB,EAAEE,OAAO7rH,OAAO0qH,IAEpB3kF,UAGI,IAAIqmF,EAAJ,CAIA,IADAA,GAAe,GACRT,EAAEr4H,QAAUy3H,EAAaY,EAAEb,aAAea,EAAEE,OAAOnnI,QAAO,CAC7D,IAAIqnI,EAAQ,GAAItyH,EAAO,GACnBxR,EAAI0jI,EAAEE,OAAOnnI,OACbinI,EAAEhkC,UAAS1/F,EAAIgF,KAAK6uB,IAAI7zB,EAAG0jI,EAAEhkC,UACjC,IAAK,IAAInjG,EAAI,EAAGA,EAAIyD,EAAGzD,IAAK,CACxB,IAAIyR,EAAO01H,EAAEE,OAAO17F,QACpB47F,EAAM7mI,KAAK+Q,GACX+0H,EAAY9lI,KAAK+Q,GACjBwD,EAAKvU,KAAK+Q,EAAKwD,MAGnBsxH,GAAc,EAEU,IAApBY,EAAEE,OAAOnnI,QACT2oD,EAAQ,SAGR09E,IAAeY,EAAEb,aACjBz9E,EAAQ,aAGZ,IAAI26E,EAAKQ,GAASsD,EAAUC,IAC5Bx4B,EAAQ95F,EAAMuuH,GAElBoE,GAAe,IAEnB1nI,OAAO,IACIinI,EAAEE,OAAOnnI,OAEpBokI,QAAQ,IACGiC,EAEXC,YAAY,IACDA,EAEXgB,KAAI,IACOL,EAAEE,OAAOnnI,OAASqmI,IAAe,EAE5C0B,QACId,EAAEr4H,QAAS,GAEf0hF,UACqB,IAAb22C,EAAEr4H,SACNq4H,EAAEr4H,QAAS,EACX8zH,GAAeuE,EAAE5lF,YA0BzB,OAtBA3iD,OAAOspI,iBAAiBf,EAAG,CACvBT,UAAW,CACPljG,UAAU,EACV79B,MAAO+hI,EAAY,cAEvBf,YAAa,CACTnjG,UAAU,EACV79B,MAAO+hI,EAAY,gBAEvBz9G,MAAO,CACHuZ,UAAU,EACV79B,MAAO+hI,EAAY,UAEvBjB,MAAO,CACHjjG,UAAU,EACV79B,MAAO+hI,EAAY,UAEvB7nI,MAAO,CACH2jC,UAAU,EACV79B,MAAO+hI,EAAY,YAGpBP,EA8OIjE,IAVf,SAAgB6B,EAAMoD,EAAMhlE,EAAU/nD,GAClCA,EAAWitB,GAAKjtB,GAChB,IAAIuoH,EAAYX,GAAU7/D,GAC1B,OAAO0iE,GAAed,GAAM,CAAC71H,EAAGlP,EAAG4jI,KAC/BD,EAAUwE,EAAMj5H,GAAG,CAAC+3B,EAAKl8B,KACrBo9H,EAAOp9H,EACP64H,EAAO38F,SAEZA,GAAO7rB,EAAS6rB,EAAKkhG,OAEI,GAgIhC,IAAIC,GAAalF,IAHjB,SAAmB6B,EAAMZ,EAAOhhE,EAAU/nD,GACtC,OAAOqoH,GAAUkB,GAAYR,GAAQY,EAAM5hE,EAAU/nD,KAErB,GAwChCitH,GAAgBnF,IAlBpB,SAAqB6B,EAAMZ,EAAOhhE,EAAU/nD,GACxC,IAAIuoH,EAAYX,GAAU7/D,GAC1B,OAAOilE,GAAWrD,EAAMZ,GAAO,CAACn3F,EAAK42F,KACjCD,EAAU32F,GAAK,CAAC/F,KAAQhkC,IAChBgkC,EAAY28F,EAAO38F,GAChB28F,EAAO38F,EAAKhkC,QAExB,CAACgkC,EAAKqhG,KAEL,IADA,IAAIxwG,EAAS,GACJ93B,EAAI,EAAGA,EAAIsoI,EAAWpoI,OAAQF,IAC/BsoI,EAAWtoI,KACX83B,EAASA,EAAOv0B,UAAU+kI,EAAWtoI,KAI7C,OAAOob,EAAS6rB,EAAKnP,QAGa,GA+K1C,SAASywG,GAAc/wF,EAAO9T,GAC1B,MAAO,CAAC4/F,EAAQ9rG,EAAKmsG,EAAWH,KAC5B,IACIgF,EADAC,GAAa,EAEjB,MAAMtlE,EAAW6/D,GAAUW,GAC3BL,EAAO9rG,GAAK,CAAC7xB,EAAO25C,EAAGlkC,KACnB+nD,EAASx9D,GAAO,CAACshC,EAAKnP,IACdmP,IAAe,IAARA,EAAsB7rB,EAAS6rB,GAEtCuQ,EAAM1f,KAAY0wG,GAClBC,GAAa,EACbD,EAAa9kG,GAAU,EAAM/9B,GACtByV,EAAS,KAAMyoH,UAE1BzoH,SAEL6rB,IACC,GAAIA,EAAK,OAAOu8F,EAAGv8F,GACnBu8F,EAAG,KAAMiF,EAAaD,EAAa9kG,GAAU,QAwIzD,SAASglG,GAAY19H,GACjB,MAAO,CAACoI,KAAOnQ,IAAS+/H,GAAU5vH,EAAV4vH,IAAiB//H,GAAM,CAACgkC,KAAQ0hG,KAE7B,iBAAZlnI,UAEHwlC,EAEIxlC,QAAQ5B,OACR4B,QAAQ5B,MAAMonC,GAEXxlC,QAAQuJ,IACf29H,EAAW5pI,SAAQmQ,GAAKzN,QAAQuJ,GAAMkE,SAkHtD,SAAS05H,GAAczlE,GACnB,MAAO,CAACx9D,EAAOmD,EAAOsS,IAAa+nD,EAASx9D,EAAOyV,GApWxC8nH,IAHf,SAAgB6B,EAAM5hE,EAAU/nD,GAC5B,OAAOitH,GAActD,EAAMz+F,EAAAA,EAAU68B,EAAU/nD,KAEnB,GAyBX8nH,IAHrB,SAAsB6B,EAAM5hE,EAAU/nD,GAClC,OAAOitH,GAActD,EAAM,EAAG5hE,EAAU/nD,KAEA,GAoJ7B8nH,IAHf,SAAgB6B,EAAM5hE,EAAU/nD,GAC5B,OAAOmtH,IAAcxxE,GAAQA,IAAM,CAACmhD,EAAKxpG,IAASA,GAA3C65H,CAAiD5C,GAAUZ,EAAM5hE,EAAU/nD,KAEtD,GA4BZ8nH,IAHpB,SAAqB6B,EAAMZ,EAAOhhE,EAAU/nD,GACxC,OAAOmtH,IAAcxxE,GAAQA,IAAM,CAACmhD,EAAKxpG,IAASA,GAA3C65H,CAAiD5D,GAAYR,GAAQY,EAAM5hE,EAAU/nD,KAEtD,GA2BrB8nH,IAJrB,SAAsB6B,EAAM5hE,EAAU/nD,GAClC,OAAOmtH,IAAcxxE,GAAQA,IAAM,CAACmhD,EAAKxpG,IAASA,GAA3C65H,CAAiD5D,GAAY,GAAII,EAAM5hE,EAAU/nD,KAGhD,GAgDlCstH,GAAY,OAgDLxF,IAvBjB,SAAkB//D,EAAUp1D,EAAMqN,GAC9BA,EAAW4oH,GAAS5oH,GACpB,IAEI6zB,EAFA45F,EAAM7F,GAAU7/D,GAChB2lE,EAAQ9F,GAAUj1H,GAGtB,SAASkO,EAAKgrB,KAAQhkC,GAClB,GAAIgkC,EAAK,OAAO7rB,EAAS6rB,IACb,IAARA,IACJgI,EAAUhsC,EACV6lI,KAAS7lI,EAAMu0C,IAGnB,SAASA,EAAMvQ,EAAK8hG,GAChB,OAAI9hG,EAAY7rB,EAAS6rB,IACb,IAARA,EACC8hG,OACLF,EAAI5sH,GADeb,EAAS,QAAS6zB,QADrC,EAKJ,OAAOuI,EAAM,MAAM,KAGa,GA0IzB0rF,IAJX,SAAmB6B,EAAM5hE,EAAU/nD,GAC/B,OAAOuqH,GAASZ,EAAM6D,GAAc5F,GAAU7/D,IAAY/nD,KAG/B,GA0B/B,IAAI4tH,GAAc9F,IAHlB,SAAqB6B,EAAMZ,EAAOhhE,EAAU/nD,GACxC,OAAOupH,GAAYR,EAAZQ,CAAmBI,EAAM6D,GAAc5F,GAAU7/D,IAAY/nD,KAEhC,GA4BpC6tH,GAAe/F,IAHnB,SAAoB6B,EAAM5hE,EAAU/nD,GAChC,OAAO4tH,GAAYjE,EAAM,EAAG5hE,EAAU/nD,KAEF,GA4MxC,SAAS8tH,GAAY5F,EAAQ9rG,EAAK2rC,EAAU/nD,GACxC,IAAI+tH,EAAc,IAAIjmI,MAAMs0B,EAAIt3B,QAChCojI,EAAO9rG,GAAK,CAACtoB,EAAGpG,EAAO86H,KACnBzgE,EAASj0D,GAAG,CAAC+3B,EAAKl8B,KACdo+H,EAAYrgI,KAAWiC,EACvB64H,EAAO38F,SAEZA,IACC,GAAIA,EAAK,OAAO7rB,EAAS6rB,GAEzB,IADA,IAAIgI,EAAU,GACLjvC,EAAI,EAAGA,EAAIw3B,EAAIt3B,OAAQF,IACxBmpI,EAAYnpI,IAAIivC,EAAQvuC,KAAK82B,EAAIx3B,IAEzCob,EAAS,KAAM6zB,MAIvB,SAASm6F,GAAc9F,EAAQyB,EAAM5hE,EAAU/nD,GAC3C,IAAI6zB,EAAU,GACdq0F,EAAOyB,GAAM,CAAC71H,EAAGpG,EAAO86H,KACpBzgE,EAASj0D,GAAG,CAAC+3B,EAAKl8B,KACd,GAAIk8B,EAAK,OAAO28F,EAAO38F,GACnBl8B,GACAkkC,EAAQvuC,KAAK,CAACoI,MAAAA,EAAOnD,MAAOuJ,IAEhC00H,EAAO38F,SAEZA,IACC,GAAIA,EAAK,OAAO7rB,EAAS6rB,GACzB7rB,EAAS,KAAM6zB,EACVZ,MAAK,CAACxiC,EAAGD,IAAMC,EAAE/C,MAAQ8C,EAAE9C,QAC3BpD,KAAIqF,GAAKA,EAAEpF,YAIxB,SAAS0jI,GAAQ/F,EAAQyB,EAAM5hE,EAAU/nD,GAErC,OADaiyB,GAAY03F,GAAQmE,GAAcE,IACjC9F,EAAQyB,EAAM/B,GAAU7/D,GAAW/nD,GAu5CrD,SAASqtB,GAAO66F,EAAQ9rG,EAAKmsG,EAAWvoH,GACpC,MAAM+nD,EAAW6/D,GAAUW,GAC3B,OAAO0F,GAAQ/F,EAAQ9rG,GAAK,CAAC7xB,EAAO69H,KAChCrgE,EAASx9D,GAAO,CAACshC,EAAKl8B,KAClBy4H,EAAGv8F,GAAMl8B,QAEdqQ,GAv/CO8nH,IAHd,SAAe6B,EAAM5hE,EAAU/nD,GAC3B,OAAOmtH,IAAcxxE,IAASA,IAAMmhD,IAAQA,GAArCqwB,CAA0C5C,GAAUZ,EAAM5hE,EAAU/nD,KAEjD,GA0BX8nH,IAHnB,SAAoB6B,EAAMZ,EAAOhhE,EAAU/nD,GACvC,OAAOmtH,IAAcxxE,IAASA,IAAMmhD,IAAQA,GAArCqwB,CAA0C5D,GAAYR,GAAQY,EAAM5hE,EAAU/nD,KAEjD,GAyBpB8nH,IAHpB,SAAqB6B,EAAM5hE,EAAU/nD,GACjC,OAAOmtH,IAAcxxE,IAASA,IAAMmhD,IAAQA,GAArCqwB,CAA0C1C,GAAgBd,EAAM5hE,EAAU/nD,KAE3C,GAiH3B8nH,IAHf,SAAiB6B,EAAM5hE,EAAU/nD,GAC7B,OAAOiuH,GAAQ1D,GAAUZ,EAAM5hE,EAAU/nD,KAEb,GAyBZ8nH,IAHpB,SAAsB6B,EAAMZ,EAAOhhE,EAAU/nD,GACzC,OAAOiuH,GAAQ1E,GAAYR,GAAQY,EAAM5hE,EAAU/nD,KAEb,GAuBrB8nH,IAHrB,SAAuB6B,EAAM5hE,EAAU/nD,GACnC,OAAOiuH,GAAQxD,GAAgBd,EAAM5hE,EAAU/nD,KAEP,GA4C5B8nH,IAXhB,SAAiB9vH,EAAI4uG,GACjB,IAAIrxE,EAAOqzF,GAAShiB,GAChBrvB,EAAOqwC,GAzWf,SAAqB5vH,GACjB,OAAI2vH,GAAQ3vH,GAAYA,EACjB,YAAanQ,GAChB,IAAImY,EAAWnY,EAAKwyB,MAChB6zG,GAAO,EACXrmI,EAAKvC,MAAK,IAAI6oI,KACND,EACA1G,IAAe,IAAMxnH,KAAYmuH,KAEjCnuH,KAAYmuH,MAGpBn2H,EAAGlU,MAAMV,KAAMyE,GACfqmI,GAAO,GA4VUE,CAAYp2H,IAOjC,OALA,SAAS6I,EAAKgrB,GACV,GAAIA,EAAK,OAAO0J,EAAK1J,IACT,IAARA,GACJ0rD,EAAK12E,GAEFA,KAEuB,GAmDbinH,IA7BrB,SAAsB6B,EAAMZ,EAAOhhE,EAAU/nD,GACzC,IAAIuoH,EAAYX,GAAU7/D,GAC1B,OAAOilE,GAAWrD,EAAMZ,GAAO,CAACn3F,EAAK42F,KACjCD,EAAU32F,GAAK,CAAC/F,EAAKv6B,IACbu6B,EAAY28F,EAAO38F,GAChB28F,EAAO38F,EAAK,CAACv6B,IAAAA,EAAKsgC,IAAAA,SAE9B,CAAC/F,EAAKqhG,KAKL,IAJA,IAAIxwG,EAAS,IAET,eAAC7gB,GAAkBrY,OAAOa,UAErBO,EAAI,EAAGA,EAAIsoI,EAAWpoI,OAAQF,IACnC,GAAIsoI,EAAWtoI,GAAI,CACf,IAAI,IAAC0M,GAAO47H,EAAWtoI,IACnB,IAACgtC,GAAOs7F,EAAWtoI,GAEnBiX,EAAe7T,KAAK00B,EAAQprB,GAC5BorB,EAAOprB,GAAKhM,KAAKssC,GAEjBlV,EAAOprB,GAAO,CAACsgC,GAK3B,OAAO5xB,EAAS6rB,EAAKnP,QAIe,GAmJlC4wG,GAAY,OAqCCxF,IAbvB,SAAwBv2H,EAAKw3H,EAAOhhE,EAAU/nD,GAC1CA,EAAWitB,GAAKjtB,GAChB,IAAIquH,EAAS,GACT9F,EAAYX,GAAU7/D,GAC1B,OAAOwhE,GAAYR,EAAZQ,CAAmBh4H,GAAK,CAACqgC,EAAKtgC,EAAKuP,KACtC0nH,EAAU32F,EAAKtgC,GAAK,CAACu6B,EAAKnP,KACtB,GAAImP,EAAK,OAAOhrB,EAAKgrB,GACrBwiG,EAAO/8H,GAAOorB,EACd7b,EAAKgrB,SAEVA,GAAO7rB,EAAS6rB,EAAKwiG,OAGoB,GAsRjCjiF,GARXi7E,GACWlhF,QAAQmhF,SACZH,GACIC,aAEAG,IAKCO,IAAS,CAACI,EAAQiE,EAAOnsH,KACrC,IAAI6zB,EAAU5B,GAAYk6F,GAAS,GAAK,GAExCjE,EAAOiE,GAAO,CAAC50C,EAAMjmF,EAAKg9H,KACtB1G,GAAUrwC,EAAVqwC,EAAgB,CAAC/7F,KAAQnP,KACjBA,EAAO53B,OAAS,KACf43B,GAAUA,GAEfmX,EAAQviC,GAAOorB,EACf4xG,EAAOziG,SAEZA,GAAO7rB,EAAS6rB,EAAKgI,OACzB,GA2ZGhS,OAAOsS,SA4JA2zF,IATb,SAAcqE,EAAOnsH,GAEjB,GADAA,EAAWitB,GAAKjtB,IACXlY,MAAMgD,QAAQqhI,GAAQ,OAAOnsH,EAAS,IAAImuB,UAAU,yDACzD,IAAKg+F,EAAMrnI,OAAQ,OAAOkb,IAC1B,IAAK,IAAIpb,EAAI,EAAGyD,EAAI8jI,EAAMrnI,OAAQF,EAAIyD,EAAGzD,IACrCgjI,GAAUuE,EAAMvnI,GAAhBgjI,CAAoB5nH,KAIA,GAqPb8nH,IAHf,SAAmB6B,EAAM5hE,EAAU/nD,GAC/B,OAAOqtB,GAAOk9F,GAAUZ,EAAM5hE,EAAU/nD,KAEV,GAyBd8nH,IAHpB,SAAsB6B,EAAMZ,EAAOhhE,EAAU/nD,GACzC,OAAOqtB,GAAOk8F,GAAYR,GAAQY,EAAM5hE,EAAU/nD,KAEZ,GAuBrB8nH,IAHrB,SAAuB6B,EAAM5hE,EAAU/nD,GACnC,OAAOqtB,GAAOo9F,GAAgBd,EAAM5hE,EAAU/nD,KAEN,GA0d/B8nH,IAHb,SAAc6B,EAAM5hE,EAAU/nD,GAC1B,OAAOmtH,GAAcziD,SAASoyB,GAAOA,GAA9BqwB,CAAmC5C,GAAUZ,EAAM5hE,EAAU/nD,KAE5C,GA2BV8nH,IAHlB,SAAmB6B,EAAMZ,EAAOhhE,EAAU/nD,GACtC,OAAOmtH,GAAcziD,SAASoyB,GAAOA,GAA9BqwB,CAAmC5D,GAAYR,GAAQY,EAAM5hE,EAAU/nD,KAE5C,GA0BnB8nH,IAHnB,SAAoB6B,EAAM5hE,EAAU/nD,GAChC,OAAOmtH,GAAcziD,SAASoyB,GAAOA,GAA9BqwB,CAAmC1C,GAAgBd,EAAM5hE,EAAU/nD,KAEtC,GAyKzB8nH,IAjBf,SAAiB6B,EAAM5hE,EAAU/nD,GAC7B,IAAIuoH,EAAYX,GAAU7/D,GAC1B,OAAOyiE,GAAMb,GAAM,CAAC71H,EAAG00H,KACnBD,EAAUz0H,GAAG,CAAC+3B,EAAK0iG,KACf,GAAI1iG,EAAK,OAAO28F,EAAO38F,GACvB28F,EAAO38F,EAAK,CAACthC,MAAOuJ,EAAGy6H,SAAAA,UAE5B,CAAC1iG,EAAKgI,KACL,GAAIhI,EAAK,OAAO7rB,EAAS6rB,GACzB7rB,EAAS,KAAM6zB,EAAQZ,KAAKu7F,GAAYlkI,KAAIqF,GAAKA,EAAEpF,YAGvD,SAASikI,EAAWj0E,EAAMpE,GACtB,IAAI1lD,EAAI8pD,EAAKg0E,SAAU/9H,EAAI2lD,EAAMo4E,SACjC,OAAO99H,EAAID,GAAK,EAAIC,EAAID,EAAI,EAAI,KAGR,GA8WhBs3H,IAlBhB,SAAiBqE,EAAOnsH,GACpB,IACI0c,EADAj4B,EAAQ,KAEZ,OAAOopI,GAAa1B,GAAO,CAAC50C,EAAM+2C,KAC9B1G,GAAUrwC,EAAVqwC,EAAgB,CAAC/7F,KAAQhkC,KACrB,IAAY,IAARgkC,EAAe,OAAOyiG,EAAOziG,GAE7BhkC,EAAK/C,OAAS,GACb43B,GAAU70B,EAEX60B,EAAS70B,EAEbpD,EAAQonC,EACRyiG,EAAOziG,EAAM,KAAO,UAEzB,IAAM7rB,EAASvb,EAAOi4B,QAgFdorG,IAtBf,SAAgBn1H,EAAMo1D,EAAU/nD,GAC5BA,EAAW4oH,GAAS5oH,GACpB,IAAIytH,EAAM7F,GAAU7/D,GAChB2lE,EAAQ9F,GAAUj1H,GAClBkhC,EAAU,GAEd,SAAShzB,EAAKgrB,KAAQ4iG,GAClB,GAAI5iG,EAAK,OAAO7rB,EAAS6rB,GACzBgI,EAAU46F,GACE,IAAR5iG,GACJ6hG,EAAMtxF,GAGV,SAASA,EAAMvQ,EAAK8hG,GAChB,OAAI9hG,EAAY7rB,EAAS6rB,IACb,IAARA,EACC8hG,OACLF,EAAI5sH,GADeb,EAAS,QAAS6zB,QADrC,EAKJ,OAAO65F,EAAMtxF,KAEe,GA6Hd0rF,IAtBlB,SAAoBqE,EAAOnsH,GAEvB,GADAA,EAAWitB,GAAKjtB,IACXlY,MAAMgD,QAAQqhI,GAAQ,OAAOnsH,EAAS,IAAI5Y,MAAM,8DACrD,IAAK+kI,EAAMrnI,OAAQ,OAAOkb,IAC1B,IAAI0uH,EAAY,EAEhB,SAASC,EAAS9mI,GACH+/H,GAAUuE,EAAMuC,KAC3Bn3C,IAAQ1vF,EAAM+gI,GAAS/nH,IAG3B,SAASA,EAAKgrB,KAAQhkC,GAClB,IAAY,IAARgkC,EACJ,OAAIA,GAAO6iG,IAAcvC,EAAMrnI,OACpBkb,EAAS6rB,KAAQhkC,QAE5B8mI,EAAS9mI,GAGb8mI,EAAS,OC5pLb,MAAMhnI,IAAS2B,EAAAA,EAAAA,yCAKA,MAAMslI,GAIjBpyH,cDq5HJ,IAAkByuH,EAAQC,EAClBv3B,ECr5HAvwG,KAAKyrI,QDo5HK5D,ECp5HU7nI,KAAK0rI,mBAAmB9qI,KAAKZ,MDo5H/B8nI,ECp5HsC,EDq5HxDv3B,EAAUi0B,GAAUqD,GACjB/mI,IAAM,CAAC6qI,EAAO3G,KACjBz0B,EAAQo7B,EAAM,GAAI3G,KACnB8C,EAAa,ICv5HZ9nI,KAAK4rI,UAAW,EAMpBxkE,QACIpnE,KAAKyrI,OAAOlC,OAMhBmC,mBAAmBv3C,EAAM03C,GACrB,IACI13C,EAAK03C,GACP,MAAOxqI,GACLkD,GAAOlD,MAAO,gBAAeA,MAAAA,OAAhB,EAAgBA,EAAO4C,SACpC4nI,EAAiBxqI,IAqBzBa,KAAKiyF,EAAMv3E,GACH5c,KAAK4rI,SACLhvH,GAAYA,EAAS,IAAI5Y,MAAM,+BAInChE,KAAKyrI,OAAOvpI,KAAKiyF,EAAMv3E,GAO3BkvH,WACI9rI,KAAK4rI,UAAW,iBCnEjB,IAAKG,aAAAA,GAAAA,EAAAA,QAAAA,UAAAA,EAAAA,OAAAA,SAAAA,EAAAA,MAAAA,SAAAA,KAAAA,GAAAA,KAqBL,MAAMC,GAAUD,GAAmBC,QAC7B5kC,GAAS2kC,GAAmB3kC,OAC5B6kC,GAAQF,GAAmBE,MCjBlC1nI,IAAS2B,EAAAA,EAAAA,4CAOA,MAAMgmI,WAAsBv8B,GAcvCv2F,YACQ4oG,EACAmqB,EACA/sB,EACAtc,EACAspC,EACAC,EACAC,GACJpnD,QACAllF,KAAKgiH,IAAMA,EACXhiH,KAAKmsI,SAAWA,EAChBnsI,KAAKo/G,UAAYA,EACjBp/G,KAAK8iG,WAAaA,EAClB9iG,KAAKosI,iBAAmBA,EACxBpsI,KAAKqsI,SAAWA,EAOhBrsI,KAAKssI,YAAcA,EAMnBtsI,KAAKusI,SAAU,EAKfvsI,KAAKwsI,cAAgB,GAMrBxsI,KAAKuhG,KAAO,KAOZvhG,KAAKysI,gBAAkB,KAMvBzsI,KAAK6rC,MAAQ,KAMb7rC,KAAK0hG,IAAM,KAOXgrC,mBACA,OAAO1sI,KAAKssI,YAActsI,KAAKmsI,SAAWnsI,KAAKo/G,UAO/CutB,mBACA,OAAO3sI,KAAKssI,YAActsI,KAAKo/G,UAAYp/G,KAAKmsI,SAcpD59C,WAAWgT,EAAMG,EAAKkrC,EAAgB7sI,GAClC,GAAmB,OAAfC,KAAK6rC,MAAgB,CACrB,MAAMyzE,EACC,kCAAiCt/G,KAAKgiH,oCAC3BhiH,KAAK6rC,QAGvB,MADAtnC,GAAOlD,MAAMi+G,GACP,IAAIt7G,MAAMs7G,GAIpBt/G,KAAKuhG,KAAOA,EACZvhG,KAAK0hG,IAAMA,EACX1hG,KAAKysI,gBAAkBG,EACvB5sI,KAAK6rC,MAAQkgG,GACb/rI,KAAK6sI,aAAa9sI,GAStB8sI,aAAa9sI,IAWb+sI,iBAAiB1tF,IAQjB2tF,WACI,OAAO/sI,KAAK6rC,MAUhBmhG,WAAW5tF,IAOX6tF,cAAc7tF,IAiBd8tF,UAAUn9C,EAASo9C,EAASptI,IAW5BqtI,YAAY3V,EAAQ1nC,EAASo9C,IAK7BE,mBACI,OAAOrtI,KAAKssI,YAActsI,KAAKmsI,SAAWnsI,KAAKo/G,eCjNlDkuB,aAAAA,GAAAA,EAAAA,iCAAAA,kDAAAA,KAAAA,GAAAA,KAOL,YCqBM/oI,IAAS2B,EAAAA,EAAAA,8CAOTqnI,GAAa,IAkDJ,MAAMC,WAAwBtB,GASjB,yBAACuB,GACrB,MAAMC,EAAgBD,EAAeplI,KAAK,0BAE1C,GAAIqlI,EAAchsI,OAAQ,CACtB,MAAMigI,EAAU+L,EAAc,GAAGlrH,aAAa,WAE9C,GAAgB,SAAZm/G,GACe,cAAZA,GACY,cAAZA,GACY,SAAZA,EACH,OAAOA,EAIf,OAAO,KASe,2BAAC8L,GACvB,MAAME,EAAoBF,EAAeplI,KAAK,2CAE9C,OAAOslI,EAAkBjsI,OAASoN,OAAO6+H,EAAkB3rI,QAAU,KAqBzEoX,YACQ4oG,EACAmqB,EACA/sB,EACAtc,EACAspC,EACAC,EACA98C,EACA+8C,GACJpnD,MACI88B,EACAmqB,EACA/sB,EAAWtc,EAAYspC,EAAkBC,EAAUC,GAWvDtsI,KAAK4tI,iBAAmB,KAQxB5tI,KAAK6tI,wBAAqB9hI,EAQ1B/L,KAAK8tI,wBAAqB/hI,EAQ1B/L,KAAK+tI,6BAA+B,KAYpC/tI,KAAKguI,2BAA6B,KAOlChuI,KAAKiuI,6BAA0BliI,EAgB/B/L,KAAKkuI,mBAAoB,EAYzBluI,KAAKmuI,oBAAqB,EAS1BnuI,KAAKouI,oBAAqB,EAE1BpuI,KAAKquI,kBAAmB,EACxBruI,KAAKg1B,QAAS,EAQdh1B,KAAKuvF,MAAQA,EAObvvF,KAAKsuI,8BAA2BviI,EAOhC/L,KAAKuuI,kBAAoB,IAAI/C,GAO7BxrI,KAAKwuI,cAAe,EAQpBxuI,KAAKyuI,2BAAwB1iI,EAE7B/L,KAAK0uI,eAAiB,GACtB1uI,KAAK0uI,eAAexsI,KAChB4gG,EAAWz2D,iBACPyzE,GAAe38B,OAAO48B,oBACtB//G,KAAK2uI,oBAAoB/tI,KAAKZ,QAGtCA,KAAK4uI,iDAA8C7iI,EAUvD8iI,kBACI,OAAO7uI,KAAK6rC,QAAUkgG,GAO1Bc,aAAa9sI,GAAS,UAClBC,KAAK6/H,QAAUv4C,QAAQvnF,EAAQ8/H,SAC/B7/H,KAAKquI,kBAAmB,EACxBruI,KAAKD,QAAUA,EAMfC,KAAK8uI,aAAc,EAMnB9uI,KAAK+uI,WAAY,EACjB/uI,KAAKgvI,oBAAsB1nD,QAAQvnF,EAAQivI,qBAC3ChvI,KAAKivI,oBAAsB3nD,QAAQvnF,EAAQkvI,qBAE3C,MAAMC,EAAY,CAAE3jB,WAAYxrH,EAAQwrH,YAqBxC,GAnBIxrH,EAAQovI,cACRD,EAAUE,SApSI,KAsSlBF,EAAUG,uBAAwB,EAClCH,EAAUI,wBAA0BvvI,EAAQuvI,wBAC5CJ,EAAUK,aAAexvI,EAAQwvI,aACjCL,EAAUM,eAAiBzvI,EAAQyvI,eACnCN,EAAU5V,aAAev5H,EAAQu5H,aACjC4V,EAAUrlI,gBAAkB7J,KAAK6J,gBAC3B07B,GAAQskD,wBACFtkD,GAAQ8gD,aACL9gD,GAAQ4hD,kBACP5hD,GAAQ2hD,mBAGLlnF,KAAKuvF,MAHR,oBAIExvF,EAAQs6F,WAJV,aAIE,EAAao1C,6BAJf,mBAKE1vI,EAAQ0vI,6BALV,WAOZzvI,KAAKuvF,MAAO,CAEZ2/C,EAAUQ,kBAAmB,EAC7B,MAAMC,EAAqB3vI,KAAK4vI,2BAA2B7vI,QAEzB,IAAvB4vI,IACPT,EAAUS,mBAAqBA,OAEhC,SAEHT,EAAUQ,iBACJ3vI,EAAQ2vI,kBACF3vI,EAAQ8vI,aAAe9vI,EAAQ+vI,aAC/B/vI,EAAQwvI,cAAgBxvI,EAAQwvI,aAAaQ,iBAAmBjR,GAAAA,KAI5EoQ,EAAUG,sBAAwBH,EAAUQ,oBACa,iBAAhD,UAAO3vI,EAAQ+5H,+BAAf,aAAO,EAAiCziG,OACtC,UAAAt3B,EAAQ+5H,+BAAR,eAAiCziG,KTxWnB,GS4WzBolE,GAAWe,UAAUnT,uBAAuB,CAAEglD,sBAAuBH,EAAUG,wBAG/EtvI,EAAQ6mG,cACRsoC,EAAUtoC,aAAc,GAG5B5mG,KAAKusF,eACCvsF,KAAK0hG,IAAIsuC,qBACHhwI,KAAKysI,gBACLzsI,KAAKqsI,SACLrsI,KAAKuvF,MACL2/C,GAEZlvI,KAAKusF,eAAe0jD,eAAiB7H,IACjC,IAAKA,EAMD,OAIJ,MAAM12D,EAAY02D,EAAG12D,UACfzkB,EAAM3qD,OAAOijG,YAAYt4C,MAE/B,GAAIykB,EAAW,CAC6B,OAApC1xE,KAAKguI,6BACLhuI,KAAKguI,2BAA6B/gF,GAItC,IAAI2kB,EAAWF,EAAUE,SAEzB,GAAwB,iBAAbA,EAEP,GADAA,EAAWA,EAASz6C,cACH,QAAby6C,GAAmC,WAAbA,GACtB,GAAI5xE,KAAKivI,oBACL,YAED,GAAiB,QAAbr9D,GACH5xE,KAAKgvI,oBACL,YAIJhvI,KAAKouI,qBAEb3xC,GAAWoE,cACPze,GACA,CACI8tD,MAAO,YACP/oI,MAAO8lD,EAAMjtD,KAAKguI,2BAClB3zC,IAAKr6F,KAAKuvF,MACV4gD,UAAWnwI,KAAKssI,cAExBtsI,KAAKouI,oBAAqB,GAE9BpuI,KAAKowI,iBAAiB1+D,IAU1B1xE,KAAKusF,eAAe8jD,uBAAyB,KACE,WAAvCrwI,KAAKusF,eAAe+jD,eACpBtwI,KAAK+uI,WAAY,EAC6B,WAAvC/uI,KAAKusF,eAAe+jD,gBACgB,WAAxCtwI,KAAKusF,eAAegkD,iBACvBvwI,KAAKuhG,KAAK/N,aAAa37D,KAAKoF,GAAW,WAAXA,iBAA6Bj9B,OAUjEA,KAAKusF,eAAeikD,2BAA6B,KAC7C,MAAMvjF,EAAM3qD,OAAOijG,YAAYt4C,MAC/B,IAAIwjF,GAAW,EAuBf,OArBKzwI,KAAKuvF,QACNvvF,KAAKuhG,KAAKqB,gBACL,aAAY5iG,KAAKusF,eAAemkD,sBAC/BzjF,GAEV1oD,GAAOD,IAAK,cAAatE,KAAKusF,eAAemkD,sBAAsB1wI,KAAKuvF,MAAQ,MAAQ,WAAYtiC,GAEpGwvC,GAAWoE,cACPve,GACA,CACI+X,IAAKr6F,KAAKuvF,MACV1jD,MAAO7rC,KAAKusF,eAAemkD,mBAC3B,gBAAmB1wI,KAAKusF,eAAe+jD,eACvCK,UAAW3wI,KAAK8uI,YAChB3nI,MAAO8lD,IAGfjtD,KAAKuhG,KAAK/N,aAAa37D,KACnBoF,GAAW,WAAXA,6BACAj9B,KACAA,KAAKusF,eAAemkD,oBAChB1wI,KAAKusF,eAAemkD,oBAC5B,IAAK,WACD1wI,KAAK+tI,6BAA+B9gF,EACpC,MACJ,IAAK,YAGD,GAA2C,WAAvCjtD,KAAKusF,eAAe+jD,eAA6B,CACjDG,GAAW,EACX,MAAMG,GAA2B5wI,KAAKD,QAAQ8wI,kBACvC7wI,KAAKuhG,KAAKwwB,8BAEb/xH,KAAK8uI,aAAe8B,IACpB5wI,KAAKuhG,KAAK/N,aAAa37D,KACnBoF,GAAW,WAAXA,oBAAgCj9B,MAW5C,IAAKA,KAAKwuI,eACFxuI,KAAK+uI,WACF0B,GACCzwI,KAAK6J,iBAAmB7J,KAAKssI,aAAe/mG,GAAQ2hD,mBAAqB,CAEjFuV,GAAWoE,cACPze,GACA,CACI8tD,MAAO,WACP/oI,MAAO8lD,EAAMjtD,KAAK+tI,6BAClB1zC,IAAKr6F,KAAKuvF,MACV4gD,UAAWnwI,KAAKssI,cAMxB,MAAMwE,EACA7mI,KAAK6uB,IACH94B,KAAK+tI,6BACL/tI,KAAKguI,4BAEbhuI,KAAKyuI,sBAAwBxhF,EAAM6jF,EAEnCr0C,GAAWoE,cACPze,GACA,CACI8tD,MAAO,gBACP/oI,MAAOnH,KAAKyuI,sBACZp0C,IAAKr6F,KAAKuvF,MACV4gD,UAAWnwI,KAAKssI,cAGxBtsI,KAAKwuI,cAAe,EACpBxuI,KAAKuhG,KAAK/N,aAAa37D,KACnBoF,GAAW,WAAXA,uBAAmCj9B,MAE3CA,KAAK8uI,aAAc,EACnB,MACJ,IAAK,eACD9uI,KAAK8uI,aAAc,EAIf9uI,KAAK+uI,WACL/uI,KAAKuhG,KAAK/N,aAAa37D,KACnBoF,GAAW,WAAXA,uBAAmCj9B,MAE3C,MACJ,IAAK,SACDA,KAAKuhG,KAAK/N,aAAa37D,KACnBoF,GAAW,WAAXA,sBAAkCj9B,QAU9CA,KAAKusF,eAAewkD,wBAA0B,KAC1C,MAAMC,EAAWhxI,KAAKusF,eAAemkD,mBAGhC,WADG1wI,KAAKusF,eAAegkD,iBAMP,iBAAbS,GACAhxI,KAAKuhG,KAAK/N,aAAa37D,KACnBoF,GAAW,WAAXA,sBAAkCj9B,OAUlDA,KAAKusF,eAAe0kD,oBAAsB,KACtC,MAAMplG,EAAQ7rC,KAAKusF,eAAe+jD,eAC5BY,EAAoBlxI,KAAKusF,eAAe2kD,kBAE9C,GAAIlxI,KAAK6J,kBACD7J,KAAKuvF,OACI,WAAV1jD,GACAqlG,GACiC,iBAA1BA,EAAkBnpI,IAAkB,CAC9CxD,GAAOiH,KAAM,GAAExL,qCAAqCA,KAAKusF,kBAEzD,MAAM4kD,EAAetF,IACjB,MAAMuF,EAAS,IAAIhS,GAAIp/H,KAAKusF,eAAe8kD,iBAAiBtpI,KAE5D/H,KAAKsxI,eACA1wF,MAAK,IAAM5gD,KAAKusF,eAAeglD,kCAC/B3wF,MAAK,KACF,MAAM4wF,EAAS,IAAIpS,GAAIp/H,KAAKusF,eAAe8kD,iBAAiBtpI,KAE5D/H,KAAKyxI,mBAAmBL,EAAQI,MAEnC5wF,MAAK,IAAMirF,MAAoBxqI,GAASwqI,EAAiBxqI,MAGlErB,KAAKuuI,kBAAkBrsI,KACnBivI,GACA9vI,IACQA,EACAkD,GAAOlD,MAAO,GAAErB,iCAAkCqB,GAElDkD,GAAOynF,MAAO,GAAEhsF,+CAYxC0xI,8BACI,GAAI1xI,KAAKuvF,MACL,OAAOvvF,KAAKsuI,yBAWpB8B,iBAAiB1+D,GACb,MAAMigE,EAAW,IAAIvS,GAAIp/H,KAAKusF,eAAe8kD,iBAAiBtpI,KAE9D,GAAI2pE,GAAaA,EAAUA,UAAUhwE,SAAW1B,KAAKquI,iBAAkB,CACnE,MAAMuD,EAAMxW,GAAAA,UAAkBuW,EAAShqI,MAAM+pE,EAAUmgE,eAAgBF,EAASnqI,SAC1EsqI,EAAQ1W,GAAAA,kBAA0B1pD,EAAUA,WAElD,IAAMkgE,IAAOE,EAAQ,CACjB,MAAMC,EAAgB,6BAKtB,OAHAv5G,KAAAA,iBAAsC,IAAIx0B,MAAM+tI,SAChDxtI,GAAOlD,MAAM0wI,GAIjBH,EAAIx9H,MAAQ,uCAERpU,KAAKusI,SAC6B,IAA9BvsI,KAAKwsI,cAAc9qI,QACnBc,YAAW,KAC2B,IAA9BxC,KAAKwsI,cAAc9qI,SAGvB1B,KAAKgyI,kBAAkBhyI,KAAKwsI,eAC5BxsI,KAAKwsI,cAAgB,MA/mBV,KAknBnBxsI,KAAKwsI,cAActqI,KAAKwvE,IAExB1xE,KAAKgyI,kBAAkB,CAAEtgE,SAG7BntE,GAAOD,IAAK,GAAEtE,yCAGdA,KAAKquI,kBAAmB,EAUhC2D,kBAAkBliI,GACd,IAAK9P,KAAK6uI,gBAAgB,qBAEtB,OAGJtqI,GAAOD,IAAK,GAAEtE,0BAA0BoB,KAAKF,UAAU4O,MACvD,MAAMgtH,GAAO9d,EAAAA,GAAAA,KAAI,CAAEC,GAAIj/G,KAAKo/G,UACxBx3G,KAAM,QACLuF,EAAE,SAAU,CAAEiH,MAAO,oBAClB3M,OAAQ,iBACR0oI,UAAWnwI,KAAK0sI,aAChB1qB,IAAKhiH,KAAKgiH,MAEZ2vB,EAAW,IAAIvS,GAAIp/H,KAAKusF,eAAe8kD,iBAAiBtpI,KAE9D,IAAK,IAAImsE,EAAM,EAAGA,EAAMy9D,EAAShqI,MAAMjG,OAAQwyE,IAAO,CAClD,MAAM+9D,EAAQniI,EAAW/I,QAAOsK,GAAMA,EAAGwgI,gBAAkB39D,IACrDiC,EACAilD,GAAAA,WAAmBuW,EAAShqI,MAAMusE,GAAKhwE,MAAM,QAAQ,IAE3D,GAAI+tI,EAAMvwI,OAAS,EAAG,CAClB,MAAMkwI,EACAxW,GAAAA,UAAkBuW,EAAShqI,MAAMusE,GAAMy9D,EAASnqI,SAEtDoqI,EAAIx9H,MAAQ,uCACZ0oH,EAAK3vH,EAAE,UAAW,CACdyzH,QAAS5gI,KAAK0sI,eAAiB1sI,KAAKmsI,SAC9B,YAAc,YACpB3/H,KAAMylI,EAAM,GAAGC,OAASD,EAAM,GAAGC,OAAS/7D,EAAMxuE,QACjDwF,EAAE,YAAaykI,GAClB,IAAK,IAAIpwI,EAAI,EAAGA,EAAIywI,EAAMvwI,OAAQF,IAAK,CACnC,MAAMkwE,EACA0pD,GAAAA,kBAA0B6W,EAAMzwI,GAAGkwE,WAIrC1xE,KAAK6/H,UACLnuD,EAAU1hE,GAAK,WAEnB8sH,EAAK3vH,EAAE,YAAaukE,GAAWqzC,KAInC,MAAMotB,EACA/W,GAAAA,SACEuW,EAAShqI,MAAMusE,GACf,iBAAkBy9D,EAASnqI,SAEnC,GAAI2qI,EAAiB,CACjB,MAAM10G,EAAM29F,GAAAA,iBAAyB+W,GAErC10G,EAAI20G,UAAW,EACftV,EAAK3vH,EACD,cACA,CAAEiH,MAAO,gCACRpP,EAAEy4B,EAAIi/F,oBACJj/F,EAAIi/F,YACXI,EAAKxnH,MAAMmoB,GACXq/F,EAAK/X,KAET+X,EAAK/X,KACL+X,EAAK/X,MAOb/kH,KAAK8iG,WAAWugB,OACZyZ,EAAM,KAAM98H,KAAKqyI,sBAAsBvV,GAAOyQ,IAUtD+E,4BACI,MAAMC,GACAvzB,EAAAA,GAAAA,KAAI,CACFC,GAAIj/G,KAAKo/G,UACTx3G,KAAM,QACTuF,EAAE,SAAU,CAAEiH,MAAO,oBAClB3M,OAAQ,eACR0oI,UAAWnwI,KAAK0sI,aAChB1qB,IAAKhiH,KAAKgiH,MACb70G,EAAE,YAAa,CAAEiH,MAAO,oCACxBpP,EAAE,UACF+/G,KAEL/kH,KAAK4tI,kBACE2E,EAAYplI,EACX,iBAAkB,CACdiH,MAAO,kCACP/O,GAAIrF,KAAK4tI,mBAGrB5tI,KAAK8iG,WAAWoc,QACZqzB,EAAa,CAMTz6E,QAAS,KAEZ9T,MAAMhkD,KAAKqyI,sBAAsBE,IAM1CzF,iBAAiBz9F,GACb,GAA2C,WAAvCrvC,KAAKusF,eAAe+jD,eAGpB,YAFA/rI,GAAO2T,KAAM,GAAElY,uDAKnB,MAAMwyI,EAAgB,GAEtBnjG,EAAKhnC,KAAK,gCACL+mC,MAAK,CAAC0K,EAAK43B,KACR,IAAI5tE,EAAOs3H,GAAAA,oBAA4B1pD,GAEvC5tE,EAAOA,EAAK2M,QAAQ,OAAQ,IAAIA,QAAQ,KAAM,IAI9C,MAAMgiI,EAAe,IAAIC,gBAAgB,CACrCb,cAAe,EAOfK,OAAQ,GACRxgE,UAAW5tE,IAGf0uI,EAActwI,KAAKuwI,MAGtBD,EAAc9wI,QAsBnB6C,GAAOynF,MAAO,GAAEhsF,oBAAoBwyI,EAAc9wI,+BAClD1B,KAAKuuI,kBAAkBrsI,MAbF2pI,IACjB,IAAK,MAAM8G,KAAgBH,EACvBxyI,KAAKusF,eAAeqmD,gBAAgBD,GAC/B/xF,MACG,IAAMr8C,GAAOynF,MAAO,GAAEhsF,8BACtByoC,GAAOlkC,GAAOlD,MAAO,GAAErB,+BAAgCyoC,KAGnEojG,IACAtnI,GAAOynF,MAAO,GAAEhsF,yCAlBhBuE,GAAOlD,MAAO,GAAErB,kCAAmCqvC,EAAK,IAAMA,EAAK,GAAGwjG,WA6B9EC,aAAa1zF,GAEHmf,IAAAA,CAAEnf,GAAU/2C,KACV,gEAGF+mC,MAAK,CAAC5tC,EAAGuxI,KACX,MAAMnsI,EAAOkI,OAAOikI,EAAYvwH,aAAa,SAE7C,GAAIxiB,KAAKuvF,MAELvvF,KAAKysI,gBAAgBuG,aACjBpsI,EAAMm7F,GAAAA,QAAAA,mBAA2B/hG,KAAKo/G,gBACvC,CACH,GAAIiY,GAAAA,gCAEI0b,EAAYxvH,aAAa,QAAS,CAClC,MAAM69G,EAAa2R,EAAYvwH,aAAa,QAE5CxiB,KAAKysI,gBAAgBwG,mBAAmBrsI,EAAMw6H,GAGtD7iE,IAAAA,CAAEw0E,GACG1qI,KAAK,gDACL+mC,MAAK,CAAC8jG,EAAIC,KACP,MAAMjuF,EAAQiuF,EAAgB3wH,aAAa,SAt0BnE,IAAuB4wH,EAw0BKluF,GAASA,EAAMxjD,SACXgoC,MAAM9iC,IAASA,EAAO,EACtBrC,GAAO2T,KAAM,GAAElY,qBAAqB4G,wBAA2Bs+C,KAE/DllD,KAAKysI,gBAAgBuG,aACjBpsI,GA70BbwsI,EA80B2BluF,EA70BvC68C,GAAAA,QAAAA,mBAA2BqxC,IAAoBA,YA01BtDC,uBACQrzI,KAAKusF,eACLvsF,KAAKusF,eAAe8mD,uBAEpB9uI,GAAOlD,MAAO,GAAErB,6DAOxBszI,0BACI,OAAOtzI,KAAKusF,eAAe+mD,0BAuB/BlG,YAAYmG,EAAaxjD,EAASo9C,EAAS96B,GACvCryG,KAAKwzI,oBACDD,GACA,KAIIvzI,KAAKyzI,mBAAkB,KACnB1jD,IAEA/vF,KAAKuhG,KAAK/N,aAAa37D,KAAKoF,GAAW,WAAXA,eAA2Bj9B,SAE3DqB,IACI8rI,EAAQ9rI,GAERrB,KAAKuhG,KAAK/N,aAAa37D,KAAKoF,GAAW,WAAXA,qBAAiCj9B,KAAMqB,QAG3E8rI,EACA96B,GAWRkhB,SAAyB,IAAlBlhB,EAAkB,uDAAJ,GACjB,IAAKryG,KAAKssI,YACN,MAAM,IAAItoI,MAAM,+CAoBpBO,GAAOynF,MAAO,GAAEhsF,2BAChBA,KAAKuuI,kBAAkBrsI,MAnBF2pI,IACjB,MAAM6H,EAAY,GAElB,IAAK,MAAMC,KAActhC,EACrBqhC,EAAUxxI,KAAKlC,KAAKusF,eAAeqnD,SAASD,EAAY3zI,KAAKssI,cAGjEviG,QAAQ8pG,IAAIH,GACP9yF,MAAK,IAAM5gD,KAAKusF,eAAeunD,YAAY9zI,KAAKosI,oBAChDxrF,MAAKmzF,GAAY/zI,KAAKusF,eAAeynD,oBAAoBD,KACzDnzF,MAAK,KAGF5gD,KAAKi0I,oBAAoBj0I,KAAKusF,eAAe8kD,iBAAiBtpI,QAEjE64C,MAAK,IAAMirF,MAAoBxqI,GAASwqI,EAAiBxqI,QAM9DA,IACQA,EACAkD,GAAOlD,MAAO,GAAErB,oBAAqBqB,GAErCkD,GAAOynF,MAAO,GAAEhsF,gCAehCi0I,oBAAoBF,GAChB,IAAInqG,GAAOo1E,EAAAA,GAAAA,KAAI,CACXC,GAAIj/G,KAAKo/G,UACTx3G,KAAM,QACPuF,EAAE,SAAU,CACXiH,MAAO,oBACP3M,OAAQ,mBACR0oI,UAAWnwI,KAAK0sI,aAChB1qB,IAAKhiH,KAAKgiH,MAGd,IAAIod,GAAI2U,GAAUtT,SACd72F,EACA5pC,KAAKssI,YAAc,YAAc,aACrC1iG,EAAOA,EAAKo6E,OACZz/G,GAAOynF,MAAO,GAAEhsF,0BAA2B4pC,GAC3C5pC,KAAK8iG,WAAWugB,OAAOz5E,GACnB,KACIrlC,GAAOiH,KAAM,GAAExL,6CAEnBqB,IACIkD,GAAOlD,MAAO,GAAErB,gCAAiCqB,KAErDksI,IAOR2G,UAAUC,GACN,IAAKn0I,KAAKssI,YACN,MAAM,IAAItoI,MAAM,oDAEpBhE,KAAKwzI,oBACDW,GACA,KAEI,GADA5vI,GAAOiH,KAAM,GAAExL,8BACXA,KAAK6J,iBAAmB07B,GAAQ2hD,kBAAmB,CACnD,MAAMiqD,EAAetF,IAGjB,MAAMuI,EAAYp0I,KAAKusF,eAAe2kD,kBAAkBnpI,IAClDmpI,EAAoB,IAAIjlI,sBAAsB,CAChDrE,KAAM,QACNG,IAAKqsI,IAGT,OAAOp0I,KAAKq0I,sBAAsBnD,GACjCtwF,MAAK,IAAMirF,MAAoBxqI,GAASwqI,EAAiBxqI,MAG9DkD,GAAOynF,MAAO,GAAEhsF,yCAChBA,KAAKuuI,kBAAkBrsI,KACnBivI,GACA9vI,IACQA,EACAkD,GAAOlD,MAAO,GAAErB,2DAA2DqB,KAE3EkD,GAAOynF,MAAO,GAAEhsF,wDAKpCqB,IACIkD,GAAOlD,MAAO,GAAErB,0BAA2BqB,MAmBvDmyI,oBAAoBc,EAAqBvkD,EAASo9C,GAA2B,IAAlB96B,EAAkB,uDAAJ,GA+DrE9tG,GAAOynF,MAAO,GAAEhsF,wCAChBA,KAAKuuI,kBAAkBrsI,MA/DF2pI,IACjB,MAAM6H,EAAY,GAElB,IAAK,MAAMv7D,KAASk6B,EAChBqhC,EAAUxxI,KAAKlC,KAAKusF,eAAeqnD,SAASz7D,EAAOn4E,KAAKssI,cAG5D,MAAMiI,EACAv0I,KAAKw0I,yBAAyBF,GAC9BG,EACAz0I,KAAKusF,eAAe8kD,iBAAiBtpI,IAMrC2sI,EAHAn2E,IAAAA,CAAE+1E,GACCjsI,KAAK,4DAEwBqN,KAAK,MAEvCg/H,IAAoB10I,KAAK4tI,mBACzB5tI,KAAK4tI,iBAAmB8G,GAG5B3qG,QAAQ8pG,IAAIH,GACP9yF,MAAK,IAAM5gD,KAAKsxI,aAAaiD,EAAahwF,OAC1C3D,MAAK,KA2BF,GA1BI5gD,KAAK6rC,QAAUkgG,KACf/rI,KAAK6rC,MAAQkgG,IAeT/rI,KAAKuvF,OACAvvF,KAAKkuI,oBAAqBluI,KAAKiuI,yBACpCjuI,KAAK20I,qBAQTF,EAAa,CACb,MAAMG,EACA,IAAIxV,GAAIp/H,KAAKusF,eAAe8kD,iBAAiBtpI,KAEnD/H,KAAKyxI,mBACD,IAAIrS,GAAIqV,GAAcG,OAGjCh0F,MAAK,IAAMirF,MAAoBxqI,GAASwqI,EAAiBxqI,QAM9DA,IACQA,GACAkD,GAAOlD,MAAO,GAAErB,yCAAyCqB,KACzD8rI,EAAQ9rI,KAERkD,GAAOynF,MAAO,GAAEhsF,sCAChB+vF,QAYhB8kD,iBAAkD,IAAnCC,EAAmC,uDAAvB,KAAMtgG,EAAiB,uDAAN,KACxC,MAAMv+B,EAAUjW,KAAKusF,eAAe+mD,0BAEpC,GAAItzI,KAAK6uI,mBAAqBiG,IAAc7+H,EAAS,CACjD1R,GAAOiH,KAAM,GAAExL,mCAAmCiW,QAAc6+H,KAChE90I,KAAKusF,eAAesoD,eAAeC,EAAWtgG,GAG9C,MAAM28F,EAAetF,IACjB7rI,KAAKsxI,eAAe1wF,MAChB,KACIr8C,GAAOynF,MAAO,GAAEhsF,oCAET6rI,OACRxqI,IACCkD,GAAOlD,MAAO,GAAErB,oCAAoCqB,KAE7CwqI,EAAiBxqI,OAIpCkD,GAAOynF,MAAO,GAAEhsF,mCAGhBA,KAAKuuI,kBAAkBrsI,KAAKivI,IAcpC4D,iBAAiBC,EAAiBjlD,EAASo9C,GACvC,GAAIntI,KAAKD,QAAQk1I,mBAAoB,CACjC,MAAMltI,EAAM,IAAIq3H,GAAIp/H,KAAKusF,eAAe8kD,iBAAiBtpI,KAKzD,OAHA/H,KAAKk1I,oBAAoBntI,EAAKgoF,EAASo9C,QACvCntI,KAAKuhG,KAAK/N,aAAa37D,KAAKoF,GAAW,WAAXA,qBAAiCj9B,MAIjEA,KAAKuhG,KAAK/N,aAAa37D,KAAKoF,GAAW,WAAXA,eAA2Bj9B,MAMvD,MAAMm1I,EAAgBH,EAAgBhlG,QAEtCglG,EACK3sI,KAAK,yBACLqN,KAAK,UAAW,YAQrBs/H,EACK3sI,KAAK,+BACL2U,SACLg4H,EACK3sI,KAAK,mCACL2U,SAML,MAAMo4H,EAAiBJ,EAAgB3sI,KAAK,kCAE5C+sI,EAAe1/H,KAAK,OAAQ,SAC5B0/H,EAAepzI,KAAK,+DAGpBhC,KAAKwzI,oBACDwB,GACA,KAEIh1I,KAAKwzI,oBACD2B,GACA,KACI,MAAMxD,EACA,IAAIvS,GAAIp/H,KAAKusF,eAAe8kD,iBAAiBtpI,KAEnD/H,KAAKk1I,oBAAoBvD,EAAU5hD,EAASo9C,GAE5CntI,KAAKuhG,KAAK/N,aAAa37D,KACnBoF,GAAW,WAAXA,oBACAj9B,KACAm1I,KAERhI,KAERA,GAYRsG,kBAAkB1jD,EAASo9C,GAGvB,MAAMwE,EAAW,IAAIvS,GAAIp/H,KAAKusF,eAAe8kD,iBAAiBtpI,KACxDstI,GAASr2B,EAAAA,GAAAA,KAAI,CAAEC,GAAIj/G,KAAKo/G,UAC1Bx3G,KAAM,QACLuF,EAAE,SAAU,CAAEiH,MAAO,oBAClB3M,OAAQ,iBACR0oI,UAAWnwI,KAAK0sI,aAChB4I,UAAWt1I,KAAK2sI,aAChB3qB,IAAKhiH,KAAKgiH,MAEdhiH,KAAKivI,sBACL0C,EAAS7R,qBAAsB,GAE/B9/H,KAAKgvI,sBACL2C,EAAS5R,qBAAsB,GAE/B//H,KAAK6/H,UACL8R,EAAS9R,SAAU,GAEvB8R,EAASlR,SACL4U,EACAr1I,KAAK0sI,eAAiB1sI,KAAKmsI,SAAW,YAAc,aAExD5nI,GAAOiH,KAAM,GAAExL,+BACfuE,GAAOynF,MAAMqpD,EAAOrxB,QACpBhkH,KAAK8iG,WAAWugB,OAAOgyB,EACnBtlD,EACA/vF,KAAKqyI,sBAAsBgD,GAAQh0I,IAC/B8rI,EAAQ9rI,GAIRrB,KAAKuhG,KAAK/N,aAAa37D,KACnBoF,GAAW,WAAXA,uBAAmCj9B,SAE3CutI,IA4BRoH,oBACI,MAAMY,EAAiBv1I,KAAKiuI,wBACtBtM,EAAU3hI,KAAKkuI,kBAAoB,OAAS,OAElD,IAAIsH,GACEx2B,EAAAA,GAAAA,KAAI,CACFC,GAAIj/G,KAAKo/G,UACTx3G,KAAM,QAELuF,EAAE,SAAU,CACTiH,MAAO,oBACP3M,OAAQ,iBACR0oI,UAAWnwI,KAAK0sI,aAChB1qB,IAAKhiH,KAAKgiH,MAEb70G,EAAE,UAAW,CACVX,KAAMsoF,GAAU2G,MAChBkmC,QAAAA,SAGkB,IAAnB4T,IACPC,EAAgBA,EACXroI,EAAE,mBAAoB,CAAEiH,MAAO,mCAC/BpP,EAAEuwI,IAGXhxI,GAAOiH,KAAM,GAAExL,+CAA+C2hI,wBAA8B4T,KAC5FhxI,GAAOynF,MAAMwpD,EAAcxxB,QAE3BhkH,KAAK8iG,WAAWugB,OACZmyB,EACA,KACAx1I,KAAKqyI,sBAAsBmD,GAC3BjI,IASRkI,2BAA2BF,GACvBhxI,GAAOiH,KAAM,GAAExL,uDAAuDu1I,KAEtEv1I,KAAKiuI,wBAA0BsH,EAE3Bv1I,KAAKuvF,MAGDvvF,KAAK6rC,QAAUkgG,IACf/rI,KAAK20I,oBAGT30I,KAAK0hG,IAAI+zC,2BAA2BF,GAc5CL,oBAAoBvD,EAAU5hD,EAASo9C,GACnC,MAAMuI,GAAkB12B,EAAAA,GAAAA,KAAI,CAAEC,GAAIj/G,KAAKo/G,UACnCx3G,KAAM,QACLuF,EAAE,SAAU,CACTiH,MAAO,oBACP3M,OAAQ,mBACR0oI,UAAWnwI,KAAK0sI,aAChB1qB,IAAKhiH,KAAKgiH,MAGlB2vB,EAAShqI,MAAMpH,SAAQ,CAACo1I,EAAY77F,KAChC,MAAMq8B,EAAQilD,GAAAA,WAAmBua,EAAWzxI,MAAM,QAAQ,IAE1DwxI,EAAgBvoI,EAAE,UACd,CACIyzH,QACI5gI,KAAK0sI,eAAiB1sI,KAAKmsI,SACrB,YACA,YACV3/H,KAAM2pE,EAAMxuE,QAGpBgqI,EAAS/P,kBAAkB9nF,EAAK47F,GAChCA,EAAgB3wB,QAGpBxgH,GAAOiH,KAAM,GAAExL,iCACfuE,GAAOynF,MAAM0pD,EAAgB1xB,QAE7BhkH,KAAK8iG,WAAWugB,OAAOqyB,EACnB3lD,EACA/vF,KAAKqyI,sBAAsBqD,EAAiBvI,GAC5CI,IAcRqI,oBAAoB7lD,EAASo9C,GAGzB,MAAM0I,GAAkB72B,EAAAA,GAAAA,KAAI,CAAEC,GAAIj/G,KAAKo/G,UACnCx3G,KAAM,QACLuF,EAAE,SAAU,CACTiH,MAAO,oBACP3M,OAAQ,mBACR0oI,UAAWnwI,KAAK0sI,aAChB1qB,IAAKhiH,KAAKgiH,MAGlBz9G,GAAOiH,KAAM,GAAExL,mCACfuE,GAAOynF,MAAM6pD,EAAgB7xB,QAE7BhkH,KAAK8iG,WAAWugB,OAAOwyB,EACnB9lD,EACA/vF,KAAKqyI,sBAAsBwD,EAAiB1I,GAC5CI,IAURuI,yBAAyBP,GAAmC,IAAnBnU,EAAmB,uDAAN,KAClD,GAAIphI,KAAK6uI,kBAAmB,CACxBtqI,GAAOiH,KAAM,GAAExL,kCAAkCu1I,kBAA+BnU,KAEhF,MAAM2U,EAAkB3U,EAClBphI,KAAK0hG,IAAIs0C,sBAAsB3tI,MAAK8vE,GAASA,EAAM89D,kBAAoB7U,IACvEphI,KAAK0hG,IAAIw0C,qBAEf,OAAOl2I,KAAKusF,eAAe4pD,0BAA0BZ,EAAgBQ,GAGzE,OAAOhsG,QAAQC,UAMnBkjG,UAAUn9C,EAASo9C,EAASptI,GACxB,GAAIC,KAAK6rC,QAAUkgG,GAAnB,CAIA,IAAKhsI,GAAWunF,QAAQvnF,EAAQq2I,sBAAuB,CACnD,MAAMC,GACAr3B,EAAAA,GAAAA,KAAI,CACFC,GAAIj/G,KAAKo/G,UACTx3G,KAAM,QAELuF,EAAE,SAAU,CACTiH,MAAO,oBACP3M,OAAQ,oBACR0oI,UAAWnwI,KAAK0sI,aAChB1qB,IAAKhiH,KAAKgiH,MAEb70G,EAAE,UACFA,EAAGpN,GAAWA,EAAQw4B,QAAW,WACjCwsF,KAELhlH,GAAWA,EAAQu2I,kBACnBD,EACKlpI,EAAE,QACFnI,EAAEjF,EAAQu2I,mBACVvxB,KACAA,KAELsxB,EAAiBtxB,KAGrB/kH,KAAK4tI,kBACEyI,EAAiBlpI,EAChB,iBAAkB,CACdiH,MAAO,kCACP/O,GAAIrF,KAAK4tI,iBACT2I,QAASx2I,IAAsC,IAA3BA,EAAQy2I,iBAC7BzxB,KAEXxgH,GAAOiH,KAAM,GAAExL,kCACfuE,GAAOynF,MAAMqqD,EAAiBryB,QAE9BhkH,KAAK8iG,WAAWugB,OACZgzB,EACAtmD,EACA/vF,KAAKqyI,sBAAsBgE,EAAkBlJ,GAC7CI,SAEJhpI,GAAOiH,KAAM,GAAExL,0CAInBA,KAAK8iG,WAAW20B,OAAOyV,UAAUltI,KAAKgiH,MAQ1Cy0B,aAAaC,EAAiBC,GAI1BpyI,GAAOiH,KAAM,GAAExL,0BAA2B02I,EAAiBC,GAE3D32I,KAAK0uI,eAAenuI,SAAQ4pC,GAAkBA,MAC9CnqC,KAAK0uI,eAAiB,GAElB1uI,KAAK4uI,6CACL5uI,KAAK4uI,8CAGT5uI,KAAK42I,QAQTjI,oBAAoB1/C,GACZA,IAAW6wB,GAAeG,OAAOqQ,WAAatwH,KAAK6tI,qBACnDtpI,GAAOiH,KAAM,GAAExL,yCACfA,KAAKyxI,mBACDzxI,KAAK6tI,mBACL7tI,KAAK8tI,qBAcjB+I,4BAA4BC,EAAeC,GACvC,MAAMC,EAAc,GACdr3I,EAAOK,KAiEb,OA/DAu+D,IAAAA,CAAEu4E,GAAe1nG,MAAK,CAAC6nG,EAAIhoI,KACvB,MAAMzC,EAAO+xD,IAAAA,CAAEtvD,GAASyG,KAAK,QAC7B,IAAI+9D,EAAQ,GAEZlV,IAAAA,CAAEtvD,GACG5G,KAAK,uDACL+mC,MAAK,WAEF,MAAM7mC,EAAYvI,KAAKwiB,aAAa,aAC9B1b,EACAy3D,IAAAA,CAAEv+D,MACCqI,KAAK,WACLnB,KAAI,WAED,OAAOlH,KAAKwiB,aAAa,WAE5BwC,MAELle,EAAMpF,SACN+xE,GAAU,gBAAelrE,KAAazB,EAAMyC,KAAK,eAMvDg1D,IAAAA,CAAEtvD,GAAS5G,KACT,mDAGJ+mC,MAAK,WACL,MAAMxoC,EAAO23D,IAAAA,CAAEv+D,MAAM0V,KAAK,QAEtBqhI,EAAiBxW,aAAa35H,KAG5BjH,EAAKkK,kBAAmBlK,EAAK4vF,QACxBhrF,GAAO2T,KAAM,GAAEvY,2CAA8CiH,KAMxE23D,IAAAA,CAAEv+D,MAAMqI,KAAK,cAAc+mC,MAAK,WAC5BqkC,GAAU,UAAS7sE,KAAQ23D,IAAAA,CAAEv+D,MAAM0V,KAAK,UACpC6oD,IAAAA,CAAEv+D,MAAM0V,KAAK,UAAY6oD,IAAAA,CAAEv+D,MAAM0V,KAAK,SAAShU,SAC/C+xE,GAAU,IAAGlV,IAAAA,CAAEv+D,MAAM0V,KAAK,YAE9B+9D,GAAS,aAKjBsjE,EAAiBpvI,MAAMpH,SAAQ,CAACoH,EAAOuvI,KAC9B9b,GAAAA,SAAiBzzH,EAAQ,SAAQ6E,OAGjCwqI,EAAYE,KACbF,EAAYE,GAAM,IAEtBF,EAAYE,IAAOzjE,SAIpBujE,EAOXG,gBAAgB9nG,GACZrvC,KAAKo3I,0BAAyB,EAAgB/nG,GAOlDgoG,mBAAmBhoG,GACfrvC,KAAKo3I,0BAAyB,EAAoB/nG,GAStDioG,2BAA2BjyI,GAqBvBd,GAAOynF,MAAO,GAAEhsF,+DAA+DqF,KAE/ErF,KAAKuuI,kBAAkBrsI,MAtBFq1I,IACjB,MAAMC,EAAiBx3I,KAAKusF,eAAekrD,iCAAiCpyI,GAE5E,GAAImyI,EAAe91I,OAAQ,CACvB,MAAM+yI,EAAc,IAAIrV,GAAIp/H,KAAKusF,eAAe8kD,iBAAiBtpI,KAC3DwsI,EAAev0I,KAAK03I,2BAA2BF,GAErDx3I,KAAKsxI,aAAaiD,EAAahwF,KAC1B3D,MAAK,KACF,MAAM+2F,EAAc,IAAIvY,GAAIp/H,KAAKusF,eAAe8kD,iBAAiBtpI,KAEjE/H,KAAKyxI,mBAAmBgD,EAAakD,GACrCJ,OAEHvzF,OAAMvb,GAAO8uG,EAAe9uG,UAEjC8uG,OAQJl2I,IACQA,EACAkD,GAAOlD,MAAO,GAAErB,yCAA0CqB,GAE1DkD,GAAOiH,KAAM,GAAExL,4CAa/Bo3I,yBAAyBQ,EAAOvoG,GAC5B,MAAMwoG,EAAYD,EAAQ,kBAAoB,qBAE1CA,GACA53I,KAAK8yI,aAAazjG,GAoDtB9qC,GAAOynF,MAAO,GAAEhsF,eAAe63I,UAG/B73I,KAAKuuI,kBAAkBrsI,MApDF2pI,IACjB,IAAK7rI,KAAKusF,eAAe8kD,mBACjBrxI,KAAKusF,eAAe8kD,iBAAiBtpI,IAAK,CAC9C,MAAM+vI,EAAU,GAAED,qCAKlB,OAHAtzI,GAAOlD,MAAMy2I,QACbjM,EAAiBiM,GAKrBvzI,GAAOD,IAAK,GAAEtE,mBAAmB63I,KAEjC,MAAMpD,EAAc,IAAIrV,GAAIp/H,KAAKusF,eAAe8kD,iBAAiBtpI,KAC3DA,EAAM,IAAIq3H,GAAIp/H,KAAKusF,eAAe2kD,kBAAkBnpI,KACpDgwI,EACAH,EACI53I,KAAK62I,4BAA4BxnG,EAAMtnC,GACvC/H,KAAKg4I,+BAA+B3oG,EAAMtnC,GAC9CwsI,EACAqD,EACI53I,KAAKi4I,wBAAwBF,GAC7B/3I,KAAK03I,2BAA2BK,GAOpC7G,EAAoB,IAAIjlI,sBAAsB,CAChDrE,KAAM,QACNG,IAAKwsI,EAAahwF,OAENqzF,GAAS53I,KAAK6J,iBAAmB7J,KAAKuvF,OAAShqD,GAAQ2hD,kBACjElnF,KAAKq0I,sBAAsBnD,GAC3BlxI,KAAKsxI,aAAaiD,EAAahwF,MAE7B3D,MAAK,KACT,MAAMg0F,EAAc,IAAIxV,GAAIp/H,KAAKusF,eAAe8kD,iBAAiBtpI,KAEjExD,GAAOD,IAAK,GAAEtE,QAAQ63I,UACtB73I,KAAKyxI,mBAAmBgD,EAAaG,GACrC/I,OACDxqI,IACCkD,GAAOlD,MAAO,GAAErB,QAAQ63I,YAAqBx2I,GAC7CwqI,EAAiBxqI,SAe7BmzI,yBAAyBvyC,GACrB,MAAMmyC,EAAY,IAAIhV,GAAI,IAe1B,OAbIp/H,KAAKivI,sBACLmF,EAAUtU,qBAAsB,GAEhC9/H,KAAKgvI,sBACLoF,EAAUrU,qBAAsB,GAEhC//H,KAAK6/H,UACLuU,EAAUvU,SAAU,GAGxBuU,EAAU7R,WAAWtgC,GACrBjiG,KAAK8yI,aAAav0E,IAAAA,CAAE0jC,GAAS55F,KAAK,aAE3B+rI,EAUXsD,2BAA2BF,GACvB,MAAMpD,EAAYp0I,KAAK6J,gBACjB,IAAIu1H,GAAIp/H,KAAKusF,eAAeA,eAAe2kD,kBAAkBnpI,KAC7D,IAAIq3H,GAAIp/H,KAAKusF,eAAe2kD,kBAAkBnpI,KAmCpD,OAjCAyvI,EAAej3I,SAAQ,CAACkzE,EAAO35B,MAE3B25B,EAAQA,EAAMvvE,MAAM,SACd+yB,MACFj3B,KAAK6J,gBACL4pE,EAAMlzE,SAAQuD,IACV,MAAMowE,EAAMkgE,EAAUzsI,MAAMuwI,WAAUvxI,GAASA,EAAM82G,SAAS35G,KAE9D,GAAIowE,GAAO,EAEP,GADAkgE,EAAUzsI,MAAMusE,GAAOkgE,EAAUzsI,MAAMusE,GAAKzjE,QAAS,GAAE3M,QAAY,IAC/D9D,KAAKuvF,MAAO,OACZ,MAAMtM,EAAS,UAAGm4C,GAAAA,WAAmBgZ,EAAUzsI,MAAMusE,GAAKhwE,MAAM,QAAQ,WAAzD,aAAG,EAA2DyD,MACvEwwI,EAAmBn4I,KAAKusF,eAAe6rD,yBAAyBn1D,GAAW,GAEjF,CAAEi8C,GAAAA,SAAyBA,GAAAA,UAA0B3+H,SAAQ6L,IACzDgoI,EAAUzsI,MAAMusE,GAAOkgE,EAAUzsI,MAAMusE,GAClCzjE,QAAS,KAAIrE,IAAc,KAAI+rI,aAIxC/D,EAAUzsI,MAAMusE,GAAOkgE,EAAUzsI,MAAMusE,GAClCzjE,QAAS,KAAIyuH,GAAAA,WAA4B,KAAIA,GAAAA,eAK9DzrD,EAAMlzE,SAAQuD,IACVswI,EAAUzsI,MAAMmyC,GAAOs6F,EAAUzsI,MAAMmyC,GAAKrpC,QAAS,GAAE3M,QAAY,UAI/EswI,EAAU7vF,IAAM6vF,EAAU5sI,QAAU4sI,EAAUzsI,MAAM4B,KAAK,IAElD6qI,EAUX6D,wBAAwBjB,GACpB,MAAM5C,EAAY,IAAIhV,GAAIp/H,KAAKusF,eAAe2kD,kBAAkBnpI,KAmBhE,OAjBAivI,EAAYz2I,SAAQ,CAACkzE,EAAO35B,KAKxB,GAJAs6F,EAAUzsI,MAAMmyC,IAAQ25B,EAIpBzzE,KAAKuvF,OAASvvF,KAAK6J,gBAAiB,OACpC,MAAMo5E,EAAS,UAAGm4C,GAAAA,WAAmBgZ,EAAUzsI,MAAMmyC,GAAK51C,MAAM,QAAQ,WAAzD,aAAG,EAA2DyD,MACvEwwI,EAAmBn4I,KAAKusF,eAAe6rD,yBAAyBn1D,GAAW,GAEjF,CAAEi8C,GAAAA,SAAyBA,GAAAA,UAA0B3+H,SAAQ6L,IACzDgoI,EAAUzsI,MAAMmyC,GAAOs6F,EAAUzsI,MAAMmyC,GAClCrpC,QAAS,KAAIrE,IAAc,KAAI+rI,YAIhD/D,EAAU7vF,IAAM6vF,EAAU5sI,QAAU4sI,EAAUzsI,MAAM4B,KAAK,IAElD6qI,EAYX9C,aAAa+G,GACT,GAA2C,WAAvCr4I,KAAKusF,eAAe+jD,eAA6B,CACjD,MAAMjvI,EAAQ,IAAI2C,MAAM,4CAIxB,OAFAhE,KAAKuhG,KAAK/N,aAAa37D,KAAKoF,GAAW,WAAXA,qBAAiC57B,EAAOrB,MAE7D+pC,QAAQE,OAAO5oC,GAG1B,MAAM+yI,EACAiE,GAAqBr4I,KAAKusF,eAAe2kD,kBAAkBnpI,IAEjE,IAAKqsI,EAAW,CACZ,MAAM/yI,EAAQ,IAAI2C,MAAO,kEAAiEhE,KAAK6rC,SAI/F,OAFA7rC,KAAKuhG,KAAK/N,aAAa37D,KAAKoF,GAAW,WAAXA,qBAAiC57B,EAAOrB,MAE7D+pC,QAAQE,OAAO5oC,GAG1B,MAAM6vI,EAAoB,IAAIjlI,sBAAsB,CAChDrE,KAAM5H,KAAKssI,YAAc,SAAW,QACpCvkI,IAAKqsI,IAGT,OAAIp0I,KAAKssI,YACEtsI,KAAKs4I,sBAAsBpH,GAG/BlxI,KAAKq0I,sBAAsBnD,GAStCmD,sBAAsBnD,GAGlB,OAFA3sI,GAAOynF,MAAO,GAAEhsF,gDAETA,KAAKusF,eAAegsD,qBAAqBrH,GAC3CtwF,MAAK,KACFr8C,GAAOynF,MAAO,GAAEhsF,qCAETA,KAAKusF,eAAeisD,aAAax4I,KAAKosI,kBACxCxrF,MAAK63F,IACFl0I,GAAOynF,MAAO,GAAEhsF,+CAETA,KAAKusF,eAAeynD,oBAAoByE,SAWnEH,sBAAsBpH,GAGlB,OAFA3sI,GAAOynF,MAAO,GAAEhsF,oCAETA,KAAKusF,eAAeunD,YAAY9zI,KAAKosI,kBACvCxrF,MAAK83F,IACFn0I,GAAOynF,MAAO,GAAEhsF,+CAETA,KAAKusF,eAAeynD,oBAAoB0E,GAC1C93F,MAAK,KACFr8C,GAAOynF,MAAO,GAAEhsF,gDAGTA,KAAKusF,eAAegsD,qBAAqBrH,SAapE0C,SAASD,GACL,IAAKtc,GAAAA,gCACGr3H,KAAK6J,iBACN8pI,EAAW/rI,OAASktF,GAAU2G,MACjC,OAAO1xD,QAAQE,OAAO,IAAIjmC,MAAM,4DAGpC,MAAMmtI,EAAetF,IACjB,MAAMuI,EAAY,IAAIhV,GAAIp/H,KAAKusF,eAAeA,eAAe2kD,kBAAkBnpI,KAG/EqsI,EAAUpU,0BAA0BlrC,GAAU2G,OAC9Cz7F,KAAKsxI,aAAa8C,EAAU7vF,KACvB3D,MAAK,IAAMirF,MAAoBxqI,GAASwqI,EAAiBxqI,MAGlE,OAAO,IAAI0oC,SAAQ,CAACC,EAASC,KACzB1lC,GAAOynF,MAAO,GAAEhsF,4CAEhBA,KAAKuuI,kBAAkBrsI,KACnBivI,GACA9vI,IACI,IAAIA,EAOA,OAHAkD,GAAOynF,MAAO,GAAEhsF,mDAGTA,KAAK24I,aAAa,KAAMhF,GAC1B/yF,MAAK,IAAM5W,MACXga,OAAM,IAAM/Z,MARjB1lC,GAAOlD,MAAO,GAAErB,0CAA2CqB,GAC3D4oC,EAAO5oC,SAyB3Bs3I,aAAaC,EAAUC,GACnB,MAAM1H,EAAetF,IACjBtnI,GAAOynF,MAAO,GAAEhsF,gDAAgD44I,iBAAwBC,KAExF,MAAMpE,EAAcz0I,KAAKusF,eAAe8kD,iBAAiBtpI,IAEpD/H,KAAK6J,kBAKF7J,KAAKusF,eAAexsF,QAAQsvI,uBACzBuJ,GAAYC,GAAYA,EAASrzC,gBAMpCxlG,KAAKusF,eAAeusD,qBAInBF,GAAYC,GAAYA,EAASrzC,eAMlCxlG,KAAKusF,eAAeusD,oBAGbF,GAAYA,EAASpzC,iBAAmBqzC,IAK/C74I,KAAKusF,eAAeusD,oBACpB94I,KAAKusF,eAAe8mD,yBAI5BrzI,KAAKusF,eAAeosD,aAAaC,EAAUC,GACtCj4F,MAAKm4F,IACF,IAAIr4F,EAAU3W,QAAQC,UAetB,OAbAzlC,GAAOynF,MAAO,GAAEhsF,uDACZ+4I,2BAA2C/4I,KAAK6rC,SAEhDktG,IACIH,GAAYC,IACb74I,KAAK6rC,QAAUkgG,KAClBrrF,EAAU1gD,KAAKsxI,eAAe1wF,MAAK,KAC/B,MAAM+2F,EAAc,IAAIvY,GAAIp/H,KAAKusF,eAAe8kD,iBAAiBtpI,KAEjE/H,KAAKyxI,mBAAmB,IAAIrS,GAAIqV,GAAckD,OAI/Cj3F,EAAQE,MAAK,KAChB,GAAIi4F,MAAAA,GAAAA,EAAUrzC,eAIV,OAHAjhG,GAAOynF,MAAO,GAAEhsF,sDAGTA,KAAKusF,eAAeglD,8BAA8BsH,SAIpEj4F,MAAK,IAAMirF,MAAoBxqI,GAASwqI,EAAiBxqI,MAGlE,OAAO,IAAI0oC,SAAQ,CAACC,EAASC,KACzB1lC,GAAOynF,MAAO,GAAEhsF,8CAA8C44I,kBAAyBC,KAEvF74I,KAAKuuI,kBAAkBrsI,KACnBivI,GACA9vI,IACQA,GACAkD,GAAOlD,MAAO,GAAErB,4BAA6BqB,GAC7C4oC,EAAO5oC,KAEPkD,GAAOiH,KAAM,GAAExL,6BACfgqC,WAgBpBguG,+BAA+BgB,EAAkBjC,GAC7C,MAAMS,EAAiB,GA2DvB,OAzDAj5E,IAAAA,CAAEy6E,GAAkB5pG,MAAK,CAAC6nG,EAAIhoI,KAC1B,MAAMzC,EAAO+xD,IAAAA,CAAEtvD,GAASyG,KAAK,QAC7B,IAAI+9D,EAAQ,GAEZlV,IAAAA,CAAEtvD,GACG5G,KAAK,uDACL+mC,MAAK,WAEF,MAAM7mC,EAAYvI,KAAKwiB,aAAa,aAC9B1b,EACAy3D,IAAAA,CAAEv+D,MACCqI,KAAK,WACLnB,KAAI,WACD,OAAOlH,KAAKwiB,aAAa,WAE5BwC,MAELle,EAAMpF,SACN+xE,GACQ,gBAAelrE,KACfzB,EAAMyC,KAAK,eAK/B,MAAMzC,EAAQ,GAIRy3D,IAAAA,CAAEtvD,GAAS5G,KACT,mDAEJ+mC,MAAK,WAEL,MAAMxoC,EAAO23D,IAAAA,CAAEv+D,MAAM0V,KAAK,QAE1B5O,EAAM5E,KAAK0E,MAEfmwI,EAAiBpvI,MAAMpH,SAAQ,CAACoH,EAAOuvI,KAC9B9b,GAAAA,SAAiBzzH,EAAQ,SAAQ6E,OAGjCgrI,EAAeN,KAChBM,EAAeN,GAAM,IAEzBpwI,EAAMvG,SAAQqG,IACV,MAAMq1H,EACAb,GAAAA,UAAkBzzH,EAAQ,UAASf,KAErCq1H,EAAUv6H,SACV81I,EAAeN,IAAQ,GAAEjb,EAAU1yH,KAAK,kBAGhDiuI,EAAeN,IAAOzjE,SAIvB+jE,EAeXyB,qBAAqBC,EAAeC,GAChC,MAAMC,EACA,IAAIha,GAAIp/H,KAAKusF,eAAe8kD,iBAAiBtpI,KACnD,IAAIsxI,EAAU,IAAI3Z,GAAUyZ,EAAQC,GACpC,MAAME,EAAaD,EAAQtW,cAE3B,GAAI3iI,OAAOC,KAAKi5I,GAAY53I,OAGxB,OAFA6C,GAAOlD,MAAO,GAAErB,kCAAkCk5I,IAAiBI,IAE5D,EAGXD,EAAU,IAAI3Z,GAAU0Z,EAAiBD,GACzC,MAAMI,EAAeF,EAAQtW,cAE7B,OAAI3iI,OAAOC,KAAKk5I,GAAc73I,SAC1B6C,GAAOlD,MAAO,GAAErB,qCAAqCk5I,IAAiBK,IAE/D,GAcfC,iBAAiBrhE,GACb,OAAOn4E,KAAKy5I,6BACR,EAA2BthE,GAC1Bv3B,MAAK,KAGF,GAAIu3B,EAAMqtB,eACN,OAAOxlG,KAAKusF,eAAeglD,8BAA8Bp5D,MAazEuhE,kBAAkBvhE,GACd,OAAOn4E,KAAKy5I,6BACR,EAA2BthE,GAUnCshE,4BAA4BE,EAAQxhE,GAChC,IAAKA,EACD,OAAOpuC,QAAQE,OAAO,kCAE1B,MAAMivG,EAAgBS,EAAS,kBAAoB,iBAC7CxI,EAAetF,IACjB,MAAM18C,EAAMnvF,KAAKusF,eAEjB,IAAK4C,EAKD,YAJA08C,EACK,iBAAgBqN,yCAKzB,MAAMU,EAAczqD,EAAIkiD,iBAAiBtpI,KAEnC4xI,EACIxqD,EAAI0qD,gBAAgB1hE,GACpBgX,EAAI2qD,eAAe3hE,IAGxBv3B,MAAKm4F,IACEA,GAAqBa,GAAezqD,EAAI+hD,kBAAkBnpI,IAC1D/H,KAAKsxI,eACA1wF,MAAK,MAGD5gD,KAAK6J,iBAAmB7J,KAAKi5I,qBAAqBC,EAAe,IAAI9Z,GAAIwa,IAC1E,MAAMhF,EAAczlD,EAAIkiD,iBAAiBtpI,IAGzC/H,KAAKyxI,mBAAmB,IAAIrS,GAAIwa,GAAc,IAAIxa,GAAIwV,IACtD/I,OAGRA,MAGRA,IAKR,OAFAtnI,GAAOynF,MAAO,GAAEhsF,eAAek5I,UAExB,IAAInvG,SAAQ,CAACC,EAASC,KACzBjqC,KAAKuuI,kBAAkBrsI,KACnBivI,GACA9vI,IACQA,GACAkD,GAAOlD,MAAO,GAAErB,QAAQk5I,YACxBjvG,EAAO5oC,KAEPkD,GAAOynF,MAAO,GAAEhsF,QAAQk5I,UACxBlvG,WAgBpB+vG,uBAAuBC,EAAaC,GAChC,IAAKj6I,KAAKusF,eACN,OAAOxiD,QAAQE,OACX,uEAIR,MAAMiwG,EAAcF,EAAc,eAAiB,iBAC7CG,EAAcF,EAAc,eAAiB,iBAEnD11I,GAAOiH,KAAM,GAAExL,oBAAoBm6I,MAAgBD,UAEnD,MAAM/I,EAAetF,IACjB,MAAMuO,EAAkBp6I,KAAK6rC,QAAUkgG,GAMjCsO,EACAr6I,KAAKusF,eAAe+tD,uBAAuBN,GAE7Ch6I,KAAKkuI,oBAAsB+L,IAC3Bj6I,KAAKkuI,kBAAoB+L,EAUrBj6I,KAAKuvF,OAAS6qD,GACdp6I,KAAK20I,qBAIb,MAAM4F,EACAv6I,KAAKusF,eAAeiuD,uBAClBx6I,KAAKkuI,mBAAqBluI,KAAKmuI,oBAInCiM,IACQC,GAAsBE,GAC9Bv6I,KAAKsxI,eACA1wF,KACGirF,EACAA,GAERA,KAIR,OAAO,IAAI9hG,SAAQ,CAACC,EAASC,KACzBjqC,KAAKuuI,kBAAkBrsI,KACnBivI,GACA9vI,IACQA,GACAkD,GAAOlD,MAAO,GAAErB,aAAam6I,MAAgBD,kBAC7CjwG,EAAO5oC,KAEPkD,GAAOynF,MAAO,GAAEhsF,aAAam6I,MAAgBD,gBAC7ClwG,WAgBpBywG,eAAehN,GACX,MAAMiN,EACAlN,GAAgBmN,kBAAkBlN,GAClCmN,EACApN,GAAgBqN,oBAAoBpN,GAGtCmN,IACAr2I,GAAOiH,KAAM,GAAExL,0CAA0C46I,KACzD56I,KAAKsuI,yBAA2BsM,EAChC56I,KAAKwzF,aAAa37D,KACdy1G,GAAAA,iCAAqDttI,OAGrC,OAApB06I,GAoBJn2I,GAAOynF,MAAO,GAAEhsF,oDAAoD06I,OAEpE16I,KAAKuuI,kBAAkBrsI,MAdF2pI,IACb7rI,KAAK6uI,gBAAgB,mBACd7uI,KAAK86I,yBAAyBJ,GAGrC16I,KAAKsxI,eACA1wF,KAAKirF,EAAkBA,GAE5BA,OAQJxqI,IACQA,EACAkD,GAAOlD,MAAO,GAAErB,+BAAgCqB,GAEhDkD,GAAOynF,MAAO,GAAEhsF,6CAA6C06I,gBA3BrEn2I,GAAOlD,MACF,GAAErB,8EAyCf86I,yBAAyBC,GACrB,MAAMC,EACuB,SAAvBD,GAC6B,cAAvBA,GAAsC/6I,KAAKssI,aACpB,cAAvByO,IAAuC/6I,KAAKssI,YAOxD,OALI0O,IAAwBh7I,KAAKmuI,qBAC7B5pI,GAAOynF,MAAO,GAAEhsF,iCAAiCg7I,KACjDh7I,KAAKmuI,mBAAqB6M,GAGvBh7I,KAAKusF,eAAeiuD,uBACvBx6I,KAAKkuI,mBAAqBluI,KAAKmuI,oBAQvCsD,mBAAmB0H,EAAQ8B,GACvB,GAAIj7I,KAAK6rC,QAAUkgG,GAGf,YAFAxnI,GAAO2T,KAAM,GAAElY,iCAAiCA,KAAK6rC,kBAKzD,IAAK7rC,KAAK8iG,WAAW4a,UAQjB,OANK19G,KAAK6tI,qBACN7tI,KAAK6tI,mBAAqBsL,GAE9Bn5I,KAAK8tI,mBAAqBmN,OAC1B12I,GAAO2T,KAAM,GAAElY,oEAKnBA,KAAK6tI,wBAAqB9hI,EAC1B/L,KAAK8tI,wBAAqB/hI,EAE1B,MAAMmvI,EAAwBC,IAC1B,MAAMjY,EAAWiY,EAAUpY,cAC3B,IAAIj8H,EAAQ,GACRm8E,EAAY,KAYhB,OATA7iF,OAAOC,KAAK6iI,GAAU3iI,SAAQ66I,IAC1B,MAAMC,EAAgBj7I,OAAOC,KAAK6iI,EAASkY,GAAYt0I,OAEvDm8E,EAAYigD,EAASkY,GAAYlnE,IAC7BmnE,MAAAA,GAAAA,EAAe35I,SACfoF,EAAQA,EAAM/B,OAAOs2I,OAItB,CACHp4D,UAAAA,EACAn8E,MAAAA,IAKR,IAAIq0I,EAAY,IAAIzb,GAAUub,EAAQ9B,GACtC,MAAMn8H,GAASgiG,EAAAA,GAAAA,KAAI,CAAEC,GAAIj/G,KAAKo/G,UAC1Bx3G,KAAM,QACLuF,EAAE,SAAU,CACTiH,MAAO,oBACP3M,OAAQ,gBACR0oI,UAAWnwI,KAAK0sI,aAChB1qB,IAAKhiH,KAAKgiH,MAGZs5B,EAAkBH,EAAU1a,SAASzjH,GAIrCu+H,EAAM,GAEZ,GAAID,EAAiB,CACjB,MAAME,EAAaN,EAAsBC,GAGzC52I,GAAOiH,KAAM,GAAExL,kCAAkCw7I,EAAWv4D,mBAAmBu4D,EAAW10I,SAC1F9G,KAAK8iG,WAAWugB,OACZrmG,GACA,KACIhd,KAAKuhG,KAAK/N,aAAa37D,KAAKoF,GAAW,WAAXA,cAA0Bj9B,KAAMu7I,KAEhEv7I,KAAKqyI,sBAAsBr1H,GAAQ3b,IAC/BrB,KAAKuhG,KAAK/N,aAAa37D,KAAKoF,GAAW,WAAXA,oBAAgCj9B,KAAMqB,EAAOk6I,MAE7EhO,IAIR4N,EAAY,IAAIzb,GAAUyZ,EAAQ8B,GAClC,MAAMt7F,GAAMq/D,EAAAA,GAAAA,KAAI,CAAEC,GAAIj/G,KAAKo/G,UACvBx3G,KAAM,QACLuF,EAAE,SAAU,CACTiH,MAAO,oBACP3M,OAAQ,aACR0oI,UAAWnwI,KAAK0sI,aAChB1qB,IAAKhiH,KAAKgiH,MAMlB,GAFyBm5B,EAAU1a,SAAS9gF,GAEtB,CAClB,MAAM67F,EAAaN,EAAsBC,GAGzC52I,GAAOiH,KAAM,GAAExL,+BAA+Bw7I,EAAWv4D,mBAAmBu4D,EAAW10I,SACvF9G,KAAK8iG,WAAWugB,OACZ1jE,GACA,KACI3/C,KAAKuhG,KAAK/N,aAAa37D,KAAKoF,GAAW,WAAXA,WAAuBj9B,KAAMu7I,KAE7Dv7I,KAAKqyI,sBAAsB1yF,GAAKt+C,IAC5BrB,KAAKuhG,KAAK/N,aAAa37D,KAAKoF,GAAW,WAAXA,iBAA6Bj9B,KAAMqB,EAAOm6I,EAAWv4D,UAAWs4D,MAEhGhO,KAsBZ8E,sBAAsBoJ,EAASruB,GAC3B,OAAOsuB,IAEH,MAAMr6I,EAAQ,GAGRs6I,EAAap9E,IAAAA,CAAEm9E,GAAarzI,KAAK,SAEvC,GAAIszI,EAAWj6I,OAAQ,CACnBL,EAAM0Z,KAAO4gI,EAAWjmI,KAAK,QAC7B,MAAMkmI,EAAiBr9E,IAAAA,CAAEm9E,GAAarzI,KAAK,gBAEvCuzI,EAAel6I,SACfL,EAAMk3B,OAASqjH,EAAe,GAAG1lI,SAGrC,MAAM2lI,EAAcF,EAAWtzI,KAAK,SAEhCwzI,EAAYn6I,SACZL,EAAME,IAAMs6I,EAAY75I,QAI3B05I,IACDr6I,EAAMk3B,OAAS,WAGnBl3B,EAAMmG,QAAUxH,KAAKkhB,WAEjBksG,EACAA,EAAU/rH,GACHrB,KAAK6rC,QAAUkgG,IACM,mBAAjB1qI,EAAMk3B,OAMjBh0B,GAAOynF,MAAO,GAAEhsF,sBAAsBoB,KAAKF,UAAUG,MAErDm3B,KAAAA,iBACI,IAAIx0B,MACC,iBAAgB5C,KAAKF,UAAUG,QASpDy6I,wBACI,OAAO97I,KAAKusF,eAAewvD,qBAM/BnF,QACI52I,KAAK6rC,MAAQkgG,GACb/rI,KAAKyuI,2BAAwB1iI,EAEzB/L,KAAKusF,iBACLvsF,KAAKusF,eAAe0jD,eAAiB,KACrCjwI,KAAKusF,eAAeikD,2BAA6B,KACjDxwI,KAAKusF,eAAe0kD,oBAAsB,KAC1CjxI,KAAKusF,eAAe8jD,uBAAyB,MAGjD9rI,GAAOynF,MAAO,GAAEhsF,mCAGhBA,KAAKuuI,kBAAkBnnE,QAEvB7iE,GAAOynF,MAAO,GAAEhsF,6BAChBA,KAAKuuI,kBAAkBrsI,MAAKq1I,IAExBv3I,KAAKusF,gBAAkBvsF,KAAKusF,eAAeqqD,QAC3CW,IACAhzI,GAAOynF,MAAO,GAAEhsF,+BAGpBuE,GAAOynF,MAAO,GAAEhsF,oCAGhBA,KAAKuuI,kBAAkBzC,WAO3B5qH,WACI,MAAQ,2BAA0BlhB,KAAKuvF,MAAQ,MAAQ,mBAAmBvvF,KAAKssI,mBAAmBtsI,KAAKgiH,OAS3G4tB,2BAA2B,GAAe,IAAf,UAAEoM,GAAa,EACtC,IAAKA,IAAcA,EAAUC,uBACzB,OAMJ,MAAM94C,EAAMnjG,KAAKqtI,mBAEjB,OAAO7yG,EAAAA,GAAAA,aAAY2oE,GAAO,GAAM,GC5rFxC,MAAM5+F,IAAS2B,EAAAA,EAAAA,6CAYf,SAASg2I,GAAoB94I,GACzB,MAAM0M,EAAayuD,IAAAA,CAAEn7D,GAAWiF,KAAK,cAC/B8zI,EAAkB,GAexB,OAZArsI,EAAWs/B,MAAK,CAAC0R,EAAG4wB,KAChB,MAAM7xD,EAAa6xD,EAAU7xD,WACvBu8H,EAAiB,GAEvB,IAAK,IAAI56I,EAAI,EAAGA,EAAIqe,EAAWne,OAAQF,IAAK,CACxC,MAAMkU,EAAOmK,EAAWre,GAExB46I,EAAel6I,KAAM,GAAEwT,EAAKlJ,SAASkJ,EAAKvO,SAE9Cg1I,EAAgBj6I,KAAKk6I,EAAe7yI,KAAK,SAGtC4yI,EAMI,MAAME,WAA+Br+B,GAQhD5kG,YAAYsjF,EAAMlJ,EAAc8oD,GAC5Bp3D,QACAllF,KAAK08F,KAAOA,EACZ18F,KAAKwzF,aAAeA,EACpBxzF,KAAKu8I,SAAW,GAChBv8I,KAAKw8I,aAAeF,EAAUG,IAC9Bz8I,KAAK08I,aAAeJ,EAAUjiD,IAC9Br6F,KAAKosI,iBAAmB,CACpBuQ,qBAAqB,EACrBC,qBAAqB,GAQ7BhzG,KAAKk5D,GACD5d,MAAMt7C,KAAKk5D,GACX9iG,KAAK8iG,WAAWrqE,WAAWz4B,KAAK68I,SAASj8I,KAAKZ,MAC1C,oBAAqB,KAAM,MAAO,KAAM,MAOhD68I,SAAS99B,GACL,MAAMiD,EAAMzjD,IAAAA,CAAEwgD,GAAI12G,KAAK,UAAUqN,KAAK,OAChCjO,EAAS82D,IAAAA,CAAEwgD,GAAI12G,KAAK,UAAUqN,KAAK,UACnConI,EAAU/9B,EAAGv8F,aAAa,QAG1B+zF,GAAMyI,EAAAA,GAAAA,KAAI,CAAEp3G,KAAM,SACpBq3G,GAAI69B,EACJz3I,GAAI05G,EAAGv8F,aAAa,QAGxB,IAAIu6H,EAAO/8I,KAAKu8I,SAASv6B,GAEzB,GAAe,qBAAXv6G,EAA+B,CAC/B,IAAKs1I,EAcD,OAbAxmC,EAAIjhG,MAAM,CAAE1N,KAAM,UAClB2uG,EAAIppG,EAAE,QAAS,CAAEvF,KAAM,WAClBuF,EAAE,iBAAkB,CACjBiH,MAAO,wCAEV2wG,KACA53G,EAAE,kBAAmB,CAClBiH,MAAO,6BAEf7P,GAAO2T,KAAM,uBAAsB8pG,KACnCz9G,GAAOynF,MAAM+yB,GACb/+G,KAAK8iG,WAAWwgB,KAAK/M,IAEd,EAIX,GAAIumC,IAAYC,EAAK39B,UAcjB,OAbA76G,GAAO2T,KACH,8BAA+B8pG,EAAK+6B,EAAK39B,UAAWL,GACxDxI,EAAIjhG,MAAM,CAAE1N,KAAM,UAClB2uG,EAAIppG,EAAE,QAAS,CAAEvF,KAAM,WAClBuF,EAAE,iBAAkB,CACjBiH,MAAO,wCAEV2wG,KACA53G,EAAE,kBAAmB,CAClBiH,MAAO,6BAEfpU,KAAK8iG,WAAWwgB,KAAK/M,IAEd,OAER,QAAaxqG,IAATgxI,EAYP,OATAxmC,EAAIjhG,MAAM,CAAE1N,KAAM,UAClB2uG,EAAIppG,EAAE,QAAS,CAAEvF,KAAM,WAClBuF,EAAE,sBAAuB,CACtBiH,MAAO,wCAEV2wG,KACLxgH,GAAO2T,KAAK,uBAAwB8pG,EAAKjD,GACzC/+G,KAAK8iG,WAAWwgB,KAAK/M,IAEd,EAEX,MAAMtpD,EAAM3qD,OAAOijG,YAAYt4C,MAKzBsiC,EAAgD,UAAxCwS,GAAAA,QAAAA,mBAA2B+6C,GAInCE,EAAez+E,IAAAA,CAAEwgD,GAAI12G,KAAK,uBAEhC,GAAI20I,MAAAA,GAAAA,EAAct7I,OAAQ,OACtB,IAAIu7I,EAEJ14I,GAAOiH,KAAM,mCAAkC/D,sCAC/C,IAAK,IAAIjG,EAAI,EAAGA,EAAIw7I,EAAat7I,OAAQF,IAErCy7I,EAAkBvlB,GAAsB3Y,EAAIi+B,EAAax7I,IAG7D,aAAIy7I,SAAJ,OAAI,EAAiBj4E,KAAM,CACvB,MAAMk4E,EAAa,GAEnB,IAAK,MAAMC,KAAYF,EAAgB58I,OACnC68I,EAAWh7I,KAAM,GAAEi7I,MAAaF,EAAgBj4H,IAAIm4H,OAExD54I,GAAOynF,MAAO,YAAWvkF,UAAeq1I,kBAAwBI,EAAW3zI,KAAK,UAOxF,OAAQ9B,GACR,IAAK,mBAAoB,CACrBlD,GAAOD,IAAI,sCAAuC2oD,GAClD,MAAMmwF,EAAa7+E,IAAAA,CAAEwgD,GAAI12G,KAAK,qBAG9B,GADAknF,GAAShrF,GAAOynF,MAAO,YAAWvkF,UAAeq1I,KAC7CM,MAAAA,GAAAA,EAAY17I,OAAQ,CACpB,MAAMukG,EAAam3C,EAAW1nI,KAAKo/E,GAAUqH,OACvC+J,EAAak3C,EAAW1nI,KAAKo/E,GAAU2G,OAE7Cz7F,KAAKwzF,aAAa37D,KACdoF,GAAW,WAAXA,uBACe,SAAfgpE,EACe,SAAfC,GAER,MAAMmmC,EAAW98C,EAAQvvF,KAAK08I,aAAe18I,KAAKw8I,aAElDO,EACM,IAAIvP,GACFjvE,IAAAA,CAAEwgD,GAAI12G,KAAK,UAAUqN,KAAK,OAC1B6oD,IAAAA,CAAEwgD,GAAIrpG,KAAK,MACXonI,EACA98I,KAAK8iG,WACL9iG,KAAKosI,iBAILhrI,KAAKwJ,MAAMxJ,KAAKF,UAAUmrI,IAC1B98C,GACgB,GAExBvvF,KAAKu8I,SAASQ,EAAK/6B,KAAO+6B,EAC1B/8I,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,cAA0B8/G,EAAMx+E,IAAAA,CAAEwgD,GAAI12G,KAAK,WAAY4kD,GAC9E,MAEJ,IAAK,iBAAkB,CACnB,MAAMnmD,EAAQ,GACRs4C,EAAWmf,IAAAA,CAAEwgD,GAAI12G,KAAK,kBAG5B,IAAK,MAAM4G,KAAWmwC,EAAU,CAC5B,MAAMx4C,EAAO23D,IAAAA,CAAEtvD,GAAS5G,KAAK,eAAeqN,KAAK,QAEjD9O,GAAQE,EAAM5E,KAAK0E,GAEvBrC,GAAOynF,MAAO,YAAWvkF,UAAeq1I,gBAAsBh2I,KAC9D9G,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,cAA0B8/G,EAAMx+E,IAAAA,CAAEwgD,GAAI12G,KAAK,YAClE,MAEJ,IAAK,iBAAkB,CACnB,MAAMw0B,EAAS0hC,IAAAA,CAAEwgD,GAAI12G,KAAK,iDAE1B9D,GAAOynF,MAAO,YAAWvkF,UAAeq1I,6BAAmCjgH,MAAAA,OAA9D,EAA8DA,EAAQ76B,UACnF+6I,EAAKtC,eAAel8E,IAAAA,CAAEwgD,GAAI12G,KAAK,YAC/B,MAEJ,IAAK,iBAAkB,CACnB,MAAMyH,EAAaosI,GAAoB39E,IAAAA,CAAEwgD,GAAI12G,KAAK,6BAElD9D,GAAOynF,MAAO,YAAWvkF,UAAeq1I,oBAA0BhtI,EAAWvG,KAAK,SAClFvJ,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,eAA2B8/G,EAAMx+E,IAAAA,CAAEwgD,GAAI12G,KAAK,YACnE,MAEJ,IAAK,oBAAqB,CACtB9D,GAAOD,IAAI,iBAAkBy4I,EAAK/6B,KAClC,IAAI00B,EAAkB,KAClBC,EAAa,KAEbp4E,IAAAA,CAAEwgD,GAAI12G,KAAK,kBAAkB3G,SAC7Bg1I,EACMn4E,IAAAA,CAAEwgD,GAAI12G,KAAK,yBAAyB,GAAG6N,QAC7CygI,EAAap4E,IAAAA,CAAEwgD,GAAI12G,KAAK,uBAAuBrG,QAEnDuC,GAAOynF,MAAO,YAAWvkF,UAAeq1I,uBAA6BnG,KACrE32I,KAAKktI,UAAU6P,EAAK/6B,IAAK00B,EAAiBC,GAC1C32I,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,WAAuB8/G,EAAMrG,EAAiBC,GACrE,MAEJ,IAAK,oBAAqB,OACtBpyI,GAAOiH,KAAK,oCAAqCyhD,GACjD,MAAM7pD,EAAYm7D,IAAAA,CAAEwgD,GAAI12G,KAAK,4BACvByH,EAAaosI,GAAoB94I,GACjCi6I,EAAW9+E,IAAAA,CAAEn7D,GAAWsS,KAAK,SAC7B4nI,EAAS/+E,IAAAA,CAAEn7D,GAAWsS,KAAK,OAC3B6nI,EAAe,UAAGh/E,IAAAA,CAAEn7D,GAAWiF,KAAK,uBAArB,aAAG,EAAmCrG,OAE3DuC,GAAOynF,MAAO,YAAWvkF,UAAeq1I,mBAAyBO,aACpDC,uBAA4BC,iBAA+BztI,EAAWvG,KAAK,SAExFkzF,GAAWoE,cAAc/d,GACrBnB,GACA,CACI0Y,IAAK9K,EACLpoF,MAAO8lD,KAGf8vF,EAAKhI,iBAAiBx2E,IAAAA,CAAEwgD,GAAI12G,KAAK,YAAY,KACzC,MAAMm1I,EAAcl7I,OAAOijG,YAAYt4C,MAEvC1oD,GAAOiH,KAAK,sCAAuCgyI,GACnD/gD,GAAWoE,cAAc/d,GACrBlB,GACA,CACIyY,IAAK9K,EACLpoF,MAAOq2I,QAEhBn8I,IACCm3B,KAAAA,iBAAsCn3B,GACtCkD,GAAOlD,MAAM,2BAA4BA,GACzC07I,EAAKnH,yBAET,MAEJ,IAAK,aACDmH,EAAK5F,gBAAgB54E,IAAAA,CAAEwgD,GAAI12G,KAAK,oBAChC,MACJ,IAAK,gBACD00I,EAAK1F,mBAAmB94E,IAAAA,CAAEwgD,GAAI12G,KAAK,oBACnC,MACJ,QACI9D,GAAO2T,KAAK,gCAAiCzQ,GAC7C8uG,EAAIjhG,MAAM,CAAE1N,KAAM,UAClB2uG,EAAIppG,EAAE,QAAS,CAAEvF,KAAM,WAClBuF,EAAE,cACC,CAAEiH,MAAO,wCACZ2wG,KAKT,OAFA/kH,KAAK8iG,WAAWwgB,KAAK/M,IAEd,EAUXknC,oBAAoBC,EAAIjuD,GACpB,MAAMstD,EACA,IAAIvP,GACFv0G,KAAAA,gBAA2B,IAC3BykH,EACAjuD,EACAzvF,KAAK8iG,WACL9iG,KAAKosI,iBACLpsI,KAAK08I,cACK,GACM,GAIxB,OAFA18I,KAAKu8I,SAASQ,EAAK/6B,KAAO+6B,EAEnBA,EASX7P,UAAUlrB,EAAK00B,EAAiBC,GACxB32I,KAAKu8I,SAAS9jI,eAAeupG,KACI,UAA7BhiH,KAAKu8I,SAASv6B,GAAKn2E,OACnB7rC,KAAKu8I,SAASv6B,GAAKy0B,aAAaC,EAAiBC,UAE9C32I,KAAKu8I,SAASv6B,IAO7B27B,4BAcI39I,KAAK8iG,WAAWugB,QACZrE,EAAAA,GAAAA,KAAI,CAAEp3G,KAAM,MACRq3G,GAAIj/G,KAAK08F,KAAK38F,QAAQqrH,MAAM1J,SAC3Bv0G,EAAE,WAAY,CAAEiH,MAAO,yBAC5BwpI,GAAS59I,KAAK69I,gCAAgCD,KAC9C,KACIr5I,GAAO2T,KAAK,sEACZlY,KAAK8iG,WAAWugB,QACZrE,EAAAA,GAAAA,KAAI,CAAEp3G,KAAM,MACRq3G,GAAIj/G,KAAK08F,KAAK38F,QAAQqrH,MAAM1J,SAC3Bv0G,EAAE,WAAY,CAAEiH,MAAO,yBAC5B0pI,GAAS99I,KAAK69I,gCAAgCC,KAC9C,KACIv5I,GAAO2T,KAAK,mCACZ3T,GAAO2T,KAAK,qEAYhC2lI,gCAAgCnkC,GAC5B,MAAMqkC,EAAa,GAEnBx/E,IAAAA,CAAEm7C,GAAKrxG,KAAK,qBAAqB+mC,MAAK,CAAC0K,EAAKzoC,KAGxC,MAAM2sI,EAAO,GACPp2I,GAFNyJ,EAAKktD,IAAAA,CAAEltD,IAESqE,KAAK,QAErB,OAAQ9N,GACR,IAAK,OACDo2I,EAAKC,KAAQ,QAAO5sI,EAAGqE,KAAK,UACxBrE,EAAGqE,KAAK,UACRsoI,EAAKC,MAAS,IAAG5sI,EAAGqE,KAAK,WAE7BqoI,EAAW77I,KAAK87I,GAChB,MACJ,IAAK,OACL,IAAK,QAAS,CACVA,EAAKC,KAAQ,GAAEr2I,KACfo2I,EAAKxkE,SAAWnoE,EAAGqE,KAAK,YACxBsoI,EAAKC,MAAQ5sI,EAAGqE,KAAK,QACRrE,EAAGqE,KAAK,UAGjBsoI,EAAKC,MAAS,IAAG5sI,EAAGqE,KAAK,WAE7B,MAAMtS,EAAYiO,EAAGqE,KAAK,aAEtBtS,GAA2B,QAAdA,IACb46I,EAAKC,MAAS,cAAa76I,KAG/B46I,EAAKE,WAAa7sI,EAAGqE,KAAK,aACfsoI,EAAKE,WAChBH,EAAW77I,KAAK87I,GAChB,WAKR,MAAMj+I,EAAUC,KAAK08F,KAAK38F,QAG1B,IAAK,IAAIyB,EAAIu8I,EAAWr8I,OAAS,EAAGF,EAAI,EAAGA,IAAK,CAC5C,MAAMwJ,EAAIf,KAAKC,MAAMD,KAAKE,UAAY3I,EAAI,IACpCy6C,EAAO8hG,EAAWv8I,GAExBu8I,EAAWv8I,GAAKu8I,EAAW/yI,GAC3B+yI,EAAW/yI,GAAKixC,EAGpB,IAAIl1C,EAYJ,OATIA,EADAhH,EAAQo+I,WACCtxI,GAAKA,EAAEoxI,KAAKv9B,WAAW,QAGvB7zG,GAAKA,EAAEoxI,KAAKv9B,WAAW,SAAY7zG,EAAEoxI,KAAK56I,QAAQ,kBAAoB,EAGnFrD,KAAKw8I,aAAa4B,WAAaL,EAAWh3I,OAAOA,GACjD/G,KAAK08I,aAAa0B,WAAaL,EAExBA,EAAWr8I,OAAS,EAM/B28I,SACI,MAAM5nI,EAAO,GAgBb,OAdArW,OAAOC,KAAKL,KAAKu8I,UAAUh8I,SAAQyhH,IAC/B,MACMp1B,EADU5sF,KAAKu8I,SAASv6B,GACXz1B,eAEfK,GAAMA,EAAG0xD,YAET7nI,EAAM,UAASurG,KAAS,CACpBs8B,UAAW1xD,EAAG0xD,UACd1qD,MAAOhH,EAAGgH,MACVzrD,IAAK7lC,OAAO0M,SAASu4B,UAK1B9wB,GC/df,MAAM8nI,WAAsBvgC,GAIxB5kG,cACI8rE,QACAllF,KAAKsE,IAAM,GAOfslC,KAAKk5D,GACD5d,MAAMt7C,KAAKk5D,GACX9iG,KAAK8iG,WAAWya,SAAWv9G,KAAKw+I,YAAY59I,KAAKZ,MACjDA,KAAK8iG,WAAW27C,UAAYz+I,KAAK0+I,YAAY99I,KAAKZ,MAOtDw+I,YAAYj7B,GACRvjH,KAAKsE,IAAIpC,KAAK,EAAE,IAAIiD,MAAOq6G,UAAW,WAAY+D,IAOtDm7B,YAAYn7B,GACRvjH,KAAKsE,IAAIpC,KAAK,EAAE,IAAIiD,MAAOq6G,UAAW,WAAY+D,KCjC1D,MAAMh/G,IAAS2B,EAAAA,EAAAA,2CAETy4I,GAAa,kBAKJ,MAAMC,WAA6B5gC,GAK9Cp0E,KAAKk5D,GACD5d,MAAMt7C,KAAKk5D,GAEX9iG,KAAK8iG,WAAWrqE,WACZz4B,KAAK6+I,OAAOj+I,KAAKZ,MAAO2+I,GAAY,KAAM,MAAO,KAAM,MAO/DE,OAAO9/B,GACHx6G,GAAOiH,KAAK,UAAWuzG,GAa3B6W,KAAK3W,EAAIpgB,EAAMpnE,EAAUqnH,EAAUxwB,GAC/B,OAAO,IAAIvkF,SAAQ,CAACC,EAASC,KACzB,IAAKqkF,EAGD,YAFArkF,EAAO,IAAIjmC,MAAM,oBAIrB,MAAM+6I,GAAM//B,EAAAA,GAAAA,KAAI,CACZp3G,KAAM,MACNq3G,GAAIqP,IAGRywB,EAAI5xI,EAAE,OAAQ,CACViH,MAAOuqI,GACP1/B,GAAAA,EACApgB,KAAAA,IAEJkgD,EAAI5xI,EAAE,SAAU,CACZX,KAAM,cACNrF,MAAOswB,IACRstF,KAEC+5B,GAAYA,EAASp9I,QACrBq9I,EAAI5xI,EAAE,SAAU,CACZX,KAAM,kBACNrF,MAAO23I,IACR/5B,KAGP/kH,KAAK8iG,WAAWugB,OACZ07B,GACAzlH,IACI/0B,GAAOiH,KAAK,eAAgB8tB,GAG5B,MAAM8pE,EAAW7kC,IAAAA,CAAEjlC,GAAQjxB,KAAK,OAAOqN,KAAK,OAE5C1V,KAAKg/I,aAAe57C,EAAS/+F,OAAO,QAAQ3C,QAC5C6C,GAAOiH,KAAM,2BAA0BxL,KAAKg/I,gBAC5Ch1G,OAEJ3oC,IACIkD,GAAOiH,KAAK,cAAenK,GAC3B4oC,EAAO5oC,SAUvBy0H,SACI,OAAO,IAAI/rF,SAAQ,CAACC,EAASC,KACzB,IAAKjqC,KAAKg/I,aAIN,OAHA/0G,EAAO,IAAIjmC,MAAM,6BACjBO,GAAO2T,KAAK,uBAKhB,MAAM6mI,GAAM//B,EAAAA,GAAAA,KAAI,CACZp3G,KAAM,MACNq3G,GAAIj/G,KAAKg/I,eAGbD,EAAI5xI,EAAE,SAAU,CACZiH,MAAOuqI,KAGX3+I,KAAK8iG,WAAWugB,OAAO07B,GAAKzlH,IACxB/0B,GAAOiH,KAAK,iBAAkB8tB,GAC9Bt5B,KAAKg/I,aAAe,KACpBh1G,OACD3oC,IACCkD,GAAOiH,KAAK,gBAAiBnK,GAC7BrB,KAAKg/I,aAAe,KACpB/0G,EAAO,IAAIjmC,MAAM,yBCjHjC,MAAMO,IAAS2B,EAAAA,EAAAA,2CAkBf,IAAI+4I,IAAmB,EAQvB,MAAMC,GAA8B,6BAO9BC,GACA,wDCnBA56I,IAAS2B,EAAAA,EAAAA,mCAKTk5I,GAAgB,4DAwDf,MAAMC,GAAuB,CAChC,CAAEpB,KAAM,6CASCnpC,GAAsB,OAMtBwqC,GAAiB,mCAOjBhrC,GAAe,8BAKb,MAAM0Z,WAAare,GAiB9Bv2F,YAAYrZ,EAASg+C,GAAO,MACxBmnC,QACAllF,KAAK8iG,WAAa,KAClB9iG,KAAKu/I,sBAAuB,EAC5Bv/I,KAAK4iG,gBAAkB,GACvB5iG,KAAKD,QAAUA,EACfC,KAAK+9C,MAAQA,EACb/9C,KAAKw/I,mBAAoB,EDvF7Bz9C,GAAAA,QAAAA,IAAc,SAASv9F,EAAOjD,GAe1B,OATAgD,GAAOk7I,MAAM,UAAWj7I,EAAOjD,GACZ,iBAARA,IAC6B,IAA7BA,EAAI8B,QAAQ,cAC0C,IAAtD9B,EAAI8B,QAAQ,uCAEnBmB,EAAQu9F,GAAAA,QAAAA,SAAAA,MAIJv9F,GACR,KAAKu9F,GAAAA,QAAAA,SAAAA,OAGwB,IAArBk9C,IACOC,GAA4B3vI,KAAKhO,KACxCgD,GAAOynF,MAAM,yBACbizD,IAAmB,GAEvB,MACJ,KAAKl9C,GAAAA,QAAAA,SAAAA,KACDx9F,GAAO2T,KAAM,YAAW3W,KACxB,MAAMm+I,EAAmBP,GAAuBppH,KAAKx0B,GAEjDm+I,GAAgD,IAA5BA,EAAiBh+I,SACrCu9I,GAAkBx2I,SAASi3I,EAAiB,GAAI,IAChDn7I,GAAOynF,MAAO,2BAA0BizD,OAE5C,MACJ,KAAKl9C,GAAAA,QAAAA,SAAAA,MACL,KAAKA,GAAAA,QAAAA,SAAAA,MAEDxgG,EAAO,YAAWA,IAClBi3B,KAAAA,iBAAsC,IAAIx0B,MAAMzC,IAChDgD,GAAOlD,MAAME,KAarBwgG,GAAAA,QAAAA,mBAA6B,WACzB,OAAOk9C,IAGXl9C,GAAAA,QAAAA,gBAA0B,SAAS9S,GAC/B,OAAQA,GACR,KAAK8S,GAAAA,QAAAA,OAAAA,aACD,MAAO,eACX,KAAKA,GAAAA,QAAAA,OAAAA,MACD,MAAO,QACX,KAAKA,GAAAA,QAAAA,OAAAA,WACD,MAAO,aACX,KAAKA,GAAAA,QAAAA,OAAAA,SACD,MAAO,WACX,KAAKA,GAAAA,QAAAA,OAAAA,eACD,MAAO,iBACX,KAAKA,GAAAA,QAAAA,OAAAA,SACD,MAAO,WACX,KAAKA,GAAAA,QAAAA,OAAAA,UACD,MAAO,YACX,KAAKA,GAAAA,QAAAA,OAAAA,aACD,MAAO,eACX,KAAKA,GAAAA,QAAAA,OAAAA,cACD,MAAO,gBACX,KAAKA,GAAAA,QAAAA,OAAAA,SACD,MAAO,WACX,QACI,MAAO,YFjFfA,GAAAA,QAAAA,oBAA4B,SAAU,IAAIw8C,IG6FtC,MAAMh+B,EAAWxgH,EAAQwgH,UAAY,GAGrCA,EAASmB,OAAS3hH,EAAQqrH,MAAM1J,OAEhC1hH,KAAK8iG,WArGb,YAOgB,IAPU,sBACtBod,EADsB,WAEtBG,EAAa,aAFS,MAGtBC,EAHsB,MAItBviE,EAJsB,mBAKtBoiE,EALsB,sBAMtBC,EANsB,SAOtBG,GAAY,EAQZ,OALIxiE,IAEAsiE,GAAe,IAA+B,IAA7BA,EAAWh9G,QAAQ,KAAc,IAAM,YAAY06C,KAGjE,IAAI+hE,GAAe,CACtBI,sBAAAA,EACAG,WAAAA,EACAF,mBAAAA,EACAC,sBAAAA,EACAG,SAAAA,EACAD,MAAAA,IAgFkBq/B,CAAiB,CAC/Bz/B,sBAAuBngH,EAAQmgH,sBAG/BG,WAAYtgH,EAAQsgH,YAActgH,EAAQ6/I,KAC1C7hG,MAAAA,EACAoiE,mBAAoBpgH,EAAQogH,mBAC5BC,sBAAuBrgH,EAAQqgH,sBAC/BG,SAAAA,EACAD,MAAK,UAAEvgH,EAAQ8/I,sBAAV,aAAE,EAAwBv/B,QAInCtgH,KAAK8iG,WAAWv4D,GAAGu1E,GAAe38B,OAAO68B,oBAAoB,KAEzD,MAAM8/B,EAAU,CACZC,eAAe,EACfC,aAAchgJ,KAAK8iG,WAAW+b,KAAKY,qBACnCwgC,wBAAyBjgJ,KAAK8iG,WAAW8a,2BAI7C59G,KAAKwzF,aAAa37D,KACdk3E,GACAI,QACApjG,OACAA,EACA+zI,MAGR9/I,KAAKkgJ,sBAELlgJ,KAAKw2E,KAAO,IAAIsjC,GAAK95G,KAAK8iG,WAA6B,gCAGvD9iG,KAAKmgJ,mBAOL5hF,IAAAA,CAAEj8D,QAAQioC,IAAMvqC,KAAKD,QAAQqgJ,4BAA8B,GAAK,iBAAlD,UAA2EhY,IACrFpoI,KAAK60F,WAAWuzC,GAAIpkF,OAAM,YAUlCm8F,mBAGIngJ,KAAKw2E,KAAK4jC,WAAW,qBACrBp6G,KAAKw2E,KAAK4jC,WAAW,8BACrBp6G,KAAKw2E,KAAK4jC,WAAW,wCACrBp6G,KAAKw2E,KAAK4jC,WAAW,+BACrBp6G,KAAKw2E,KAAK4jC,WAAW,0CACrBp6G,KAAKw2E,KAAK4jC,WAAW,kCACrBp6G,KAAKw2E,KAAK4jC,WAAW,kCACrBp6G,KAAKw2E,KAAK4jC,WAAW,0CAEfp6G,KAAKD,QAAQwrH,YAAehmF,GAAQwkD,eACtC/pF,KAAKw2E,KAAK4jC,WAAW,sBAEU,IAA/Bp6G,KAAKD,QAAQsgJ,eAA0B96G,GAAQqkD,oBAC/C5pF,KAAKw2E,KAAK4jC,WAAW,mCAGc,IAA5Bp6G,KAAKD,QAAQugJ,YAA8BtgJ,KAAKD,QAAQugJ,aAC/DtgJ,KAAKw2E,KAAK4jC,WAAW,yBAIpB70E,GAAQ8gD,kBAAkD,IAA3BrmF,KAAKD,QAAQwgJ,YAA6BvgJ,KAAKD,QAAQwgJ,WACvFvgJ,KAAKw2E,KAAK4jC,WAAW,wBASzBp6G,KAAKw2E,KAAK4jC,WAAW,qBACrBp6G,KAAKw2E,KAAK4jC,WAAW,qBAKjB70E,GAAQ2hD,oBAAoD,IAA/BlnF,KAAKD,QAAQygJ,gBAC1Cj8I,GAAOiH,KAAK,sBACZxL,KAAKw2E,KAAK4jC,WAAW,kCAGrBp6G,KAAK8iG,WAAW+yB,MAChB71H,KAAKw2E,KAAK4jC,WAAW,0BAGrBtB,GAAc72F,YAAYjiB,KAAKD,UAC/BC,KAAKw2E,KAAK4jC,WAAW9F,IAAc,GAAO,GAOlDmsC,gBACI,OAAOzgJ,KAAK8iG,WAchB49C,oBAAiD,IAA/BC,EAA+B,uDAAjB,GAAI1xD,EAAa,uCAAL1tF,EAAK,uCAC7C,MAAM0rD,EAAM3qD,OAAOijG,YAAYt4C,MACzB2zF,EAAY7+C,GAAAA,QAAAA,gBAAwB9S,GAAQ93D,cASlD,GAPAn3B,KAAK4iG,gBAAgBg+C,GAAa3zF,EAClC1oD,GAAOD,IACF,kBAAiBs8I,IAAYr/I,EAAO,IAAGA,KAAS,QACjD0rD,GAEJjtD,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,0BAAsC0jH,EAAa1xD,EAAQ1tF,GAClFvB,KAAK6gJ,+BACD5xD,IAAW8S,GAAAA,QAAAA,OAAAA,WAA4B9S,IAAW8S,GAAAA,QAAAA,OAAAA,SAE9C/hG,KAAK8gJ,qBACL9gJ,KAAK8iG,WAAWgZ,aAAailC,cAAc/gJ,KAAK8gJ,oBAChD9gJ,KAAK8gJ,mBAAqB,MAG9B9gJ,KAAKghJ,eAAiBhhJ,KAAK8iG,WAAW20B,OAAOkmB,4BAE7Cp5I,GAAOiH,KAAM,iBAAgBxL,KAAK8iG,WAAWK,OAG7CnjG,KAAKihJ,cAGLjhJ,KAAKkhJ,oBAAqB,EAC1BlhJ,KAAKghJ,eAAiBhhJ,KAAKw2E,KAAKokC,yBAAyB56G,KAAKD,QAAQqrH,MAAM1J,QACvE9gE,MAAK,IAA8B,IAA7B,SAAEghD,EAAF,WAAYgY,GAAiB,EAC3BhY,EAASriD,IAAIwiD,GAAAA,QAAAA,GAAAA,OACdx9F,GAAOlD,MAAO,yBACVrB,KAAKD,QAAQqrH,MAAM1J,0DAG3B1hH,KAAKmhJ,4BACDvnC,OAAY7tG,MAEnBi4C,OAAM3iD,IACH,MAAMi+G,EAAS,0BAEf9mF,KAAAA,iBACI,IAAIx0B,MAAO,GAAEs7G,MAAWj+G,MAC5BkD,GAAOlD,MAAMi+G,EAAQj+G,GAErBrB,KAAK6gJ,8BAA6B,MAI1C7gJ,KAAKghJ,eAAgB,EAEjBL,EAAY9lG,WACZ76C,KAAKw/I,mBAAoB,GAEzBx/I,KAAK8iG,YAAc9iG,KAAK8iG,WAAW4a,WAChC3b,GAAAA,QAAAA,mBAA2B/hG,KAAK8iG,WAAWK,MAG9CnjG,KAAKwzF,aAAa37D,KACdk3E,GACAhN,GAAAA,QAAAA,mBAA2B/hG,KAAK8iG,WAAWK,WAEhD,GAAIlU,IAAW8S,GAAAA,QAAAA,OAAAA,SACN,+BAARxgG,EACAvB,KAAKohJ,2BAA4B,EAEjCphJ,KAAKqhJ,kBAAmB,EAE5BrhJ,KAAKshJ,aAAe//I,EACR,cAARA,GACAvB,KAAKwzF,aAAa37D,KACdk3E,GACAI,GAAmC5tG,QAExC,GAAI0tF,IAAW8S,GAAAA,QAAAA,OAAAA,MAClB/hG,KAAKshJ,aAAe//I,OACjB,GAAI0tF,IAAW8S,GAAAA,QAAAA,OAAAA,aAA6B,CAE/C/hG,KAAK8iG,WAAW+b,KAAKU,eACrB,MAAMgiC,EAA2Bj6D,QAAQtnF,KAAKu/I,sBACxCzH,EAASv2I,GAAOvB,KAAKshJ,aAE3B,GAAIthJ,KAAKohJ,0BAELphJ,KAAKwzF,aAAa37D,KACdk3E,GACAI,SACD,GAAInvG,KAAKqhJ,iBACZrhJ,KAAKwzF,aAAa37D,KACdk3E,GACAI,GACA2oC,OACA/rI,EACA/L,KAAKwhJ,0CACN,GAAID,EACPvhJ,KAAKwzF,aAAa37D,KACdk3E,GAA+C+oC,OAChD,CAMHvzI,GAAOlD,MAAM,4BAIb,MAAM49I,EAAkBl9C,GAAAA,QAAAA,qBAEpBk9C,GAAmB,KAAOA,EAAkB,IAC5Cj/I,KAAKwzF,aAAa37D,KACdk3E,GACAI,GACA2oC,GAAU,oBACQ/rI,EAClB/L,KAAKwhJ,qCAETxhJ,KAAKwzF,aAAa37D,KACdk3E,GACAI,GACA2oC,GAAU,gCACQ/rI,EAClB/L,KAAKwhJ,2CAGd,GAAIvyD,IAAW8S,GAAAA,QAAAA,OAAAA,SAAyB,CAC3C,MAAM0/C,EAAuBzhJ,KAAKygJ,gBAAgB9iC,uBAGlD39G,KAAKwzF,aAAa37D,KACdk3E,GACAI,GACA5tG,GAAOvB,KAAK0hJ,8BAA8BD,GAC1Cd,IAWZQ,4BAA4BvnC,EAAYhY,GAEpCgY,EAAWr5G,SAAQ2rG,IAaf,GAZsB,kBAAlBA,EAAStkG,OACT5H,KAAK6kH,6BAA+B3Y,EAAS1/F,MAG3B,iBAAlB0/F,EAAStkG,OACT5H,KAAK2hJ,6BAA+Bz1C,EAAS1/F,MAG3B,wBAAlB0/F,EAAStkG,OACT5H,KAAK4hJ,mCAAqC11C,EAAS1/F,MAGjC,eAAlB0/F,EAAStkG,KAAuB,CAChC5H,KAAKsnH,gBAAiB,EACtB,MAAMu6B,EAAuBztH,IACzBA,EAAE7zB,SAAQuhJ,IACFA,EAAGC,SAAS,0BACZ/hJ,KAAKwzF,aAAa37D,KAAKk3E,QAK/BnN,EACAigD,EAAqBjgD,GAErBsK,EAAS1/F,MAAQxM,KAAKw2E,KAAKokC,yBAAyB1O,EAAS1/F,KAAM0/F,EAAStkG,MACvEg5C,MAAK,QAAGghD,SAAUxtE,GAAb,SAAqBytH,EAAqBztH,MAC/C4vB,OAAMj3C,GAAKxI,GAAO2T,KAAK,qCAAsCnL,GAAKA,EAAEiO,WAI3D,UAAlBkxF,EAAStkG,OACT5H,KAAKD,QAAQ8/I,eAAev/B,MAAQtgH,KAAK8iG,WAAWwd,MAAQpU,EAAS1/F,MAGnD,WAAlB0/F,EAAStkG,OACT5H,KAAKD,QAAQ8/I,eAAemC,OAAShiJ,KAAK8iG,WAAWk/C,OAAS91C,EAAS1/F,MAGrD,mBAAlB0/F,EAAStkG,OACT5H,KAAKymH,8BAAgCva,EAAS1/F,SAItDxM,KAAK6gJ,8BAA6B,IAE9B7gJ,KAAK6kH,8BACF7kH,KAAK2hJ,8BACL3hJ,KAAK4hJ,oCACL5hJ,KAAKymH,gCACRzmH,KAAK8iG,WAAWrqE,WAAWz4B,KAAKiiJ,kBAAkBrhJ,KAAKZ,MAAO,KAAM,UAAW,KAAM,MAU7F0hJ,8BAA8BngJ,GAC1B,IAAKA,EACD,OAAO,KAGX,MAAMuhB,EAAUs8H,GAAcrpH,KAAKx0B,GAEnC,OAAOuhB,EAAUA,EAAQ,GAAK,KAQlCo/H,SAAS/+C,EAAKtoD,GA4BV76C,KAAKihJ,cAGLjhJ,KAAKghJ,eAAgB,EACrBhhJ,KAAKkhJ,oBAAqB,EAEtBlhJ,KAAK8iG,WAAWgZ,cAAgB97G,KAAK8iG,WAAWgZ,aAAaqmC,eAC7DniJ,KAAK8gJ,mBAAqB9gJ,KAAK8iG,WAAWgZ,aAAaqmC,eACnDniJ,KAAKoiJ,iBAAiBxhJ,KAAKZ,MAC3B,KACA,WAGJuE,GAAO2T,KAAK,gEAGhBlY,KAAK8iG,WAAWxQ,QACZ6Q,EACAtoD,EACA76C,KAAK0gJ,kBAAkB9/I,KAAKZ,KAAM,CAC9BmjG,IAAAA,EACAtoD,SAAAA,KAUZunG,iBAAiB7gJ,GAEb,GAAwC,IAApCg9D,IAAAA,CAAEh9D,GAAK8G,KAAK,aAAa3G,QAAiD,IAAjC68D,IAAAA,CAAEh9D,GAAK8G,KAAK,UAAU3G,OAC/D,OAGJ1B,KAAKghJ,eAAgB,EAErB,MAAMqB,EAAkBriJ,KAAK8iG,WAAW20B,OAAOomB,gCAAgCt8I,IAEzE,SAAEqgG,EAAF,WAAYgY,GAAeD,GAAep4G,GAEhDvB,KAAKmhJ,4BAA4BvnC,EAAYhY,IAEzCygD,GAAmBzoC,EAAW50C,KAAO,GAAK48B,EAAS58B,KAAO,KAC1DhlE,KAAK8iG,WAAWgZ,aAAailC,cAAc/gJ,KAAK8gJ,oBAChD9gJ,KAAK8gJ,mBAAqB,MAWlC/+B,OAAOhiH,GACHC,KAAKihJ,cAGLjhJ,KAAKghJ,eAAgB,EAErB,MAAM/zF,EAAMjtD,KAAK4iG,gBAAgB0/C,UAAYhgJ,OAAOijG,YAAYt4C,MAEhE1oD,GAAOD,IAAI,8BAA+B2oD,GAC1CjtD,KAAK8iG,WAAWif,OAAOhiH,EAAQojG,IAAKpjG,EAAQiiH,IACxCv5G,SAAS1I,EAAQkiH,IAAK,IAAM,EAC5BjiH,KAAK0gJ,kBAAkB9/I,KAAKZ,KAAM,CAC9BmjG,IAAKpjG,EAAQojG,IACbtoD,SAAU96C,EAAQ86C,YAQ9BomG,cACIjhJ,KAAKohJ,2BAA4B,EACjCphJ,KAAKqhJ,kBAAmB,EACxBrhJ,KAAKshJ,kBAAev1I,EACpB/L,KAAKu/I,0BAAuBxzI,EAQhCumF,QAAQ6Q,EAAKtoD,GACT,IAAKsoD,EAAK,CACN,MAAM,gBAAEspB,EAAF,OAAmB/K,GAAW1hH,KAAKD,QAAQqrH,MACjD,IAAIm3B,EAAe91B,GAAmB/K,EAStC,MAAM,SAAE1yG,GAAa1M,OAErB,GAAImqH,EAAiB,CACjB,MAAMxlF,EAASj4B,GAAYA,EAASi4B,QAE/BA,IAA4C,IAAlCA,EAAO5jC,QAAQ,eACnBrD,KAAK+9C,SACZwkG,EAAe7gC,GAKvBve,EAAMo/C,GAAiBvzI,GAAYA,EAASwzI,SAGhD,OAAOxiJ,KAAKkiJ,SAAS/+C,EAAKtoD,GAa9ButE,WAAW3wF,EAAU13B,EAAS0iJ,GAE1B,MAAM/gC,EAASjqF,EAASiqF,QAAU3hH,EAAQooH,aAG1C,IAAIllB,EAAW,GAAEjjG,KAAK0iJ,WAAWjrH,EAAUiqF,MAC3C,MAAMihC,EAAcF,EACdA,EAAiBziJ,KAAK8iG,WAAWK,IAAKnjG,KAAKw/I,mBAC3CvmH,KAAAA,gBAA2B,GAAG9B,cAKpC,OAHA5yB,GAAOiH,KAAM,OAAMxL,KAAK8iG,WAAWK,0BAA0Bw/C,KAC7D1/C,GAAW0/C,EAEJ3iJ,KAAK8iG,WAAWC,KAAKqlB,WAAWnlB,EAAS,KAAMljG,GAU1D2iJ,WAAWjrH,EAAUiqF,GACjB,MAAQ,GAAEjqF,KAAYiqF,GAAkB1hH,KAAKD,QAAQqrH,MAAMw3B,IAAIzrH,gBASnEw/F,cAAcl/F,EAAUiqF,GACpB,OAAO1hH,KAAK8iG,WAAWC,KAAK4zB,cAAc32H,KAAK0iJ,WAAWjrH,EAAUiqF,IAQxElb,SACI,OAAOxmG,KAAK8iG,WAAWK,IAO3B0/C,eACI,MAAMprB,EAASz3H,KAAK8iG,WAAW20B,OAG/B,OAAOA,EAASA,EAAO4mB,SAAW,GAMtCyE,aACI,OAAQ9iJ,KAAK8iG,WAAWv+F,QAAU,IAAID,KAAO,KAMjDsxH,OACI51H,KAAK8iG,WAAW+yB,KAAKD,QAAQ,WASjC/W,KAAK/mD,GACD,OAAO,IAAI/tB,SAAQ,CAACC,EAASC,KACzBjqC,KAAK8iG,WAAW+b,KAAKA,KAAK7+G,KAAK8iG,WAAW8e,WAAY53E,EAASC,EAAQ6tB,MAO/EirF,cACI,OAAO/iJ,KAAK8iG,WAAW20B,OAAO8kB,SAUlC1nD,WAAWuzC,GACP,OAAIpoI,KAAKu/I,qBACEv/I,KAAKu/I,qBACJv/I,KAAK8iG,YAIjB9iG,KAAKu/I,qBAAuB,IAAIx1G,SAAQC,IACpC,MAAMg5G,EAAqB,CAACrC,EAAa1xD,KACjCA,IAAW8S,GAAAA,QAAAA,OAAAA,eACX/3D,IACAhqC,KAAKwzF,aAAarpD,eAAelN,GAAW,WAAXA,0BAAsC+lH,KAI/EhjJ,KAAKwzF,aAAajpD,GAAGtN,GAAW,WAAXA,0BAAsC+lH,MAG/DhjJ,KAAKijJ,uBAAuB7a,GAErBpoI,KAAKu/I,sBAhBDx1G,QAAQC,UA4BvBi5G,uBAAuB7a,GAWnB,IAFCpoI,KAAK8iG,WAAWwe,kBAAoBthH,KAAK8iG,WAAWrgG,SAEhDzC,KAAK8iG,WAAWwe,kBAAjB,MAAqC8mB,EAA0C,CAC/E,MAAM8a,EAAS9a,EAAGxgI,KAElB,IAAe,iBAAXs7I,GAAwC,WAAXA,KAI7BljJ,KAAK8iG,WAAW/iG,QAAQ+qI,MAAO,EAG3B9qI,KAAK8iG,WAAW2gB,yBAEhB,OAKZzjH,KAAK8iG,WAAWjO,cAEqB,IAAjC70F,KAAK8iG,WAAW/iG,QAAQ+qI,MACxB9qI,KAAK8iG,WAAWrgG,QAOxBy9I,sBACI,MAAM5D,EAAY,CACdG,IAAK,CAAE2B,WAAY,IACnB/jD,IAAK,CAAE+jD,WAAY,KAGjB+E,EAAkBnjJ,KAAKD,QAAQs6F,KAC9Br6F,KAAKD,QAAQs6F,IAAI+oD,aAAgB/D,GAEpC36I,MAAMgD,QAAQy7I,KACd5+I,GAAOiH,KAAK,qBAAsB23I,GAClC7G,EAAUjiD,IAAI+jD,WAAa+E,GAG3BnjJ,KAAKD,QAAQs6F,KAAOr6F,KAAKD,QAAQs6F,IAAIgpD,qBACrC9+I,GAAOiH,KAAK,6BACRxL,KAAKD,QAAQs6F,IAAIgpD,oBAErB/G,EAAUjiD,IAAIgpD,mBACRrjJ,KAAKD,QAAQs6F,IAAIgpD,oBAG3BrjJ,KAAK8iG,WAAWke,oBAAoB,OAAQ,IAAI0V,GAAoB12H,OACpEA,KAAK8iG,WAAWke,oBAAoB,SAAU,IAAIq7B,GAAuBr8I,KAAMA,KAAKwzF,aAAc8oD,IAClGt8I,KAAK8iG,WAAWke,oBAAoB,OAAQ,IAAI49B,IASpD4C,oCACI,MAAM1B,EAAU,GAGhB,GAAI9/I,KAAKD,QAAQ8/I,gBACV7/I,KAAKD,QAAQ8/I,eAAev/B,OAC5BtgH,KAAK8iG,WAAW6e,oBAAqB,CAGxC,MAAM2hC,EAAatjJ,KAAK8iG,WAAW6e,oBAC9BvjD,OAAOl6D,MAAM,WACZi/G,EAAU,GAEhBmgC,EAAW/iJ,SAAQuD,IACf,MAAMoH,EAAQpH,EAAKI,MAAM,MACnBq/I,EAASr4I,EAAMiiC,QACfhmC,EAAQ+D,EAAM3B,KAAK,MAEzB45G,EAAQogC,GAAUp8I,KAItB24I,EAAQC,cACF//I,KAAKD,QAAQ8/I,eAAev/B,QACtB6C,EAAQ,iBAUxB,OAJA28B,EAAQE,aAAehgJ,KAAK8iG,WAAW+b,KAAKY,qBAC5CqgC,EAAQG,wBAA0BjgJ,KAAK8iG,WAAW8a,0BAG3CkiC,EAQX3vD,yBAAyB0P,GAErB,IAAK7/F,KAAK2hJ,+BAAiC9hD,EACvC,OAGJ,MAAMt+F,GAAMujH,EAAAA,GAAAA,MAAK,CAAE7F,GAAIj/G,KAAK2hJ,+BAE5BpgJ,EAAI4L,EAAE,eAAgB,CAClBiH,MAAO,2BACPmtF,KAAM1B,IACLklB,KAEL/kH,KAAK8iG,WAAWwgB,KAAK/hH,GAQzBiiJ,0BAA0B3jD,EAAS8E,GAE/B,IAAK3kG,KAAK2hJ,+BAAiC9hD,EACvC,OAGJ,MAAMt+F,GAAMujH,EAAAA,GAAAA,MAAK,CAAE7F,GAAIj/G,KAAK2hJ,+BAE5BpgJ,EAAI4L,EAAE,mBAAoB,CACtBiH,MAAO,2BACPmtF,KAAM1B,EACN4jD,WAAY9+C,EAAQ++C,iBACpBtvD,SAAUuQ,EAAQvQ,WACnB2wB,KAEH/kH,KAAK8iG,WAAWwgB,KAAK/hH,GAYzBoyH,sBAAsBgwB,GAElB,IAAKA,EACD,OAAO,EAGX,IACI,MAAM/sC,EAAOx1G,KAAKwJ,MAAM+4I,GASxB,GAAI/sC,GAAwB,iBAATA,EAAmB,CAClC,MAAMhvG,EAAOgvG,EAAK9B,IAElB,QAAoB,IAATltG,EACP,OAAOgvG,EAGXryG,GAAOynF,MAAM,yDACM,UAAWpkF,IAEpC,MAAOmF,GAGL,OAFAxI,GAAOlD,MAAO,sBAAqBsiJ,IAAc52I,IAE1C,EAGX,OAAO,EAUXk1I,kBAAkB1gJ,GACd,MAAMs9F,EAAOt9F,EAAIihB,aAAa,QAE9B,GAAMq8E,IAAS7+F,KAAK2hJ,8BACb9iD,IAAS7+F,KAAK4hJ,oCACd/iD,IAAS7+F,KAAK6kH,8BACdhmB,IAAS7+F,KAAKymH,8BACjB,OAAO,EAGX,MAAMgN,EAAcl1D,IAAAA,CAAEh9D,GAAK8G,KAAK,iBAC3BrG,OACC0xH,EAAa1zH,KAAK2zH,sBAAsBF,GAE9C,OAAKC,IAImC,iBAApCA,EAAW5e,KAA2C4e,EAAWkwB,MACjE5jJ,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,uBAAmCy2F,EAAWkwB,OAC1B,wBAApClwB,EAAW5e,KAAkD4e,EAAWmwB,kBAC/E7jJ,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,8BAA0Cy2F,EAAWmwB,mBACjC,kBAApCnwB,EAAW5e,IAClB90G,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,uBAAmCy2F,GACf,mBAApCA,EAAW5e,KAClB90G,KAAKwzF,aAAa37D,KAAKoF,GAAW,WAAXA,qBAAiCy2F,IAGrD,GAWXmtB,6BAA6Bn+I,GACzB,MAAMohJ,EAAmB,CACrB/hD,GAAAA,QAAAA,OAAAA,MACAA,GAAAA,QAAAA,OAAAA,SACAA,GAAAA,QAAAA,OAAAA,SACAA,GAAAA,QAAAA,OAAAA,aACAA,GAAAA,QAAAA,OAAAA,aAGJ,KAAKr/F,GAAWohJ,EAAiBrmC,SAASz9G,KAAK8iG,WAAW7T,SAAWjvF,KAAKkhJ,oBACtE,OAKJ,MAAM6C,EAAS/jJ,KAAKD,QAAQ8/I,eAE5B,GAAIkE,GAAU3jJ,OAAOC,KAAK0jJ,GAAQriJ,OAAS,EAAG,CAC1C,MAAMwiG,EAAY,CAElBA,GAAe,mBACf,IAAK,MAAMxuF,KAAQquI,EACXA,EAAOtrI,eAAe/C,KACtBwuF,EAAUxuF,GAAQquI,EAAOruI,IAIjC+mF,GAAW0D,QAAQ/+F,KAAKF,UAAUgjG,IAGtClkG,KAAKkhJ,oBAAqB,GCh+BnB,SAAS8C,GAAT,GAYZ,IAEKC,GAd2C,GAE/C5+I,EAF+C,SAG/Cw1C,EAH+C,iBAI/C4nG,EAJ+C,kBAQ/CyB,EAR+C,aAW/CC,GACD,EACKve,GAAW,EAEXlpC,EAAO,IAAIsxB,GAAKhuH,KAAK8iG,WAAW/iG,SAEpC,MAAMgjD,EAAU,IAAIhZ,SAAQ,CAACC,EAASC,KAIlCg6G,EAAgBh6G,EAGhByyD,EAAK9kE,YACDsqD,IACA,KACIwa,OAAO3wF,KAEf2wF,EAAK9kE,YACDikD,IACA,KACQ+pD,IAKJse,GAAqBA,IAGRxnD,EAAK0rB,WACdpoH,KAAKD,QAAQyM,KACbxM,KAAKD,QAAQ0N,OACbg1I,GAGCj0B,UAAU5B,eACVhsE,MAAK,KACF87C,GAAQA,EAAK7H,aAET+wC,IAOJ5lI,KAAKuJ,KAAK46I,GAEVn6G,QAEHga,OAAM,IAAwB,IAAvB,MAAE3iD,EAAF,QAAS2Z,GAAc,EAC3B0hF,EAAK7H,aAEL5qD,EAAO,CACHm6G,oBAAqB/iJ,EACrB2Z,QAAAA,WAIpB0hF,EAAK9kE,YACDo3E,IACA,CAACq1C,EAAiBrpI,EAAS2lI,KACvB12G,EAAO,CACHo6G,gBAAAA,EACA1D,YAAAA,EACA3lI,QAAAA,IAEJ0hF,OAAO3wF,KAGf65H,GAAYlpC,EAAKpK,QAAQjtF,EAAIw1C,MAgBjC,OANAkI,EAAQkqB,OAAS,KACb24D,GAAW,EACXqe,EAAc,IACdvnD,GAAQA,EAAK7H,cAGV9xC,ECpJX,MAAMx+C,IAAS2B,EAAAA,EAAAA,4CASR,MAAMo+I,GAcTlrI,YAAYslF,EAAY3+F,GACpBC,KAAK0+F,WAAaA,EAClB1+F,KAAKD,QAAUA,EAGfC,KAAKukJ,cAAgBxkJ,EAAQwkJ,gBAAkBzlB,GAAAA,SACzC/yH,EACA/L,KAAKwkJ,kBAAkBzkJ,EAAQwkJ,eAGrC,MAAME,EAAWzkJ,KAAKwkJ,kBAAkBzkJ,EAAQ0kJ,UAC1CC,EAAW1kJ,KAAKwkJ,kBAAkBzkJ,EAAQ2kJ,UAEhD1kJ,KAAK2kJ,kBAAoBF,GAAYzkJ,KAAK4kJ,kBAAkBH,GAAYA,EAAW3lB,GAAAA,IACnF9+H,KAAK6kJ,kBAAoBH,GAAY1kJ,KAAK4kJ,kBAAkBF,GAAYA,EAAW5lB,GAAAA,IACnFv6H,GAAOynF,MAAO,iDAAgDhsF,KAAK2kJ,wCACxD3kJ,KAAK6kJ,qBAEZ7kJ,KAAK2kJ,oBAAsB7lB,GAAAA,KAAsBv5F,GAAQwjD,gBACzD/oF,KAAK2kJ,kBAAoB7lB,GAAAA,KAG7B9+H,KAAK0+F,WAAWn0D,GACZ2wC,IACA,IAAMl7E,KAAK8kJ,0BACf9kJ,KAAK0+F,WAAWn0D,GACZ2wC,IACA,IAAMl7E,KAAK8kJ,0BACf9kJ,KAAK0+F,WAAWn0D,GACZ2wC,IACA1zE,GAAWxH,KAAK0xG,uBAAuBlqG,KAU/Cg9I,kBAAkB7xE,GACd,MAAqB,iBAAVA,EACAvyE,OAAOkJ,OAAOw1H,IAAez2H,MAAKlB,GAASA,IAAUwrE,EAAMx7C,gBAG/D,KAUXytH,kBAAkB7U,GAGd,SAAIxqG,GAAQ8gD,cAAe9gD,GAAQmhD,kBAI5BpkF,OAAO+lF,gBACP/lF,OAAO+lF,eAAeC,iBACtBhmF,OAAO+lF,eAAeC,gBAAgB,SAASvS,OACjDnqE,MAAK+mE,GAASA,EAAM3+D,SAASmjB,gBAAmB,SAAQ44G,MAWjEr+B,uBAAuBqzC,GACnB,MAAMhV,EAAiBgV,EAAax1D,MAAQvvF,KAAK6kJ,kBAAoB7kJ,KAAK2kJ,kBACpEJ,EAAgBvkJ,KAAKukJ,eAAiBvkJ,KAAK4kJ,kBAAkB5kJ,KAAKukJ,eAClEvkJ,KAAKukJ,cACL,KAENvkJ,KAAK8kJ,sBAAsBC,EAAchV,EAAgBwU,GAW7DO,wBAAwF,IAA7C/U,EAA6C,uDAA5B,KAAMwU,EAAsB,uDAAN,KAC9E,MAAM/8I,GAD8E,uDAAnD,OACaxH,KAAK0+F,WAAWuC,iBACxD+jD,EAAejV,GAAkC/vI,KAAK2kJ,kBAC5D,IAAIM,EAAgBD,EAEpB,GAAIx9I,IAAYA,EAAQ+nF,QAAUvvF,KAAKD,QAAQmlJ,sBAAuB,CAClE,MAAMC,EAAqBnlJ,KAAK0+F,WAAW6H,kBAAkBr/F,KAAI26F,GAAeA,EAAYsI,UAE5F,IAAK,MAAMi7C,KAAUD,EAAoB,CACrC,MAAME,EAAgB79I,EAAQilI,gBAAgB6Y,iBAAiBF,EAAQtwD,GAAU2G,OAC3E8pD,EAAYF,MAAAA,OAAH,EAAGA,EAAe7vB,UAE7B+vB,GACGA,IAAcP,IACbO,IAAczmB,GAAAA,KAAqBv5F,GAAQwjD,iBAC/Ck8D,EAAgBM,IAI5B/9I,GAAWA,EAAQqtI,eAAeoQ,EAAeV,GAUrDiB,oBACI,OAAOxlJ,KAAK2kJ,mBCtJb,MAsBP,GAba,UAab,GARsB,mBAQtB,GAHU,OCfJpgJ,IAAS2B,EAAAA,EAAAA,2CAMA,MAAMu/I,GAWjBrsI,YAAYmzE,EAAgBm5D,EAAO57G,GAC/B,IAAKyiD,IAAmBm5D,EACpB,MAAM,IAAI36G,UAAU,kDACjB,GAAIwhD,GAAkBm5D,EACzB,MAAM,IAAI36G,UAAU,qDA4BxB,GAzBIwhD,EACAhoF,GAAOynF,MAAM,qCAEbznF,GAAOynF,MAAO,6BAA4B05D,MAK9C1lJ,KAAK2lJ,SAAW,KAGhB3lJ,KAAK4lJ,cAAgB97G,EAIrB9pC,KAAK6lJ,MAAQ,KAGb7lJ,KAAK8lJ,oBAAqB,EAG1B9lJ,KAAK+lJ,mBAAoB,EAIrBx5D,EAAgB,CAChB,MAAMy5D,EACAz5D,EAAe05D,kBACb,mBAAoB,CAChBr0E,SAAU,uCAItB5xE,KAAKkmJ,eAAeF,GACpBhmJ,KAAK6lJ,MAAQ,mBAGNH,IACP1lJ,KAAK8lJ,oBAAqB,EAC1B9lJ,KAAKmmJ,OAAST,EACd1lJ,KAAKomJ,kBASbA,iBAEI,MAAMC,EAAK,IAAI9kC,UAAUvhH,KAAKmmJ,QAG9BnmJ,KAAKkmJ,eAAeG,GACpBrmJ,KAAK6lJ,MAAQ,YAQjBS,0BACI,IAAIC,EAAW,EAEf,MAAMC,EAAS,KACPxmJ,KAAKymJ,WAGTzmJ,KAAKomJ,eAAepmJ,KAAKmmJ,QACzBI,EAAWt8I,KAAK6uB,IAAe,EAAXytH,EAAc,IAClCvmJ,KAAK0mJ,cAAgBlkJ,WAAWgkJ,EAAmB,IAAXD,KAG5CvmJ,KAAK0mJ,cAAgBlkJ,WAAWgkJ,EAAmB,IAAXD,GAQ5CI,yBACQ3mJ,KAAK0mJ,gBACLnkJ,aAAavC,KAAK0mJ,eAClB1mJ,KAAK0mJ,mBAAgB36I,GAU7B66I,0BAA0BC,GACtB,IAAK7mJ,KAAK8lJ,mBACN,OAEJ,MAAM,KAAE/qI,EAAF,OAAQwd,GAAWsuH,EAEzBpqD,GAAWoE,czEuX2B,EAAE9lF,EAAcwd,KAAhB,CAC1C3wB,KAAMq5E,GAAgBC,iBACtBz5E,OAAQ,uBACRoY,WAAY,CACR9E,KAAAA,EACAwd,OAAAA,KyE5XyBuuH,CAA+B/rI,EAAMwd,IAC9Dv4B,KAAK8lJ,oBAAqB,EAC1B9lJ,KAAK4lJ,cAAc/7G,KAAK9O,GAAAA,QAAAA,mBAA6B,KACjD/6B,KAAK2mJ,yBACL3mJ,KAAK8lJ,oBAAqB,KAE9B9lJ,KAAKsmJ,0BAOLS,WACA,OAAO/mJ,KAAK6lJ,MAMhBjP,QAII,GAHA52I,KAAK+lJ,mBAAoB,EACzB/lJ,KAAK2mJ,yBACL3mJ,KAAK8lJ,oBAAqB,EACtB9lJ,KAAK2lJ,SAAU,CACf,IACI3lJ,KAAK2lJ,SAAS/O,QAChB,MAAOv1I,IAETrB,KAAK2lJ,SAAW,MASxBc,SACI,OAAOzmJ,KAAK2lJ,WAA0C,SAA7B3lJ,KAAK2lJ,SAASn9G,YAChCxoC,KAAK2lJ,SAASn9G,aAAe+4E,UAAUC,MAQlDwlC,yBAAyBriD,GACrB3kG,KAAKinJ,MAAM,CACPC,aAAc,mBACXviD,IAaXsS,YAAYgI,EAAIta,GACZ3kG,KAAKinJ,MAAM,CACPC,aAAc,kBACdC,WAAYxiD,EACZsa,GAAAA,IAQRmoC,oBAAoBjgJ,GAChB5C,GAAOD,IAAK,iBAAgB6C,MAE5BnH,KAAKinJ,MAAM,CACPC,aAAc,oBACdG,MAAOlgJ,IAYfmgJ,6BAA6BC,GACzBhjJ,GAAOD,IAAK,+BAA8BijJ,MAE1CvnJ,KAAKinJ,MAAM,CACPC,aAAc,gCACdM,kBAAmBD,IAS3BE,mCAAmCC,GAC/BnjJ,GAAOD,IAAK,uDAAsDojJ,OAClE1nJ,KAAKinJ,MAAM,CACPC,aAAc,0BACd3R,eAAgBmS,IASxBC,uCAAuClnE,GACnCl8E,GAAOD,IAAK,yCAAwClD,KAAKF,UAAUu/E,MACnEzgF,KAAKinJ,MAAM,CACPC,aAAc,8BACXzmE,IAUXmnE,qBAAqBniD,GACjBlhG,GAAOynF,MAAO,+CAA8CyZ,KAC5DzlG,KAAKinJ,MAAM,CACPC,aAAc,mBACdzhD,UAAAA,IAWRoiD,2BAA2BzmB,EAAY37B,GACnClhG,GAAOiH,KAAM,kDAAiD41H,MAAe37B,KAC7EzlG,KAAKinJ,MAAM,CACPC,aAAc,yBACd9lB,WAAAA,EACA37B,UAAAA,IAORygD,eAAe4B,GACX,MAAMh+G,EAAU9pC,KAAK4lJ,cAErBkC,EAAQC,OAAS,KACbxjJ,GAAOiH,KAAM,GAAExL,KAAK6lJ,wBAQpB/7G,EAAQjS,KAAKkD,GAAAA,QAAAA,oBAGjB+sH,EAAQ5vH,QAAUI,IAGK,cAAft4B,KAAK6lJ,OACLthJ,GAAOlD,MAAO,kBAAiBi3B,EAAMtd,YAI7C8sI,EAAQE,UAAY,IAAc,IAE1B75I,GAFa,KAAEsI,GAAW,EAI9B,IACItI,EAAM/M,KAAKwJ,MAAM6L,GACnB,MAAOpV,GAIL,OAHAm3B,KAAAA,iBAAsCn3B,QACtCkD,GAAOlD,MAAM,4CAA6CoV,EAAMpV,GAKpE,MAAM6lJ,EAAe/4I,EAAI+4I,aAEzB,OAAQA,GACR,IAAK,qCAAsC,CACvC,MAAM,wBAAEe,EAAF,iBAA2BC,EAAmB,IAAO/5I,EAE3D5J,GAAOynF,MAAO,qBAAoBi8D,yBAA+CC,KACjFp+G,EAAQjS,KAAKkD,GAAAA,QAAAA,yBAAoCktH,EAAyBC,GAC1E,MAEJ,IAAK,wCAAyC,CAC1C,MAAM/K,EAAWhvI,EAAIgvI,SACfrzC,EAA0B,SAAf37F,EAAIg6I,OAErB5jJ,GAAOiH,KAAM,uCAAsC2xI,YAAmBrzC,KACtEhgE,EAAQjS,KAAKkD,GAAAA,QAAAA,6BAAwCoiH,EAAUrzC,GAE/D,MAEJ,IAAK,kBACDhgE,EAAQjS,KAAKkD,GAAAA,QAAAA,0BAAqC5sB,EAAI0wF,KAAM1wF,EAAIg5I,YAEhE,MAEJ,IAAK,gBACDr9G,EAAQjS,KAAKkD,GAAAA,QAAAA,wBAAmC5sB,EAAI0wF,KAAM1wF,GAE1D,MAEJ,IAAK,4BACD,IAAKkpH,GAAAA,+BAA6C,CAG9C,MAAM+wB,EAAiBj6I,EAAIi6I,eAE3B7jJ,GAAOiH,KAAM,4BAA2B48I,KACxCt+G,EAAQjS,KAAKkD,GAAAA,QAAAA,uBAAkCqtH,GAGnD,MAEJ,IAAK,mBACD,GAAI/wB,GAAAA,+BAA6C,CAE7C,MAAMgxB,EAAmBl6I,EAAIk6I,iBAE7B9jJ,GAAOiH,KAAM,0BAAyB68I,KACtCv+G,EAAQjS,KAAKkD,GAAAA,QAAAA,0BAAqCstH,GAGtD,MAEJ,IAAK,yBAA0B,CAC3B,MAAMC,EAAmBn6I,EAAIm6I,iBAEzBA,IACA/jJ,GAAOiH,KAAM,2BAA0BpK,KAAKF,UAAUonJ,MACtDx+G,EAAQjS,KAAKkD,GAAAA,QAAAA,iCAA4CutH,IAE7D,MAEJ,IAAK,0BACD,GAAIjxB,GAAAA,+BAA6C,CAC7C,MAAM,WAAE+J,EAAF,UAAczG,GAAcxsH,EAER,iBAAfizH,GAAgD,iBAAdzG,GAEzCp2H,GAAOiH,KAAM,4BAA2BpK,KAAKF,UAAU,CAAEkgI,WAAAA,EAAYzG,UAAAA,OACrE7wF,EAAQjS,KACJkD,GAAAA,QAAAA,iCAA4C,CACxCqmG,WAAAA,EACAzG,UAAAA,KAIRp2H,GAAOlD,MAAO,oCAAmCD,KAAKF,UAAUiN,MAGxE,MAEJ,IAAK,cACD5J,GAAOiH,KAAM,iCAAgC2C,EAAI8C,YACjD,MAEJ,QACI1M,GAAOynF,MAAM,mCAAoC79E,GAMjD27B,EAAQjS,KAAM,mBAAkBqvH,IAAgB/4I,KAKxD25I,EAAQS,QAAUjwH,IACd/zB,GAAOiH,KAAM,sBAAoBxL,KAAK+lJ,kBAAoB,SAAW,WAElD,cAAf/lJ,KAAK6lJ,QACA7lJ,KAAK+lJ,oBACNxhJ,GAAOlD,MAAO,mBAAkBi3B,EAAMvd,QAAQud,EAAMC,UACpDv4B,KAAK4mJ,0BAA0BtuH,KAKvCt4B,KAAK2lJ,SAAW,MAIpB3lJ,KAAK2lJ,SAAWmC,EAUpBb,MAAMuB,GACF,MAAMV,EAAU9nJ,KAAK2lJ,SAErB,IAAK3lJ,KAAKymJ,SAEN,MADAliJ,GAAOlD,MAAM,2CACP,IAAI2C,MAAM,qBAGpB8jJ,EAAQxkC,KAAKliH,KAAKF,UAAUsnJ,KCnc7B,MAYP,GARiB,cAQjB,GAHU,qBCCV,MAAMjkJ,IAAS2B,EAAAA,EAAAA,sCAKXq/B,GAAQ0jD,eACRzvD,EAAQ,KAGZ,MAAMg6D,GAAe,IAAI7pD,MASnB8+G,GAAsB,CACxB7nE,MAAO,CACH/jD,OAAQ,CACJ6rH,MAAO,IACPrxH,IAAK,IACLyB,IAAK,KAET8D,MAAO,CACH8rH,MAAO,KACPrxH,IAAK,KACLyB,IAAK,OAOjB,IAAI6vH,GAAsB,UAEtBC,IAAqB,EAGrBC,IAAY,EAGZC,IAAa,EAGbC,IAAY,EAGZC,IAAa,EAGbzvB,GAAS,KAEb,MAAM0vB,GAA0BhvH,SAAShX,cAAc,SACjDimI,QAC6C,IAAtCD,GAAwBE,UAErC,IACIC,GADAC,GAAmB,GAMvB,SAASC,MA0FT,SAASC,GAAyBC,EAAIp5I,GAClC,MAAMq5I,EACAniE,QAAQl3E,IAAWA,EAAOs5I,iBAAiBhoJ,OAAS,EACpDioJ,EACAriE,QAAQl3E,IAAWA,EAAOw5I,iBAAiBloJ,OAAS,EACpDmoJ,EAAqB,IAEE,IAAzBL,EAAGnmJ,QAAQ,WACXwmJ,EAAmBjpE,MAAQ+oE,IAEF,IAAzBH,EAAGnmJ,QAAQ,WACXwmJ,EAAmB/wD,MAAQ2wD,GAG/Bj2D,GAAa37D,KAAKkD,GAAAA,QAAAA,oBAA+B8uH,GA4CrD,SAASC,GAA0BC,GAC/B,MAAMC,EACAD,EAAWhjJ,QAAOizB,GAAgB,eAAXA,EAAEu8C,OAAuB70E,OAChDuoJ,EACAF,EAAWhjJ,QAAOizB,GAAgB,gBAAXA,EAAEu8C,OAAwB70E,OACjDwoJ,EACAH,EAAWhjJ,QAAOizB,GAAgB,eAAXA,EAAEu8C,OAAuB70E,OAChDyoJ,EACAJ,EAAWhjJ,QAAOizB,GAAgB,gBAAXA,EAAEu8C,OAAwB70E,OAEvDqoJ,EAAWxpJ,SAAQ6pJ,IACf,MAAMvqI,EAAa,CACf,yBAA4BmqI,EAC5B,0BAA6BC,EAC7B,yBAA4BC,EAC5B,0BAA6BC,EAC7B,UAAaC,EAAOC,SACpB,gBAAmBD,EAAOE,QAC1B,YAAeF,EAAO7zE,KACtB,aAAgB6zE,EAAOG,OAG3B9tD,GAAWoE,cAAc5e,GAAkBpiE,MAenD,SAAS2qI,GAAmBC,IAzE5B,SAAsCC,GAClC,OAAIA,EAAWhpJ,SAAW2nJ,GAAiB3nJ,QAOvCgpJ,EAAWxjJ,IAAIyjJ,GAAuB96G,OAAOtmC,KAAK,MAC1C8/I,GACCniJ,IAAIyjJ,GAAuB96G,OAAOtmC,KAAK,IAQpD,SAASohJ,EAAsBn/I,GAC3B,OAAOpK,KAAKF,UAAU,CAClBq1E,KAAM/qE,EAAK+qE,KACX8zE,SAAU7+I,EAAK6+I,SACfC,QAAS9+I,EAAK8+I,QACdC,MAAO/+I,EAAK++I,MACZK,OAAQp/I,EAAKo/I,WAkDjBC,CAA6BJ,KAYjCpB,GAX8BoB,EAWK9lJ,MAAM,GACzCJ,GAAOiH,KAAK,qCAAsC69I,IAElDS,GAA0BT,IAG1B71D,GAAa37D,KAAKkD,GAAAA,QAAAA,wBAAmCsuH,IAErD71D,GAAa37D,KAAKkD,GAAAA,QAAAA,oBAA+BsuH,KAinBrD,MAAMyB,GAAW,IA3mBjB,cAAuBn7C,GAInBv2F,cACI8rE,MAAMsO,IAYV5pD,OAAmB,UAAd7pC,EAAc,uDAAJ,GAkmBnB,IAA+BgrJ,EAjmBW,kBAAvBhrJ,EAAQ+oJ,aACfA,GAAa/oJ,EAAQ+oJ,WACrBvkJ,GAAOiH,KAAM,gBAAes9I,OAEC,kBAAtB/oJ,EAAQgpJ,YACfA,GAAYhpJ,EAAQgpJ,UACpBxkJ,GAAOiH,KAAM,eAAcu9I,OAEE,kBAAtBhpJ,EAAQ8oJ,YACfA,GAAY9oJ,EAAQ8oJ,UACpBtkJ,GAAOiH,KAAM,eAAcq9I,OAEG,kBAAvB9oJ,EAAQipJ,aACfA,GAAajpJ,EAAQipJ,WACrBzkJ,GAAOiH,KAAM,gBAAew9I,OAEY,kBAAxC,UAAOjpJ,EAAQu5H,oBAAf,aAAO,EAAsBC,UAC7BA,GAASx5H,EAAQu5H,aAAaC,OAC9Bh1H,GAAOiH,KAAM,WAAU+tH,OAG3Bj3H,OAAO2wF,cAAcm2D,IACrBA,QAA4Br9I,EAExBw5B,GAAQmhD,iBACR1mF,KAAKgrJ,sBAAwBC,kBAE7BjrJ,KAAKkrJ,uBAAoBn/I,EAEzB/L,KAAKmrJ,YAAc,YAAiB,IAAR,GAAE9lJ,GAAM,EAKhC,MACkB,iBAAPA,EACDA,EACA+1H,GAAAA,mBAA2B/1H,IAEzCrF,KAAKorJ,WAAa,QAAC,GAAE/lJ,GAAH,SAAYA,KAE9BrF,KAAKgrJ,sBAAwBC,kBAE7BjrJ,KAAKkrJ,mBAsjBcH,EArjBS,CAACvyI,EAASpI,KAC1BoI,IACAA,EAAQ6yI,UAAYj7I,IAojBjC,SAASoI,EAASpI,GAErB,MAAMspG,EAAMqxC,EAAsBrqJ,MAAMoqJ,GAAUnqJ,WA4BlD,OA1BIyP,GACO06I,GAASQ,wBAAwB,WACjCl7I,EAAOs5I,gBACPt5I,EAAOs5I,iBAAiBhoJ,QAGxBknJ,IACPpwI,EAAQ2wI,UAAU2B,GAASS,wBACtBvnG,OAAM,SAAS1D,GACZ,MAAM7X,EACA,IAAI63C,GAAgBhgC,EAAI,KAAM,CAAE,gBAEtC9nB,KAAAA,8BAAmD,CAC/CkoB,QAAS1gD,KACTu4B,OAAQkQ,IAGZlkC,GAAO2T,KACH,sGAGAM,EACAiwB,MAITixE,IA9kBH15G,KAAKmrJ,YAAc,QAAC,GAAE9lJ,GAAH,SAAYA,GAC/BrF,KAAKorJ,WAAa,QAAC,GAAE/lJ,GAAH,SAAYA,IAGlCrF,KAAKwrJ,cAAgBjmH,GAAQ2hD,mBAAqB3hD,GAAQmhD,gBACpD,CAAE2zC,SAAU,CACV,CAAEoxB,yBAA0B,KAC5B,CAAEC,yBAAyB,KAE7B,GAENC,GAAAA,KAAoB5rJ,GAEhBC,KAAK4rJ,yBACL5rJ,KAAK6rJ,kBAAiBC,IAClBzC,GAAmByC,EAAGnnJ,MAAM,GAE5BJ,GAAOynF,MAAM,sBAAuBq9D,IACpCS,GAA0BT,IAE1B71D,GAAa37D,KACTkD,GAAAA,QAAAA,sBACAsuH,IAEA9jH,GAAQgjD,4BACRlE,UAAUkD,aAAal7C,iBACnB,gBACA,IAAMrsC,KAAK6rJ,iBAAiBvC,MAIhCF,GAA4B9mJ,OAAOiwF,aAC/B,IAAMvyF,KAAK6rJ,iBAAiBvC,KA7WP,QAwXzCuC,iBAAiBjvI,GACbynE,UAAUkD,aAAaskE,mBAClBjrG,MAAK2/B,IACFiqE,GAAmBjqE,GACnB3jE,EAAS2jE,MAEZv8B,OAAM3iD,IACHkD,GAAO2T,KAAM,iCAAgC7W,KAC7CmpJ,GAAmB,IACnB5tI,EAAS,OAarBmvI,cAAcC,GAA0C,IAA/BvrE,EAA+B,uDAAjB,GAAI3oB,EAAa,uDAAH,EACjD,OAAO,IAAI/tB,SAAQ,CAACC,EAASC,KACzB,IAAIgiH,EAAYC,GAAiB,EAEV,iBAAZp0F,IAAyBpuB,MAAMouB,IAAYA,EAAU,IAC5Dm0F,EAAazpJ,YAAW,KACpB0pJ,GAAiB,EACjBD,OAAalgJ,EACbk+B,EAAO,IAAIq2C,GAAgBd,OAC5B1nB,IAGPusB,UAAUkD,aAAaC,aAAa/G,GAC/B7/B,MAAKxwC,IACF7L,GAAOD,IAAI,sBACXilJ,GAAyByC,EAAW57I,GAC/B87I,SACyB,IAAfD,GACP1pJ,aAAa0pJ,GAEjBjiH,EAAQ55B,OAGf4zC,OAAM3iD,IACHkD,GAAO2T,KAAM,wCAAuC7W,KAASD,KAAKF,UAAUu/E,MAC5E,MAAMw4C,EAAa,IAAI34C,GAAgBj/E,EAAOo/E,EAAaurE,GAEtDE,SACyB,IAAfD,GACP1pJ,aAAa0pJ,GAEjBhiH,EAAOgvF,IAGPA,EAAWzsH,OAASgzE,IACpB+pE,GAAyByC,OAAWjgJ,SAmBxDogJ,mBACI,OAAKR,GAAAA,cAIE,IAAI5hH,SAAQ,CAACC,EAASC,KACzB0hH,GAAAA,cACIv7I,IACI45B,EAAQ55B,MAEZ/O,IACI4oC,EAAO5oC,SATR0oC,QAAQE,OAAO,IAAIjmC,MAAM,sCAyBxCooJ,oBAAiD,IAA/BC,EAA+B,uDAAZ,GAAIj8I,EAAQ,uCAC7C,MAAMk8I,EAAiB,GAEjBC,EAAuBF,EAAiB5uC,SAAS,SACjDgsC,EACAr5I,GAAUA,EAAOs5I,iBAAiBhoJ,OAAS,EAE7C6qJ,IAAyB9C,GACzB6C,EAAepqJ,KAAK,SAGxB,MAAMsqJ,EAAuBH,EAAiB5uC,SAAS,SACjDksC,EACAv5I,GAAUA,EAAOw5I,iBAAiBloJ,OAAS,EAMjD,OAJI8qJ,IAAyB7C,GACzB2C,EAAepqJ,KAAK,SAGjBoqJ,EAqBXG,+BAA+B1sJ,GAC3B,MAAM,QACF+3D,KACG40F,GACH3sJ,EAEE4sJ,EAAuB,GAYvBC,EAA4B,WAK9B,IAFwC,KAFtBF,EAAansE,SAAW,IAE1Bl9E,QAAQ,WAGpB,OAAO0mC,QAAQC,UAGnB,MAAM,2BACF6iH,GACAH,EAIJ,GAAIG,EAA4B,CAC5B,MAAMC,EACAzD,IAAoBA,GAAiBhhJ,MAAK+hJ,GACxB,eAAhBA,EAAO7zE,OACC6zE,EAAOC,WAAawC,GACrBzC,EAAOG,QAAUsC,KAEhC,IAAKC,EACD,OAAO/iH,QAAQE,OAAO,IAAIq2C,GACtB,CAAE9zE,KAAM,+BACR,GACA,CAAEqgJ,KAIV,MAAMR,EAAmB,CAAE,SACrB5rE,EAAc,CAChBG,MAAO,CACHypE,SAAUyC,EAAezC,WAMjC,OAAOrqJ,KAAK+rJ,cAAcM,EAAkB5rE,EAAa3oB,GACpDlX,MAAKxwC,IACK,CACHyqH,WAAY,SACZzqH,OAAAA,MAKhB,OAAOpQ,KAAKmsJ,oBACdvrJ,KAAKZ,MAqDD+sJ,EAA6B,WAC/B,MACMC,GADYN,EAAansE,SAAW,CAAE,QAAS,UACXx5E,QAAOqjJ,GAAqB,UAAXA,GAAiC,UAAXA,IAEjF,IAAK4C,EAAwBtrJ,OACzB,OAAOqoC,QAAQC,UAGnB,MAAMy2C,EAjkBlB,WAA+C,IAAvB+oE,EAAuB,uDAAlB,GAAIzpJ,EAAc,uDAAJ,GAGvC,MAAM0gF,EAAcw/C,IAAAA,CAAUlgI,EAAQ0gF,aAAegoE,IAErD,GAAIe,EAAGnmJ,QAAQ,UAAY,EAAG,CAE1B,GAAIs5B,GAAAA,QAAY58B,EAAQw1F,YAAa,CACjC,MAAMroF,EAAIyvB,GAAAA,QAAY58B,EAAQw1F,YAE9B9U,EAAYG,MAAM/jD,OAAS,CAAE6rH,MAAOx7I,EAAE2vB,QACtC4jD,EAAYG,MAAMhkD,MAAQ,CAAE8rH,MAAOx7I,EAAE0vB,OAuBzC,GApBK6jD,EAAYG,QACbH,EAAYG,MAAQ,IAOpBr7C,GAAQ4hD,kBACJ1G,EAAYG,MAAM/jD,QAAU4jD,EAAYG,MAAM/jD,OAAO6rH,MACrDjoE,EAAYG,MAAM/jD,OAAS,CAAE6rH,MAAOjoE,EAAYG,MAAM/jD,OAAO6rH,OAE7DnkJ,GAAO2T,KAAK,8DAEZuoE,EAAYG,MAAMhkD,OAAS6jD,EAAYG,MAAMhkD,MAAM8rH,MACnDjoE,EAAYG,MAAMhkD,MAAQ,CAAE8rH,MAAOjoE,EAAYG,MAAMhkD,MAAM8rH,OAE3DnkJ,GAAO2T,KAAK,8DAGhBnY,EAAQktJ,eACRxsE,EAAYG,MAAMypE,SAAWtqJ,EAAQktJ,mBAClC,CACH,MAAMC,EAAantJ,EAAQmtJ,YAAcC,GAEzC1sE,EAAYG,MAAMssE,WAAaA,QAGnCzsE,EAAYG,OAAQ,EAsBxB,OAnBI4oE,EAAGnmJ,QAAQ,UAAY,GAClBo9E,EAAYqY,OAAsC,kBAAtBrY,EAAYqY,QACzCrY,EAAYqY,MAAQ,IAGxBrY,EAAYqY,MAAQ,CAChB0gC,iBAAkBwvB,KAAeH,GACjCwB,SAAUtqJ,EAAQqtJ,YAClB1zB,kBAAmBovB,KAAeD,GAClClvB,kBAAmBovB,KAAcF,IAGjCtvB,IACAn5H,OAAOqmC,OAAOg6C,EAAYqY,MAAO,CAAE2gC,aAAc,KAGrDh5C,EAAYqY,OAAQ,EAGjBrY,EAigBqB4sE,CAAeL,EAAyBN,GAI5D,OAFAnoJ,GAAOiH,KAAK,0BAA2BpK,KAAKF,UAAUu/E,IAE/CzgF,KAAK+rJ,cAAciB,EAAyBvsE,EAAa3oB,IAClEl3D,KAAKZ,MA0CP,OAAO4sJ,IACFhsG,MAlGiC,SAAS0sG,GAC3C,IAAKA,EACD,OAGJ,MAAM,OAAEl9I,EAAF,SAAUwqH,EAAV,WAAoBC,GAAeyyB,EAEnCC,EAAqBn9I,EAAOs5I,iBAElC,GAAI6D,EAAmB7rJ,OAAQ,CAC3B,MAAM8rJ,EAAqB,IAAIC,YAAYF,GAE3CZ,EAAqBzqJ,KAAK,CACtBkO,OAAQo9I,EACR5yB,SAAAA,EACAC,WAAAA,EACA1iD,MAAOq1E,EAAmB9D,iBAAiB,KAInD,MAAMgE,EAAqBt9I,EAAOw5I,iBAElC,GAAI8D,EAAmBhsJ,OAAQ,CAC3B,MAAMisJ,EAAqB,IAAIF,YAAYC,GAE3Cf,EAAqBzqJ,KAAK,CACtBkO,OAAQu9I,EACR/yB,SAAAA,EACAC,WAAAA,EACA1iD,MAAOw1E,EAAmB/D,iBAAiB,GAC3CnkD,UAAW3oE,GAAU,UAAVA,cAqElB8jB,KAAKmsG,GACLnsG,MAlC6B,SAASgtG,GACvC,IAAKA,EACD,OAGJ,MAAMC,EAAcD,EAASlE,iBAE7B,GAAImE,EAAYnsJ,OAAQ,CACpB,MAAMosJ,EAAc,IAAIL,YAAYI,GAEpClB,EAAqBzqJ,KAAK,CACtBkO,OAAQ09I,EACR31E,MAAO21E,EAAYpE,iBAAiB,GACpCqE,QAASrB,EAAaqB,UAI9B,MAAMviD,EAAcoiD,EAAShE,iBAE7B,GAAIp+C,EAAY9pG,OAAQ,CACpB,MAAMssJ,EAAc,IAAIP,YAAYjiD,GAEpCmhD,EAAqBzqJ,KAAK,CACtBkO,OAAQ49I,EACR71E,MAAO61E,EAAYpE,iBAAiB,GACpCnkD,UAAW3oE,GAAU,UAAVA,OACXixH,QAASrB,EAAaqB,cAS7BntG,MAAK,IAAM+rG,IACX3oG,OAAM3iD,IACHsrJ,EAAqBpsJ,SAAQ,IAAgB,IAAf,OAAE6P,GAAa,EACzCpQ,KAAKiuJ,gBAAgB79I,MAGlB25B,QAAQE,OAAO5oC,MAUlCuqJ,wBACI,OAAOtkE,QACHjD,UAAUkD,cACHlD,UAAUkD,aAAaskE,kBAUtCP,wBAAwB4C,GACpB,MAAmB,WAAfA,GAA0C,gBAAfA,EACpBhF,GAMS,eAAfgF,GAA8C,UAAfA,IAA2B3oH,GAAQ6hD,eAY3E6mE,gBAAgBE,GACPA,IAILA,EAAY7gD,YAAY/sG,SAAQ43E,IACxBA,EAAMp1E,MACNo1E,EAAMp1E,UAKVorJ,EAAYprJ,MACZorJ,EAAYprJ,OAMZorJ,EAAYC,SACZD,EAAYC,WAQpBC,0BACI,OAAO1C,GAAAA,cAWX2C,qBAAqBjE,GACjB,OAAKrqJ,KAAKsrJ,wBAAwB,UAK3BrC,GAAwBE,UAAUkB,GACpCzpG,MAAK,KACF+nG,GAAsB0B,EACtBzB,IAAqB,EAErBrkJ,GAAOD,IAAK,8BAA6B+lJ,KAEzC72D,GAAa37D,KAAKkD,GAAAA,QAAAA,4BACdsvH,MAZDtgH,QAAQE,OACX,IAAIjmC,MAAM,gDAqBtBk3H,2BAA2BC,GACvBwwB,GAAAA,2BAA0CxwB,GAQ9CowB,uBACI,OAAO5C,GAQX4F,oCACI,OAAOlF,GAOXmF,2CACI,OAAOnF,GAAiBz9I,MAAKw+I,GAAU9iE,QAAQ8iE,EAAOG,SAO1DkE,4BAA4BrE,GACxB,MAAML,EAAa,GACb2E,EAAa,CACf,SAAYtE,EAAOC,SACnB,KAAQD,EAAO7zE,KACf,MAAS6zE,EAAOG,MAChB,QAAWH,EAAOE,SAKtB,OAFAP,EAAW7nJ,KAAKwsJ,GAET,CAAE3E,WAAAA,GAWb4E,gBAAgBluE,EAAasiC,GACpBtiC,EAAY45C,WACb55C,EAAY45C,SAAW,IAK3B55C,EAAY45C,SACN55C,EAAY45C,SAAStzH,QACnBoG,IAAMA,EAAEsL,eAAe,gCAE3BsqG,GACAtiC,EAAY45C,SAASn4H,KAAK,CAAE0sJ,2BAA4B,WAgDpE,MCp7BMrqJ,IAAS2B,EAAAA,EAAAA,wCAKT2oJ,GAAoB,CACtB,WAAc,SACd,aAAgB,WAChB,YAAe,WAMJ,MAAMC,WAAmBnlH,MAcpCvwB,YACQslF,EACAtuF,EACA+nE,EACA42E,EACAC,EACAvpD,GACJvgB,QAGAllF,KAAKqsC,iBAAmBrsC,KAAK43B,YAC7B53B,KAAKusC,oBAAsBvsC,KAAKqtC,IAAMrtC,KAAKmqC,eAM3CnqC,KAAKivJ,WAAa,GAClBjvJ,KAAK0+F,WAAaA,EAClB1+F,KAAKuxF,YAAc,EACnBvxF,KAAK4H,KAAOonJ,EACZhvJ,KAAKm4E,MAAQA,EACbn4E,KAAKylG,UAAYA,EACjBzlG,KAAKg4B,SAAW,IAAIquC,IASpBrmE,KAAKiqF,UAAW,EAShBjqF,KAAKkvJ,uBAAyBH,EAE9B/uJ,KAAKmvJ,WAAW/+I,GAWpBg/I,+BAA+B/2H,GACvBkN,GAAQ8gD,YACRrmF,KAAKm4E,MAAMk3E,QAAUh3H,EAErBr4B,KAAKoQ,OAAOk/I,WAAaj3H,EAUjCk3H,YAAY3nJ,EAAMywB,GACd,GAAKw2H,GAAkBp2I,eAAe7Q,IAWtC,GANIywB,EACAr4B,KAAKg4B,SAAS9S,IAAItd,EAAMywB,GAExBr4B,KAAKg4B,SAASu4D,OAAO3oF,GAGrB5H,KAAKoQ,OACL,IAAK,MAAM+nE,KAASn4E,KAAKoQ,OAAOk9F,YAC5Bn1B,EAAM02E,GAAkBjnJ,IAASywB,OAZrC9zB,GAAOlD,MAAO,wBAAuBuG,KAqB7C4nJ,sBACI,GAAKxvJ,KAAKoQ,OAAV,CAOA,IAAK,MAAMxI,KAAQ5H,KAAKg4B,SAAS33B,OAE7B,IAAK,MAAMovJ,KAAczvJ,KAAKoQ,OAAOw5I,iBACjC6F,EAAWZ,GAAkBjnJ,SAASmE,EAG1C/L,KAAKkvJ,wBACLlvJ,KAAKovJ,oCAA+BrjJ,QAbpCxH,GAAO2T,KACF,GAAElY,0DAuBfmvJ,WAAW/+I,GACP,GAAIpQ,KAAKoQ,SAAWA,IAIpBpQ,KAAKoQ,OAASA,EAMVpQ,KAAKoQ,QAAQ,CACb,IAAK,MAAMxI,KAAQ5H,KAAKg4B,SAAS33B,OAC7BL,KAAKuvJ,YAAY3nJ,EAAM5H,KAAKg4B,SAAShT,IAAIpd,IAEzC5H,KAAKkvJ,wBACLlvJ,KAAKovJ,+BAA+BpvJ,KAAKkvJ,yBAQrDQ,eACI,OAAO1vJ,KAAKylG,UAMhBtE,UACI,OAAOnhG,KAAK4H,KAMhB2wF,eACI,OAAOv4F,KAAKmhG,YAAcrM,GAAUqH,MASxCqR,qBACI,OAAOxtG,KAAKm4E,OAASn4E,KAAKm4E,MAAMynB,MAMpC4F,eACI,OAAOxlG,KAAKmhG,YAAcrM,GAAU2G,MAQxCxL,UACI,MAAM,IAAIjsF,MAAM,+BAQpB2rJ,oBACI,OAAO3vJ,KAAKu4F,gBAAkBv4F,KAAKiwF,UAMvC2/D,oBACI,OAAO5vJ,KAAKoQ,OAOhBy/I,cACI,OAAO7vJ,KAAKoQ,OAASpQ,KAAKoQ,OAAO/K,GAAK,KAO1CyqJ,WACI,OAAO9vJ,KAAKm4E,MAOhB43E,gBACI,OAAO/vJ,KAAKm4E,MAAMoyE,MAOtByF,aACI,OAAOhwJ,KAAKm4E,MAAQn4E,KAAKm4E,MAAM9yE,GAAK,KAQxC4qJ,gBACI,OAAIjwJ,KAAKu4F,eACE,MAGJv4F,KAAKylG,UAAYzlG,KAAKylG,UAAY,UAS7CyqD,wBAAwB19F,GAChBxyD,KAAK0+F,YAAclsC,GACnBxyD,KAAK0+F,WAAWyxD,eAAenwJ,KAAMwyD,GAc7CuvD,OAAOvvD,GACCxyD,KAAKoQ,SACLpQ,KAAKmwJ,eAAe39F,GACpB49F,GAAAA,kBAA2B59F,EAAWxyD,KAAKoQ,SAE/CpQ,KAAKivJ,WAAW/sJ,KAAKswD,GACrBxyD,KAAKkwJ,wBAAwB19F,GAC7BxyD,KAAKqwJ,mBAAmB79F,GAW5B3B,OAAO2B,GACH,IAAK,IAAIr1C,EAAKnd,KAAKivJ,WAAYztJ,EAAI2b,EAAGzb,OAAS,EAAGF,GAAK,IAAKA,EAAG,CAC3D,MAAM2L,EAAIgQ,EAAG3b,GAERgxD,IACDxyD,KAAKswJ,eAAenjJ,GACpBijJ,GAAAA,kBAA2BjjJ,EAAG,OAE7BqlD,GAAarlD,IAAMqlD,GACpBr1C,EAAG3Z,OAAOhC,EAAG,GAIjBgxD,IACAxyD,KAAKswJ,eAAe99F,GACpB49F,GAAAA,kBAA2B59F,EAAW,OAW9C29F,eAAe39F,IAWf89F,eAAe99F,IAYf69F,mBAAmB79F,IASnB83B,UAKI,OAJAtqF,KAAKstC,qBAELttC,KAAKiqF,UAAW,EAETlgD,QAAQC,UAOnBumH,mBAQApmD,QACI,OAAInqG,KAAKoQ,OACEggJ,GAAAA,YAAqBpwJ,KAAKoQ,QAG9B,KASX05F,WACI,YAAkC,IAAvB9pG,KAAKoQ,OAAO+3I,QACZnoJ,KAAKoQ,OAAO+3I,OAc3BxhD,cAAcpV,EAAYpC,GACtB,IAAIqhE,EAAgBj/D,EAMhBhsD,GAAQsjD,8BAA0C,IAARsG,GAAuBnvF,KAAKkhG,YACtEsvD,EAAgB,GAGhBxwJ,KAAKuxF,aAAei/D,GACpBxwJ,KAAKuxF,WAAai/D,EAClBxwJ,KAAK63B,KACDupE,GACAovD,EACArhE,IAIuB,IAApBnvF,KAAKuxF,YACS,IAAlBi/D,GACAxwJ,KAAKiwF,YACJjwF,KAAKwtG,sBACTxtG,KAAK63B,KACDupE,GACAovD,GAQZC,UACI,MAAMz2B,EAAWh6H,KAAK6vJ,cAChBa,EAAU1wJ,KAAKgwJ,aAErB,OAAOh2B,GAAY02B,EAAW,GAAE12B,KAAY02B,IAAY,KAW5DC,eAAehI,GACX,OAAKyH,GAAAA,wBAAiC,UAOlCpwJ,KAAKwlG,eACEz7D,QAAQC,UAIfD,QAAQ8pG,IACJ7zI,KAAKivJ,WAAW/nJ,KACZsR,GACIA,EAAQ2wI,UAAUR,GACb3kG,OAAM3iD,IAOH,MANAkD,GAAO2T,KACH,+GAGAM,EACAnX,GACEA,QAGrBu/C,MAAK,KACF5gD,KAAK63B,KACDupE,GACAunD,MA5BL5+G,QAAQE,OACX,IAAIjmC,MAAM,iDCxc1B,MAAMO,IAAS2B,EAAAA,EAAAA,6CAMA,MAAM0qJ,WAAwB9B,GAkBzC11I,YAAY,GAYT,IAZS,SACRixI,EADQ,WAER6C,EAFQ,UAGRjqE,EAHQ,WAIRsS,EAJQ,MAKRs7D,EALQ,SAMRj2B,EANQ,WAORC,EAPQ,OAQRzqH,EARQ,MASR+nE,EATQ,UAURstB,EAVQ,QAWRsoD,EAAU,IACX,EACC7oE,MACqB,KACjB90E,EACA+nE,GAC4B,IAAMn4E,KAAK63B,KAAKivE,KAC5C7jB,EACAwiB,GAEJzlG,KAAK8wJ,sBAAuB,EAC5B,MAAMC,EAAShD,EAAQ1lJ,MAAK0E,GAAKA,EAAE+kG,UAAU9xG,QAEzC+wJ,GACA/wJ,KAAKgxJ,mBAAmBD,GAG5B,MAAME,EAAiBxrD,IAAc3oE,GAAU,UAAVA,QAC/Bq7C,EAAM+4E,cAAcD,eACpB,KAKNjxJ,KAAKmxJ,SAAW,CACZtvJ,UAAWsD,KAAK8nD,SACbgkG,EAAiB,CAAEA,eAAAA,GAAmB,IAS7CjxJ,KAAK6wJ,MAAQA,EACb7wJ,KAAK46H,SAAWA,EAChB56H,KAAK66H,WAAaA,EAIlB76H,KAAKu1F,WAAapd,EAAM+4E,cAAcr0H,OACtC78B,KAAKoxJ,qBAAuB77D,EAI5Bv1F,KAAKqxJ,aAAel5E,EAAMk1E,iBAGrBjtJ,OAAOC,KAAKL,KAAKqxJ,cAAc3vJ,QAAU+jG,IAAc3oE,GAAU,UAAVA,SACxD98B,KAAKqxJ,aAAe,CAChBx0H,OAAQs7C,EAAM+4E,cAAcr0H,OAC5BD,MAAOu7C,EAAM+4E,cAAct0H,QAInC58B,KAAKqqJ,SAAWA,EAUhBrqJ,KAAKsxJ,cAAgBvnH,QAAQC,UAS7BhqC,KAAKuxJ,YAAcrE,EAMnBltJ,KAAKwxJ,aAAc,EAKnBxxJ,KAAKyxJ,cAAe,EAOpBzxJ,KAAK0xJ,eAAgB,EAQrB1xJ,KAAK2xJ,cAAkC,KAAlB3xJ,KAAKqqJ,cAAkBt+I,EAAY/L,KAAKqqJ,SAG7DrqJ,KAAK4xJ,YAAc,KAEnB5xJ,KAAK6xJ,cAAgB,EAErB7xJ,KAAK8xJ,wBAA0BvxE,IAC3B,MAAMwxE,EAAkB/xJ,KAAK2xJ,cAE7B3xJ,KAAKgyJ,+BAA+BzxE,SAMO,IAA/BvgF,KAAK8vJ,WAAWtnH,iBACa,IAAvBxoC,KAAK2xJ,gBACXpxE,EAAQl4E,MAAK2xB,GAAKA,EAAEqwH,WAAarqJ,KAAK2xJ,sBAOf,IAApBI,QAAiE,IAAvB/xJ,KAAK2xJ,iBAE1D3xJ,KAAKwxJ,aAAc,IAQvBxxJ,KAAKu4F,gBAAkB63D,GAAAA,wBAAiC,YACxDpwJ,KAAKiyJ,4BAA8BjyJ,KAAK2wJ,eAAe/vJ,KAAKZ,MAC5DowJ,GAAAA,YACIr1H,GAAAA,QAAAA,4BACA/6B,KAAKiyJ,8BAGb7B,GAAAA,YAAqBr1H,GAAAA,QAAAA,wBAAmC/6B,KAAK8xJ,yBAE7D9xJ,KAAKkyJ,gCASTC,iCACI,OAAKnyJ,KAAK0+F,WAUH,IAAI30D,SAAQ,CAACC,EAASC,KACzBjqC,KAAK0+F,WAAW0zD,uBAAuBpyJ,MAClC4gD,KAAK5W,GAAS3oC,GAAS4oC,EAAO,IAAIjmC,MAAM3C,SAXtC0oC,QAAQC,UAqBvBqoH,6BACI,MAAMlrJ,GAASnH,KAAKsyJ,kBAEpBtyJ,KAAK63B,KAAKovE,GAAqB9/F,GAG/Bs1F,GAAWoE,c7EyIwB,EAAE5d,EAAuC97E,KAAzC,CACvC0Y,WAAY,CACR,WAAcojE,EACd97E,MAAAA,GAEJM,OAAQ,4BACRG,KAAMq5E,GAAgBC,mB6E/IOqxE,CAA4BvyJ,KAAKmhG,UAAWh6F,IACrEs1F,GAAW0D,QAAQ/+F,KAAKF,UAAU,CAC9BsL,KAAMy6F,GACN3iG,IAAK6C,KAUb+qJ,gCACSlyJ,KAAKwyJ,qCAIVxyJ,KAAKuvJ,YAAY,cAAc,KAC3BvvJ,KAAK6xJ,cAAgBvvJ,OAAOijG,YAAYt4C,MACxCjtD,KAAKqyJ,gCAGTryJ,KAAKuvJ,YAAY,gBAAgB,KAC7BvvJ,KAAKqyJ,6BACL51D,GAAWkE,oBACPne,GACA,CACI,WAAcxiF,KAAKmhG,UACnB,WAAc,QACdh6F,MAAO7E,OAAOijG,YAAYt4C,MAAQjtD,KAAK6xJ,mBAI/C7xJ,KAAKwlG,gBAAkBxlG,KAAKylG,YAAc3oE,GAAU,UAAVA,QAC1C98B,KAAKuvJ,YAAY,eAAe,KACvBvvJ,KAAKsyJ,mBACNtyJ,KAAKqyJ,iCAYrBG,mCAEI,OAAQxyJ,KAAKwlG,gBAAkBxlG,KAAKylG,YAAc3oE,GAAU,UAAVA,QAYtD21H,eAAe7yD,GACX,MAAM8yD,EAAW1yJ,KAAK2yJ,UAAU/xJ,KAAKZ,KAAM4/F,GAI3C,OAFA5/F,KAAKsxJ,cAAgBtxJ,KAAKsxJ,cAAc1wG,KAAK8xG,EAAUA,GAEhD1yJ,KAAKsxJ,cAWhBsB,kCAAkCC,EAAiB94H,GAC1C/5B,KAAK0+F,WAKV1+F,KAAK0+F,WAAWo0D,wBAAwB9yJ,MAAM4gD,KAC1CiyG,GACAxxJ,GAAS04B,EAAc,IAAI/1B,MAAM3C,MANjCwxJ,IAgBRE,gBAAgB7jE,GACRlvF,KAAK0+F,YACL1+F,KAAK0+F,WAAWs0D,oBAAoBhzJ,KAAKmhG,UAAWnhG,KAAMkvF,IAASlvF,KAAK0+F,WAAW6C,KAAKkZ,eAWhGk4C,UAAU/yD,GACN,GAAI5/F,KAAKkhG,YAActB,EACnB,OAAO71D,QAAQC,UAGnB,GAAIhqC,KAAKiqF,SACL,OAAOlgD,QAAQE,OAAO,IAAIq2C,GAAgBJ,KAG9C,IAAIx/B,EAAU3W,QAAQC,UAGtB,MAAMipH,EAAc,IAAM1uJ,GAAOiH,KAAM,QAAOxL,SAAS4/F,KAEvD,GAAI5/F,KAAKu4F,gBACEv4F,KAAKylG,YAAc3oE,GAAU,UAAVA,UAClByI,GAAQ0hD,8BAChBgsE,IAKIjzJ,KAAKkzJ,eAAiBlzJ,KAAKkzJ,cAAcR,SACzC1yJ,KAAKkzJ,cAAcR,SAAS9yD,GACrB5/F,KAAKm4E,QACZn4E,KAAKm4E,MAAMsuB,SAAW7G,QAEvB,GAAIA,EACPl/C,EAAU,IAAI3W,SAAQ,CAACC,EAASC,KAC5BgpH,IACAjzJ,KAAK4yJ,mCACD,KACQ5yJ,KAAKkzJ,eACLlzJ,KAAKmzJ,oBAMTnzJ,KAAKwvJ,sBACLxvJ,KAAKozJ,aACLpzJ,KAAKmvJ,WAAW,MAEhBnlH,MAEJC,UAEL,CACHgpH,IAGA,MAAMI,EAAgB,CAClBpG,eAAgBjtJ,KAAKszJ,cACrB/yE,QAAS,CAAEuU,GAAU2G,OACrBsyD,QAAS/tJ,KAAKkzJ,cAAgB,CAAElzJ,KAAKkzJ,eAAkB,GACvDhG,WAAYltJ,KAAKuzJ,uBAGrB7yG,EACM0vG,GAAAA,+BAAwChwJ,OAAOqmC,OAC7C,GACA4sH,EACA,CAAE5yE,YAAa,CAAEG,MAAO5gF,KAAKqxJ,iBAErC3wG,EAAUA,EAAQE,MAAK4yG,IAEnB,MAAMvwE,EAAYjjF,KAAKmhG,YAAcrM,GAAU2+D,UAAY3+D,GAAU2G,MAAQz7F,KAAKmhG,UAC5EuyD,EAAaF,EAAYnrJ,MAAKmD,GAAQA,EAAK2sE,MAAM5B,OAAS0M,IAEhE,IAAIywE,EAaA,MAAM,IAAIpzE,GAAgBH,IAU9B,OAtBIngF,KAAKmvJ,WAAWuE,EAAWtjJ,QAC3BpQ,KAAKm4E,MAAQu7E,EAAWv7E,MAIpBn4E,KAAKylG,YAAciuD,EAAWjuD,YAC9BlhG,GAAO2T,KACF,GAAElY,6CACHA,KAAKylG,UAAWiuD,EAAWjuD,WAC/BzlG,KAAKylG,UAAYiuD,EAAWjuD,WAMhCzlG,KAAKkzJ,eACLlzJ,KAAKgxJ,mBAAmBhxJ,KAAKkzJ,eAGjClzJ,KAAKivJ,WAAW/nJ,KACZysJ,GAAQvD,GAAAA,kBAA2BuD,EAAM3zJ,KAAKoQ,UAE3CpQ,KAAKmyJ,oCAIpB,OAAOzxG,EACFE,MAAK,KACF5gD,KAAK+yJ,gBAAgBnzD,GAGrB5/F,KAAKwlG,gBAAkBxlG,KAAK0+F,YAAc1+F,KAAK0+F,WAAWk1D,4BAA4B5zJ,MACtFA,KAAK63B,KAAKqmD,GAAoBl+E,SAY1CgyJ,+BAA+BzxE,GAC3B,MAAMpI,EAAQn4E,KAAK8vJ,WACbv5E,EAAQ,GAAE4B,EAAM5B,YAGtB,IAAI6zE,EAAS7pE,EAAQl4E,MAAK2xB,GAAKA,EAAEu8C,OAASA,GAAQv8C,EAAEuwH,QAAUpyE,EAAMoyE,OAASvwH,EAAEqwH,WAAarqJ,KAAKqqJ,WAEjG,IAAKD,GAAiC,YAAvBpqJ,KAAK2xJ,cAA6B,CAI7C,MAAMpH,GAASpyE,EAAMoyE,OAAS,IAAI95I,QAAQ,aAAc,IAExD25I,EAAS7pE,EAAQl4E,MAAK2xB,GAAKA,EAAEu8C,OAASA,GAAQv8C,EAAEuwH,QAAUA,IAI1DvqJ,KAAK2xJ,cADLvH,EACqBA,EAAOC,cAEPt+I,EAW7BojJ,WAAW/+I,GACP80E,MAAMiqE,WAAW/+I,GAEbA,GAEApQ,KAAK6zJ,WAAa7zJ,KAAKywJ,UACvBlsJ,GAAOynF,MAAO,qBAAoBhsF,KAAK6zJ,iBAAiB7zJ,SAExDuE,GAAOynF,MAAO,4BAA2BhsF,QAWjDgxJ,mBAAmBD,GACf/wJ,KAAKkzJ,cAAgBnC,EACrB/wJ,KAAK8zJ,gBAAkB9zJ,KAAKoQ,OAC5BpQ,KAAKmvJ,WAAWnvJ,KAAKkzJ,cAAca,YAAY/zJ,KAAK8zJ,kBACpD9zJ,KAAKm4E,MAAQn4E,KAAKoQ,OAAOk9F,YAAY,GASzC6lD,oBACQnzJ,KAAKkzJ,gBACLlzJ,KAAKkzJ,cAAcc,aACnBh0J,KAAKmvJ,WAAWnvJ,KAAK8zJ,iBACrB9zJ,KAAK8zJ,gBAAkB,KACvB9zJ,KAAKm4E,MAAQn4E,KAAKoQ,OAASpQ,KAAKoQ,OAAOk9F,YAAY,GAAK,MAehE2mD,gBACQj0J,KAAKwlG,gBACExlG,KAAKylG,YAAc3oE,GAAU,UAAVA,QACiB,mBAA7B98B,KAAKm4E,MAAM87E,gBACzBj0J,KAAKm4E,MAAM87E,gBAEXj0J,KAAKuxJ,YACCvxJ,KAAKuxJ,cAAgBpE,GACjBA,GACAA,IAWlB+G,oBAAoBnD,GACZ/wJ,KAAKkzJ,gBACLlzJ,KAAKmzJ,oBACLnzJ,KAAKkzJ,mBAAgBnnJ,GAErBglJ,GACA/wJ,KAAKgxJ,mBAAmBD,GAYhCzmE,UACI,IAAI5pC,EAAU3W,QAAQC,UAwBtB,OApBIhqC,KAAKkzJ,gBACLxyG,EAAU1gD,KAAKm0J,aAGfn0J,KAAK0+F,aACLh+C,EAAUA,EAAQE,MAAK,IAAM5gD,KAAK0+F,WAAW01D,YAAYp0J,SAGzDA,KAAKoQ,SACLpQ,KAAKozJ,aACLpzJ,KAAK6wD,UAGTu/F,GAAAA,eAAwBr1H,GAAAA,QAAAA,wBAAmC/6B,KAAK8xJ,yBAE5D9xJ,KAAKiyJ,6BACL7B,GAAAA,eAAwBr1H,GAAAA,QAAAA,4BACpB/6B,KAAKiyJ,6BAGNvxG,EAAQE,MAAK,IAAMskC,MAAMoF,YASpCipE,sBACI,GAAIvzJ,KAAKwlG,gBAAkBxlG,KAAKylG,YAAc3oE,GAAU,UAAVA,OAAkB,SAQ5D,MAAMu3H,EAAa,WAAG,EAAAr0J,KAAKm4E,OAAM+4E,mBAAd,aAAG,UAEtB,OAAImD,GAAiB,eAAgBA,EAC1BA,EAAcnH,gBAGO,IAArBltJ,KAAKuxJ,YACLvxJ,KAAKuxJ,YAMTpE,IAWfmG,cACI,OAAOtzJ,KAAK2xJ,eAAiB3xJ,KAAKqqJ,SAQtCiK,cACI,OAAQnvJ,KAAK8nD,MAAQ,IAASjtD,KAAKmxJ,SAAStvJ,UAAY,IAS5D42F,mBACI,OAAOz4F,KAAK0+F,YAAc1+F,KAAK0+F,WAAWmG,WAQ9CoxC,gBACI,OAAOj2I,KAAK4xJ,YAQhB2C,UACI,OAAIv0J,KAAKwlG,gBAAkBxlG,KAAKkhG,UAGrBlhG,KAAKwxJ,YAGsB,UAA/BxxJ,KAAK8vJ,WAAWtnH,YAA0BxoC,KAAKwxJ,YAQ1DvhE,UACI,OAAO,EAQXiR,UAEI,OAAKlhG,KAAKoQ,WAGNpQ,KAAKwlG,gBAAmBxlG,KAAK8pG,cAK7B9pG,KAAKkzJ,eAAiBlzJ,KAAKkzJ,cAAchyD,QAClClhG,KAAKkzJ,cAAchyD,WAGtBlhG,KAAKm4E,QAAUn4E,KAAKm4E,MAAMsuB,SAWtC6rD,kBACI,SAAItyJ,KAAKwlG,iBACDxlG,KAAKkhG,YAAalhG,KAAKw0J,uBAAyBx0J,KAAKylG,YAAc3oE,GAAU,UAAVA,YAItE98B,KAAKoQ,SAUKpQ,KAAKy0J,eAAiBz0J,KAAK8zJ,gBAAkB9zJ,KAAKoQ,QAEnDk9F,YAAY1hG,MAAKusE,KACxB,eAAgBA,GAA+B,SAArBA,EAAM3vC,YACzB,UAAW2vC,IAA0B,IAAhBA,EAAMynB,SAQ7C1Q,OACI,OAAOlvF,KAAKyyJ,gBAAe,GAU/B5rD,wBAAwB1X,EAAKmM,GACrBA,EAAY,IACZt7F,KAAKyxJ,cAAe,GAExB,MAAM/gB,EAAqBvhD,EAAI4sD,qBAE3B/7I,KAAK0xJ,eAAwC,cAAvBhhB,IACtBluI,YAAW,KACFxC,KAAKyxJ,eACNltJ,GAAO2T,KAAM,GAAElY,mDACTs7F,KAENmB,GAAWe,UAAU3S,UAAUtI,GAAe,CAAE,WAAcviF,KAAKmhG,eAExE,KACHnhG,KAAK0xJ,eAAgB,GAU7BgD,cAAch2D,GACV1+F,KAAK0+F,WAAaA,EAMlB,IAAK,IAAIl9F,EAAI,EAAGA,EAAIxB,KAAKivJ,WAAWvtJ,OAAQF,IACxCxB,KAAKkwJ,wBAAwBlwJ,KAAKivJ,WAAWztJ,IAUrD2yJ,UAAUpD,GACN,QAAkC,IAAvB/wJ,KAAKkzJ,oBAAmD,IAAXnC,EACpD,OAAOhnH,QAAQC,UAGnB,QAAsB,IAAX+mH,IAA2BA,EAAOj/C,UAAU9xG,MACnD,OAAO+pC,QAAQE,OAAO,IAAIjmC,MAAM,kCAGpC,IAAkC,IAA9BhE,KAAK8wJ,qBACL,OAAO/mH,QAAQE,OAAO,IAAIjmC,MAAM,mCAKpC,GAAIhE,KAAKkhG,YAAclhG,KAAKu4F,eAGxB,OAFAv4F,KAAKkzJ,cAAgBnC,EAEdhnH,QAAQC,UAGnB,MAAM00D,EAAa1+F,KAAK0+F,WAExB,OAAKA,GASL1+F,KAAK8wJ,sBAAuB,EAGrBpyD,EAAW01D,YAAYp0J,MACzB4gD,MAAK,KACF5gD,KAAKk0J,oBAAoBnD,GACrB/wJ,KAAKwlG,gBACLxlG,KAAKivJ,WAAW1uJ,SAAQozJ,GAAQvD,GAAAA,kBAA2BuD,EAAM3zJ,KAAKoQ,UAGnEsuF,EAAWk1C,SAAS5zI,SAE9B4gD,MAAK,KACF5gD,KAAK8wJ,sBAAuB,KAE/B9sG,OAAM3iD,IAMH,MAHArB,KAAK8wJ,sBAAuB,EAC5B9wJ,KAAKk0J,sBACL3vJ,GAAOlD,MAAM,sCAAuCA,GAC9CA,OA7BVrB,KAAKk0J,oBAAoBnD,GACrB/wJ,KAAKwlG,gBACLxlG,KAAKivJ,WAAW1uJ,SAAQozJ,GAAQvD,GAAAA,kBAA2BuD,EAAM3zJ,KAAKoQ,UAGnE25B,QAAQC,WAiCvB2qH,cAAcnoJ,GACVxM,KAAK4xJ,YAAcplJ,EAQvB4mJ,aASIpzJ,KAAKw0J,uBAAwB,EAE7B,IACIpE,GAAAA,gBAAyBpwJ,KAAKoQ,QADlC,QAGIpQ,KAAKw0J,uBAAwB,GASrCtzI,WACI,MAAQ,cAAalhB,KAAK6wJ,SAAS7wJ,KAAKmhG,aAQ5CyzD,SACI,OAAO50J,KAAKyyJ,gBAAe,ICx4BnC,MA+EA,GA/Ec,SAASjrJ,EAASwJ,GAgC5B,YA/BuB,IAAZxJ,QAAoD,IAAlBA,EAAQG,OAAyBjD,MAAMgD,QAAQF,EAAQG,QAChGH,EAAQG,MAAMpH,SAAQoG,IACdA,EAAMmE,SAAWnE,EAAMmE,QAAQpJ,SAC/BiF,EAAMG,MAAQ,GACdH,EAAMmE,QAAQvK,SAAQ8L,IAClBjM,OAAOC,KAAKgM,GAAQ9L,SAAQ0G,IACN,OAAdA,GAGJN,EAAMG,MAAM5E,KAAK,CACbmD,GAAIgH,EAAOhH,GACX4B,UAAAA,EACAE,MAAOkF,EAAOpF,kBAInBN,EAAMmE,SAIbnE,EAAMyB,YAAczB,EAAMyB,WAAW1G,QACrCiF,EAAMyB,WAAW7H,SAAQy9H,SACU,IAApBA,EAAUl3H,OAClBpC,MAAMgD,QAAQs2H,EAAUl3H,SACvBk3H,EAAUl3H,MAAQk3H,EAAUl3H,MAAMyC,KAAK,YAOpD,SAAgB/B,EAASwJ,IA+CpC,GArCc,SAASjJ,GACnB,MAAMP,EAAU,SAAgBO,GAiChC,YA/BuB,IAAZP,QAAoD,IAAlBA,EAAQG,OAAyBjD,MAAMgD,QAAQF,EAAQG,QAChGH,EAAQG,MAAMpH,SAAQoG,SAES,IAAhBA,EAAMG,OAAyBpC,MAAMgD,QAAQf,EAAMG,SAC1DH,EAAMmE,QAAU,GAChBnE,EAAMG,MAAMvG,SAAQqG,IAChB,MAAMiuJ,EAAQluJ,EAAMmE,QAAQotI,WAAU7rI,GAAUA,EAAOhH,KAAOuB,EAAKvB,KAEnE,GAAIwvJ,GAAS,EACTluJ,EAAMmE,QAAQ+pJ,GAAOjuJ,EAAKK,WAAaL,EAAKO,UACzC,CACH,MAAM2R,EAAM,CAAEzT,GAAIuB,EAAKvB,IAEvByT,EAAIlS,EAAKK,WAAaL,EAAKO,MAC3BR,EAAMmE,QAAQ5I,KAAK4W,cAGpBnS,EAAMG,YAIe,IAArBH,EAAMyB,YAA8B1D,MAAMgD,QAAQf,EAAMyB,aAC/DzB,EAAMyB,WAAW7H,SAAQy9H,IACU,iBAApBA,EAAUl3H,QACjBk3H,EAAUl3H,MAAQk3H,EAAUl3H,MAAM5C,MAAM,YAOrDsD,GCjFLstJ,GAAc,CAAE,QAAS,QAAS,QAClCC,GAAe/2B,GAAaA,EAAU31H,MAAK2sJ,GAAyB,QAAlBA,EAAIzsJ,YACtD0sJ,GAAej3B,GAAaA,EAAU31H,MAAK2sJ,GAAyB,QAAlBA,EAAIzsJ,YAW5D,SAAS2sJ,GAAmBvuJ,EAAOwB,EAAUgtJ,EAAcC,GACvD,IAAKzuJ,IAAUwB,EACX,OAEJ,MAAMktJ,EAAiBv8I,GAAOs8I,EAAW/sJ,MAAKgE,GAAUA,EAAOhH,GAAG6b,aAAepI,IAEjF3Q,EAASrB,MAAMvG,SAAQuY,IACnBnS,EAAMmE,QAAQ5I,KAAKmzJ,EAAev8I,IAGlC,MAAMw8I,EAAkBH,EAAa1sJ,SAASqQ,EAAK,KAAKzQ,MAAK2sJ,GAAyB,QAAlBA,EAAIzsJ,YAExE,GAAI+sJ,EAAiB,CACjB,MAAMC,EAAcD,EAAgBxuJ,MAAMuB,MAAKwE,GAAKA,IAAMiM,IAE1DnS,EAAMmE,QAAQ5I,KAAKmzJ,EAAeE,IAClC5uJ,EAAMyB,WAAWlG,KAAKozJ,OAK9B3uJ,EAAMyB,WAAWlG,KAAKiG,GAgB1B,SAASqtJ,GAAkB7uJ,EAAOC,EAAMuuJ,EAAcC,GAClD,IAAKzuJ,IAAUC,EACX,OAMJ,GAJAD,EAAMmE,QAAU,GAChBnE,EAAMyB,WAAa,IAGd+sJ,EAAavuJ,EAAKvB,IAInB,OAHAsB,EAAMmE,QAAQ5I,KAAK0E,QACnBD,EAAMmD,KAAOlD,EAAKkD,MAItB,MAGM3B,EAAW4sJ,GAAaI,EAAavuJ,EAAKvB,KAC1CoF,EAAWwqJ,GAAaE,EAAavuJ,EAAKvB,KAGhD,GAAI8C,EACA+sJ,GAAmBvuJ,EAAOwB,EAAUgtJ,EAAcC,QAC/C,GAAI3qJ,EAAU,CAEjB,MAAMgrJ,EAAYhrJ,EAAS3D,MAAMuB,MAAKwE,GAAKA,IAAMjG,IAC3C8uJ,EAAYX,GAAaI,EAAaM,IAExCC,EACAR,GAAmBvuJ,EAAO+uJ,EAAWP,EAAcC,IAGnD3qJ,EAAS3D,MAAMvG,SAAQuY,IACnBnS,EAAMmE,QAAQ5I,KAnBH4W,CAAAA,GAAOs8I,EAAW/sJ,MAAKgE,GAAUA,EAAOhH,GAAG6b,aAAepI,IAmBlDu8I,CAAev8I,OAEtCnS,EAAMyB,WAAWlG,KAAKuI,IAK9B9D,EAAMmD,KAAOnD,EAAMmE,QAAQ,GAAGhB,KAqDlC,SAAS6rJ,GAA0B/uJ,EAAMuuJ,EAAcS,GASnD,IAAKA,EAAOvtJ,MARc8tE,KAClBA,EAAMrrE,SACCqrE,EAAMrrE,QAAQc,MAAKS,GAAUA,EAAOhH,KAAOuB,EAAKvB,OAM1B,CAGjC,IAAK8vJ,EAAavuJ,EAAKvB,IACnB,OAAO,EAEX,MAAM8C,EAAW4sJ,GAAaI,EAAavuJ,EAAKvB,KAC1CoF,EAAWwqJ,GAAaE,EAAavuJ,EAAKvB,KAEhD,OAAI8C,EACOytJ,EAAOhqJ,MAAKuqE,GAASA,EAAMrrE,SAC3BqrE,EAAMrrE,QAAQc,MAAKkN,GAAOA,EAAIzT,GAAG6b,aAAe/Y,EAASrB,MAAM,UAC/D2D,GAAY7D,EAAKvB,GAAG6b,aAAezW,EAAS3D,MAAM,KAGlD6uJ,GAFW,CAAEtwJ,GAAIoF,EAAS3D,MAAM,IAEKquJ,EAAcS,GAOlE,OAAO,EAiCJ,MAAMC,GAMTC,QAAQhgF,GACJ,IAAKA,GAA0C,iBAApBA,EAAY/tE,IAGnC,OAFA9E,QAAQiV,KAAK,mDAEN49D,EAIX,MAAMtuE,EAAU,GAAgBsuE,EAAY/tE,KAG5C,IAAKP,EAAQG,QAAUH,EAAQG,MAAMjG,OAGjC,OAFAuB,QAAQiV,KAAK,iCAEN49D,EAIX,GAAItuE,EAAQG,MAAMqb,OAAM7e,IAAqC,IAAhC2wJ,GAAYzxJ,QAAQc,EAAE+vE,OAG/C,OAFAjxE,QAAQiV,KAAK,uDAEN49D,EAGX,MAAMnuE,EAAQ,GACRouJ,EAAevuJ,EAAQG,MAE7BH,EAAQG,MAAQ,GAChBouJ,EAAax1J,SAAQoG,IACjB,MAAMiB,EAAOjB,EAAMiB,KAEnB,GAAa,gBAATA,EAIA,OAHAjB,EAAMutE,IAAM,YACZvsE,EAAMhB,EAAMutE,KAAOvtE,GAIvB,QAA2B,IAAhBgB,EAAMC,GAAuB,CACpC,MAAMouJ,EAAQ,GAAUrvJ,GAGpBqvJ,EAAMlrJ,SAAWpG,MAAMgD,QAAQsuJ,EAAMlrJ,UACrCkrJ,EAAMlrJ,QAAQvK,SAAQ8L,IAClB1F,EAAMmD,KAAOuC,EAAOvC,KAAOnD,EAAMmD,YAAcuC,EAAOvC,QAUzDksJ,EAAM5tJ,YAAezB,EAAMmD,OAC5BksJ,EAAM5tJ,WAAa,WAEhB4tJ,EAAMlsJ,KACbksJ,EAAM9hF,IAAMtsE,EACZD,EAAMC,GAAQouJ,OACPrvJ,EAAMmD,OAETnD,EAAMmE,SAAWpG,MAAMgD,QAAQf,EAAMmE,WACrCnD,EAAMC,GAAMkD,SAAWnD,EAAMC,GAAMkD,SAAW,IAAI/F,OAAO4B,EAAMmE,eAEnC,IAArBnE,EAAMyB,YAA8B1D,MAAMgD,QAAQf,EAAMyB,cAC/DT,EAAMC,GAAMQ,WAAaT,EAAMC,GAAMQ,WAAWrD,OAAO4B,EAAMyB,iBAIzEZ,EAAQG,MAAQvH,OAAOkJ,OAAO3B,GAG9B,MAAMsuJ,EAAS,GAEf71J,OAAOkJ,OAAO3B,GAAOpH,SAAQ41E,IACD,aAApBA,EAAM/pE,WACN6pJ,EAAO/zJ,KAAKi0E,EAAMjC,QAK1B1sE,EAAQqtC,OAAOt0C,SAAQ+H,IACA,WAAfA,EAAMV,OACNU,EAAM43H,KAAO+1B,EAAO1sJ,KAAK,SAKjC/B,EAAQ0uJ,aAAe,CACnBC,SAAU,MACVp4G,MAAO,KAEX,MAAMq4G,EAAS,GAAgB5uJ,GAE/B,OAAO,IAAIyE,sBAAsB,CAC7BrE,KAAMkuE,EAAYluE,KAClBG,IAAKquJ,IAYbC,cAAcvgF,EAAa7/D,EAAU,MACjC,IAAK6/D,GAA0C,iBAApBA,EAAY/tE,IAGnC,OAFA9E,QAAQiV,KAAK,mDAEN49D,EAIX,MAAMtuE,EAAU,GAAgBsuE,EAAY/tE,KAG5C,IAAKP,EAAQG,QAAUH,EAAQG,MAAMjG,OAGjC,OAFAuB,QAAQiV,KAAK,iCAEN49D,EAIX,GAAItuE,EAAQG,MAAMjG,OAAS,GAAK8F,EAAQG,MAAMqb,OAAM7e,IAAqC,IAAhC2wJ,GAAYzxJ,QAAQc,EAAE+vE,OAG3E,OAFAjxE,QAAQiV,KAAK,6CAEN49D,EAEX,MAAMwgF,EAAcrgJ,EAAU,GAAgBA,EAAQlO,KAAO,KACvDwuJ,EAtPd,SAA4BC,EAASC,GACjC,IAAKD,IAAYC,GAAoC,IAAzBD,EAAQ7uJ,MAAMjG,QAAyC,IAAzB+0J,EAAQ9uJ,MAAMjG,OACpE,OAAO,EAGX,MAAMg1J,EAAWF,EAAQ7uJ,MAAM,GACzBgvJ,EAAWF,EAAQ9uJ,MAAM,GAE/B,OAAO+uJ,EAASrZ,WAAasZ,EAAStZ,UAAYqZ,EAASpZ,SAAWqZ,EAASrZ,OA8OxDsZ,CAAmBpvJ,EAAS8uJ,GACzCO,EAAcrvJ,EAAQG,MAAM,GAAG01I,SAC/ByZ,EAAYtvJ,EAAQG,MAAM,GAAG21I,OAC7BlI,EAAiB5tI,EAAQG,MAAM,GAAG+0H,YAClC/0H,EAAQ,GAEdH,EAAQG,MAAMpH,SAAQoG,IAClB,MAAMiB,EAAOjB,EAAMiB,KAEnB,GAAa,gBAATA,EAAwB,CACxB,IAAK0uJ,IAAgBA,EAAY3uJ,MAAO,CACpC,MAAMovJ,EAAW,GAAUpwJ,GAK3B,OAHAowJ,EAAS7iF,IAAM9zE,OAAOC,KAAKsH,GAAOjG,OAAOwf,gBACzCvZ,EAAMhB,EAAMutE,KAAO6iF,GAIvB,MAAMC,EAAeV,EAAY3uJ,MAAMuwI,WAAU/zI,GAAKA,EAAEyD,OAASA,IAOjE,YALIovJ,IACAV,EAAY3uJ,MAAMqvJ,GAAgBrwJ,EAClC2vJ,EAAY3uJ,MAAMqvJ,GAAc9iF,IAAM8iF,IAO9C,MAAMC,EA/LlB,SAA8B9B,GAC1B,MAAM8B,EAAa,GAEnB,OAAK9B,GAAiBzwJ,MAAMgD,QAAQytJ,IAGpCA,EAAa50J,SAAQ+H,IACbA,EAAMxB,OAASpC,MAAMgD,QAAQY,EAAMxB,QACnCwB,EAAMxB,MAAMvG,SAAQqG,SACgB,IAArBqwJ,EAAWrwJ,KAClBqwJ,EAAWrwJ,GAAQ,IAEvBqwJ,EAAWrwJ,GAAM1E,KAAKoG,SAK3B2uJ,GAbIA,EA2LgBC,CAAqBvwJ,EAAMyB,YAK9C,GAAKzB,EAAMmE,QAUXnE,EAAMmE,QAAQvK,SAAQ,CAACqG,EAAMkzC,KAGzB,IAAKlzC,EAAKkD,KACN,OAIJ,IAAKwsJ,IAAgBA,EAAY3uJ,MAAO,CACpC,GAAIguJ,GAA0B/uJ,EAAMqwJ,EAAY72J,OAAOkJ,OAAO3B,IAC1D,OAEJ,MAAMovJ,EAAW,GAAUpwJ,GAU3B,OARAowJ,EAAS7iF,IAAM9zE,OAAOC,KAAKsH,GAAOjG,OAAOwf,WACzC61I,EAAS3qJ,UAAY0tC,GAEK,aAApBnzC,EAAMyF,UADN,WAC8C,WACpD2qJ,EAASI,gBAAaprJ,EACtBypJ,GAAkBuB,EAAUnwJ,EAAMqwJ,EAAYtwJ,EAAMmE,cACpDnD,EAAMovJ,EAAS7iF,KAAO6iF,GAM1B,GAAIpB,GAA0B/uJ,EAAMqwJ,EAAYX,EAAY3uJ,OACxD,OAIJ,MAAMyvJ,GAhTgBn0E,EAgToCr7E,GAhT1CE,EAgT6BwuJ,IA/S3CrzE,EAIPn7E,EAAKH,MAAMU,MAAKlE,GAAgB,IAAXA,EAAE8L,MAAc9L,EAAEyD,OAASq7E,IAH5C,MAFf,IAAgCn7E,EAAMm7E,EAkTtB,GAAIm0E,EAKA,OAJAA,EAAcnnJ,KAAOtJ,EAAMsJ,KAC3BmnJ,EAAchrJ,UAAY,gBAC1BopJ,GAAkB4B,EAAexwJ,EAAMqwJ,EAAYtwJ,EAAMmE,SAM7D,MAAMisJ,EAAW,GAAUpwJ,GAE3BowJ,EAAS7iF,IAAMoiF,EAAY3uJ,MAAMjG,OAAOwf,WACxC61I,EAAS3qJ,UAAY,WACrBopJ,GAAkBuB,EAAUnwJ,EAAMqwJ,EAAYtwJ,EAAMmE,SACpDwrJ,EAAY3uJ,MAAMzF,KAAK60J,WAxDvB,IAAKT,EAAa,CACd,MAAMS,EAAW,GAAUpwJ,GAE3BowJ,EAAS7iF,IAAM9zE,OAAOC,KAAKsH,GAAOjG,OAAOwf,WACzCvZ,EAAMhB,EAAMutE,KAAO6iF,MAuD/BvvJ,EAAQG,MAAQ2uJ,EAAcA,EAAY3uJ,MAAQvH,OAAOkJ,OAAO3B,GAChE,MAAMu4H,EAAO,GAEb14H,EAAQG,MAAMpH,SAAQoG,IAClBu5H,EAAKh+H,KAAKyE,EAAMutE,KACZqiF,IACA5vJ,EAAM02I,SAAWwZ,EACjBlwJ,EAAM22I,OAASwZ,EACfnwJ,EAAM+1H,YAAc0Y,MAK5B5tI,EAAQqtC,OAAOt0C,SAAQ+H,IACA,WAAfA,EAAMV,OACNU,EAAM43H,KAAOA,EAAK32H,KAAK,SAK/B/B,EAAQ0uJ,aAAe,CACnBC,SAAU,MACVp4G,MAAO,KAIXv2C,EAAQwhC,OAAOywC,iBACf,MAAM49E,EAAY,GAAgB7vJ,GAElC,OAAO,IAAIyE,sBAAsB,CAC7BrE,KAAMkuE,EAAYluE,KAClBG,IAAKsvJ,KCzeV,IAAKC,aAAAA,GAAAA,EAAAA,mBAAAA,sBAAAA,EAAAA,wBAAAA,2BAAAA,KAAAA,GAAAA,KAkBL,MAAMC,GAAqBD,GAAgBC,mBACrCC,GAA0BF,GAAgBE,wBCOhD,SAASC,GAA2B5tD,EAAY5mB,EAAWy0E,GAG9D,MAAQ,GAAE7tD,KAFqB5mB,EAAU9yE,UAAU,EAAG,KAELunJ,IAU9C,SAASC,GAA2Bv2B,GACvC,MAAMw2B,EAA4Bx2B,EAAW/9H,QAAQ,KAAO,EAE5D,GAAIu0J,GAA6B,EAC7B,MAAM,IAAI5zJ,MAAO,wBAAuBo9H,KAG5C,MAAMy2B,EAAyBz2B,EAAW/8H,OAAOuzJ,EAA2B,GAE5E,IAAK,MAAMhwJ,KAAQxH,OAAOkJ,OAAOwrF,IAC7B,GAAIltF,EAAKvD,OAAO,EAAG,KAAOwzJ,EACtB,OAAOjwJ,EAIf,MAAM,IAAI5D,MAAO,wBAAuBo9H,KAiB7B,MAAM02B,WAAuBnoD,GAOxCooD,aAAanxJ,GACT,MAAM,IAAI5C,MAAM,mBAgBpBshJ,iBAAiBpgG,EAAO+9B,GACpB,MAAM,IAAIj/E,MAAM,mBASpBg0J,kBAAkB9yG,EAAOk8E,GACrB,MAAM,IAAIp9H,MAAM,mBAQpBi0J,mBAAmBrxJ,GACf,MAAM,IAAI5C,MAAM,oBC5GjB,SAASk0J,GAAiB5vJ,GAC7B,OAAOG,SAASH,EAAMxB,MAAM5C,MAAM,KAAK,GAAI,IAQxC,SAASi0J,GAAmB7vJ,GAC/B,OAAOG,SAASH,EAAMxB,MAAM5C,MAAM,KAAK,GAAI,IAQ/C,SAASk0J,GAAczxJ,GACnB,OAAKA,EAAMG,MAIJH,EAAMG,MACRI,KAAIF,GAAYA,EAAS3B,KACzB0B,QAAO,CAACH,EAAM0D,EAAOC,IAAUA,EAAMlH,QAAQuD,KAAU0D,IACvD5I,OANM,EAaf,MAAM22J,GAOFj/I,YAAYzS,GACR,IAAKA,EACD,MAAM,IAAI3C,MAAM,sBAGpBhE,KAAK2G,MAAQA,EAUbG,YAKA,OAJK9G,KAAK2G,MAAMG,QACZ9G,KAAK2G,MAAMG,MAAQ,IAGhB9G,KAAK2G,MAAMG,MASlBA,UAAMA,GACN9G,KAAK2G,MAAMG,MAAQA,EAOnBsF,gBACA,OAAOpM,KAAK2G,MAAMyF,UAOlBA,cAAUA,GACVpM,KAAK2G,MAAMyF,UAAYA,EAOvBhE,iBAKA,OAJKpI,KAAK2G,MAAMyB,aACZpI,KAAK2G,MAAMyB,WAAa,IAGrBpI,KAAK2G,MAAMyB,WAQlBA,eAAWA,GACXpI,KAAK2G,MAAMyB,WAAaA,EAW5BkwJ,iBAAiBC,EAAY1jI,GACzB,MAAM5tB,EAAYjH,KAAK8G,MAAMuB,MACzBmwJ,GAAWA,EAAQnzJ,KAAOkzJ,GACvBC,EAAQvxJ,YAAc4tB,IAG7B,OAAO5tB,GAAaA,EAAUE,MAQlCsxJ,WAAW90B,GACF3jI,KAAK2G,MAAMG,OAAU9G,KAAK2G,MAAMG,MAAMpF,SAI3C1B,KAAK2G,MAAMG,MACL9G,KAAK2G,MAAMG,MAAMC,QAAOyxJ,GAAWA,EAAQnzJ,KAAOs+H,KAQ5D+0B,iBAAiBF,GACbx4J,KAAK8G,MAAM5E,KAAKs2J,GAWpBG,UAAUpwJ,EAAWzB,GACjB,OAAO9G,KAAKoI,WAAWC,MACnBC,GACIA,EAAMC,YAAcA,KACXzB,GAASA,IAAUwB,EAAMxB,SAS9C8xJ,WAAWrwJ,GACP,OAAOvI,KAAKoI,WAAWrB,QACnBuB,GAASA,EAAMC,YAAcA,IASrCswJ,uBAAuBtwJ,EAAWuwJ,GAC9B,OAAO94J,KAAKoI,WAAWC,MACnBC,GAASA,EAAMC,YAAcA,GACtB2vJ,GAAiB5vJ,KAAWwwJ,IAS3CC,eAAejvJ,GACX,OAAO9J,KAAK8G,MAAMuB,MACdmwJ,GAAiC,SAAtBA,EAAQvxJ,YACF,OAAT6C,GAAiB0uJ,EAAQrxJ,QAAU2C,KAOnDkvJ,eACI,OAAOZ,GAAcp4J,KAAK2G,OAQ9BsyJ,wBACI,YAAiCltJ,IAA1B/L,KAAK2G,MAAMyB,WAQtB8wJ,sBACI,MAAMj2E,EAAYjjF,KAAK2G,MAAMiB,KAE7B,GAAkB,UAAdq7E,EACA,MAAM,IAAIj/E,MACL,qCAAoCi/E,MAK7C,GAAiB,IAFAm1E,GAAcp4J,KAAK2G,OAIhC,OAAO3G,KAAK2G,MAAMG,MAAM,GAAGzB,GAI/B,GAAIrF,KAAK2G,MAAMyB,WAAY,CACvB,MAAMD,EAAWnI,KAAK24J,UAAU,OAEhC,GAAIxwJ,EACA,OAAO+vJ,GAAiB/vJ,GAE5B,MAAMsC,EAAWzK,KAAK24J,UAAU,OAEhC,GAAIluJ,EACA,OAAOytJ,GAAiBztJ,GAE5B,MAAM0uJ,EAAWn5J,KAAK24J,UAAU,UAEhC,GAAIQ,EACA,OAAOjB,GAAiBiB,IAcpCC,WAAW3vJ,GACP,MAAMgB,EAAWzK,KAAK64J,uBAAuB,MAAOpvJ,GAGpD,OAAOgB,GAAY0tJ,GAAmB1tJ,GAO1C4uJ,WACI,OAAOr5J,KAAK8G,MACPI,KAAIF,GAAYA,EAAS3B,KACzB0B,QAAO,CAACH,EAAM0D,EAAOC,IAAUA,EAAMlH,QAAQuD,KAAU0D,IAQhEgvJ,uBACI,MAAMr2E,EAAYjjF,KAAK2G,MAAMiB,KAE7B,GAAkB,UAAdq7E,EACA,MAAM,IAAIj/E,MACL,0CAAyCi/E,KAGlD,MAAMs2E,EAAav5J,KAAKq5J,WAExB,IAAK,MAAMG,KAAiBx5J,KAAKoI,WAI7B,GAAgC,QAA5BoxJ,EAAcjxJ,WACqB,WAA5BixJ,EAAcjxJ,UAAwB,CAE7C,MAAMwuE,EAAgBohF,GAAmBqB,GAEzCD,EAAW/1J,OACP+1J,EAAWl2J,QAAQ0zE,GAAgB,GAI/C,OAAOwiF,EAMXE,iBACI,OAAOr4J,KAAKF,UAAUlB,KAAK2G,MAAMyB,YAQrCsxJ,qBAAqB9yJ,GACZ5G,KAAK2G,MAAMyB,aAIhBpI,KAAK2G,MAAMyB,WAAapI,KAAK2G,MAAMyB,WAC9BrB,QAAO0qH,IAAqD,IAAxCA,EAAU3qH,MAAMzD,QAAS,GAAEuD,QAOxD+yJ,wBAAwBpxJ,GACfvI,KAAK2G,MAAMyB,aAIhBpI,KAAK2G,MAAMyB,WACLpI,KAAK2G,MAAMyB,WACRrB,QAAO0qH,GAAaA,EAAUlpH,YAAcA,KAQzDqxJ,YAAYC,EAASC,GACb95J,KAAK2G,MAAMG,OACX9G,KAAK2G,MAAMG,MAAMvG,SAAQyG,IACjBA,EAAS3B,KAAOw0J,IAChB7yJ,EAAS3B,GAAKy0J,MAW9BC,aAAazxJ,GACTtI,KAAKoI,WAAWlG,KAAKoG,IAoBtB,MAAM0xJ,GAOT5gJ,YAAY6gJ,GACRj6J,KAAKk6J,UAAY5zJ,GAAAA,MAAgB2zJ,GAWrCE,YAAYl3E,GACR,MAAMm3E,EAAiBp6J,KAAKk6J,UAAUvyJ,MACjCZ,QAAOJ,GAASA,EAAMiB,OAASq7E,IAC/B/7E,KAAIP,GAAS,IAAI0xJ,GAAU1xJ,KAEhC,OAAOyzJ,MAAAA,EAAAA,EAAkB,KAQ7BC,WACI,OAAO/zJ,GAAAA,MAAgBtG,KAAKk6J,YCrapC,MAAM31J,IAAS2B,EAAAA,EAAAA,4CAUA,MAAMo0J,GAQjBlhJ,YAAY+1E,EAAKorE,GACbv6J,KAAKmvF,IAAMA,EACXnvF,KAAKu6J,gBAAkBA,EAkB3BC,+BAA+BC,GAAa,MAExC,MAAMC,EAAc16J,KAAKmvF,IAAIyM,eAAe9G,GAAU2G,OAEtD,IAAKi/D,EAAYh5J,OACb,OAAO,EACuB,IAAvBg5J,EAAYh5J,QACnB6C,GAAOlD,MACF,GAAErB,KAAKmvF,qEAC6BurE,GAG7C,MAAM98B,EAAU,UAAG68B,EAAYN,YAAYrlE,GAAU2G,cAArC,aAAG,EAA2C,GAE9D,IAAKmiC,EAKD,OAJAr5H,GAAOynF,MACF,GAAEhsF,KAAKmvF,+DAGL,EAGX,IAAIu0C,GAAW,EAEf,IAAK,MAAM+rB,KAAciL,EAAa,CAClC,MAAM96D,EAAQ6vD,EAAWvuD,UACnBitD,EAAcsB,EAAWG,oBACzB+K,EAAWlL,EAAWhqD,YAAc3oE,GAAU,UAAVA,OAKpC89H,EACAzM,GAAenuJ,KAAKmvF,IAAI0rE,kBAAkB1M,GAGhD,IAFsBwM,IAAa/6D,GAAUg7D,EAGzC,SAIJ,MAAME,EACA96J,KAAKmvF,IAAI4rE,gBACL/6J,KAAKmvF,IAAI6rE,UAAU1zJ,UACnB,CAAEtH,KAAKmvF,IAAI8rE,eAAeC,mBAEpC,IAAKJ,EAAcp5J,OAAQ,CACvB6C,GAAOlD,MAAO,wBAAuBouJ,QAAiBzvJ,KAAKmvF,OAE3D,SAGJu0C,GAAW,EAMX9F,EAAWxxH,UAAY8yH,GAAAA,SAGvB,MAMMi8B,EAAgB,YANFL,EAAc,KAQlC,IAAK,MAAMn3B,KAAWm3B,EAElBl9B,EAAW66B,WAAW90B,GAGtB/F,EAAW86B,iBAAiB,CACxBrzJ,GAAIs+H,EACJ18H,UAAW,QACXE,MAAOg0J,IAEXv9B,EAAW86B,iBAAiB,CACxBrzJ,GAAIs+H,EACJ18H,UAAW,OACXE,MAAOsoJ,EAAWoE,aAG1B,GAAIiH,EAAcp5J,OAAS,EAAG,CAC1B,MAAM4G,EAAQ,CACVxB,MAAOg0J,EAAcvxJ,KAAK,KAC1BhB,UAAW,OAGVq1H,EAAW+6B,UAAUrwJ,EAAMC,UAAWD,EAAMxB,QAE7C82H,EAAWm8B,aAAazxJ,GAQ3BtI,KAAKmvF,IAAIpvF,QAAQwrH,YAClBvrH,KAAKmvF,IAAIisE,YAAYC,gBAAgBz9B,GAI7C,OAAO8F,EAWX43B,uBAAuBr4E,EAAWytE,GAA0B,IAAjB12B,EAAiB,uDAAN,KAClD,IAAM/2C,IAAaytE,EAGf,OAFAnsJ,GAAO2T,KAAM,yCAAwCw4I,mBAAyBztE,gBAEvE,KAEX,MAAMs4E,EAAOv7J,KAAKmvF,IAAI9pF,GAKtB,MAAiB,MAAb20H,GAAqBA,EAIjB,GAAEA,KAAYuhC,KAAQ7K,KAAW6K,IAH7B,GAAEv7J,KAAKu6J,mBAAmBt3E,KAAas4E,KAAQ7K,KAAW6K,IAe1EC,2BAA2BvnF,GAAc,QACrC,MAAMgP,EAAS,UAAGhP,EAAattE,aAAhB,aAAG,EAAoBiB,KAChC2zJ,EAAOv7J,KAAKmvF,IAAI9pF,GAChBo2J,EAAkB,IAAIp1F,IAE5B,IAAK,MAAMy3D,KAAY7pD,EAAantE,MAChC,OAAQg3H,EAAS72H,WACjB,IAAK,QACL,IAAK,QACL,IAAK,UACD62H,EAAS32H,MAAQ22H,EAAS32H,OAAU,GAAE22H,EAAS32H,SAASo0J,IACxD,MACJ,IAAK,OACD,GAAIz9B,EAAS32H,MAAO,CAChB,MAAMu0J,EAAoB59B,EAAS32H,MAAMjD,MAAM,KAE/C,IAAI81H,EAAW0hC,EAAkB,GACjC,MAAMhL,EAAUgL,EAAkB,GAG9BrkC,GAAAA,+BACGr3H,KAAKmvF,IAAItlF,mBACTo5E,IAAc6R,GAAU2G,QAGV,MAAbu+B,GAAqBA,IACrBA,EAAY,GAAEh6H,KAAKu6J,mBAAmBt3E,KAIrCw4E,EAAgBl8G,IAAImxG,KACrB12B,EAAY,GAAEA,KAAYyhC,EAAgBz2F,OAC1Cy2F,EAAgBv2I,IAAIwrI,EAAS12B,KAIrC8D,EAAS32H,MAAQnH,KAAKs7J,uBAAuBr4E,EAAWytE,EAAS+K,EAAgBz2I,IAAI0rI,SAErFnsJ,GAAO2T,KAAM,uDAAsD4lH,EAAS32H,SAQxF,IAAKnH,KAAKmvF,IAAItlF,kBACV,OAMJ,MAAM8xJ,EAAc,UAAG1nF,EAAattE,aAAhB,aAAG,EAAoByF,UAE3C,GAAIuvJ,IAAmBz8B,GAAAA,UAA2By8B,IAAmBz8B,GAAAA,SACjEjrD,EAAantE,WAAQiF,EACrBkoE,EAAa7rE,gBAAa2D,MAIvB,WACH,MAAMmwH,EAAQ,UAAGjoD,EAAattE,aAAhB,aAAG,EAAoBmD,KAC/B4mJ,EAAUx0B,GAAYA,EAASh4H,MAAM,KAAK,GAC1C4G,EAAU,IAAK,IAAIw7D,IAAJ,UAAQ2N,EAAattE,aAArB,iBAAQ,EAAoBG,aAA5B,aAAQ,EAA2BI,KAAI2F,GAAKA,EAAExH,OAEnE,IAAK,MAAMgH,KAAUvB,EAIjB,IAHmBmpE,EAAantE,MAC3BuB,MAAKzB,GAAQA,EAAKvB,KAAOgH,GAA6B,SAAnBzF,EAAKK,YAE5B,CACb,MAAM20J,EAAgB57J,KAAKs7J,uBAAuBr4E,EAAWytE,GAE7Dz8E,EAAantE,MAAM5E,KAAK,CACpBmD,GAAIgH,EACJpF,UAAW,OACXE,MAAOy0J,MAe3BC,mCAAmC/zJ,GAC/B,IAAKA,EACD,MAAM,IAAI9D,MAAM,mCAGpB,MAAMy2J,EAAc,IAAIT,GAAiBlyJ,EAAKC,KAE9C,OAAI/H,KAAKw6J,+BAA+BC,GAC7B,IAAIxuJ,sBAAsB,CAC7BrE,KAAME,EAAKF,KACXG,IAAK0yJ,EAAYJ,aAIlBvyJ,EAkBXg0J,2BAA2BC,GAAa,QAEpC,IAAKA,IAAgBA,EAAYh0J,MAAQg0J,EAAYn0J,KACjD,OAAOm0J,EAGX,MAAMtB,EAAc,IAAIT,GAAiB+B,EAAYh0J,KAC/Ci0J,EAAU,UAAGvB,EAAYN,YAAYrlE,GAAUqH,cAArC,aAAG,EAA2C,GAE1D6/D,IACAh8J,KAAKw7J,2BAA2BQ,GAChCh8J,KAAKi8J,mBAAmBD,IAG5B,MAAMp+B,EAAU,UAAG68B,EAAYN,YAAYrlE,GAAU2G,cAArC,aAAG,EAA2C,GAO9D,OALImiC,IACA59H,KAAKw7J,2BAA2B59B,GAChC59H,KAAKi8J,mBAAmBr+B,IAGrB,IAAI3xH,sBAAsB,CAC7BrE,KAAMm0J,EAAYn0J,KAClBG,IAAK0yJ,EAAYJ,aAczB4B,mBAAmBhoF,GAAc,UAC7B,IAAKojD,GAAAA,+BACD,OAGJ,MAAMvsH,EAAU,IAAK,IAAIw7D,IAAJ,UAAQ2N,EAAattE,aAArB,iBAAQ,EAAoBG,aAA5B,aAAQ,EAA2BI,KAAI2F,GAAKA,EAAExH,OAC7D49E,EAAS,UAAGhP,EAAattE,aAAhB,aAAG,EAAoBiB,KAEtC,IAAKq7E,EACD,MAAM,IAAIj/E,MAAM,8DAGpB,IAAK,MAAMqI,KAAUvB,EACEmpE,EAAantE,MAAMuB,MAAKzB,GAAQA,EAAKvB,KAAOgH,GAA6B,SAAnBzF,EAAKK,aAI1EgtE,EAAantE,MAAM5E,KAAK,CACpBmD,GAAIgH,EACJpF,UAAW,OACXE,MAAOswJ,GAA2Bz3J,KAAKu6J,gBAAiBt3E,EAAW,MC5WvF,MAAM1+E,IAAS2B,EAAAA,EAAAA,yCAef,SAASg2J,GAA0Bv1J,EAAOw1J,EAAiBC,GACvD,MAAM3yJ,EAAc0yJ,EAAgB92J,GAC9BuE,EAAkBuyJ,EAAgBryJ,KAClCH,EAAmBwyJ,EAAgBhxJ,MAEnCkxJ,EAAkB11J,EAAMyyJ,WAAW3vJ,GAErC4yJ,IAAoBD,IAGpBC,IAGA11J,EAAM8xJ,WAAW4D,GACjB11J,EAAM+yJ,qBAAqB2C,IAE/B11J,EAAM+xJ,iBAAiB,CACnBrzJ,GAAI+2J,EACJn1J,UAAW,QACXE,MAAOwC,IAEXhD,EAAM+xJ,iBAAiB,CACnBrzJ,GAAI+2J,EACJn1J,UAAW,OACXE,MAAOyC,IAEXjD,EAAMozJ,aAAa,CACfxxJ,UAAW,MACXzB,MAAQ,GAAE2C,KAAe2yJ,OAYlB,MAAME,GAIjBljJ,cAKIpZ,KAAKu8J,sBAAwB,IAAIl2F,IAQrCr+D,iBACIhI,KAAKu8J,sBAAsBn1F,QAS/Bn/D,aAAau0J,GACTj4J,GAAOynF,MAAM,yBAA0BwwE,GACvCx8J,KAAKu8J,sBAAwBC,EAUjCC,eAAeC,GACX,IAAIh5B,GAAW,EACf,MAAMi5B,EAAiB,IAAI3C,GAAiB0C,GACtCE,EAAcD,EAAexC,YAAYrlE,GAAU2G,OAEzD,GAAKmhE,MAAAA,IAAAA,EAAal7J,OAGd,OAFA6C,GAAOynF,MAAO,sCAAqC0wE,KAE5CA,EAGX,IAAK,MAAM9+B,KAAcg/B,EACjB58J,KAAKq7J,gBAAgBz9B,KACrB8F,GAAW,GAInB,OAAOA,EAAWi5B,EAAetC,WAAaqC,EAUlDrB,gBAAgBz9B,GACZ,GAAIA,EAAWxxH,YAAc8yH,GAAAA,SACzB,OAAO,EAEX,GAAItB,EAAWo7B,eAAiB,EAC5B,OAAO,EAEX,MAAM6D,EAAoBj/B,EAAW07B,uBAErC,IAAK,MAAM1yJ,KAAQi2J,EAAmB,CAClC,MAAM/yJ,EAAO8zH,EAAW06B,iBAAiB1xJ,EAAM,QACzCuE,EAAQyyH,EAAW06B,iBAAiB1xJ,EAAM,SAChD,IAAIk2J,EAAuB98J,KAAKu8J,sBAAsBv3I,IAAIpe,GAE1D,IAAKk2J,EAAsB,CAMnBA,EAHgCl/B,EAAWw7B,WAAWxyJ,IAK/Bw0H,GAAAA,eAE3Bp7H,KAAKu8J,sBAAsBr3I,IAAIte,EAAMk2J,GAEzCZ,GACIt+B,EACA,CACIv4H,GAAIuB,EACJuE,MAAAA,EACArB,KAAAA,GAEJgzJ,GAKR,OAAO,EASXC,SAASL,GACL,MAAMC,EAAiB,IAAI3C,GAAiB0C,GACtCE,EAAcD,EAAexC,YAAYrlE,GAAU2G,OAEzD,GAAKmhE,MAAAA,IAAAA,EAAal7J,OAGd,OAFA6C,GAAOynF,MAAO,sCAAqC0wE,KAE5CA,EAGX,IAAK,MAAM9+B,KAAcg/B,EACrB,GAAIh/B,EAAWxxH,YAAc8yH,GAAAA,UACtBtB,EAAWo7B,gBACXp7B,EAAWq7B,wBAAyB,CACvC,MAAM+D,EAAYp/B,EAAWg7B,WAAW,OAGxCh7B,EAAW+7B,wBAAwB,OAGnC,IAAK,MAAMlvJ,KAAYuyJ,EAAW,CAC9B,MAAMZ,EAAUjE,GAAmB1tJ,GAEnCmzH,EAAW66B,WAAW2D,IAKlC,OAAOO,EAAetC,YClM9B,MAAM91J,IAAS2B,EAAAA,EAAAA,4CASA,MAAM+2J,GAOjB7jJ,YAAYy+H,GACR73I,KAAKk9J,sBACLl9J,KAAK63I,UAAYA,EAQrBqlB,sBACIl9J,KAAKk7J,kBAAoB,KACzBl7J,KAAKm9J,gBAAiB,EAU1BC,eAAe3zJ,GACX,GAA2B,iBAAhBA,EACP,MAAM,IAAIzF,MAAM,kCAEpBhE,KAAKk7J,kBAAoBzxJ,EAO7B4zJ,uBACI,OAAO/1E,QAAQtnF,KAAKk7J,mBAcxBoC,gCAAgCZ,GAAQ,MACpC,MAAMC,EAAiB,IAAI3C,GAAiB0C,GACtC9+B,EAAU,UAAG++B,EAAexC,YAAYrlE,GAAU2G,cAAxC,aAAG,EAA8C,GAEjE,IAAKmiC,EAGD,OAFAr5H,GAAOynF,MAAO,GAAEhsF,KAAK63I,gDAAgD6kB,KAE9DA,EAGX,GAA6B,aAAzB9+B,EAAWxxH,UAGPpM,KAAKk7J,mBAAqBl7J,KAAKm9J,eAC/Bv/B,EAAW86B,iBAAiB,CACxBrzJ,GAAIrF,KAAKk7J,kBACTj0J,UAAW,QACXE,MAAQ,YAAWnH,KAAKk7J,sBAG5B32J,GAAOiH,KAAM,GAAExL,KAAK63I,8DAErB,CACH,MAAM0lB,EAAiB3/B,EAAWs7B,sBAElC,IAAKqE,EAGD,OAFAh5J,GAAOiH,KAAM,GAAExL,KAAK63I,6DAEb6kB,EAEX,GAAI18J,KAAKk7J,kBAAmB,CACxBt9B,EAAWg8B,YAAY2D,EAAgBv9J,KAAKk7J,mBAC5C,IAAK,MAAM5yJ,KAASs1H,EAAWx1H,WAC3B,GAAwB,QAApBE,EAAMC,UAAqB,CAC3B,MAAMkB,EAAcyuJ,GAAiB5vJ,GAC/B8zJ,EAAUjE,GAAmB7vJ,GAG/BmB,IAAgB8zJ,IAChBj1J,EAAMxB,MACC,GAAE9G,KAAKk7J,qBAAqBkB,WAK/Cp8J,KAAKk7J,kBAAoBqC,EAE7Bv9J,KAAKm9J,gBAAiB,EAG1B,OAAOR,EAAetC,YCrGf,MAAMmD,GASjBpkJ,YAAYrZ,GACRC,KAAKwgH,SAAWzgH,EAChBC,KAAKy9J,WAAa,IAAIp3F,IAEjBrmE,KAAKwgH,SAASn5G,cACfrH,KAAKwgH,SAASn5G,YAhCI,GA2CzBq2J,oBAAoB/2J,GACjB,MAAMutE,EAAMvtE,EAAMutE,IACZypF,EAAc39J,KAAKy9J,WAAWz4I,IAAIkvD,GAClC0pF,EAAW59J,KAAKkI,gBAAgBvB,GAChCuC,EAAUlJ,KAAK69J,kBAAkBl3J,EAAOi3J,EAAS,GAAI,QACrDz0J,EAAWnJ,KAAK69J,kBAAkBl3J,EAAOi3J,EAAS,GAAI,SAE5Dj3J,EAAMG,MAAQ,GACdH,EAAMyB,WAAa,GAEnB,IAAK,MAAMxB,KAAQ+2J,EACfh3J,EAAMG,MAAM5E,KAAK,CACbmD,GAAIuB,EACJK,UAAW,OACXE,MAAO+B,IAEXvC,EAAMG,MAAM5E,KAAK,CACbmD,GAAIuB,EACJK,UAAW,QACXE,MAAOgC,IASf,OALAxC,EAAMyB,WAAWlG,KAAK,CAClBqG,UAAW,MACXzB,MAAO62J,EAAYp0J,KAAK,OAGrB5C,EAWXm3J,8BAA8Bn3J,EAAmC8C,GAC7D,MAAM0B,EAAQnL,KAAK69J,kBAAkBl3J,EAAO8C,EAAa,SACzD,IAAIK,EAAO9J,KAAK69J,kBAAkBl3J,EAAO8C,EAAa,QACtD,MAAMs0J,EAA0B,CAACp3J,EAAmCC,KAChED,EAAMG,MAAM5E,KAAK,CACbmD,GAAIuB,EACJK,UAAW,QACXE,MAAOgE,IAEXxE,EAAMG,MAAM5E,KAAK,CACbmD,GAAIuB,EACJK,UAAW,OACXE,MAAO2C,KAOVA,IACDA,EAAOnD,EAAMmD,KACQnD,EAAMG,MAEdvG,SAAQqG,IACjBD,EAAMG,MAAM5E,KAAK,CACbmD,GAAIuB,EAAKvB,GACT4B,UAAW,OACXE,MAAO2C,QAMnB,MAAMC,EAAW,GAEjB,IAAK,IAAIvI,EAAI,EAAGA,EAAIxB,KAAKwgH,SAASn5G,YAAc,IAAK7F,EAAG,CACpD,MAAMwI,EAAUhK,KAAKg+J,gBAErBD,EAAwBp3J,EAAOqD,GAC/BD,EAAS7H,KAAK8H,GASlB,OANArD,EAAMyB,WAAazB,EAAMyB,YAAc,GACvCzB,EAAMyB,WAAWlG,KAAK,CAClBqG,UAAW,MACXzB,MAAO2C,EAAc,IAAMM,EAASR,KAAK,OAGtC5C,EAQXq3J,gBAGI,OAAO/zJ,KAAKC,MAFA,WAEMD,KAAKE,UAW3B0zJ,kBAAkBl3J,EAAmCC,EAAcC,GAA4C,QAC3G,iBAAOF,EAAMG,aAAb,iBAAO,EAAauB,MAChBrB,GAAY8H,OAAO9H,EAAS3B,MAAQuB,GACjCI,EAASC,YAAcJ,WAF9B,aAAO,EAEuCM,MASlDe,gBAAgBvB,GAA0D,QACtE,MAAMwB,EAAQ,UAAGxB,EAAMyB,kBAAT,aAAG,EAAkBC,MAAKC,GAA6B,QAApBA,EAAMC,YAEvD,OAAIJ,EACOA,EAASrB,MAAM5C,MAAM,KAAKgD,KAAIN,GAAQkI,OAAOlI,KAGxD,UAAID,EAAMG,aAAV,OAAI,EAAapF,OACN,CAAEoN,OAAOnI,EAAMG,MAAM,GAAGzB,KAG5B,KAYX8G,sBAAsB2pE,GAClB,IAAKA,IAAgBA,EAAY/tE,IAC7B,OAAO+tE,EAEX,MAAMtuE,EAAUlB,GAAAA,MAAgBwvE,EAAY/tE,KAE5C,IAAK,IAAIJ,KAASH,EAAQG,MAAO,WAE7B,GAAIA,EAAMyE,YAAc8yH,GAAAA,UAA2Bv3H,EAAMyE,YAAc8yH,GAAAA,SACnE,SAIJ,GAAIv3H,EAAMC,OAASktF,GAAU2G,MACzB,SAEJ,MAAMvnB,EAAMvsE,EAAMusE,IACZ7pE,EAAW,IAAIi8D,IAAJ,UAAQ3+D,EAAMb,aAAd,aAAQ,EAAaI,KAAIF,GAAYA,EAAS3B,MACzDmF,EAAS,oBAAG7C,EAAMS,kBAAT,aAAG,EAAkB1G,cAArB,QAA+B,EAC9C,IAAI+H,EAGJ,KAAsB,IAAlBY,EAAS26D,MAAc36D,EAAS26D,KAAO,GAAwB,IAAlB36D,EAAS26D,MAA4B,IAAdx6D,GAAxE,CAGA,GAAsB,IAAlBH,EAAS26D,KAAY,OACrBv7D,EAAcqF,OAAM,UAACnH,EAAMb,MAAM,UAAb,aAAC,EAAgBzB,QAClC,CACH,MAAMoF,EAAW9C,EAAMS,WAAWC,MAAKC,GAA6B,QAApBA,EAAMC,YAElDkC,IACAhB,EAAcqF,OAAOrE,EAAS3D,MAAM5C,MAAM,KAAK,KAIvD,GAAIlE,KAAKy9J,WAAWl+G,IAAI20B,GACpBvsE,EAAQ3H,KAAK09J,oBAAoB/1J,OAC9B,CACHA,EAAQ3H,KAAK89J,8BAA8Bn2J,EAAO8B,GAClD,MAAMwB,EAAiBjL,KAAKkI,gBAAgBP,GAG5C3H,KAAKy9J,WAAWv4I,IAAIgvD,EAAKjpE,KAIjC,OAAO,IAAIgB,sBAAsB,CAC7BrE,KAAMkuE,EAAYluE,KAClBG,IAAKzB,GAAAA,MAAgBkB,KAU7BkD,uBAAuBorE,GACnB,IAAKA,IAAgBA,EAAY/tE,IAC7B,OAAO+tE,EAGX,MAAMtuE,EAAUlB,GAAAA,MAAgBwvE,EAAY/tE,KAE5C,IAAK,MAAMJ,KAASH,EAAQG,MAAO,OAC/B,GAAIA,EAAMC,OAASktF,GAAU2G,MACzB,SAGJ,GAAI9zF,EAAMyE,YAAc8yH,GAAAA,SACpB,SAKJ,GAAI,UAACv3H,EAAMS,kBAAP,QAAC,EAAkB1G,QAAWiG,MAAAA,IAAAA,EAAOb,MAAMpF,OAC3C,SAIJ,MAAMu8J,EAAc,IAAI33F,IAAI3+D,EAAMb,MAAMnC,SAClCu5J,EAAmB,IAAI53F,IAAI3+D,EAAMS,WAAWzD,SAC5Cq4J,EAAYr1J,EAAMS,WAAWrB,QAAOuB,GAA6B,QAApBA,EAAMC,YACnDJ,EAAWR,EAAMS,WAAWC,MAAKC,GAA6B,QAApBA,EAAMC,YAChDkB,EAActB,MAAAA,OAAH,EAAGA,EAAUrB,MAAM5C,MAAM,KAAK,GAG/C,GAAI84J,EAAUt7J,QAAUyG,EAAU,CAC9B,MAAMsC,EAAWuyJ,EAAU30J,MAAKC,GAASA,EAAMxB,MAAM22G,SAASh0G,KACxDstE,EAAgBtsE,EAAS3D,MAAM5C,MAAM,KAAK,GAEhD,IAAK,MAAM85H,KAAar2H,EAAMS,WACtB41H,IAAcvzH,GACdyzJ,EAAiB3tE,OAAOytC,GAGhC,IAAK,MAAMp3H,KAAQe,EAAMb,MACjBF,EAAKvB,GAAG6b,aAAezX,GACpB7C,EAAKvB,GAAG6b,aAAe61D,GAC1BknF,EAAY1tE,OAAO3pF,QAKxB,GAAIuB,EAAU,CACjB+1J,EAAiB3tE,OAAOpoF,GAExB,IAAK,MAAMvB,KAAQe,EAAMb,MACjBF,EAAKvB,GAAG6b,aAAezX,GACvBw0J,EAAY1tE,OAAO3pF,GAK/Be,EAAMb,MAAQpC,MAAMm6F,KAAKo/D,GACzBt2J,EAAMS,WAAa1D,MAAMm6F,KAAKq/D,GAGlC,OAAO,IAAIjyJ,sBAAuB,CAC9BrE,KAAMkuE,EAAYluE,KAClBG,IAAKzB,GAAAA,MAAgBkB,MC3S1B,IAAK22J,aAAAA,GAAAA,EAAAA,OAAAA,SAAAA,EAAAA,SAAAA,WAAAA,EAAAA,YAAAA,cAAAA,EAAAA,UAAAA,aAAAA,KAAAA,GAAAA,KAkCZ,MAAM55J,IAAS2B,EAAAA,EAAAA,2DA2BR,MAAMk4J,GA+EoB,8BACrBC,EACA12D,EACAC,EACAC,GAGJ,OAAID,EAGOu2D,GAAqB/2D,OAI5B7hE,GAAQ2iD,qCACH2f,EAGMw2D,EACA12D,EAAsBw2D,GAAqB72D,YAAc62D,GAAqB52D,UAGlF42D,GAAqB92D,SALjB82D,GAAqB/2D,OAS7Bi3D,EAAuBF,GAAqB/2D,OAAS+2D,GAAqB92D,SAcxD,8BAACO,EAAuBC,GACjD,OAAKtiE,GAAQ2iD,qCAKN0f,IAAiBC,EAClBs2D,GAAqB/2D,OAAS+2D,GAAqB72D,YAJ9C62D,GAAqB/2D,OAqBpChuF,YAAYsoF,EAAUhD,EAA6BvmB,EAAyBp4E,GAKxEC,KAAK0hG,IAAMA,EACX1hG,KAAK0+F,WAAaA,EAClB1+F,KAAKm4E,MAAQA,EAEbn4E,KAAKs+J,eAAiB,KACtBt+J,KAAKmoG,kBAAoB,KACzBnoG,KAAKu+J,mBAAqB,GAC1Bv+J,KAAKw+J,WAAa,KAElBx+J,KAAKy+J,6BAA+E,iBAAzC1+J,EAAQ0+J,6BAC7C1+J,EAAQ0+J,6BApL2B,IAsLzCz+J,KAAKioG,kBAAyD,iBAA9BloG,EAAQkoG,kBAClCloG,EAAQkoG,kBAlLe,KAoL7BjoG,KAAKkoG,eAAmD,iBAA3BnoG,EAAQmoG,eAC/BnoG,EAAQmoG,eAhLW,IAiLzB3jG,GAAOiH,KAAM,0BAAyBxL,KAAKkoG,kBAS/CK,yBACI,MAAM64B,EAAaphI,KAAKm4E,MAAM89D,gBAE9B,OAAOj2I,KAAK0hG,IAAI28D,qBAAqBj9B,GAC/BphI,KAAKkoG,eACLloG,KAAK0+F,WAAW8J,cAAgBxoG,KAAKioG,kBAAoBjoG,KAAKy+J,6BAMxE70H,OAEI5pC,KAAK2oG,aAAe3oG,KAAK0+J,yBAAyB99J,KAAKZ,MACvDA,KAAK0+F,WAAWn0D,GAAG2wC,EAAsBmC,WAAYr9E,KAAK2oG,cAG1D3oG,KAAK6oG,YAAc7oG,KAAK8oG,WAAWloG,KAAKZ,MACxCA,KAAK0+F,WAAWn0D,GAAG2wC,EAAsBqD,UAAWv+E,KAAK6oG,aAIrDtjE,GAAQ2iD,uCAERloF,KAAK+oG,iBAAmB/oG,KAAKgpG,gBAAgBpoG,KAAKZ,MAClDA,KAAK0hG,IAAI9pE,YAAYmD,GAAAA,QAAAA,kBAA6B/6B,KAAK+oG,kBAEvD/oG,KAAKipG,mBAAqBjpG,KAAKkpG,kBAAkBtoG,KAAKZ,MACtDA,KAAK0hG,IAAI9pE,YAAYmD,GAAAA,QAAAA,oBAA+B/6B,KAAKipG,oBAGzDjpG,KAAKqpG,yBAA2BrpG,KAAKspG,wBAAwB1oG,KAAKZ,MAClEA,KAAKm4E,MAAM5tC,GAAG62D,GAAqCphG,KAAKqpG,0BAGxDrpG,KAAKupG,yBAA2BvpG,KAAKwpG,wBAAwB5oG,KAAKZ,MAClEA,KAAKm4E,MAAM5tC,GAAG62D,GAA0CphG,KAAKupG,2BAGjEvpG,KAAK2+J,2BAA6B3+J,KAAK4+J,0BAA0Bh+J,KAAKZ,MACtEA,KAAK0+F,WAAWn0D,GAAG2wC,EAAsB5/C,0BAA2Bt7B,KAAK2+J,4BAEzE3+J,KAAK0pG,qBAAuB1pG,KAAK0+J,yBAAyB99J,KAAKZ,MAC/DA,KAAK0hG,IAAIn3D,GAAGxP,GAAAA,QAAAA,oBAA+B/6B,KAAK0pG,sBAMpDpf,UACQ/kD,GAAQ2iD,uCACRloF,KAAK0hG,IAAIv3D,eAAepP,GAAAA,QAAAA,kBAA6B/6B,KAAK+oG,kBAC1D/oG,KAAK0hG,IAAIv3D,eAAepP,GAAAA,QAAAA,oBAA+B/6B,KAAKipG,oBAE5DjpG,KAAKm4E,MAAM9qC,IAAI+zD,GAAqCphG,KAAKqpG,2BAG7DrpG,KAAK0+F,WAAWrxD,IAAI6tC,EAAsB5/C,0BAA2Bt7B,KAAK2+J,4BAC1E3+J,KAAK0+F,WAAWrxD,IAAI6tC,EAAsBmC,WAAYr9E,KAAK2oG,cAC3D3oG,KAAK0+F,WAAWrxD,IAAI6tC,EAAsBqD,UAAWv+E,KAAK6oG,aAC1D7oG,KAAK0hG,IAAIv3D,eAAepP,GAAAA,QAAAA,oBAA+B/6B,KAAK0pG,sBAE5D1pG,KAAKuC,eACLvC,KAAK4pG,yBACL5pG,KAAK6+J,mCAAmC15J,KAAK8nD,OAC7CjtD,KAAK0+J,2BAOTI,uBAAuB70D,GACnB,GAAIjqG,KAAKm4E,MAAM4mF,4BAA8B90D,EAAW,CAEpD,MAAMm3B,EAAaphI,KAAKm4E,MAAM89D,gBAE9Bj2I,KAAKm4E,MAAM6mF,yBAAyB/0D,GAEpC1lG,GAAOynF,MAAO,+BAA8B7mF,KAAK8nD,UAAUm0E,MAAen3B,KAG1ExN,GAAW0D,QACP/+F,KAAKF,UAAU,CACXmE,GAAI,yBACJ8yE,MAAOipD,EACPnyC,OAAQgb,KAGhBjqG,KAAKm4E,MAAMtgD,KAAKupE,GAAiD6I,IAQzE1nG,eACQvC,KAAKw+J,aACLl8J,OAAOC,aAAavC,KAAKw+J,YACzBx+J,KAAKw+J,WAAa,MAO1B50D,yBACI5pG,KAAKmoG,kBAAoB,KAW7BN,qBACI,IAAKtiE,GAAQ2iD,qCACT,OAAO,EAGX,MAAM+2E,EAAkBj/J,KAAKm4E,MAAMq1B,qBAC7BrF,EAAoBnoG,KAAKmoG,kBACzBrwC,EAAU93D,KAAKuoG,yBAErB,OAAO02D,GAAgD,iBAAtB92D,GAAmChjG,KAAK8nD,MAAQk7C,GAAsBrwC,EAM3G4mG,2BACI,MAAMt9B,EAAaphI,KAAKm4E,MAAM89D,gBACxBxrC,EAAYzqG,KAAK0+F,WAAW8J,cAC5BkC,EAAsB1qG,KAAK2qG,uBAC3BC,EAA+C,IAA/B5qG,KAAK0+F,WAAWmM,WAIhCjD,EAAe5nG,KAAKm4E,MAAM+oB,WAAa0J,EACvC/C,EAAqB7nG,KAAK6nG,qBAC1Bw2D,EAAuBr+J,KAAK0hG,IAAI28D,qBAAqBj9B,GAErDr2B,EACAN,EACI2zD,GAAyBpzD,uBACvBpD,EACAC,GACFu2D,GAAyBnzD,uBACvBozD,EACA3zD,EACA9C,EACAC,GAGRkD,IAAaozD,GAAqB52D,WAClCvnG,KAAKkrG,uBAGT3mG,GAAOynF,MACF,8BAA6Bo1C,sBAC1Bx5B,yBACAC,eACA4C,8BACA4zD,iCACAr+J,KAAKm4E,MAAM4mF,gCAAgCh0D,KAEnD,MAAMm0D,EAAqBl/J,KAAKu+J,oBAAsB,GAItD,KAAM,QAASW,MACN,oBAAqBA,IACvBA,EAAmB7kE,MAAQoQ,GAC3By0D,EAAmBC,kBAAoBp0D,EAAU,CAEpD,MAAMM,EAAQlmG,KAAK8nD,MAEnBjtD,KAAK6+J,mCAAmCxzD,GAExCrrG,KAAKu+J,mBAAqB,IACnBW,EACHC,gBAAiBp0D,EACjB1Q,IAAKoQ,EACLc,UAAWF,GAKT,cAAerrG,KAAKu+J,qBACtBv+J,KAAKu+J,mBAAmB94D,UAAYzlG,KAAKm4E,MAAMu3E,gBAGvD1vJ,KAAK8+J,uBAAuB/zD,GAQhC8zD,mCAAmCxzD,GAC/B,MAAM+zD,EAAuBp/J,KAAKu+J,mBAE9Ba,GACG,cAAeA,GACf,cAAeA,GACf,oBAAqBA,GACrB,QAASA,IACZA,EAAqBj4J,MAAQkkG,EAAQ+zD,EAAqB7zD,UAC1D9O,GAAWoE,cvF1GwB,eAAEhhF,EAAF,uDAAuB,GAAvB,MAAiC,CAC5EjY,KAAMq5E,GAAgBC,iBACtB70E,OAAQ,yBACR5E,OAAQ,WACRoY,WAAAA,GuFsGiCw/I,CAAgCD,KAYjER,4BAGiC,IAFzBU,EAEyB,uDAFW,GACpCC,EACyB,uDADY,GACrC19J,EAAyB,uCAE7B,MAAMu/H,EAAaphI,KAAKm4E,MAAM89D,gBAE9B1xI,GAAOynF,MAAO,oCAAmCszE,eAC7CC,QAA+B19J,KAK9B0jC,GAAQ2iD,sCACTloF,KAAK0+J,2BAGLY,EAAwB7hD,SAAS2jB,KACjCphI,KAAKm4E,MAAMqnF,yCACXx/J,KAAKkrG,uBACL3lE,GAAQ2iD,sCAAwCloF,KAAK0+J,4BAGrDa,EAAyB9hD,SAAS2jB,KAElCphI,KAAKm4E,MAAMsnF,qCAAqC59J,GAChD0jC,GAAQ2iD,sCAAwCloF,KAAK0+J,4BAO7DxzD,uBACI,MAAMY,EAAS9rG,KAAKs+J,eAEhBxyD,IACAvpG,aAAaupG,GACb9rG,KAAKs+J,eAAiB,MAa9B3zD,uBACI,MAAM+0D,EAAmC1/J,KAAKm4E,MAAMwnF,uCAEpD,SAAID,GACIv6J,KAAK8nD,MAAQyyG,GA3cK,OAidX1/J,KAAKs+J,iBAGhBt+J,KAAKs+J,eAAiB97J,YAAW,IAAMxC,KAAK0+J,4BApdtB,OAudnB,GAIXkB,gBAAgBznF,GACZ,OAAOA,EAAM89D,kBAAoBj2I,KAAKm4E,MAAM89D,gBAOhDntC,WAAWzjG,GACHrF,KAAKm4E,MAAMsgB,qBAAuBpzF,IAClCrF,KAAK6+J,mCAAmC15J,KAAK8nD,OAC7CjtD,KAAKu+J,mBAAqB,IASlCv1D,gBAAgB7wB,GACZ,IAAKn4E,KAAK4/J,gBAAgBznF,GACtB,OAGJ,MAAMipD,EAAajpD,EAAM89D,gBAKzB,GAHA1xI,GAAOynF,MAAO,6BAA4Bo1C,IAAcj8H,KAAK8nD,OAE7DjtD,KAAKmoG,kBAAoBhjG,KAAK8nD,OACzBkrB,EAAM+oB,UAAW,CAGlBlhG,KAAKuC,eAGL,MAAMu1D,EAAU93D,KAAKuoG,yBAErBvoG,KAAKw+J,WAAal8J,OAAOE,YAAW,KAChC+B,GAAOynF,MAAO,6BAA4Bo1C,QAAiBtpE,QAC3D93D,KAAKuC,eACLvC,KAAK0+J,6BACN5mG,IASXoxC,kBAAkB/wB,GACd,IAAKn4E,KAAK4/J,gBAAgBznF,GACtB,OAGJ,MAAMipD,EAAaphI,KAAKm4E,MAAM89D,gBAE9B1xI,GAAOynF,MAAO,+BAA8Bo1C,IAAcj8H,KAAK8nD,OAE/DjtD,KAAKuC,eACLvC,KAAK4pG,yBAEL5pG,KAAK0+J,2BASTp1D,wBAAwBnxB,GACpB,IAAKn4E,KAAK4/J,gBAAgBznF,GACtB,OAGJ,MAAMipD,EAAaphI,KAAKm4E,MAAM89D,gBAE9B1xI,GAAOynF,MAAO,8CAA6Co1C,IAAcjpD,EAAM+oB,WAE/ElhG,KAAK0+J,2BAQTl1D,wBAAwB5hG,GACpB,MAAMyjG,EAAQlmG,KAAK8nD,MAEnBjtD,KAAK6+J,mCAAmCxzD,GAExCrrG,KAAKu+J,mBAAqB,IACnBv+J,KAAKu+J,oBAAsB,GAC9B94D,UAAW79F,EACX2jG,UAAWF,IAKvB,YC/nBM9mG,GAASi1B,EAAAA,IAAAA,6CAETuB,GAAYvB,EAAQ,KAE1B,IAAIqmI,IAA2B,EAC3BC,IAA2B,EAM/B,MAAMC,GAAkB,CAAE,QAAS,iBAAkB,QAAS,SAO/C,MAAMC,WAAyBlR,GAoB1C11I,YACQsoF,EACAhD,EACAuhE,EACA7vJ,EACA+nE,EACA8K,EACAwiB,EACA7+F,EACAg5F,EACArQ,EACA6xC,GAaJ,GAZAl8C,MACIwZ,EACAtuF,EACA+nE,GACA,QAGA8K,EACAwiB,GACJzlG,KAAK0hG,IAAMA,EAGS,iBAAT96F,EACP,MAAM,IAAImkC,UAAW,QAAOnkC,qBAEhC5G,KAAK4G,KAAOA,EACZ5G,KAAKigK,gBAAkBA,EACvBjgK,KAAK4/F,MAAQA,EACb5/F,KAAKuvF,MAAQA,EACbvvF,KAAK4xJ,YAAcxwB,EACnBphI,KAAKkgK,sBAAwB,KAC7BlgK,KAAKmgK,0BAA4B,KAQjCngK,KAAKogK,kCAAoC,KAEzCpgK,KAAKqsC,iBAAmBrsC,KAAKuqC,GAAKvqC,KAAKqgK,kBAAkBz/J,KAAKZ,MAC9DA,KAAKusC,oBAAsBvsC,KAAKqtC,IAAMrtC,KAAKsgK,qBAAqB1/J,KAAKZ,MAErEuE,GAAOynF,MAAO,2BAA0BhsF,QAKxCA,KAAKugK,aAAe3gE,EAGhB5/F,KAAK0hG,KAAO1hG,KAAKm4E,OACjBn4E,KAAKwgK,qBAETxgK,KAAKygK,mBAAqB,GAC1BV,GAAgBx/J,SAAQ+3B,IACpBt4B,KAAKygK,mBAAmBnoI,GAASt4B,KAAK0gK,uBAAuB9/J,KAAKZ,KAAMs4B,MAUhFkoI,qBACIxgK,KAAKm4E,MAAM9rC,iBAAiB,QAAQ,IAAMrsC,KAAK2gK,iBAC/C3gK,KAAKm4E,MAAM9rC,iBAAiB,UAAU,IAAMrsC,KAAK4gK,mBACjD5gK,KAAKm4E,MAAM9rC,iBAAiB,SAAS,KACjC9nC,GAAOynF,MAAO,mBAAkB7mF,KAAK8nD,WAAWjtD,WAWxDqgK,kBAAkB/nI,EAAOD,GACrB6sD,MAAMttD,YAAYU,EAAOD,GAErBg/F,GAAAA,gCACG/+F,IAAU8oE,IACVphG,KAAKosC,cAAcg1D,MAClBphG,KAAKmgK,4BAETngK,KAAK6gK,4BACLt8J,GAAOynF,MAAO,wCAAuChsF,KAAK4xJ,gBAUlE0O,qBAAqBhoI,EAAOD,GACxB6sD,MAAM/6C,eAAe7R,EAAOD,GAExBg/F,GAAAA,gCACG/+F,IAAU8oE,KACTphG,KAAKosC,cAAcg1D,MAEvBphG,KAAK8gK,+BACLv8J,GAAOynF,MAAO,qCAAoChsF,KAAK4xJ,gBAW/D+O,eACIp8J,GAAOynF,MAAO,kBAAiB7mF,KAAK8nD,WAAWjtD,QAE/CA,KAAK0hG,IAAIlO,aAAa37D,KAAKkD,GAAUe,kBAAmB97B,MAU5D4gK,iBACIr8J,GAAOynF,MAAO,oBAAmB7mF,KAAK8nD,WAAWjtD,QAEjDA,KAAK0hG,IAAIlO,aAAa37D,KAAKkD,GAAUiB,oBAAqBh8B,MAQ9DsqF,UAKI,OAJI+sC,GAAAA,gCACAr3H,KAAK8gK,+BAGF57E,MAAMoF,UAOjBy2E,QAAQ55J,GACAnH,KAAK4/F,QAAUz4F,IAIfA,IACAnH,KAAKugK,cAAe,GAIpBvgK,KAAKoQ,SACLpQ,KAAKoQ,OAAOwvF,MAAQz4F,GAGxBnH,KAAK4/F,MAAQz4F,EACbnH,KAAK63B,KAAKupE,GAAqCphG,OAQnDkhG,UACI,OAAOlhG,KAAK4/F,MAShBnH,mBACI,OAAOz4F,KAAKigK,gBAMhBhwE,UACI,OAAO,EASX+wE,UACI,OAAOhhK,KAAK4G,KAShBqvI,gBACI,OAAOj2I,KAAK4xJ,YAQhBqP,cAAcr5J,GACN5H,KAAKylG,YAAc79F,IAGvB5H,KAAKylG,UAAY79F,EACjB5H,KAAK63B,KAAKupE,GAA0Cx5F,IAMxDs5J,gBACI,IAAKlhK,KAAK0+F,WAAW6C,KACjB,OAGJ,MAAM35F,EAAO5H,KAAKwlG,eAAiB,QAAU,QAEvCv4C,EAAM3qD,OAAOijG,YAAYt4C,MAE/BhqD,QAAQqB,IAAK,iBAAgBsD,OAAWqlD,GACxCjtD,KAAK0+F,WAAWyiE,qBAAsB,GAAEv5J,YAAiBqlD,EAKzD,MAAMm0G,EAAW9+J,OAAOsgG,gBAAgB,2BAClCy+D,EAAS/+J,OAAOsgG,gBAAgB,yBAChC0+D,EACC53H,MAAM23H,IAAY33H,MAAM03H,GAAgC,EAApBC,EAASD,EAI9CG,EAAOt0G,GACNjtD,KAAK0+F,WAAWyiE,qBAAqB,oBAClCnhK,KAAK0+F,WAAWyiE,qBAAqB,eACzCG,ExFgOmBzhJ,IAAAA,EwF9NzB7f,KAAK0+F,WAAWyiE,qBAAsB,GAAEv5J,UAAe25J,EACvDt+J,QAAQqB,IAAK,eAAcsD,OAAW25J,GAEtC9kE,GAAWoE,exF2NchhF,EwF1NrB,CACI,WAAcjY,EACdg4F,MAAO5/F,KAAKugK,aACZp5J,MAAOo6J,GxFuNkC7+E,GAAmC,OAAQ7iE,KwF3MhGwwI,mBAAmB79F,GACVqtG,IAA4B7/J,KAAKu4F,gBAC9BunE,IAA4B9/J,KAAKwlG,iBAIrCxlG,KAAKu4F,iBACLsnE,IAA2B,GAE3B7/J,KAAKwlG,iBACLs6D,IAA2B,GAG/BttG,EAAUnmB,iBAAiB,UAAWrsC,KAAKkhK,cAActgK,KAAKZ,QASlEmwJ,eAAe39F,GACXutG,GAAgBx/J,SAAQ+3B,IACpBk6B,EAAUnmB,iBAAiB/T,EAAOt4B,KAAKygK,mBAAmBnoI,OAUlEg4H,eAAe99F,GACXutG,GAAgBx/J,SAAQ+3B,IACpBk6B,EAAUjmB,oBAAoBjU,EAAOt4B,KAAKygK,mBAAmBnoI,OASrEooI,uBAAuB94J,GACnBrD,GAAOynF,MAAO,GAAEpkF,sDAAyD5H,QAQ7EwhK,aACI,MAAM,QAAE/6D,EAAF,MAAW7G,EAAX,WAAkBp3D,GAAexoC,KAAKm4E,MAE5C,MAAQ,eAAc3vC,aAAsBo3D,eAAmB6G,IAMnEo6D,4BACI,MAAMpzJ,EAASzN,KAAK0+F,WAAW3+F,QAAQ0N,OAEvCzN,KAAKkgK,sBAAwB/B,GAAqB/2D,OAElDpnG,KAAKmgK,0BAA4B,IAAI/B,GACjCp+J,KAAK0hG,IACL1hG,KAAK0+F,WACL1+F,KACA,CAGIioG,kBAAmBx6F,EAAOg0J,6BAC1Bv5D,eAAgBz6F,EAAOi0J,8BACvBjD,6BAA8BhxJ,EAAOk0J,mCAG7C3hK,KAAKmgK,0BAA0Bv2H,OAMnCk3H,+BACQ9gK,KAAKmgK,4BACLngK,KAAKmgK,0BAA0B71E,UAC/BtqF,KAAKmgK,0BAA4B,KACjCngK,KAAKkgK,sBAAwB,MASrClB,yBAAyB/vE,GACrBjvF,KAAKkgK,sBAAwBjxE,EAWjC8vE,0BACI,OAAO/+J,KAAKkgK,sBAMhBV,yCACIx/J,KAAKogK,kCAAoC,KAQ7CX,qCAAqC59J,GACjC7B,KAAKogK,kCAAoCv+J,EAQ7C89J,uCACI,OAAO3/J,KAAKogK,kCAOhBl/I,WACI,MAAQ,uBAAsBlhB,KAAKy4F,6BAA6Bz4F,KAAKmhG,oBACjEnhG,KAAKghK,mBAAmBhhK,KAAKuvF,sBAAsBvvF,KAAK4xJ,wBAAwB5xJ,KAAKwhK,iBCndjG,MAAMj9J,IAAS2B,EAAAA,EAAAA,sCAQF07J,GAAa,KAIbC,GAAiB,CARN,IACA,IACA,KAYjB,MAAMC,GAMT1oJ,YAAYmzE,GAAgB,UACxBvsF,KAAK4sF,GAAKL,EACV,MAAMw1E,EAAe,UAAG/hK,KAAK4sF,GAAG7sF,eAAX,iBAAG,EAAiBwvI,oBAApB,aAAG,EAA+ByyB,iBACjDC,EAAmB,CACrBC,IA1BO,IA2BPC,SA1BO,IA2BPluH,KAAM2tH,IAMV5hK,KAAKoiK,cAAgBL,MAAAA,EAAAA,EAAmBE,EACxC,MAAMI,EAAgB,UAAGriK,KAAKoiK,cAAc9pC,WAAtB,QAA6Bt4H,KAAKoiK,cAexDpiK,KAAKsiK,2BAA6B,CAC9B,CACIna,QAAQ,EACR3wE,WAAYjyC,GAAQ8gD,YAAcg8E,EAAiBpuH,KAAOouH,EAAiBH,IAC3EjgD,IApDQ,IAqDRsgD,sBAAuBh9H,GAAQ8gD,YAhDhB,EACA,GAiDnB,CACI8hE,QAAQ,EACR3wE,WAAY6qF,EAAiBF,SAC7BlgD,IAzDQ,IA0DRsgD,sBApDe,GAsDnB,CACIpa,QAAQ,EACR3wE,WAAYjyC,GAAQ8gD,YAAcg8E,EAAiBH,IAAMG,EAAiBpuH,KAC1EguE,IA9DQ,IA+DRsgD,sBAAuBh9H,GAAQ8gD,YA3DhB,EADA,IAsE3Bm8E,oBAAoB7uB,GAChB,OAAI3zI,KAAK4sF,GAAGmuE,iBAAmBpnB,EAAWnuC,eAC/BxlG,KAAKsiK,2BAGT3uB,EAAWnuC,eACZ,CAAE,CACA2iD,QAAQ,EACR3wE,WAAYx3E,KAAKoiK,cAAcnuH,OAEjC,CAAE,CAAEk0G,QAAQ,IAWtBsa,0BAA0B3sF,GACtB,MAAM4sF,EAAYp8J,GAAAA,MAAgBwvE,EAAY/tE,KA4B9C,OA1BA26J,EAAU/6J,MAAMpH,SAAQoG,IACpB,GAAIA,EAAMiB,OAASktF,GAAUqH,MACzB,OAEJ,IAAKx1F,EAAMyB,aAAezB,EAAMyB,WAAW1G,OACvC,OAEJ,IAAIihK,EAAiB,GAErB,MAAM77J,EAAQ,IAAIw/D,IAElB3/D,EAAMyB,WAAWlB,KAAIoB,GACjBA,EAAMxB,MACD5C,MAAM,KACN6C,OAAOugF,SACP/mF,SAAQqG,GAAQE,EAAM64C,IAAI/4C,OAGnCE,EAAMvG,SAAQqG,IACV,MAAMkE,EAAUnE,EAAMG,MAAMC,QAAOsF,GAAUA,EAAOhH,GAAG6b,aAAeta,IAEtE+7J,EAAiBA,EAAe59J,OAAO+F,MAE3CnE,EAAMG,MAAQ67J,KAGX,IAAI12J,sBAAsB,CAC7BrE,KAAMkuE,EAAYluE,KAClBG,IAAKzB,GAAAA,MAAgBo8J,KAW7BE,gBAAgB3/E,GAA8B,IAAnB0wD,EAAmB,uDAAN,KAKpC,OAJoBA,MAAAA,GAAAA,EAAYx7D,OAASw7D,EAAWic,oBAC9C5vJ,KAAK4sF,GAAGL,eAAes2E,kBAAkBx6J,MAAKrD,IAAC,eAAI,UAAAA,EAAEksG,cAAF,mBAAU/4B,aAAV,eAAiB9yE,MAAOsuI,EAAWqc,gBACtFhwJ,KAAK4sF,GAAGL,eAAes2E,kBAAkBx6J,MAAKrD,IAAC,eAAI,UAAAA,EAAEqkC,gBAAF,mBAAY8uC,aAAZ,eAAmB5B,QAAS0M,KAezF6/E,kCAAkCh7J,GAG9B,GAAIy9B,GAAQyjD,6BACR,OAAOlhF,EAEX,MAAMC,EAAMzB,GAAAA,MAAgBwB,EAAKC,KAC3B+xC,EAAM/xC,EAAIJ,MAAMuwI,WAAU/hE,GAASA,EAAMvuE,OAASktF,GAAU2G,QAElE,GAAI1zF,EAAIJ,MAAMmyC,GAAKwnF,OAASv5H,EAAIJ,MAAMmyC,GAAKipH,cAAgBh7J,EAAIJ,MAAMmyC,GAAKkhH,WAatE,OAVAjzJ,EAAIJ,MAAMpH,SAAQ,CAAC41E,EAAO30E,KAClB20E,EAAMvuE,OAASktF,GAAU2G,OAASj6F,IAAMs4C,IACxC/xC,EAAIJ,MAAMnG,GAAG8/H,UAAOv1H,EACpBhE,EAAIJ,MAAMnG,GAAGw5J,eAAYjvJ,EAGzBhE,EAAIJ,MAAMnG,GAAGuhK,kBAAeh3J,MAI7B,IAAIE,sBAAsB,CAC7BrE,KAAME,EAAKF,KACXG,IAAKzB,GAAAA,MAAgByB,KAK7BA,EAAIJ,MAAMmyC,GAAKwnF,KAAO,CAClB,CACIj8H,GA3LQ,IA4LR+G,UAAW,QAEf,CACI/G,GA9LQ,IA+LR+G,UAAW,QAEf,CACI/G,GAjMQ,IAkMR+G,UAAW,SAOnB,MAAM42J,EAAgBz9H,GAAQ8gD,aAAe9gD,GAAQuhD,qBAAqB,IACnE,QAAO+6E,GAAet4J,KAAK,OAC3B,YAAWs4J,GAAet4J,KAAK,OAOtC,OAJAxB,EAAIJ,MAAMmyC,GAAKipH,aAAe,CAC1B57J,MAAO67J,GAGJ,IAAI/2J,sBAAsB,CAC7BrE,KAAME,EAAKF,KACXG,IAAKzB,GAAAA,MAAgByB,KAU7B6rI,SAASD,EAAYrH,GACjB,MAAMn0D,EAAQw7D,EAAWmc,WAEzB,GAAIxjB,EAAa,CACb,MAAMtK,EAAU,GAEZ2R,EAAWic,qBACX5tB,EAAQ9/H,KAAKyxI,EAAWic,qBAK5B,MAAMqT,EAAkB,CACpB72J,UAAW8yH,GAAAA,SACX8C,QAAAA,EACAkhC,cAAe,IAGd39H,GAAQ8gD,cACT48E,EAAgBC,cAAgBljK,KAAKwiK,oBAAoB7uB,IAE7D3zI,KAAK4sF,GAAGL,eAAe42E,eAAehrF,EAAO8qF,QAK7CjjK,KAAK4sF,GAAGL,eAAeqnD,SAASz7D,GAYxCirF,8BAA8BC,EAAiBC,GAC3C,MAAM3vB,EAAa0vB,EAAgBvT,YAC7B,OAAEjzH,GAAW82G,EAAWud,cAgC9B,OA/BuBlxJ,KAAKsiK,2BAC3Bp7J,KAAIq8J,GAAY1mI,EAAS0mI,EAAShB,wBAClCr7J,KAAI,CAACg0F,EAAaphD,KAAQ,MACvB,IAAIquG,EAASkb,EAAgB3T,iBAAmB5yH,GAAU,UAAVA,QAM1CwmI,EAAY,GA5QC,KA4QI,UAAAtjK,KAAKsiK,2BAA2BxoH,UAAhC,eAAsCyoH,wBAEnDrnE,GAAeooE,EAiBzB,OAPItjK,KAAK4sF,GAAG42E,yBACLxjK,KAAK4sF,GAAG/iF,oBACP07B,GAAQ4hD,iBA3RG,IA4RZnnF,KAAKsiK,2BAA2BxoH,GAAKyoH,wBACxCpa,GAAS,GAGNA,KAafsb,2BAA2BJ,GAAiB,QACxC,MAAM59D,EAAY49D,EAAgB3T,eAC5BgU,GAAsB,UAAA1jK,KAAK4sF,GAAG7sF,eAAR,mBAAiBwvI,oBAAjB,eAA+Bo0B,iBAvTxC,IAwTbC,EAAmBP,EAAgBvP,iBAClCuP,EAAgBvP,gBAAgBzuJ,KAAOg+J,EAAgBxT,cAoB9D,OAlB0B7vJ,KAAKsiK,2BAC9Bp7J,KAAIq8J,GACevjK,KAAK4sF,GAAG42E,0BAA4Bj+H,GAAQ4hD,gBAItDy8E,EAAmBhC,GAAa8B,EAKhCj+D,IAAc3oE,GAAU,UAAVA,SAAqByI,GAAQ2hD,oBAAsBlnF,KAAK4sF,GAAG/iF,uBACrEkC,EACAw3J,EAAS/rF,aAe3BmhE,aAAaC,EAAUC,GAAU,UAC7B,MAAM51D,EAAS,UAAG41D,MAAAA,OAAH,EAAGA,EAAU13C,iBAAb,QAA0By3C,MAAAA,OAA1B,EAA0BA,EAAUz3C,UAC7ChpB,EAAK,UAAG0gE,MAAAA,OAAH,EAAGA,EAAUiX,kBAAb,QAA2B,KACtC,IAAI+T,EAGJ,GAAIjrB,IAAaA,EAAS13C,UACtB2iE,EAAc7jK,KAAK4sF,GAAGL,eAAes2E,kBAAkBx6J,MAAKrD,GAAKA,EAAEksG,OAAO/4B,QAAUygE,EAASkX,kBAK1F,GAAIz4B,GAAAA,+BAAA,UACJr3H,KAAK4sF,GAAGgP,eAAe3Y,UADnB,OACJ,EAAmCvhF,SAClCm3I,EAASn6C,WACbmlE,EAAc7jK,KAAK4sF,GAAGL,eAAes2E,kBAAkBx6J,MACnDrD,GAAKA,EAAEqkC,SAAS8uC,MAAM5B,OAAS0M,GAC5Bj+E,EAAEoH,YAAc8yH,GAAAA,UAChBl6H,EAAE8+J,mBAAqB5kC,GAAAA,eAI3B,CACH2kC,EAAc7jK,KAAK4sF,GAAGL,eAAes2E,kBAAkBx6J,MAAKrD,GAAKA,EAAEqkC,SAAS8uC,MAAM5B,OAAS0M,IAE3F,MAAMm+C,EAAayX,MAAAA,OAAH,EAAGA,EAAU5C,gBAE7B,GAAI7U,EAAY,CACZ,MAAM2iC,EAAaj1J,OAAOsyH,EAAWl9H,MAAM,KAAK,GAAGiM,UAAU,IAEzD4zJ,IACAF,EAAc7jK,KAAK4sF,GAAGL,eAAes2E,kBAChC97J,QAAO/B,GAAKA,EAAEqkC,SAAS8uC,MAAM5B,OAAS0M,GAChCj+E,EAAEoH,YAAc8yH,GAAAA,WAAyB6kC,KAKhE,OAAKF,GAGLt/J,GAAOynF,MAAO,GAAEhsF,KAAK4sF,gBAAgBgsD,UAAiBC,KAE/CgrB,EAAY3yD,OAAOynC,aAAaxgE,GAClCv3B,MAAK,IAAM7W,QAAQC,QAAQ65H,MALrB95H,QAAQE,OAAO,IAAIjmC,MAAM,yBAiBxCs2I,uBAAuB6N,GACnBnoJ,KAAK+5I,uBAAuBjlD,GAAUqH,MAAOgsD,GASjD6b,aAAa7rF,GAAO,QAChB,MAAM8K,EAAY9K,EAAMgpB,UAClB0iE,EAAc7jK,KAAK4iK,gBAAgB3/E,EAAW9K,GAC9C/E,EAAaywF,MAAAA,GAAH,UAAGA,EAAa3yD,cAAhB,aAAG,EAAqB+yD,gBAKxC,OAAK7wF,MAAAA,GAAD,UAACA,EAAY8wF,iBAAb,OAAC,EAAuBxiK,QAG5B0xE,EAAW8wF,UAAYlkK,KAAKwiK,oBAAoBrqF,GAEzC0rF,EAAY3yD,OAAOizD,cAAc/wF,IAJ7BrpC,QAAQC,UAevB+vG,uBAAuB92D,EAAWklE,GAC9B,MAAMic,EAAepkK,KAAK4sF,GAAGL,eAAes2E,kBACvC97J,QAAO/B,GAAKA,EAAEqkC,UAAYrkC,EAAEqkC,SAAS8uC,OAASnzE,EAAEqkC,SAAS8uC,MAAM5B,OAAS0M,IACvEovB,EAAcryG,KAAK4sF,GAAGgP,eAAe3Y,GAE3C1+E,GAAOiH,KAAM,GAAExL,KAAK4sF,MAAMu7D,EAAS,WAAa,gBAAgBllE,qBAChEmhF,EAAa7jK,SAAQ,CAACsjK,EAAa/pH,KAC3BquG,EAEY,IAARruG,GAAau4D,EAAY3wG,OACzBmiK,EAAYz3J,UAAY8yH,GAAAA,SAExB2kC,EAAYz3J,UAAY8yH,GAAAA,SAG5B2kC,EAAYz3J,UAAY8yH,GAAAA,YAcpCsb,uBAAuB2N,GACnBnoJ,KAAK+5I,uBAAuBjlD,GAAU2G,MAAO0sD,GAWjDkc,0BAA0BjxF,GAKhB8wF,IAAAA,EAJA3+H,GAAQ4hD,iBAAmB/T,EAAW8wF,WAAax/J,MAAMgD,QAAQ0rE,EAAW8wF,cAI5EA,EAIgB9wF,EAAW8wF,WAJJlhJ,OAAMugJ,QAAsD,IAAnCA,EAAShB,uBACpDgB,EAAShB,wBAA0B2B,EAAU,GAAG3B,yBAIvDnvF,EAAW8wF,UAAU3jK,SAAQ,CAACgjK,EAAUzpH,KACpCypH,EAAShB,sBAAwBviK,KAAKsiK,2BAA2BxoH,GAAKyoH,2BC5ctF,MAAMh+J,IAAS2B,EAAAA,EAAAA,qDA+BA,SAASo+J,GAChB5iE,EACAr8F,EACAunI,EACAP,EACA5rD,EACA8O,EACAxvF,GAUJC,KAAKukK,uBAAgD,IAAxBxkK,EAAQ6mG,aAQrC5mG,KAAKwkK,iBAAcz4J,EAkBnB/L,KAAKykK,gBAAkB,GAUvBzkK,KAAK0kK,qBAAsB,EAO3B1kK,KAAK0hG,IAAMA,EAMX1hG,KAAKqF,GAAKA,EAOVrF,KAAKuvF,MAAQA,EAObvvF,KAAK2kK,aAAe,IAAIt+F,IAMxBrmE,KAAKqyG,YAAc,IAAIhsC,IAQvBrmE,KAAK4kK,cAAgB,GAoBrB5kK,KAAK6kK,WAAa,IAAIx+F,IAKtBrmE,KAAK8kK,WAAa,KAKlB9kK,KAAK+kK,YAAc,KAOnB/kK,KAAKglK,eAAiB,KAMtBhlK,KAAK4sI,eAAiBA,EAGtB5sI,KAAKilK,sBAAwBjlK,KAAKilK,sBAAsBrkK,KAAKZ,MAC7DA,KAAK4sI,eAAeriG,GAChB+sH,GACAt3J,KAAKilK,uBAETjlK,KAAKklK,kBAAoBllK,KAAKklK,kBAAkBtkK,KAAKZ,MACrDA,KAAK4sI,eAAeriG,GAChB+sH,GACAt3J,KAAKklK,mBACTllK,KAAKD,QAAUA,EAIf,MAAMolK,EAAkB1kF,GAAe,GA6CvC,GA3CA0kF,EAAgB9qC,SAAW8qC,EAAgB9qC,UAAY,GAInD31H,MAAMgD,QAAQy9J,EAAgB9qC,UAC9B8qC,EAAgB9qC,SAASn4H,KAAK,CAAEkjK,eAAgBplK,KAAKuvF,QAErDhrF,GAAO2T,KAAK,iEAGhBlY,KAAKusF,eAAiB,IAAI6jE,GAAAA,sBAA+B/jB,EAAU84B,GAEnEnlK,KAAKqlK,SAAW,IAAIvD,GAAS9hK,MAC7BA,KAAKs+I,UAAY,GACjBt+I,KAAK4zF,MAAQ,GACb5zF,KAAKslK,cAAgB,KAKrBtlK,KAAKulK,uBAAyBvlK,KAAKD,QAAQsvI,sBAK3CrvI,KAAKwlK,iBAAmBzlK,EAAQ8J,gBAMhC7J,KAAKylK,iCAAmClgI,GAAQ6iD,4BAA8BpoF,KAAKwlK,iBACnFxlK,KAAKylK,kCACElhK,GAAOiH,KAAK,mEAMnBxL,KAAKovI,SAAWrvI,EAAQqvI,SAExBpvI,KAAK0lK,QAAU,IAAI7P,GAEf71J,KAAKwlK,iBACLxlK,KAAKg7J,UAAY,IAAIwC,GAAa,CAAEn2J,YAAaw6J,GAAengK,aAC7D,CACH,MAAM0F,EAAYoyB,EAAQ,KAE1Bx5B,KAAKg7J,UAAY,IAAI5zJ,EACjB,CACIC,YAAaw6J,GAAengK,OAC5BmJ,wBAAwB,EACxBhB,iBAAiB,IAI7B7J,KAAKi7J,eAAiB,IAAIgC,GAAej9J,KAAKkhB,YAO9ClhB,KAAK2lK,eAAiB,IAAIrL,GAAet6J,KAAMA,KAAK0hG,IAAIkkE,sBAMxD5lK,KAAKwzF,aAAekO,EAAIlO,aACxBxzF,KAAKo7J,YAAc,IAAIkB,GAMvBt8J,KAAK6lK,sBAAwB,KAM7B7lK,KAAK8lK,kBAAoB,IAAIz/F,IAG7BrmE,KAAKy/I,MAAQ,CAACxmG,EAAMztC,KAChBjH,GAAOynF,MAAM/yC,EAAMztC,GAEnBxL,KAAKs+I,UAAUp8I,KAAK,CAChBy1D,KAAM,IAAIxyD,KACVyC,KAAMqxC,EACN9xC,MAAOqE,GAAQ,MAGvBxL,KAAKiwI,eAAiB,KACtBjwI,KAAKusF,eAAe0jD,eAAiB33G,IACjCt4B,KAAKy/I,MACD,iBACAr+I,KAAKF,UAAUo3B,EAAMo5C,UAAW,KAAM,MAEd,OAAxB1xE,KAAKiwI,gBACLjwI,KAAKiwI,eAAe33G,IAKxBt4B,KAAKwlK,kBACLxlK,KAAK+lK,QAAUC,IACX,MAAM51J,EAAS41J,EAAIhkC,QAAQ,GAE3BhiI,KAAKimK,kBAAkB71J,EAAQ41J,EAAI7tF,MAAO6tF,EAAInC,aAC9CzzJ,EAAOi8B,iBAAiB,eAAet/B,IACnC/M,KAAKkmK,oBAAoB91J,EAAQrD,EAAEorE,WAG3Cn4E,KAAKusF,eAAelgD,iBAAiB,QAASrsC,KAAK+lK,WAEnD/lK,KAAKusF,eAAe45E,YAAc7tI,GAASt4B,KAAKomK,mBAAmB9tI,EAAMloB,QACzEpQ,KAAKusF,eAAe85E,eAAiB/tI,GAASt4B,KAAKsmK,qBAAqBhuI,EAAMloB,SAElFpQ,KAAKqwI,uBAAyB,KAC9BrwI,KAAKusF,eAAe8jD,uBAAyB/3G,IACzCt4B,KAAKy/I,MAAM,yBAA0Bz/I,KAAKswI,gBACN,OAAhCtwI,KAAKqwI,wBACLrwI,KAAKqwI,uBAAuB/3G,IAGpCt4B,KAAKwwI,2BAA6B,KAClCxwI,KAAKusF,eAAeikD,2BAA6Bl4G,IAC7Ct4B,KAAKy/I,MAAM,6BAA8Bz/I,KAAK0wI,oBACN,OAApC1wI,KAAKwwI,4BACLxwI,KAAKwwI,2BAA2Bl4G,IAGxCt4B,KAAKixI,oBAAsB,KAC3BjxI,KAAKusF,eAAe0kD,oBAAsB34G,IACtCt4B,KAAKy/I,MAAM,uBACsB,OAA7Bz/I,KAAKixI,qBACLjxI,KAAKixI,oBAAoB34G,IAGjCt4B,KAAK+wI,wBAA0B,KAC/B/wI,KAAKusF,eAAewkD,wBAA0Bz4G,IAC1Ct4B,KAAKy/I,MAAM,0BAA2Bz/I,KAAKuwI,iBACN,OAAjCvwI,KAAK+wI,yBACL/wI,KAAK+wI,wBAAwBz4G,IAGrCt4B,KAAKumK,cAAgB,KACrBvmK,KAAKusF,eAAeg6E,cAAgBjuI,IAChCt4B,KAAKy/I,MAAM,iBACgB,OAAvBz/I,KAAKumK,eACLvmK,KAAKumK,cAAcjuI,IAIvBt4B,KAAKovI,WACLpvI,KAAKslK,cAAgBhjK,OAAOiwF,aAAY,KACpCvyF,KAAKm3F,WAAWv2C,MAAKgzC,IACjB,GAA6B,mBAAlBA,MAAAA,OAAP,EAAOA,EAAOt6D,QAAuB,CACrC,MAAMmX,EAAUmjD,EAAMt6D,SAEtB,IAAK,IAAI93B,EAAI,EAAGA,EAAIivC,EAAQ/uC,SAAUF,EAAG,CACrC,MAAMk4G,EAAMjpE,EAAQjvC,GAEpBk4G,EAAI/sG,QAAQpM,SAAQiM,IAChBxM,KAAKwmK,aAAa9sD,EAAKltG,EAAMktG,EAAI+sD,KAAKj6J,aAI9ConF,EAAMrzF,SAAQ2M,GAAKlN,KAAKwmK,aAAat5J,EAAG,GAAIA,UAGrD,MAGP3I,GAAOiH,KAAM,cAAaxL,QAY9BskK,GAAwBrjK,UAAUulK,aAC5B,SAASh6E,EAAQhgF,EAAMk6J,GACrB,MAAMrhK,EAAM,GAAEmnF,EAAOnnF,MAAMmH,IAC3B,IAAIK,EAAI7M,KAAK4zF,MAAMvuF,GACnB,MAAM4nD,EAAM,IAAI9nD,KAEX0H,IACD7M,KAAK4zF,MAAMvuF,GAAMwH,EAAI,CACjB2nF,UAAWvnC,EACX05G,QAAS15G,EACT3jD,OAAQ,GACR8hB,MAAO,KAGfve,EAAEvD,OAAOpH,KAAKwkK,GACd75J,EAAEue,MAAMlpB,KAAK+qD,EAAIuyD,WACb3yG,EAAEvD,OAAO5H,OAAS1B,KAAKovI,WACvBviI,EAAEvD,OAAO6jC,QACTtgC,EAAEue,MAAM+hB,SAEZtgC,EAAE85J,QAAU15G,GAMpB,MAAM25G,GAAU,SAAS9wF,GACrB,OAAI,MAAOA,EACA,GAGH,SAAQA,EAAYluE,WAAWkuE,EAAY/tE,OAYvDu8J,GAAwBrjK,UAAU86I,mBAAqB,WACnD,MAAMlwG,EAAQ7rC,KAAKusF,eAAemkD,mBAElC,MAAc,cAAV7kG,EACO,YAGJA,GAcXy4H,GAAwBrjK,UAAUm3I,yBAA2B,SAASn1D,GAAmC,IAAxB4jF,EAAwB,wDACrG,MAAMC,EAAiB9mK,KAAK+mK,mBAAmB9jF,GAE/C,GAAIjjF,KAAKwlK,iBACL,OAAOqB,EACDC,EAAiB5nC,GAAAA,SAA0BA,GAAAA,SAC3C4nC,EAAiB5nC,GAAAA,SAA0BA,GAAAA,SAGrD,MAAM8nC,EAAsB/jF,IAAc6R,GAAUqH,MAAQn8F,KAAKukK,oBAAsBvkK,KAAK0kK,oBAE5F,OAAIsC,EACOF,EAAiB5nC,GAAAA,SAA0BA,GAAAA,SAG/CA,GAAAA,UAUXolC,GAAwBrjK,UAAUgmK,2BAA6B,SAASC,EAAWjkF,GAC/E,IAAI0hF,EAAe,GACfwC,EAAY,GAEhB,IAAK,MAAMhqB,KAAY+pB,EACnBvC,EAAeA,EAAa5/J,OAAO/E,KAAKonK,gBAAgBjqB,EAAUl6D,IAItE,MAAMokF,EAAiB1C,EAAaz9J,KAAIk+I,IAAM,uBAAIA,EAAOjtE,aAAX,aAAI,EAAc9yE,MAOhE,OALA8hK,EAAYnnK,KAAKusF,eAAe+6E,eAC3BvgK,QAAOsiC,GAAYA,EAAS8uC,OACtB9uC,EAAS8uC,MAAM5B,OAAS0M,GACxBokF,EAAeh/J,MAAKqoJ,GAAWA,IAAYrnH,EAAS8uC,MAAM9yE,OAE9D8hK,GAQX7C,GAAwBrjK,UAAU85J,cAAgB,WAC9C,OAAQ/6J,KAAKD,QAAQ2vI,kBASzB40B,GAAwBrjK,UAAUgkK,sBAAwB,SAClDp7D,EACApE,GAEJ,IAAKoE,EAGD,YAFAtlG,GAAOlD,MAAO,GAAErB,8CAIpB,MAAMyvJ,EAAazvJ,KAAKonK,gBAAgBv9D,EAAY/U,GAAU2G,OAE1Dg0D,EAAW/tJ,QAEX+tJ,EAAW,GAAGwR,cAAcx7D,IAWpC6+D,GAAwBrjK,UAAUikK,kBAAoB,SAC9Cr7D,EACA5mB,EACAie,GAEJ,IAAK2I,EAGD,YAFAtlG,GAAOlD,MAAO,GAAErB,4CAIpB,MAAMm4E,EAAQn4E,KAAKonK,gBAAgBv9D,EAAY5mB,GAE3C9K,EAAMz2E,QAENy2E,EAAM,GAAG4oF,QAAQ7/D,IAUzBojE,GAAwBrjK,UAAUi2F,eAAiB,WAA2B,IAAlBb,EAAkB,uDAAJ,GACtE,MAAMY,EAAc,GACdswE,EAAiBlxE,EAAY30F,OAC7B1B,KAAKinK,2BAA2B5wE,EAAavB,GAAUqH,OACvDn8F,KAAKusF,eAAe+6E,eACjBvgK,QAAOsiC,GAAYA,EAAS8uC,OAAS9uC,EAAS8uC,MAAM5B,OAASue,GAAUqH,OAAS9yD,EAAS8uC,MAAMsuB,UAcxG,OAZA8gE,EAAehnK,SAAQ6kJ,IACnB,MAAMx+I,EAAOw+I,EAAOoiB,4BAEhB5gK,GAAQA,EAAKlF,SAKbu1F,EAAYrwF,EAAK,GAAGyF,QAAUzF,EAAK,GAAG2qF,eAIvC0F,GASXqtE,GAAwBrjK,UAAU26F,eAAiB,SAAS3Y,GACxD,IAAIwkF,EAAS/iK,MAAMm6F,KAAK7+F,KAAKqyG,YAAY/oG,UAMzC,YAJkByC,IAAdk3E,IACAwkF,EAASA,EAAO1gK,QAAOoxE,GAASA,EAAMgpB,YAAcle,KAGjDwkF,GAQXnD,GAAwBrjK,UAAU+0I,oBAAsB,WACpD,OAAOh2I,KAAK47F,eAAe9G,GAAU2G,QAUzC6oE,GAAwBrjK,UAAU8lK,mBAAqB,SAAS9jF,GAC5D,IAAKA,EACD,MAAM,IAAIj/E,MAAM,2BAGpB,OAAOhE,KAAK47F,eAAe3Y,GAAWvhF,OAAS,GAWnD4iK,GAAwBrjK,UAAUmmK,gBAAkB,SAASv9D,EAAY5mB,GACrE,IAAI0hF,EAAe,GACnB,MAAMuC,EAAYr9D,EAAa,CAAEA,GAAe7pG,KAAK2kK,aAAatkK,OAElE,IAAK,MAAM88I,KAAY+pB,EAAW,CAC9B,MAAMQ,EAA4B1nK,KAAK2kK,aAAa3/I,IAAIm4H,GAExD,GAAIuqB,EACA,IAAK,MAAM1Y,KAAkB0Y,EAA0BrnK,OAE9C4iF,GAAaA,IAAc+rE,IAC5B2V,EAAeA,EAAa5/J,OAAOL,MAAMm6F,KAAK6oE,EAA0B1iJ,IAAIgqI,MAM5F,OAAO2V,GASXL,GAAwBrjK,UAAUw2I,iCAAmC,SAASpyI,GAC1E,MAAMmyI,EAAiB,GACjBmtB,EAAe3kK,KAAKonK,gBAAgB/hK,GAE1C,GAAKs/J,MAAAA,IAAAA,EAAcjjK,OACf,OAAO81I,EAEX,MAAMmwB,EAAehD,EAAaz9J,KAAIixE,GAASA,EAAM6oF,YAC/Cj5J,EAAM,IAAIq3H,GAAIp/H,KAAKkxI,kBAAkBnpI,KA2B3C,OAzBA4/J,EAAapnK,SAAQ,CAACqG,EAAMkzC,KACxB,IAAK,MAAMnyC,KAASI,EAAIJ,MAAO,CAC3B,IAAI8rE,EAAQ,GACRwoD,EAAYb,GAAAA,UAAkBzzH,EAAQ,UAASf,KAEnD,GAAIq1H,EAAUv6H,OAAQ,CACb81I,EAAe19F,KAChB09F,EAAe19F,GAAO,IAI1B,MAAM8tH,EAAWxsC,GAAAA,UAAkBzzH,EAAQ,oBAAmBf,KAE9D,GAAIghK,EAASlmK,OAAQ,CACjB,MAAMq1E,EAAgB6wF,EAAS,GAAG1jK,MAAM,KAAK,GAE7CuvE,GAAU,GAAEm0F,EAAS,SACrB3rC,EAAYA,EAAUl3H,OAAOq2H,GAAAA,UAAkBzzH,EAAQ,UAASovE,MAEpEygE,EAAe19F,IAAS,GAAEmiF,EAAU1yH,KAAK,cACzCiuI,EAAe19F,IAAQ25B,OAK5B+jE,GAQX8sB,GAAwBrjK,UAAU4mK,uBAAyB,WACvD,MAAM7iB,EAAehlJ,KAAKszI,0BAE1B,OAAOtzI,KAAKqlK,SAASjD,cAAcpd,EAAajgG,gBAAkB/kD,KAAKqlK,SAASjD,eASpFkC,GAAwBrjK,UAAUq3F,eAAiB,SAAS1xF,GACxD,GAAoB,iBAATA,EACP,MAAM,IAAI5C,MAAO,QAAO4C,qBAE5B,IAAK,MAAM+sI,KAAc3zI,KAAKqyG,YAAY/oG,SACtC,GAAItJ,KAAK67F,aAAa83C,KAAgB/sI,EAClC,OAAO+sI,EAGf,IAAK,MAAMtpC,KAAerqG,KAAKonK,kBAC3B,GAAI/8D,EAAY22D,YAAcp6J,EAC1B,OAAOyjG,EAIf,OAAO,MASXi6D,GAAwBrjK,UAAUi7F,iBAAmB,SAAS72F,GAE1D,MAAMyiK,EAAgB3vF,GAASA,EAAM23E,WAAWzqJ,KAAOA,EACjDsuI,EAAa3zI,KAAK47F,iBAAiBvzF,KAAKy/J,GAE9C,GAAIn0B,EACA,OAAO3zI,KAAK67F,aAAa83C,GAG7B,MAAMtpC,EAAcrqG,KAAKonK,kBAAkB/+J,KAAKy/J,GAEhD,OAAIz9D,EACOA,EAAY22D,UAGhB,MAOXsD,GAAwBrjK,UAAUmlK,mBAAqB,SAASh2J,GAC5D,MAAM4pH,EAAW+tC,GAAI5c,YAAY/6I,GAEjC,IAAK23J,GAAIC,iBAAiBhuC,GAGtB,YAFAz1H,GAAOiH,KAAM,GAAExL,mEAAmEg6H,MAMlFz0F,GAAQ2hD,oBACR92E,EAAO63J,WAAa3vI,IAChBt4B,KAAKimK,kBAAkB71J,EAAQkoB,EAAM6/C,QAEzC/nE,EAAO83J,cAAgB5vI,IACnBt4B,KAAKkmK,oBAAoB91J,EAAQkoB,EAAM6/C,SAK/C,MAAMgwF,EAAoB/3J,EAAOs5I,iBAEjC,IAAK,MAAM0e,KAAcD,EACrBnoK,KAAKimK,kBAAkB71J,EAAQg4J,GAEnC,MAAMC,EAAoBj4J,EAAOw5I,iBAEjC,IAAK,MAAM6F,KAAc4Y,EACrBroK,KAAKimK,kBAAkB71J,EAAQq/I,IAgBvC6U,GAAwBrjK,UAAUglK,kBAAoB,SAAS71J,EAAQ+nE,GAA2B,IAApB0rF,EAAoB,uDAAN,KACxF,MAAM7pC,EAAW+tC,GAAI5c,YAAY/6I,GAC3B6yE,EAAY9K,EAAM5B,KAExB,IAAKv2E,KAAKuvF,QAAUw4E,GAAIC,iBAAiBhuC,GAGrC,YAFAz1H,GAAOiH,KAAM,GAAExL,mEAAmEg6H,MAOtF,GAHAz1H,GAAOiH,KAAM,GAAExL,0CAA0Cg6H,UAAiB/2C,OAGrEA,EAOD,YANAzqD,GAAqBE,iBACjB,IAAI10B,MACC,oDAAmDg2H,MAOhE,MAAMsuC,EAAYtoK,KAAKwlK,iBACjB,IAAIpmC,GAAIp/H,KAAKusF,eAAe2kD,kBAAkBnpI,KAC9C,IAAIq3H,GAAIp/H,KAAKkxI,kBAAkBnpI,KACrC,IAAIwgK,EAIJ,GAAIvoK,KAAKwlK,iBACL,GAAI3B,GAAeA,EAAY3vF,IAAK,CAChC,MAAMA,EAAM2vF,EAAY3vF,IAExBq0F,EAAaD,EAAU3gK,MAAMZ,QAAOyhK,GAAOptC,GAAAA,SAAiBotC,EAAM,SAAQt0F,YAE1Eq0F,EAAaD,EAAU3gK,MAAMZ,QAAOyhK,IAChC,MAAM1+J,EAAOsxH,GAAAA,SAAiBotC,EAAK,WAEnC,MAAuB,iBAAT1+J,GAAqBkwH,IAAalwH,EAAKqG,UAAU,GAAGjM,MAAM,KAAK,WAIrFqkK,EAAaD,EAAU3gK,MAAMZ,QAAOyhK,GAAOA,EAAI9nD,WAAY,KAAIz9B,OAGnE,IAAKslF,EAAW7mK,OAKZ,YAJA82B,GAAqBE,iBACjB,IAAI10B,MAAO,2DAA0Dg2H,UAAiB/2C,OAM9F,IAAIg5C,EAAYb,GAAAA,UAAkBmtC,EAAW,GAAI,WAIjD,GAFAtsC,EACMA,EAAUl1H,QAAOjD,IAA8C,IAAtCA,EAAKT,QAAS,QAAO22H,QAC/CiC,EAAUv6H,OAKX,YAJA82B,GAAqBE,iBACjB,IAAI10B,MAAO,4DAA2Dg2H,UAAiB/2C,OAQ/F,MAAMz6E,EAAUyzH,EAAU,GAAG9rH,UAAU,GAAGjM,MAAM,KAAK,GAC/CukK,EAAY35J,OAAOtG,GACnBy3J,EAAkBjgK,KAAK4sI,eAAemrB,aAAa0Q,GAEzD,GAAI/+H,MAAM++H,IAAcA,EAAY,EAMhC,YALAjwI,GAAqBE,iBACjB,IAAI10B,MACC,uCAAsCykK,QAAgBzuC,UAAiB/2C,OAI7E,IAAKg9E,EAMR,YALAznI,GAAqBE,iBACjB,IAAI10B,MACC,8CAA6CykK,QAAgBzuC,UAAiB/2C,OAO3F,IAAIm+C,EAEA/J,GAAAA,iCACA+J,EAAaphI,KAAK4sI,eAAeqrB,mBAAmBwQ,GAI/CrnC,IACDA,EAAaq2B,GAA2BwI,EAAiBh9E,EAAW,KAK5E1+E,GAAOiH,KAAM,GAAExL,uCAAuCigK,UAAwBwI,UAChExlF,gBAAwBm+C,MAEtC,MAAMikB,EACArlJ,KAAK4sI,eAAe0Y,iBAAiB2a,EAAiBh9E,GAE5D,IAAKoiE,EAID,YAHA7sH,GAAqBE,iBACjB,IAAI10B,MAAO,GAAEhE,0CAA0CigK,MAK/D,MAAMrgE,EAAQylD,EAAczlD,MACtB6F,EAAY4/C,EAAc5/C,UAGhCzlG,KAAK0oK,mBACDzI,EAAiB7vJ,EAAQ+nE,EAAO8K,EAAWwiB,EAAWgjE,EAAW7oE,EAAOwhC,IAmBhFkjC,GAAwBrjK,UAAUynK,mBAAqB,SAC/CzI,EACA7vJ,EACA+nE,EACA8K,EACAwiB,EACA7+F,EACAg5F,EACAwhC,GACJ,IAAIunC,EAAkB3oK,KAAK2kK,aAAa3/I,IAAIi7I,GAEvC0I,IACDA,EAAkB,IAAItiG,IACtBsiG,EAAgBzjJ,IAAI4vE,GAAUqH,MAAO,IAAI71B,KACzCqiG,EAAgBzjJ,IAAI4vE,GAAU2G,MAAO,IAAIn1B,KACzCtmE,KAAK2kK,aAAaz/I,IAAI+6I,EAAiB0I,IAG3C,MAAMC,EAAwBD,EAAgB3jJ,IAAIi+D,GAElD,GAAI2lF,MAAAA,GAAAA,EAAuB5jG,MACpBtgE,MAAMm6F,KAAK+pE,GAAuBvgK,MAAKklG,GAAcA,EAAWuiD,aAAe33E,IAIlF,YAFA5zE,GAAOiH,KAAM,GAAExL,0DAA0DigK,UAAwBh9E,MAG9F,GAAI2lF,MAAAA,GAAAA,EAAuB5jG,OAASqyD,GAAAA,+BAA6C,CACpF9yH,GAAOlD,MAAO,GAAErB,0DAA0DigK,UAAwBh9E,iCAElG,MAAM4lF,EAAgBnkK,MAAMm6F,KAAK+pE,GAAuB,GAIxD5oK,KAAKkmK,oBAAoB2C,EAAcjZ,oBAAqBiZ,EAAc/Y,YAG9E,MAAMzlD,EACA,IAAI21D,GACEhgK,KAAK0hG,IACL1hG,KAAK0hG,IAAIhD,WACTuhE,EACA7vJ,EACA+nE,EACA8K,EACAwiB,EACA7+F,EACAg5F,EACA5/F,KAAKuvF,MACL6xC,GAEZwnC,EAAsBjpH,IAAI0qD,GAC1BrqG,KAAKwzF,aAAa37D,KAAKkD,GAAAA,QAAAA,mBAA8BsvE,EAAarqG,OAUtEskK,GAAwBrjK,UAAUqlK,qBAAuB,SAASl2J,GAC9D,IAAK23J,GAAIe,aAAa14J,GAAS,CAC3B,MAAM/K,EAAK0iK,GAAI5c,YAAY/6I,GAI3B,YAFA7L,GAAOiH,KAAM,uDAAsDnG,MAMvE,MAAMgjK,EAAoBj4J,EAAOw5I,iBAEjC,IAAK,MAAM6F,KAAc4Y,EACrBroK,KAAKkmK,oBAAoB91J,EAAQq/I,GAErC,MAAM0Y,EAAoB/3J,EAAOs5I,iBAEjC,IAAK,MAAM0e,KAAcD,EACrBnoK,KAAKkmK,oBAAoB91J,EAAQg4J,IAWzC9D,GAAwBrjK,UAAUilK,oBAAsB,SAAS91J,EAAQ+nE,GACrE,MAAM6hD,EAAW+tC,GAAI5c,YAAY/6I,GAC3BsgJ,EAAUv4E,GAAS4vF,GAAI3c,WAAWjzE,GAExC,IAAK4vF,GAAIC,iBAAiBhuC,GAGtB,YAFAz1H,GAAOiH,KAAM,GAAExL,qEAAqEg6H,MAKxF,IAAKA,EAGD,YAFAxhG,GAAqBE,iBAAiB,IAAI10B,MAAO,GAAEhE,oDAKvD,IAAK0wJ,EAGD,YAFAl4H,GAAqBE,iBAAiB,IAAI10B,MAAO,GAAEhE,mDAKvD,MAAM+oK,EAAc/oK,KAAKonK,kBAAkB/+J,MACvCgiG,GAAeA,EAAYwlD,gBAAkB71B,GAC1C3vB,EAAY2lD,eAAiBU,IAE/BqY,GAMLxkK,GAAOiH,KAAM,GAAExL,uCAAuCg6H,aAAoB02B,MAC1E1wJ,KAAKgpK,mBAAmBD,IANpBvwI,GAAqBE,iBAAiB,IAAI10B,MAAO,GAAEhE,wDAe3DskK,GAAwBrjK,UAAUgoK,mBAAqB,SAAS/jH,GAC5D,IAAIgkH,EAAgB,GACpB,MAAMC,EAAsBnpK,KAAK2kK,aAAa3/I,IAAIkgC,GASlD,OAPIikH,IACAD,EAAgBA,EAAcnkK,OAAOL,MAAMm6F,KAAKsqE,EAAoBnkJ,IAAI8vE,GAAUqH,SAClF+sE,EAAgBA,EAAcnkK,OAAOL,MAAMm6F,KAAKsqE,EAAoBnkJ,IAAI8vE,GAAU2G,SAClFz7F,KAAK2kK,aAAap0E,OAAOrrC,IAE7B3gD,GAAOynF,MAAO,GAAEhsF,uCAAuCklD,WAAegkH,EAAcxnK,UAE7EwnK,GASX5E,GAAwBrjK,UAAU+nK,mBAAqB,SAASD,GAAa,MACzEA,EAAYz+E,UACZ,MAAMkO,EAAgBuwE,EAAYtwE,mBAC5BmwE,EAAwB5oK,KAAK2kK,aAAa3/I,IAAIwzE,GAE/CowE,EAEM,UAACA,EAAsB5jJ,IAAI+jJ,EAAY5nE,kBAAvC,OAAC,EAAkD5Q,OAAOw4E,IACjExkK,GAAOlD,MAAO,GAAErB,yBAAyB+oK,gCAFzCxkK,GAAOlD,MAAO,GAAErB,6DAA6Dw4F,KAIjFx4F,KAAKwzF,aAAa37D,KAAKkD,GAAAA,QAAAA,qBAAgCguI,IAQ3DzE,GAAwBrjK,UAAUmoK,gBAAkB,SAASthK,GAKzD,MAAMe,EAAU,IAAIw9D,IAMdgjG,EAAY,IAAIhjG,IAEtB,GAAoB,iBAATv+D,GAA8B,OAATA,GACL,iBAAbA,EAAKC,IAGf,OAFAxD,GAAO2T,KAAK,kDAELrP,EAGX,MAAMrB,EAAUlB,GAAAA,MAAgBwB,EAAKC,KAErC,IAAKrD,MAAMgD,QAAQF,EAAQG,OACvB,OAAOkB,EAGX,IAAIlB,EAAQH,EAAQG,MAIhB3H,KAAKwlK,mBACL79J,EAAQ,GACR,CAAEmtF,GAAUqH,MAAOrH,GAAU2G,OAAQl7F,SAAQ0iF,IACzC,MAAMt8E,EAAQa,EAAQG,MAAMU,MAAKlE,GAAKA,EAAEyD,OAASq7E,IAEjDt8E,GAASgB,EAAMzF,KAAKyE,OAI5B,IAAK,MAAMA,KAASgB,EAAO,CACvB,IAAKjD,MAAMgD,QAAQf,EAAMG,OACrB,SAGJ,GAAIpC,MAAMgD,QAAQf,EAAMyB,YACpB,IAAK,MAAME,KAAS3B,EAAMyB,WACtB,QAA+B,IAApBE,EAAMC,gBACa,IAAhBD,EAAMxB,MAAuB,CAEvC,MAAMwiK,EAAahhK,EAAMxB,MAAM5C,MAAM,KAAKgD,KAAIsB,GAAWC,SAASD,EAAS,MACrEswJ,EAAcwQ,EAAW,GAG/BhhK,EAAMxB,MAAQwiK,EAGTD,EAAU9pH,IAAIu5G,IACfuQ,EAAUnkJ,IAAI4zI,EAAa,IAE/BuQ,EAAUrkJ,IAAI8zI,GAAa52J,KAAKoG,GAK5C,IAAIxB,EAAQH,EAAMG,MAGlBA,EAAQ9G,KAAKwlK,iBACP1+J,EAAMC,QAAO8F,GAAqB,UAAhBA,EAAE5F,YACpBH,EAAMC,QAAO8F,GAAqB,SAAhBA,EAAE5F,YAE1B,IAAK,MAAML,KAAQE,EAAO,CAKtB,MAAMoH,EAAMlO,KAAKwlK,iBAAmB7+J,EAAMiB,KAAOhB,EAAKO,MAChDoxJ,EAAa3xJ,EAAKvB,GACxB,IAAI2B,EAAW6B,EAAQmc,IAAI9W,GAY3B,GAVKlH,IACDA,EAAW,CACPF,MAAO,GACP+tC,OAAQ,GACR/qC,KAAMoE,GAEVrF,EAAQqc,IAAIhX,EAAKlH,IAErBA,EAASF,MAAM5E,KAAKq2J,GAEhB8Q,EAAU9pH,IAAIg5G,GAAa,CAC3B,MAAMnwJ,EAAaihK,EAAUrkJ,IAAIuzI,GAEjC,IAAK,MAAMjwJ,KAASF,EAChBpB,EAAS6tC,OAAO3yC,KAAKoG,KAMrC,OAAOO,GAsKXy7J,GAAwBrjK,UAAU46F,aAAe,SAAS83C,GACtD,MAAM3sI,EAAWhH,KAAKupK,SAAS51B,EAAWkd,OAE1C,OAAO7pJ,GAAYA,EAASF,MAAM,IAatCw9J,GAAwBrjK,UAAUuoK,oCAC5B,SAAS1hK,GACP,MAAMC,EAAMzB,GAAAA,MAAgBwB,EAAKC,KAC3B64E,EAAQ74E,EAAIJ,MAAMU,MAAK8tE,GAAwB,UAAfA,EAAMvuE,OAG5Cg5E,EAAMx4E,WAAaw4E,EAAMx4E,YAAc,GACvC,MAAM40J,EAAYp8E,EAAMx4E,WAAWrB,QAAOuB,GAA6B,QAApBA,EAAMC,YAEzD,GAAIq4E,EAAMo6E,WAAap6E,EAAMmiF,aAAc,CACvC,MAAMj8J,EAAQ,GAad,GAXIk2J,GAAaA,EAAUt7J,OACvBs7J,EAAUz8J,SAAQ+H,IACdxB,EAAM5E,KAAKoG,EAAMxB,MAAM5C,MAAM,KAAK,OAGtC08E,EAAM95E,MAAMvG,SAAQqG,IACO,SAAnBA,EAAKK,WACLH,EAAM5E,KAAK0E,EAAKvB,OAIxBu7E,EAAMx4E,WAAWC,MAAKC,GAA6B,QAApBA,EAAMC,YAErC,OAAOT,EAGX84E,EAAMx4E,WAAWlG,KAAK,CAClBqG,UAAW,MACXzB,MAAOA,EAAMyC,KAAK,OAI1B,OAAO,IAAI0C,sBAAsB,CAC7BrE,KAAME,EAAKF,KACXG,IAAKzB,GAAAA,MAAgByB,MAKjC,MAAM0hK,GAAU,CACZn5B,iBACI,OAAOtwI,KAAKusF,eAAe+jD,gBAE/BI,qBACI,OAAO1wI,KAAKusF,eAAemkD,oBAE/BH,kBACI,OAAOvwI,KAAKusF,eAAegkD,iBAE/Bc,mBACI,IAAIvpI,EAAO9H,KAAKusF,eAAe8kD,iBAE/B,OAAKvpI,GAML9H,KAAKy/I,MAAM,oCAAqCmnB,GAAQ9+J,IAIpD9H,KAAKwlK,mBAAqBxlK,KAAKuvF,OAC/BznF,EAAO9H,KAAK0lK,QAAQ5P,QAAQhuJ,GAC5B9H,KAAKy/I,MAAM,8CACPmnB,GAAQ9+J,IAEZA,EAAO9H,KAAKwpK,oCAAoC1hK,GAChD9H,KAAKy/I,MAAM,yDACPmnB,GAAQ9+J,KACJ9H,KAAKwlK,mBACTjgI,GAAQ0hD,gCACRn/E,EAAO9H,KAAK2lK,eAAe9J,mCAAmC/zJ,GAC9DvD,GAAOynF,MACH,uDAAwDlkF,IAWhEA,EA/IY,SAASupI,EAAkBtxI,GAAS,QACxD,IAAKsxI,EACD,MAAM,IAAIrtI,MAAM,mCAGpB,MAAMy2J,EAAc,IAAIT,GAAiB3oB,EAAiBtpI,KACpD2hK,EAAU,UAAGjP,EAAYN,YAAYrlE,GAAUqH,cAArC,aAAG,EAA2C,GAC9D,IAAIwtE,GAAU,EAEVD,GAAcA,EAAWt9J,YAAc8yH,GAAAA,WACnCn/H,EAAQ6mG,YACR8iE,EAAWt9J,UAAY8yH,GAAAA,SAEvBwqC,EAAWt9J,UAAY8yH,GAAAA,SAG3ByqC,GAAU,GAGd,MAAMC,EAAU,UAAGnP,EAAYN,YAAYrlE,GAAU2G,cAArC,aAAG,EAA2C,GAO9D,OALImuE,GAAcA,EAAWx9J,YAAc8yH,GAAAA,WACvC0qC,EAAWx9J,UAAY8yH,GAAAA,SACvByqC,GAAU,GAGVA,EACO,IAAI19J,sBAAsB,CAC7BrE,KAAMypI,EAAiBzpI,KACvBG,IAAK0yJ,EAAYJ,aAIlBhpB,EA8GQw4B,CAAgB/hK,EAAM9H,KAAKD,UAItC+H,EAAO9H,KAAK2lK,eAAe7J,2BAA2Bh0J,GAE/CA,IAtCHvD,GAAOynF,MAAO,GAAEhsF,sDAET,KAsCfkxI,oBACI,IAAIppI,EAAO9H,KAAKusF,eAAe2kD,kBAE/B,OAAKppI,GAKL9H,KAAKy/I,MAAM,qCAAsCmnB,GAAQ9+J,IAErD9H,KAAKwlK,mBACDxlK,KAAKuvF,MAELznF,EAAO9H,KAAK8pK,4BAA4BhiK,IAGxCA,EAAO9H,KAAK0lK,QAAQ5P,QAAQhuJ,GAC5B9H,KAAKy/I,MAAM,+CAAgDmnB,GAAQ9+J,MAIpEA,IAjBHvD,GAAOynF,MAAO,GAAEhsF,wDAET,MAmBnBI,OAAOC,KAAKopK,IAASlpK,SAAQ4rB,IACzB/rB,OAAO0kB,eACHw/I,GAAwBrjK,UACxBkrB,EAAM,CACFnH,IAAKykJ,GAAQt9I,QAKzBm4I,GAAwBrjK,UAAUsoK,SAAW,SAAS1Y,GAClD,OAAO7wJ,KAAK6kK,WAAW7/I,IAAI6rI,IAS/ByT,GAAwBrjK,UAAUuiK,sBAAwB,WACtD,OAAOxjK,KAAK+pK,oBAAsB/pK,KAAKulK,wBAQ3CjB,GAAwBrjK,UAAU8oK,iBAAmB,WACjD,MAAMtC,EAASznK,KAAKg2I,sBAEpB,OAAO1uD,QAAQmgF,EAAOp/J,MAAK8vE,GAASA,EAAMstB,YAAc3oE,GAAU,UAAVA,YAY5DwnI,GAAwBrjK,UAAU+oK,iBAAmB,SAASl0F,GAC1D,IAAK91E,KAAKiqK,gBACN,OAAOn0F,EAGX,MAAM4sF,EAAYp8J,GAAAA,MAAgBwvE,EAAY/tE,KAIxCpB,EAAQ+7J,EAAU/6J,MAAMU,MAAKlE,GAAKA,EAAEyD,OAAS5H,KAAKiqK,gBAAgBhnF,YAExE,IAAKt8E,EACD,OAAOmvE,EAGX,GAAI91E,KAAKiqK,gBAAgBlnD,OAcrB,GAbAqY,GAAAA,YAAoBz0H,EAAO3G,KAAKiqK,gBAAgBj2J,UAO5ChU,KAAKiqK,gBAAgBj2J,WAAa8qH,GAAAA,MAAsBv5F,GAAQmhD,iBAAmB1mF,KAAKuvF,OACxF6rC,GAAAA,WAAmBz0H,EAAO3G,KAAKiqK,gBAAgBj2J,UAAU,GAKzDhU,KAAKiqK,gBAAgBj2J,WAAa8qH,GAAAA,KAC/B9+H,KAAKszI,4BAA8BxU,GAAAA,IAAmB,CACzD,MAAMorC,EAAWlqK,KAAKqlK,SAASjD,cAAc7pC,KAAOv4H,KAAKqlK,SAASjD,cAC5D+H,EAAYD,EAASj2H,KAAOi2H,EAASj2H,KAAO2tH,GAC5Cj8B,EAAQ17H,KAAKC,OAAOlK,KAAK+pK,mBAAqBnI,GAAauI,GAAa,KAI9ExjK,EAAM4wE,UAAY,CAAE,CAChB3vE,KAAM,KACN+9H,MAAAA,SAOJh/H,EAAM4wE,eAAYxrE,OAGtBqvH,GAAAA,WAAmBz0H,EAAO3G,KAAKiqK,gBAAgBj2J,UAGnD,OAAO,IAAI/H,sBAAsB,CAC7BrE,KAAMkuE,EAAYluE,KAClBG,IAAKzB,GAAAA,MAAgBo8J,MAU7B4B,GAAwBrjK,UAAU2yI,SAAW,SAASz7D,GAA4B,IAArBm0D,EAAqB,wDAC9E,MAAMukB,EAAQ14E,EAAM04E,MAIpB,GAFAtsJ,GAAOiH,KAAM,GAAExL,eAAem4E,KAE1Bn4E,KAAKqyG,YAAY9yD,IAAIsxG,GAErB,OAAO9mH,QAAQE,OAAO,IAAIjmC,MAAO,GAAEm0E,mBAAuBn4E,SAG9DA,KAAKqyG,YAAYntF,IAAI2rI,EAAO14E,GAC5B,MAAMiyF,EAAejyF,EAAMy3E,oBAE3B,GAAI5vJ,KAAKwlK,iBAAkB,CACvBjhK,GAAOynF,MAAO,GAAEhsF,wCAChB,IACIA,KAAKqlK,SAASzxB,SAASz7D,EAAOm0D,GAChC,MAAOjrI,GAGL,OAFAkD,GAAOlD,MAAO,GAAErB,qBAAqBm4E,aAAiB92E,MAAAA,OAAzC,EAAyCA,EAAO2Z,WAEtD+uB,QAAQE,OAAO5oC,QAEvB,CAEH,GAAI+oK,EACApqK,KAAKqqK,WAAWD,QAGb,IAAK7kI,GAAQ0hD,+BACL9O,EAAMogB,gBACLpgB,EAAMqtB,iBAAmBrtB,EAAM+oB,UAC3C,OAAOn3D,QAAQE,OAAO,IAAIjmC,MAAO,GAAEhE,mCAAmCm4E,MAI1E,GAAI5yC,GAAQ0hD,+BAAiC9O,EAAMqtB,gBAAkBrtB,EAAM+oB,UAAW,CAClF,MAAMl6F,EAAWhH,KAAKsqK,0BAA0BnyF,GAEhDn4E,KAAKi7J,eAAemC,eAAep2J,EAASF,MAAM,IAClD,MAAMqB,EACAnB,EAAS6tC,OAAOxsC,MAAKopH,GAAqC,QAAxBA,EAAUlpH,YAE9CJ,GACAnI,KAAKg7J,UAAU/yJ,aAAaE,EAASrB,OAEzC,MAAMk2J,EACAh2J,EAAS6tC,OAAO9tC,QACd0qH,GAAqC,QAAxBA,EAAUlpH,YAE/B,GAAIy0J,EAAW,CACX,MAAMuN,EAAiB,IAAIlkG,IAE3B22F,EAAUz8J,SAAQkK,IACd,MAAMhB,EAAcgB,EAAS3D,MAAM,GAC7Bs1J,EAAU3xJ,EAAS3D,MAAM,GAE/ByjK,EAAerlJ,IAAIzb,EAAa2yJ,MAEpCp8J,KAAKo7J,YAAYnzJ,aAAasiK,KAI1C,IAAIC,EAAezgI,QAAQC,UAO3B,OAJIzE,GAAQ8gD,cACRmkF,EAAeA,EAAa5pH,MAAK,IAAMwpH,GAAgBpqK,KAAKqlK,SAASrB,aAAa7rF,MAG/EqyF,GAWXlG,GAAwBrjK,UAAU64I,eAAiB,SAAS3hE,GAGxD,GAFA5zE,GAAOiH,KAAM,GAAExL,qBAAqBm4E,gBAE/Bn4E,KAAKyqK,oBAAoB,iBAAkBtyF,GAG5C,OAAOpuC,QAAQE,OAAO,yCAG1B,MAAMygI,EAAevyF,EAAMy3E,oBAE3B,OAAK8a,EAMD1qK,KAAKwlK,iBACExlK,KAAKqlK,SAAS1sB,aAAa,KAAMxgE,GAAOv3B,MAAK,KAAM,KAG9D5gD,KAAKqqK,WAAWK,GAET3gI,QAAQC,SAAQ,KAXnBzlC,GAAOlD,MAAO,GAAErB,4BAA4Bm4E,kCAErCpuC,QAAQE,OAAO,sBAiB9Bq6H,GAAwBrjK,UAAUopK,WAAa,SAASlc,GACpDnuJ,KAAKusF,eAAeo+E,UAAUxc,GAC9BnuJ,KAAK4kK,cAAc1iK,KAAKisJ,IAO5BmW,GAAwBrjK,UAAU2pK,cAAgB,SAASzc,GACvDnuJ,KAAKusF,eAAes+E,aAAa1c,GACjCnuJ,KAAK4kK,cACC5kK,KAAK4kK,cAAc79J,QAAOqJ,GAAUA,IAAW+9I,KAczDmW,GAAwBrjK,UAAUwpK,oBAAsB,SAChD7mK,EACA+vI,GACJ,MAAMm3B,EAAa9qK,KAAKqyG,YAAY9yD,IAAIo0F,MAAAA,OAArB,EAAqBA,EAAYkd,OAMpD,OAJKia,GACDvmK,GAAOlD,MAAO,GAAErB,QAAQ4D,YAAqB+vI,2BAG1Cm3B,GAUXxG,GAAwBrjK,UAAUqyI,wBAA0B,WAAW,MACnE,MAAMvrI,EAAG,UAAG/H,KAAKusF,eAAe8kD,wBAAvB,aAAG,EAAsCtpI,IAC5CgjK,EAAejsC,GAAAA,IAErB,IAAK/2H,EACD,OAAOgjK,EAEX,MAEMp4F,EAFYrsE,GAAAA,MAAgByB,GACVJ,MAAMU,MAAKlE,GAAKA,EAAEyD,OAASktF,GAAU2G,QACzCjsF,IAAI,GAAGmjE,MAE3B,OAAIA,EACOvyE,OAAOkJ,OAAOw1H,IAAez2H,MAAKlB,GAASA,IAAUwrE,EAAMx7C,gBAG/D4zI,GAQXzG,GAAwBrjK,UAAUi6H,2BAA6B,SAASC,GACpE,MAAM6vC,EAAS7vC,GnChxDkB,EmCkxDjCn7H,KAAKulK,uBAAyBvlK,KAAK+6J,iBAAmBiQ,GAW1D1G,GAAwBrjK,UAAU4zI,eAAiB,WAAsD,IAA7C9E,EAA6C,uDAA5B,KAAMwU,EAAsB,uDAAN,KAE/F,MAAMxhC,EAA2B,OAAlBwhC,EACTvwI,EAAWuwI,GAAgCxU,EAE7C/vI,KAAKiqK,kBAAoBl6B,GAAkBwU,IAC3CvkJ,KAAKiqK,gBAAgBlnD,OAASA,EAC9B/iH,KAAKiqK,gBAAgBj2J,SAAWA,GACzB+7H,GAAkBwU,EACzBvkJ,KAAKiqK,gBAAkB,CACnBlnD,OAAAA,EACA9/B,UAAW6R,GAAU2G,MACrBznF,SAAAA,GAGJzP,GAAO2T,KAAM,GAAElY,yCAAyC+vI,cAA2BwU,iDAW3F+f,GAAwBrjK,UAAU45J,kBAAoB,SAAS1M,GAC3D,OAAOnuJ,KAAK4kK,cAAcvhK,QAAQ8qJ,IAAgB,GAUtDmW,GAAwBrjK,UAAUmzJ,YAAc,SAASzgB,GACrD,MAAM+2B,EAAe/2B,EAAWic,oBAEhC5vJ,KAAKy/I,MACD,eACA9L,EAAWkd,MAAO6Z,EAAeA,EAAarlK,QAAK0G,GAElD/L,KAAKyqK,oBAAoB,eAAgB92B,KAI9C3zI,KAAKqyG,YAAY9hB,OAAOojD,EAAWkd,OACnC7wJ,KAAK6kK,WAAWt0E,OAAOojD,EAAWkd,OAE9B6Z,GACA1qK,KAAKusF,eAAes+E,aAAaH,KAUzCpG,GAAwBrjK,UAAUgqK,iBAAmB,SAAShoF,GAC1D,GAAIjjF,KAAKusF,eAAe2+E,WACpB,OAAOlrK,KAAKusF,eAAe2+E,aAAa7iK,MAAKwE,GAAKA,EAAEsrE,OAAStrE,EAAEsrE,MAAM5B,OAAS0M,KAWtFqhF,GAAwBrjK,UAAUqxG,qBAAuB,SAASn6B,GAC9D,OAAOn4E,KAAKusF,eAAe+6E,eAAej/J,MAAK6E,GAAKA,EAAEirE,QAAUA,KAUpEmsF,GAAwBrjK,UAAUsxG,mBAAqB,SAASp6B,GAC5D,GAAIn4E,KAAKusF,eAAe2+E,WACpB,OAAOlrK,KAAKusF,eAAe2+E,aAAa7iK,MAAKwE,GAAKA,EAAEsrE,QAAUA,KAgBtEmsF,GAAwBrjK,UAAU03I,aAAe,SAASC,EAAUC,GAChE,IAAMD,IAAYC,EAGd,OAFAt0I,GAAOiH,KAAM,GAAExL,+DAER+pC,QAAQC,UAOnB,MAAMmhI,EAAoB7jF,SAASsxD,IAAa54I,KAAKqyG,YAAY9yD,IAAIq5F,MAAAA,OAArB,EAAqBA,EAAUiY,QAE/E,GAAI7wJ,KAAKwlK,iBAAkB,OACvBjhK,GAAOynF,MAAO,GAAEhsF,4CAChB,MAAMijF,EAAS,UAAG41D,MAAAA,OAAH,EAAGA,EAAU13C,iBAAb,QAA0By3C,MAAAA,OAA1B,EAA0BA,EAAUz3C,UAC7C/wF,EAASyoI,MAAAA,OAAH,EAAGA,EAAU+W,oBAQzB,OAPgB/W,IAAazoI,EAIvB25B,QAAQC,UACRhqC,KAAKqlK,SAAS1sB,aAAaC,EAAUC,IAGtCj4F,MAAKijH,IACFjrB,GAAY54I,KAAKqyG,YAAY9hB,OAAOqoD,EAASiY,OAC7ChY,GAAY74I,KAAKqyG,YAAYntF,IAAI2zH,EAASgY,MAAOhY,GACjD,MAAMuyB,EAAcnoF,IAAc6R,GAAUqH,MACtCn8F,KAAKukK,oBACLvkK,KAAK0kK,oBAgBX,OAXIb,GAAeuH,IACfvH,EAAYz3J,UAAYysI,EAAW3Z,GAAAA,SAA0BA,GAAAA,WAK/B35F,GAAQyjD,+BAAiC6vD,EACrE9uG,QAAQC,UACRhqC,KAAKqlK,SAASrB,aAAanrB,IAGAj4F,MAAK,IAAMuqH,OAIxD5mK,GAAOynF,MAAO,GAAEhsF,sCAEhB,IAAIwqK,EAAezgI,QAAQC,UAS3B,OAPI4uG,GACA54I,KAAKo0J,YAAYxb,GAEjBC,IACA2xB,EAAexqK,KAAK4zI,SAASiF,IAG1B2xB,EAAa5pH,MAAK,KAAM,KAWnC0jH,GAAwBrjK,UAAU44I,gBAAkB,SAASlG,GACzD,MAAM+2B,EAAe/2B,EAAWic,oBAMhC,OAJA5vJ,KAAKy/I,MACD,mBACA9L,EAAWkd,MAAO6Z,EAAeA,EAAarlK,GAAK,MAElDrF,KAAKyqK,oBAAoB,mBAAoB92B,GAK9C3zI,KAAKwlK,iBACExlK,KAAKqlK,SAAS1sB,aAAahF,EAAY,MAAM/yF,MAAK,KAAM,IAG/D8pH,GACAnmK,GAAOiH,KAAM,GAAExL,uBAAuB2zI,aACtC3zI,KAAK4qK,cAAcF,GAEZ3gI,QAAQC,SAAQ,KAG3BzlC,GAAOlD,MAAO,GAAErB,sDAAsD2zI,KAE/D5pG,QAAQE,OAAO,qBAhBXF,QAAQE,OAAO,0CAmB9Bq6H,GAAwBrjK,UAAUglJ,kBAAoB,SAASsE,EAAOv5I,GAGlE,OAFAhR,KAAKy/I,MAAM,oBAAqB8K,EAAOv5I,GAEhChR,KAAKusF,eAAe05D,kBAAkBsE,EAAOv5I,IAWxDszJ,GAAwBrjK,UAAUoqK,4BAA8B,SAASC,GACrE,IAAI5O,EAAS4O,EAASvjK,IAEtB,MAAMwjK,EAAkB7O,EAAOr5J,QAAQ,WACjCmoK,EAAgB9O,EAAOr5J,QAAQ,mBAAoBkoK,GACzD,IAAIE,EAAkB/O,EAAO/mI,YAAY,gBAEzC,IAAuB,IAAnB61I,IACwB,IAArBC,GACAA,IAAoBD,EACvB,OAAOF,EAGX,MAAMI,EAAchP,EAAOr5J,QAAQ,OAAQmoK,GACrCG,EAASjP,EAAOvsJ,UAAUq7J,EAAeE,EAAc,GAE7DhP,EAASA,EAAOjsJ,QAAQk7J,EAAQ,IAChCF,EAAkB/O,EAAO/mI,YAAY,gBACrC,MAAMi2I,EAAgBlP,EAAOr5J,QAAQ,OAAQooK,GACvCI,EAAUnP,EAAO/3J,MAAM,EAAGinK,GAC1BE,EAAgBH,EAAOvtG,OACvB2tG,EAAUrP,EAAO/3J,MAAMinK,GAI7B,OAFAlP,EAAU,GAAEmP,QAAcC,IAAgBC,IAEnC,IAAI9/J,sBAAsB,CAC7BrE,KAAM0jK,EAAS1jK,KACfG,IAAK20J,KAYb4H,GAAwBrjK,UAAU+qK,2BAA6B,SAAS36B,GAAkB,QACtF,MAAMopB,EAAc,IAAIT,GAAiB3oB,EAAiBtpI,KAC1D,IAAIkkK,GAAoB,EACxB,MAAMvC,EAAU,UAAGjP,EAAYN,YAAYrlE,GAAUqH,cAArC,aAAG,EAA2C,GAE9D,GAAIutE,EAAY,CACZ,MAAMwC,EAAwBlsK,KAAKo4I,yBAAyBtjD,GAAUqH,OAElEutE,EAAWt9J,YAAc8/J,IACzBxC,EAAWt9J,UAAY8/J,EACvB3nK,GAAOiH,KAAM,GAAExL,0CAA0CksK,KACzDD,GAAoB,QAGxB1nK,GAAO2T,KAAM,GAAElY,wDAGnB,MAAM4pK,EAAU,UAAGnP,EAAYN,YAAYrlE,GAAU2G,cAArC,aAAG,EAA2C,GAE9D,GAAImuE,EAAY,CACZ,MAAMuC,EAAwBnsK,KAAKo4I,yBAAyBtjD,GAAU2G,OAElEmuE,EAAWx9J,YAAc+/J,IACzBvC,EAAWx9J,UAAY+/J,EACvB5nK,GAAOiH,KAAM,GAAExL,0CAA0CmsK,KACzDF,GAAoB,QAGxB1nK,GAAO2T,KAAM,GAAElY,wDAGnB,OAAIisK,EACO,IAAIhgK,sBAAsB,CAC7BrE,KAAMypI,EAAiBzpI,KACvBG,IAAK0yJ,EAAYJ,aAIlBhpB,GAWXizB,GAAwBrjK,UAAU6oK,4BAA8B,SAAS54B,GACrE,MAAMupB,EAAc,IAAIT,GAAiB9oB,EAAkBnpI,KAc3D,MAZA,CAAE+sF,GAAUqH,MAAOrH,GAAU2G,OAAQl7F,SAAQ0iF,IAAa,MACtD,MAAMt7E,EAAK,UAAG8yJ,EAAYN,YAAYl3E,UAA3B,aAAG,EAAqC,GAC7C6jF,EAAiB9mK,KAAK+mK,mBAAmB9jF,GACzCmpF,EAAkBpsK,KAAKonK,gBAAgB,KAAMnkF,GAAWvhF,OAAS,EAEvEiG,EAAMyE,UAAY06J,GAAkBsF,EAC9BltC,GAAAA,SACA4nC,EACI5nC,GAAAA,SACAktC,EAAkBltC,GAAAA,SAA0BA,GAAAA,YAGnD,IAAIjzH,sBAAsB,CAC7BrE,KAAMspI,EAAkBtpI,KACxBG,IAAK0yJ,EAAYJ,cAWzBiK,GAAwBrjK,UAAUorK,WAAa,SAASv2F,GACpD,MAAM,aAAEwjD,GAAiBt5H,KAAKD,QAE9B,KAAKu5H,MAAAA,GAAAA,EAAcC,QAAWD,MAAAA,GAAAA,EAAcgzC,uBACxC,OAAOx2F,EAGX,MAAM4sF,EAAYp8J,GAAAA,MAAgBwvE,EAAY/tE,KACxCwkK,EAAS7J,EAAU/6J,MAEzB,IAAK,MAAMhB,KAAS4lK,EAChB,GAAmB,UAAf5lK,EAAMiB,KAAkB,CACxB,MAAM,QAAE+8F,GAAYh+F,EAAM6I,IAAInH,MAAKupE,GAAYA,EAASe,QAAUmsD,GAAAA,OAElE,IAAKn6B,EAED,SAGJ,IAAI6nE,EAAW7lK,EAAM8I,KAAKpH,MAAKupE,GAAYA,EAAS+yB,UAAYA,IAE3D6nE,IACDA,EAAW,CACP7nE,QAAAA,EACAl3F,OAAQ,KAIhB,MAAMg/J,EAAanmK,GAAAA,YAAsBkmK,EAAS/+J,QAClD,IAAIi/J,GAAa,EAYjB,GAVIpzC,MAAAA,GAAAA,EAAcC,SACdkzC,EAAWlzC,OAAS,EACpBmzC,GAAa,GAGbpzC,MAAAA,GAAAA,EAAcgzC,wBACdG,EAAWE,kBAAoBrzC,EAAagzC,sBAC5CI,GAAa,IAGZA,EAED,SAGJ,IAAIE,EAAe,GAEnB,IAAK,MAAM1+J,KAAO9N,OAAOC,KAAKosK,GAC1BG,GAAiB,GAAE1+J,KAAOu+J,EAAWv+J,OAGzCs+J,EAAS/+J,OAASm/J,EAAaxuG,OAIvC,OAAO,IAAInyD,sBAAsB,CAC7BrE,KAAMkuE,EAAYluE,KAClBG,IAAKzB,GAAAA,MAAgBo8J,MAO7B4B,GAAwBrjK,UAAU4rK,yBAA2B,WAEzD,IAAK7sK,KAAKusF,eAAe2+E,YAAclrK,KAAKglK,eACxC,OAGJ,MAAMrjC,EAAU3hI,KAAKusF,eAAe2+E,aAEb,IAAnBvpC,EAAQjgI,QAAgBigI,EAAQ,GAAGv+H,YACnCpD,KAAKglK,eAAiBrjC,EAAQ,GAAGv+H,UAEjCpD,KAAKglK,eAAe9sI,QAAU72B,IAC1BkD,GAAOlD,MAAO,GAAErB,6BAA6BqB,MAGjDrB,KAAKglK,eAAe8H,cAAgB,KAChC9sK,KAAKy/I,MAAM,8BAA+Bz/I,KAAKglK,eAAen5H,UAY1Ey4H,GAAwBrjK,UAAUswI,8BAAgC,WAAiC,IAAxB8xB,EAAwB,uDAAN,KACzF,GAAIhsC,GAAAA,+BAA6C,CAC7C,GAAIgsC,EACA,OAAOrjK,KAAKm2I,0BACRn2I,KAAK8lK,kBAAkB9gJ,IAAIq+I,EAAgBptB,iBAC3CotB,GAER,MAAMjvD,EAAW,GAEjB,IAAK,MAAMj8B,KAASn4E,KAAKg2I,sBACrB5hC,EAASlyG,KAAKlC,KAAKm2I,0BAA0Bn2I,KAAK8lK,kBAAkB9gJ,IAAImzD,EAAM89D,iBAAkB99D,IAGpG,OAAOpuC,QAAQyqE,WAAWJ,GAG9B,IAAIu/B,EAAa0vB,EAMjB,OAJK1vB,IACDA,EAAa3zI,KAAKg2I,sBAAsB,IAGrCh2I,KAAKm2I,0BAA0Bn2I,KAAK6lK,sBAAuBlyB,IAGtE2wB,GAAwBrjK,UAAU+yI,oBAAsB,SAASl+D,GAC7D,IAAIu7D,EAAmBv7D,EAmBvB,OAjBA91E,KAAKy/I,MAAM,oCAAqCmnB,GAAQv1B,IAGxDA,EAAmBrxI,KAAKqsK,WAAWh7B,GAE9BrxI,KAAKwlK,mBACNn0B,EAAmBrxI,KAAKgsK,2BAA2B36B,GACnDA,EAAmBrxI,KAAKqrK,4BAA4Bh6B,IAInDrxI,KAAKylK,mCACNp0B,EAAmBrxI,KAAKgqK,iBAAiB34B,IAG7CrxI,KAAKy/I,MAAM,qCAAsCmnB,GAAQv1B,IAElD,IAAItnG,SAAQ,CAACC,EAASC,KACzBjqC,KAAKusF,eAAeynD,oBAAoB3C,GACnCzwF,MAAK,KACF5gD,KAAKy/I,MAAM,gCACX,MAAMqlB,EAAa1pC,GAAAA,SAAiBiW,EAAiBtpI,KAEjD+8J,IAAe9kK,KAAK8kK,aACpB9kK,KAAK8kK,WAAaA,EAClB9kK,KAAKwzF,aAAa37D,KAAKkD,GAAAA,QAAAA,oBAA+B/6B,KAAM8kK,IAGhE9kK,KAAK6sK,2BAEL7iI,OACDvB,IACCzoC,KAAKy/I,MAAM,+BAAgCh3G,GAC3CzoC,KAAKwzF,aAAa37D,KAAKkD,GAAAA,QAAAA,6BAAwC0N,EAAKzoC,MACpEiqC,EAAOxB,UAkBvB67H,GAAwBrjK,UAAUq5I,uBAAyB,SAAS6N,GAChE5jJ,GAAOynF,MAAO,GAAEhsF,+BAA+BmoJ,KAC/C,MAAMwhB,EAAU3pK,KAAKukK,sBAAwBpc,EAI7C,OAFAnoJ,KAAKukK,oBAAsBpc,EAEvBnoJ,KAAKwlK,kBACLxlK,KAAKqlK,SAAS/qB,uBAAuB6N,IAG9B,GAGJwhB,GAGXrF,GAAwBrjK,UAAUs3I,qBAAuB,SAASziE,GAC9D,IAAIo7D,EAAoBp7D,EAOxB,GALA91E,KAAKy/I,MAAM,qCAAsCmnB,GAAQ9wF,IAGzDo7D,EAAoBlxI,KAAKqsK,WAAWn7B,GAEhClxI,KAAKwlK,iBAAkB,CAEvB,IAAKxlK,KAAKuvF,MAAO,CACb,MAAMw9E,EAAqB/sK,KAAKusF,eAAe2kD,kBAE/CA,EAAoBlxI,KAAK0lK,QAAQrP,cAAcnlB,EAAmB67B,GAClE/sK,KAAKy/I,MAAM,gDAAiDmnB,GAAQ11B,IAEpElxI,KAAK+6J,kBAEL7pB,EAAoBlxI,KAAKg7J,UAAUtwJ,uBAAuBwmI,GAC1DlxI,KAAKy/I,MAAM,kDAAmDmnB,GAAQ11B,IAEtEA,EAAoBlxI,KAAKqlK,SAASvC,kCAAkC5xB,GACpElxI,KAAKy/I,MAAM,oDAAqDmnB,GAAQ11B,KAE5EA,EAAoBlxI,KAAKqlK,SAAS5C,0BAA0BvxB,GAC5DlxI,KAAKy/I,MAAM,2DAA4DmnB,GAAQ11B,SAE3ElxI,KAAK+6J,kBAEL7pB,EAAoBlxI,KAAKg7J,UAAUtwJ,uBAC/BwmI,GACA,GACJlxI,KAAKy/I,MAAM,kDAAmDmnB,GAAQ11B,KAE1EA,EA/nCe,SAASppI,GAC5B,GAAoB,iBAATA,GAA8B,OAATA,GACL,iBAAbA,EAAKC,IAGf,OAFAxD,GAAO2T,KAAK,kDAELpQ,EAIX,MAAMxB,EAAYkzB,EAAQ,KACpBhyB,EAAUlB,EAAUsE,MAAM9C,EAAKC,UAEd,IAAZP,QACyB,IAAlBA,EAAQG,OACfjD,MAAMgD,QAAQF,EAAQG,QAC7BH,EAAQG,MAAMpH,SAAQoG,IASlB,MAAMqmK,EAAa,GACbC,EAAe,GAcrB,QAZgC,IAArBtmK,EAAMyB,YACV1D,MAAMgD,QAAQf,EAAMyB,aACvBzB,EAAMyB,WAAW7H,SAAQ+H,SACU,IAApBA,EAAMC,WACU,QAApBD,EAAMC,gBACkB,IAAhBD,EAAMxB,OACbkmK,EAAW9qK,KAAK4M,OAAOxG,EAAMxB,MAAM5C,MAAM,KAAK,QAM1DQ,MAAMgD,QAAQf,EAAMG,OAAQ,CAC5B,IAAItF,EAEJ,IAAKA,EAAI,EAAGA,EAAImF,EAAMG,MAAMpF,OAAQF,IACF,iBAAnBmF,EAAMG,MAAMtF,SACa,IAAtBmF,EAAMG,MAAMtF,GAAG6D,IACtB2nK,EAAW3pK,QAAQsD,EAAMG,MAAMtF,GAAG6D,KAAO,IAC5C4nK,EAAa/qK,KAAKyE,EAAMG,MAAMtF,WACvBmF,EAAMG,MAAMtF,IAI3B,IAAKA,EAAI,EAAGA,EAAImF,EAAMG,MAAMpF,OAAQF,SACF,IAAnBmF,EAAMG,MAAMtF,IACnByrK,EAAa/qK,KAAKyE,EAAMG,MAAMtF,IAItCmF,EAAMG,MA0BtB,WAAuD,IAAhBm1H,EAAgB,uDAAJ,GAC/C,IAAK12F,GAAQ4gD,aAAe5gD,GAAQuhD,qBAAqB,IACrD,OAAOm1C,EAGX,IAAIixC,EAAgB,IAAKjxC,GAsBzB,OApB2BA,EAAUl1H,QAAO+2H,GACjB,YAAvBA,EAAS72H,WAA8C,MAAnB62H,EAAS32H,QAC5CD,KAAI42H,GAAYA,EAASz4H,KAEX9E,SAAQ4sK,IAEvB,MAAMC,EAAYF,EAAc7kK,MAAKvE,GACjCA,EAAKuB,KAAO8nK,GAA6B,UAAnBrpK,EAAKmD,YAE/BmmK,EAAUjmK,MAAS,GAAE+3H,GAAAA,YAA2BiuC,IAGhDD,EACMA,EAAcnmK,QAAOjD,GAAQA,EAAKuB,KAAO8nK,IAI/CD,EAAchrK,KAAKkrK,MAGhBF,EArDmBG,CAA8BJ,OAKxD,MAAM7W,EAAS9vJ,EAAU4F,MAAM1E,GAG/B,OAAO,IAAIyE,sBAAsB,CAC7BrE,KAAME,EAAKF,KACXG,IAAKquJ,IA4jCekX,CAAep8B,GAOvC,OAHAA,EAAoBlxI,KAAKgqK,iBAAiB94B,GAC1ClxI,KAAKy/I,MAAM,0DAA2DmnB,GAAQ11B,IAEvE,IAAInnG,SAAQ,CAACC,EAASC,KACzBjqC,KAAKusF,eAAegsD,qBAAqBrH,GACpCtwF,MAAK,KACF5gD,KAAKy/I,MAAM,iCACX,MAAMslB,EAAc3pC,GAAAA,SAAiB8V,EAAkBnpI,KAEnDg9J,IAAgB/kK,KAAK+kK,cACrB/kK,KAAK+kK,YAAcA,EACnB/kK,KAAKwzF,aAAa37D,KAAKkD,GAAAA,QAAAA,qBAAgC/6B,KAAM+kK,IAGjE/kK,KAAK6sK,2BAEL7iI,OACDvB,IACCzoC,KAAKy/I,MAAM,gCAAiCh3G,GAC5CzoC,KAAKwzF,aAAa37D,KAAKkD,GAAAA,QAAAA,8BAAyC0N,EAAKzoC,MACrEiqC,EAAOxB,UAcvB67H,GAAwBrjK,UAAUk1I,0BAA4B,SAASj7C,EAAamoE,GAAiB,MACjG,GAAInoE,EAAc,EACd,MAAM,IAAIl3F,MAAO,wBAAuBk3F,KAI5C,GAAI31D,GAAQmhD,gBACR,OAAO38C,QAAQC,UASnB,GANIqtF,GAAAA,+BACAr3H,KAAK8lK,kBAAkB5gJ,IAAIm+I,EAAgBptB,gBAAiB/6C,GAE5Dl7F,KAAK6lK,sBAAwB3qE,GAG5BmoE,GAAmBA,EAAgBniE,UACpC,OAAOn3D,QAAQC,UAEnB,MAAMujI,EAAcvtK,KAAKuyG,mBAAmB8wD,EAAgBvT,YAE5D,IAAKyd,EACD,OAAOxjI,QAAQC,UAEnB,MAAMopC,EAAam6F,EAAYtJ,gBAE/B,GAAK7wF,MAAAA,GAAD,UAACA,EAAY8wF,iBAAb,QAAC,EAAuBxiK,OACxB,OAAOqoC,QAAQC,UAInB,MAAMwjI,EAAaxtK,KAAKwjK,wBAp3EW,sBADD,qBAy3ElCpwF,EAAWq6F,sBAAwBD,EACnCjpK,GAAOiH,KAAM,GAAExL,mDAAmDwtK,WAAoBnK,KAGtFrjK,KAAK0tK,sBAAwB1tK,KAAKqlK,SAASjC,8BAA8BC,EAAiBnoE,GAC1F,MAAMyyE,EAAc3tK,KAAKqlK,SAAS5B,2BAA2BJ,GACvD59D,EAAY49D,EAAgB3T,eAElC,GAAI1vJ,KAAK+6J,gBAAiB,CACtB,IAAK,MAAMwI,KAAYnwF,EAAW8wF,UAAW,CACU,QAA/C9wF,EAAW8wF,UAAUzrJ,eAAe8qJ,KACpCnwF,EAAW8wF,UAAUX,GAAUpb,OAASnoJ,KAAK0tK,sBAAsBnK,GAInEh+H,GAAQ8gD,cAAgBjT,EAAW8wF,UAAUX,GAAUkK,sBAAwBD,GAG3ExtK,KAAKszI,4BAA8BxU,GAAAA,MAC/B,UAAA9+H,KAAKD,eAAL,mBAAcwvI,oBAAd,SAA4ByyB,kBACzBhiK,KAAKwjK,yBACLxjK,KAAKwlK,oBACZpyF,EAAW8wF,UAAUX,GAAU/rF,WAAam2F,EAAYpK,KAIpEvjK,KAAKqlK,SAAShB,0BAA0BjxF,QAGrC,GAAI8nB,EAAc,EAAG,SACxB,IAAI0yE,EDz6EmB,ECu7EvB,GAXInoE,IAAc3oE,GAAU,UAAVA,QAAoBumI,EAAgB9tE,WAAa2F,IAC/D0yE,EAAc3jK,KAAKC,MAAMm5J,EAAgB9tE,WAAa2F,IAG1D9nB,EAAW8wF,UAAU,GAAG/b,QAAS,EACjC/0E,EAAW8wF,UAAU,GAAG3B,sBAAwBqL,EAGhDroI,GAAQ8gD,cAAgBjT,EAAW8wF,UAAU,GAAGuJ,sBAAwBD,GAGpExtK,KAAKszI,4BAA8BxU,GAAAA,KAAnC,UAAwD9+H,KAAKD,eAA7D,iBAAwD,EAAcwvI,oBAAtE,OAAwD,EAA4ByyB,iBAAkB,OACtG,IAAI5sE,EAAO,UAAGp1F,KAAK6nK,gCAAR,aAAG,EAA+B5zH,KAET,QAAhCwxD,IAAc3oE,GAAU,UAAVA,SACds4D,EAAO,oBAAGp1F,KAAKqlK,SAAS/C,2BACnBj6J,MAAKwlK,GAASA,EAAMtL,wBAA0BqL,WAD5C,aAAG,EACuDp2F,kBAD1D,QACwE4d,GAEnFhiB,EAAW8wF,UAAU,GAAG1sF,WAAa4d,QAGzChiB,EAAW8wF,UAAU,GAAG/b,QAAS,EAKrC,OAFA5jJ,GAAOiH,KAAM,GAAExL,2BAA2Bk7F,eAAyB95F,KAAKF,UAAUkyE,EAAW8wF,cAEtFqJ,EAAYpJ,cAAc/wF,GAAYxyB,MAAK,KAC9CyiH,EAAgBjS,qBAAuBl2D,EACvCl7F,KAAKwzF,aAAa37D,KAAKkD,GAAAA,QAAAA,2CAAsDsoI,OAiBrFiB,GAAwBrjK,UAAUu5I,uBAAyB,SAAS2N,GAChE5jJ,GAAOynF,MAAO,GAAEhsF,+BAA+BmoJ,KAC/C,MAAMwhB,EAAU3pK,KAAK0kK,sBAAwBvc,EAI7C,OAFAnoJ,KAAK0kK,oBAAsBvc,EAEvBnoJ,KAAKwlK,kBACLxlK,KAAKqlK,SAAS7qB,uBAAuB2N,IAG9B,GAGJwhB,GAYXrF,GAAwBrjK,UAAU6sK,UAAY,SAASC,GAA2C,IAApC35E,EAAoC,uDAAzB,IAAK45E,EAAoB,uDAAL,IACzF,IAAKhuK,KAAKwkK,YAAa,CACnB,GAAIxkK,KAAKusF,eAAe2+E,WAAY,CAChC,MAAM+C,EAAYjuK,KAAKusF,eAAe2+E,aAAa7iK,MAAKwE,GAAKA,EAAEqhK,OAE/DluK,KAAKwkK,YAAcyJ,GAAaA,EAAUC,KAC1CluK,KAAKwkK,aAAejgK,GAAOiH,KAAM,GAAExL,gDAGvC,IAAKA,KAAKwkK,YAAa,CACnB,MAAM2J,EAAkBzpK,MAAMm6F,KAAK7+F,KAAKqyG,YAAY/oG,UAAUjB,MAAKrD,GAAKA,EAAEuzF,iBAEtEv4F,KAAKusF,eAAe6hF,kBAAoBD,IACxCnuK,KAAKwkK,YAAcxkK,KAAKusF,eAAe6hF,iBAAiBD,EAAgBre,aAE5E9vJ,KAAKwkK,aAAejgK,GAAOiH,KAAM,GAAExL,iEAGnCA,KAAKwkK,cACLxkK,KAAKwkK,YAAY6J,aAAeruK,KAAKsuK,cAAc1tK,KAAKZ,OAIhE,GAAIA,KAAKwkK,YAAa,CAClB,GAAIxkK,KAAKwkK,YAAY+J,WAOjB,YANAvuK,KAAKykK,gBAAgBviK,KAAK,CACtB6rK,MAAAA,EACA35E,SAAAA,EACA45E,aAAAA,IAMRhuK,KAAKwkK,YAAYgK,WAAWT,EAAO35E,EAAU45E,QAE7CzpK,GAAO2T,KAAM,GAAElY,iDAavBskK,GAAwBrjK,UAAUqtK,cAAgB,SAASh2I,GAGvD,GAAIt4B,KAAKwkK,aAA8B,KAAflsI,EAAMm2I,MAAezuK,KAAKykK,gBAAgB/iK,OAAQ,CACtE,MAAM,MAAEqsK,EAAF,SAAS35E,EAAT,aAAmB45E,GAAiBhuK,KAAKykK,gBAAgBt3H,QAE/DntC,KAAKwkK,YAAYgK,WAAWT,EAAO35E,EAAU45E,KAQrD1J,GAAwBrjK,UAAUoyI,qBAAuB,WACrD,MAAMymB,EAAU1+B,GAAAA,eAEhB72H,GAAOiH,KAAM,GAAExL,oCAAoC85J,KACnD95J,KAAKi7J,eAAemC,eAAetD,IAOvCwK,GAAwBrjK,UAAU63I,kBAAoB,WAClDv0I,GAAOiH,KAAM,GAAExL,qCACfA,KAAKi7J,eAAeiC,uBAQxBoH,GAAwBrjK,UAAU21I,MAAQ,WACtC52I,KAAKy/I,MAAM,QAGXz/I,KAAK4sI,eAAev/F,IAAIiqH,GAAoCt3J,KAAKklK,mBACjEllK,KAAK4sI,eAAev/F,IAAIiqH,GAAyCt3J,KAAKilK,uBACtEjlK,KAAKwlK,kBAAoBxlK,KAAKusF,eAAehgD,oBAAoB,QAASvsC,KAAK+lK,SAE/E,IAAK,MAAM2I,KAAc1uK,KAAK2kK,aAAar7J,SACvC,IAAK,MAAMq7J,KAAgB+J,EAAWplK,SAClC,IAAK,MAAM+gG,KAAes6D,EACtB3kK,KAAKgpK,mBAAmB3+D,GAIpCrqG,KAAK2kK,aAAav9F,QAElBpnE,KAAK4kK,cAAgB,GAErB5kK,KAAKwkK,YAAc,KACnBxkK,KAAKykK,gBAAkB,GAElBzkK,KAAK0hG,IAAIitE,sBAAsB3uK,OAChCuE,GAAOlD,MAAO,GAAErB,iDAEO,OAAvBA,KAAKslK,gBACLhjK,OAAO2wF,cAAcjzF,KAAKslK,eAC1BtlK,KAAKslK,cAAgB,MAEzB/gK,GAAOiH,KAAM,GAAExL,+BACfA,KAAKusF,eAAeqqD,SAGxB0tB,GAAwBrjK,UAAUu3I,aAAe,SAAS/3D,GACtD,OAAOzgF,KAAK4uK,sBAAqB,EAAoBnuF,IAGzD6jF,GAAwBrjK,UAAU6yI,YAAc,SAASrzD,GACrD,OAAOzgF,KAAK4uK,sBAAqB,EAAkBnuF,IAGvD6jF,GAAwBrjK,UAAU2tK,qBAAuB,SACjDC,EACApuF,GACJ,MAAMquF,EAAUD,EAAU,QAAU,SAEpC7uK,KAAKy/I,MAAO,SAAQqvB,IAAW1tK,KAAKF,UAAUu/E,EAAa,KAAM,MAEjE,MAAMsuF,EAAgB,CAAC1X,EAAW2X,EAAWC,KACzC,IACIjvK,KAAKy/I,MACA,SAAQqvB,2BAAkClI,GAAQvP,IAElDr3J,KAAKwlK,mBAGDxlK,KAAK+mK,mBAAmBjyE,GAAU2G,QAC/Bz7F,KAAKi7J,eAAeoC,wBACxBr9J,KAAKqzI,uBAITgkB,EAAY,IAAIprJ,sBAAsB,CAClCrE,KAAMyvJ,EAAUzvJ,KAChBG,IAAK/H,KAAKi7J,eAAeqC,gCACrBjG,EAAUtvJ,OAGlB/H,KAAKy/I,MACA,SAAQqvB,wEAETlI,GAAQvP,KAGhB,MAAMgM,EAAkBrjK,KAAKg2I,sBAAsB,GAG/Ch2I,KAAK+6J,iBAAmBx1H,GAAQyjD,gCAC5Bq6E,MAAAA,OAAA,EAAAA,EAAiB3T,kBAAmB5yH,GAAU,UAAVA,QACrC98B,KAAKwlK,mBACJxlK,KAAKwjK,2BAETnM,EAAYr3J,KAAKg7J,UAAU7uJ,sBAAsBkrJ,GACjDr3J,KAAKy/I,MAAO,SAAQqvB,yCAAgDlI,GAAQvP,MAG3Er3J,KAAKD,QAAQwrH,YAAchmF,GAAQyjD,+BAEpCquE,EAAY,IAAIprJ,sBAAsB,CAClCrE,KAAMyvJ,EAAUzvJ,KAChBG,IAAK/H,KAAKo7J,YAAYqB,eAAepF,EAAUtvJ,OAGnD/H,KAAKy/I,MACA,SAAQqvB,2CAETlI,GAAQvP,KAGhB,MAAMxuJ,EAAU7I,KAAKopK,gBAAgB/R,GAErCr3J,KAAKkvK,sBAAsBrmK,GAE3BmmK,EAAU3X,GACZ,MAAOtqJ,GACL/M,KAAKy/I,MAAO,SAAQqvB,WAAkB/hK,GACtC/M,KAAKy/I,MAAO,SAAQqvB,WAAkBlI,GAAQvP,IAC9C9yJ,GAAOlD,MAAO,GAAErB,cAAc8uK,WAAkB/hK,EAAG65J,GAAQvP,IAE3D4X,EAASliK,KAIXoiK,EAAgB,CAAC1mI,EAAKwmI,KACxBjvK,KAAKy/I,MAAO,SAAQqvB,aAAoBrmI,GACxC,MAAM2mI,EACAP,EACI9zI,GAAAA,QAAAA,oBACAA,GAAAA,QAAAA,qBAEV/6B,KAAKwzF,aAAa37D,KAAKu3I,EAAW3mI,EAAKzoC,MAEvCivK,EAASxmI,IAKb,GAAIzoC,KAAKylK,iCAAkC,CACvC,MAAM5B,EAAc7jK,KAAKusF,eAAes2E,kBACnCx6J,MAAKrD,IAAC,eAAIA,EAAEqkC,WAAY,UAAArkC,EAAEqkC,gBAAF,mBAAY8uC,aAAZ,eAAmB5B,QAASue,GAAU2G,SAEnE,GAAIooE,EAAa,WACb,IAAIwL,EAAY,UAAGhnF,eAAeC,gBAAgBwM,GAAU2G,cAA5C,aAAG,EAAiD1lB,OACpE,MAAM/hE,EAAQ,UAAGhU,KAAKiqK,uBAAR,aAAG,EAAsBj2J,SACjC+uG,EAAM,UAAG/iH,KAAKiqK,uBAAR,aAAG,EAAsBlnD,OAEjCssD,GAAgBr7J,GAAY+uG,EAG5BssD,EAAax/H,MAAK2mC,GACPA,EAAKxiE,SAASmjB,gBAAmB,GAAE29D,GAAU2G,SAASznF,KAAc,EAAI,IAE5Eq7J,GAAgBr7J,IACvBq7J,EAAeA,EACVtoK,QAAOyvE,GAAQA,EAAKxiE,SAASmjB,gBAAmB,GAAE29D,GAAU2G,SAASznF,OAK1EuxB,GAAQ2hD,oBACRmoF,EAAeA,EACVtoK,QAAOyvE,GAAQA,EAAKxiE,SAASmjB,gBAAmB,GAAE29D,GAAU2G,SAASqjC,GAAAA,YAG9E,IACI+kC,EAAYyL,oBAAoBD,GAClC,MAAO5mI,GACLlkC,GAAO2T,KAAM,GAAElY,iCAAiCgU,YAAmB+uG,YAAkBt6E,KAKjG,OAAO,IAAIsB,SAAQ,CAACC,EAASC,KACzB,IAAIslI,EAGAA,EADAV,EACY7uK,KAAKusF,eAAeunD,YAAYrzD,GAEhCzgF,KAAKusF,eAAeisD,aAAa/3D,GAGjD8uF,EACK3uH,MACG74C,GAAOgnK,EAAchnK,EAAKiiC,EAASC,KACnC5oC,GAAS8tK,EAAc9tK,EAAO4oC,SAS9Cq6H,GAAwBrjK,UAAUuuK,oBAAsB,SAAShX,GAC7D,OAAIA,GAAWA,EAAQ3jH,QAAU2jH,EAAQ3jH,OAAOnzC,OACrC82J,EAAQ3jH,OAAO,GAAG/tC,MAAM,GACxB0xJ,GAAWA,EAAQ1xJ,OAAS0xJ,EAAQ1xJ,MAAMpF,OAC1C82J,EAAQ1xJ,MAAM,GAGlB,MAUXw9J,GAAwBrjK,UAAUiuK,sBAAwB,SAASrmK,GAC/D,IAAK,MAAMsvE,KAASn4E,KAAKqyG,YAAY/oG,SAAU,CAC3C,MAAMmmK,EAAmBzvK,KAAKwlK,iBAAmBrtF,EAAMgpB,UAAYhpB,EAAM07E,WAEzE,GAAIhrJ,EAAQ02C,IAAIkwH,GAAmB,CAC/B,MAAM3V,EAAUjxJ,EAAQmc,IAAIyqJ,GAE5B,IAAK3V,EAGD,YAFAv1J,GAAOlD,MAAO,GAAErB,iCAAiCyvK,KAIrD,MAAM5V,EAAU75J,KAAK6kK,WAAW7/I,IAAImzD,EAAM04E,OACpC6e,EAAa1vK,KAAKwvK,oBAAoB1V,GACtC6V,EAAa3vK,KAAKwvK,oBAAoB3V,GAGxC6V,IAAeC,IACfA,GAAcprK,GAAOlD,MAAO,GAAErB,mCAAmCm4E,gBAAoB2hF,KACrF95J,KAAK6kK,WAAW3/I,IAAIizD,EAAM04E,MAAOiJ,GACjC95J,KAAKwzF,aAAa37D,KAAKkD,GAAAA,QAAAA,yBAAoCo9C,EAAOu3F,SAE9Dv3F,EAAMqtB,gBAAmBrtB,EAAM+oB,WAIvC38F,GAAO2T,KAAM,GAAElY,kDAAkDm4E,aAAiBs3F,OAK9FnL,GAAwBrjK,UAAU2xI,gBAAkB,SAASlhE,GAQzD,OAPA1xE,KAAKy/I,MAAM,kBAAmBr+I,KAAKF,UAAU,CACzCwwE,UAAWA,EAAUA,UACrBwgE,OAAQxgE,EAAUwgE,OAClBL,cAAengE,EAAUmgE,cACzB3/D,iBAAkBR,EAAUQ,kBAC7B,KAAM,MAEFlyE,KAAKusF,eAAeqmD,gBAAgBlhE,IAQ/C4yF,GAAwBrjK,UAAU+6F,0BAA4B,WAC1D,IAAI4zE,EAAgB,EAEoC,MAMxD,OANI5vK,KAAK+6J,iBAAmB/6J,KAAK0tK,sBAC7BkC,EAAa,UAAG5vK,KAAK0tK,sBAAsB3mK,QAAOqJ,GAAUk3E,QAAQl3E,YAAvD,aAAG,EAA8D1O,OACvE1B,KAAK+6J,kBACZ6U,EAAgB/N,GAAengK,QAG5BkuK,GASXtL,GAAwBrjK,UAAUk2F,SAAW,WACzC,OAAOn3F,KAAKusF,eAAe4K,YAU/BmtE,GAAwBrjK,UAAUqpK,0BAA4B,SAASnyF,GACnE,MAAM04E,EAAQ14E,EAAM04E,MACpB,IAAI7pJ,EAAWhH,KAAKupK,SAAS1Y,GAO7B,GALI7pJ,GACAzC,GAAOlD,MAAO,GAAErB,6CAA6C6wJ,MAI7D7wJ,KAAK+6J,iBACD5iF,EAAMu3E,iBAAmB5yH,GAAU,UAAVA,QAAqB98B,KAAKwjK,wBAavDx8J,EAAW,CACPF,MAAO,CAAEs0H,GAAAA,gBACTvmF,OAAQ,QAfqE,CACjF7tC,EAAW,CACPF,MAAO,GACP+tC,OAAQ,IAEZ,IAAK,IAAIrzC,EAAI,EAAGA,EAAIqgK,GAAengK,OAAQF,IACvCwF,EAASF,MAAM5E,KAAKk5H,GAAAA,gBAExBp0H,EAAS6tC,OAAO3yC,KAAK,CACjB4E,MAAOE,EAASF,MAAMnC,QACtB4D,UAAW,QAQnB,IAAKvI,KAAKD,QAAQwrH,WAAY,CAK1B,MAAMskD,EAAe7oK,EAASF,MAAMpF,OAEpC,IAAK,IAAIF,EAAI,EAAGA,EAAIquK,IAAgBruK,EAAG,CACnC,MAAMiI,EAAczC,EAASF,MAAMtF,GAC7B46J,EAAUhhC,GAAAA,eAEhBp0H,EAASF,MAAM5E,KAAKk6J,GACpBp1J,EAAS6tC,OAAO3yC,KAAK,CACjB4E,MAAO,CAAE2C,EAAa2yJ,GACtB7zJ,UAAW,SAOvB,OAHAvB,EAAS8C,KAAOquE,EAAM07E,WACtB7zJ,KAAK6kK,WAAW3/I,IAAI2rI,EAAO7pJ,GAEpBA,GAQXs9J,GAAwBrjK,UAAU4I,gBAAkB,WAChD,OAAO7J,KAAKwlK,kBAQhBlB,GAAwBrjK,UAAUigB,SAAW,WACzC,MAAQ,UAASlhB,KAAKqF,WAAWrF,KAAKuvF,MAAQ,MAAQ,UC55F1D,MAAMhrF,IAAS2B,EAAAA,EAAAA,iCAMf,ICzBY4pK,GDyBRC,GAA0B,EAO1BC,GAAoB,EAiBxB,SAASC,KAA6C,IAA1BC,EAA0B,uDAAJ,GAC9C,OAAOA,EAAoBhpK,KAAIipK,IAC3B,MAAM,SACFv1C,EADE,WAEFC,EAFE,OAGFzqH,EAHE,MAIF+nE,EAJE,UAKFstB,EALE,QAMFsoD,GACAoiB,GAEE,SAAE9lB,EAAF,WAAY6C,GAAe/0E,EAAM+4E,cAOvC,OAFA8e,GAAoBx+E,GAAqBw+E,IAElC,IAAIpf,GAAgB,CACvBvG,SAAAA,EACA6C,WAAAA,EACAjqE,UAAW9K,EAAM5B,KACjBs6E,MAAOmf,GACPp1C,SAAAA,EACAC,WAAAA,EACAzqH,OAAAA,EACA+nE,MAAAA,EACAstB,UAAWA,GAAa,KACxBsoD,QAAAA,OAQG,MAAMga,WAAYp4D,GAM7Bv2F,YAAYslF,GAA0B,IAAd3+F,EAAc,uDAAJ,GAC9BmlF,QACAllF,KAAK0+F,WAAaA,EAMlB1+F,KAAKowK,gBAAkB,IAAI/pG,IAE3BrmE,KAAKqyG,YAAc,GAEnBryG,KAAKD,QAAUA,EAKfC,KAAK2lJ,SAAW,KAUhB3lJ,KAAKqwK,YAAStkK,EAQd/L,KAAKswK,gBAAkB,KASvBtwK,KAAKuwK,kBAAoB,KASzBvwK,KAAKwwK,qBAAkBzkK,EAQvB/L,KAAKywK,mBAAqB,KAG1BzwK,KAAK0wK,qBAAuB1wK,KAAKypG,gBAAgB7oG,KAAKZ,MAGtDA,KAAK2wK,gCAAkC3wK,KAAK2+J,2BAA2B/9J,KAAKZ,MAE5EA,KAAK4wK,qBAAuB5wK,KAAK4wK,qBAAqBhwK,KAAKZ,MAC3DA,KAAK6wK,iCACC7wK,KAAK6wK,iCAAiCjwK,KAAKZ,MAQjDA,KAAK8wK,WAAaC,GAId3gB,GAAAA,wBAAiC,YACjCA,GAAAA,YACIr1H,GAAAA,QAAAA,4BACA/6B,KAAK6wK,kCAGTzgB,GAAAA,YACIr1H,GAAAA,QAAAA,oBACA/6B,KAAK4wK,uBAUjBI,UACI5gB,GAAAA,eAAwBr1H,GAAAA,QAAAA,4BAAuC/6B,KAAK6wK,kCACpEzgB,GAAAA,eAAwBr1H,GAAAA,QAAAA,oBAA+B/6B,KAAK4wK,sBAExD5wK,KAAKixK,sBACLjxK,KAAKmqC,eACDpP,GAAAA,QAAAA,kBACA/6B,KAAKixK,sBAYO,yBAACC,GACrB,OAAOjB,GAAmBiB,GAYO,sCAACnxK,GAClC,OAAOqwJ,GAAAA,+BAAwCrwJ,GAC1C6gD,MAAKswH,GAAcjB,GAAmBiB,KAW/CC,wBAAwB5kF,EAAgBm5D,GACpC1lJ,KAAK2lJ,SAAW,IAAIF,GAAcl5D,EAAgBm5D,EAAO1lJ,KAAKwzF,cAE9DxzF,KAAKixK,qBAAuB,KACxB,MAAMG,EAAW,CAAC/vK,EAAOgwK,EAASlqK,KAC9BqxB,KAAAA,iBAAsCn3B,GACtCkD,GAAOlD,MAAO,eAAcgwK,KAAWjwK,KAAKF,UAAUiG,uBAA4B9F,IAKtF,GAAIrB,KAAKsxK,0BACL,IACItxK,KAAK2lJ,SAASgC,uCAAuC3nJ,KAAKsxK,2BAC5D,MAAOjwK,GACL+vK,EAAS/vK,EAAO,2BAA4BrB,KAAKsxK,2BAGzD,GAAItxK,KAAKywK,mBACL,IACIzwK,KAAK2lJ,SAAS2B,6BAA6BtnJ,KAAKywK,oBAClD,MAAOpvK,GACL+vK,EAAS/vK,EAAO,gCAAiCrB,KAAKywK,oBAG9D,QAAoC,IAAzBzwK,KAAKwwK,gBACZ,IACIxwK,KAAK2lJ,SAAS8B,mCAAmCznJ,KAAKwwK,iBACxD,MAAOnvK,GACL+vK,EAAS/vK,EAAO,0BAA2BrB,KAAKwwK,iBAGxD,QAA2B,IAAhBxwK,KAAKqwK,SAA2C,IAAjBrwK,KAAKqwK,OAC3C,IACIrwK,KAAK2lJ,SAASyB,oBAAoBpnJ,KAAKqwK,QACzC,MAAOhvK,GACL+vK,EAAS/vK,EAAO,oBAAqBrB,KAAKqwK,QAGlD,IAAKh5C,GAAAA,+BACD,IACIr3H,KAAK2lJ,SAASiC,qBAAqB5nJ,KAAK8wK,YAC1C,MAAOzvK,GACL+vK,EAAS/vK,EAAO,mBAAoBrB,KAAK8wK,YAIjD9wK,KAAKmqC,eAAepP,GAAAA,QAAAA,kBAA6B/6B,KAAKixK,sBACtDjxK,KAAKixK,qBAAuB,MAEhCjxK,KAAK43B,YAAYmD,GAAAA,QAAAA,kBAA6B/6B,KAAKixK,sBAGnDjxK,KAAK43B,YAAYmD,GAAAA,QAAAA,uBAAkC/6B,KAAK0wK,sBAEpDr5C,GAAAA,gCAEAr3H,KAAK43B,YAAYmD,GAAAA,QAAAA,0BAAqC/6B,KAAK2wK,iCAYnEC,uBACI5wK,KAAK6wK,iCAAiCzgB,GAAAA,wBAQ1C3mD,kBAAqC,IAArB2+C,EAAqB,uDAAJ,GAC7B,MAAMmpB,EAAoBvxK,KAAKswK,iBAAmB,GAClD,IAAIkB,EAAwB,GACxBC,EAAyB,GAE7BzxK,KAAKswK,gBAAkBloB,EAEvBopB,EAAwBD,EAAkBxqK,QACtC1B,IAAOrF,KAAK0nG,UAAUriG,KAE1BosK,EAAyBrpB,EAAerhJ,QACpC1B,IAAyC,IAAnCksK,EAAkBluK,QAAQgC,KAEpCrF,KAAK0+F,WAAWlL,aAAa37D,KACzBqjD,GACAs2F,EACAC,GASR9S,6BAAkD,IAAvBtW,EAAuB,uDAAJ,GAC1C,MAAMqpB,EAAsB1xK,KAAKuwK,mBAAqB,GACtD,IAAIjR,EAA0B,GAC1BC,EAA2B,GAE/Bv/J,KAAKuwK,kBAAoBloB,EAEzBiX,EAA0BoS,EAAoB3qK,QAAOq6H,IAAephI,KAAKq+J,qBAAqBj9B,KAE9Fm+B,EAA2BlX,EAAiBthJ,QACxCq6H,IAA2D,IAA7CswC,EAAoBruK,QAAQ+9H,KAE9CphI,KAAK0+F,WAAWlL,aAAa37D,KACzBqjD,GACAokF,EACAC,EACAp6J,KAAK8nD,OAOb+4C,cACQhmG,KAAK2lJ,WAOD3lJ,KAAK2lJ,UAAmC,cAAvB3lJ,KAAK2lJ,SAASoB,MAC/B/mJ,KAAK2lJ,SAAS/O,QAGlB52I,KAAK2lJ,SAAW,MASxBzqB,2BAA2BC,GACvBi1B,GAAAA,2BAAoCj1B,GASxCw2C,+BAA+BlxF,GAC3BzgF,KAAKsxK,0BAA4B7wF,EAE7BzgF,KAAK2lJ,UAAY3lJ,KAAK2lJ,SAASc,UAC/BzmJ,KAAK2lJ,SAASgC,uCAAuClnE,GAa7Dg1D,2BAA2BF,GACvBv1I,KAAKwwK,gBAAkBj7B,EAEnBv1I,KAAK2lJ,UAAY3lJ,KAAK2lJ,SAASc,UAC/BzmJ,KAAK2lJ,SAAS8B,mCAAmClS,GAWzDq8B,aAAansE,GACLzlG,KAAK8wK,aAAerrE,IACpBzlG,KAAK8wK,WAAarrE,EAEdzlG,KAAK2lJ,UAAY3lJ,KAAK2lJ,SAASc,UAC/BzmJ,KAAK2lJ,SAASiC,qBAAqBniD,IAU/CosE,oBAAoBzwC,EAAY37B,GACxBzlG,KAAK2lJ,UAAY3lJ,KAAK2lJ,SAASc,UAC/BzmJ,KAAK2lJ,SAASkC,2BAA2BzmB,EAAY37B,GAe7DqsE,gBAAgBC,GACZ/xK,KAAKywK,mBAAqBsB,EAEtB/xK,KAAK2lJ,UAAY3lJ,KAAK2lJ,SAASc,UAC/BzmJ,KAAK2lJ,SAAS2B,6BAA6ByqB,GASjC,mBAAC3C,EAAWtkI,GAC1BslH,GAAAA,YAAqBgf,EAAWtkI,GAQf,sBAACskI,EAAWtkI,GAC7BslH,GAAAA,eAAwBgf,EAAWtkI,GAO5B,cAAe,IAAd/qC,EAAc,uDAAJ,GAGlB,OAFAC,KAAKD,QAAUA,EAERqwJ,GAAAA,KAAcpwJ,KAAKD,SAmB9BiwI,qBAAqBgiC,EAAW3lC,EAAU98C,EAAOxvF,GAC7C,MAAMyrJ,EAAgBpqJ,KAAKwJ,MAAMxJ,KAAKF,UAAUkvJ,GAAAA,qBAEN,IAA/BrwJ,EAAQ4vI,qBACfygB,GAAAA,gBAAyB5E,EAAezrJ,EAAQ4vI,oBAEhDlzC,GAAWe,UAAUnT,uBACjB,CAAEslD,mBAAoB5vI,EAAQ4vI,sBAGlC5vI,EAAQuvI,0BACR/qI,GAAOynF,MAAM,iDACbqgD,EAAS4lC,0BAA2B,IAGX1sI,GAAQmhD,iBAC7BnhD,GAAQ2hD,oBAAsBnnF,EAAQ8J,mBAG1CtF,GAAOynF,MAAM,gDACbqgD,EAAS6lC,aAAe,UAGxBnyK,EAAQyvI,iBACRnD,EAASgX,mBAAqB,SAMlChX,EAAS8lC,aAAe,aAExBpC,GAA0Bv+E,GAAqBu+E,IAE/C,MAAMqC,EACA,IAAI9N,GACFtkK,KACA+vK,GACAiC,EACA3lC,EAAUmf,EACVj8D,EAAOxvF,GAIf,OAFAC,KAAKowK,gBAAgBlrJ,IAAIktJ,EAAc/sK,GAAI+sK,GAEpCA,EAYXzD,sBAAsB0D,GAClB,MAAMhtK,EAAKgtK,EAAwBhtK,GAEnC,QAAIrF,KAAKowK,gBAAgB7wH,IAAIl6C,KAEzBrF,KAAKowK,gBAAgB7/E,OAAOlrF,IAErB,GAWfitK,cAAcn6F,GACV,IAAKA,EACD,MAAM,IAAIn0E,MAAM,wCAGpBhE,KAAKqyG,YAAYnwG,KAAKi2E,GAEtBA,EAAMumB,WAAa1+F,KAAK0+F,WAO5B6zE,sBACI,OAAOvyK,KAAKuwK,kBAOhBr6B,qBACI,MAAMs8B,EAAaxyK,KAAK47F,eAAe9G,GAAU2G,OAGjD,OAAO+2E,EAAW9wK,OAAS8wK,EAAW,QAAKzmK,EAO/CiqI,sBACI,OAAOh2I,KAAK47F,eAAe9G,GAAU2G,OAOzCg3E,qBACI,MAAMC,EAAa1yK,KAAK47F,eAAe9G,GAAUqH,OAGjD,OAAOu2E,EAAWhxK,OAASgxK,EAAW,QAAK3mK,EAO/C65J,qBACI,OAAO5lK,KAAK0+F,WAAWmG,WAS3BjJ,eAAe3Y,GACX,IAAIwkF,EAASznK,KAAKqyG,YAAY1tG,QAO9B,YALkBoH,IAAdk3E,IACAwkF,EAASA,EAAO1gK,QACZoxE,GAASA,EAAMgpB,YAAcle,KAG9BwkF,EASXL,gBAAgBnkF,GACZ,IAAI0hF,EAAe,GAEnB,IAAK,MAAMx1E,KAAOnvF,KAAKowK,gBAAgB9mK,SAAU,CAC7C,MAAMqpK,EAAiBxjF,EAAIi4E,qBAAgBr7J,EAAWk3E,GAElD0vF,IACAhO,EAAeA,EAAa5/J,OAAO4tK,IAI3C,OAAOhO,EAQXtiE,aAAal7F,GACT,MAAMyrK,EAAe,GASrB,OAPA5yK,KAAK47F,eAAe9G,GAAUqH,OAAO57F,SAAQ6nK,IAEzCwK,EAAa1wK,KAAKiF,EAAQihK,EAAWl5E,OAASk5E,EAAWxT,aAKtD7qH,QAAQ8pG,IAAI++B,GAQvBpwE,aAAar7F,GACT,MAAMyrK,EAAe,GAUrB,OARA5yK,KAAK47F,eAAe9G,GAAU2G,OAAO12F,OAAO/E,KAAK47F,eAAe9G,GAAU2+D,YACrElzJ,SAAQkvJ,IAELmjB,EAAa1wK,KAAKiF,EAAQsoJ,EAAWvgE,OAASugE,EAAWmF,aAK1D7qH,QAAQ8pG,IAAI++B,GAOvBC,iBAAiB16F,GACb,MAAMziD,EAAM11B,KAAKqyG,YAAYhvG,QAAQ80E,IAExB,IAATziD,GAIJ11B,KAAKqyG,YAAY7uG,OAAOkyB,EAAK,GAQT,yBAACo9I,EAAY1iK,GACjC,OAAOggJ,GAAAA,kBAA2B0iB,EAAY1iK,GAOhC,mBAACA,GACf,OAAOggJ,GAAAA,YAAqBhgJ,GAOf,kBAAC+nE,GACd,OAAOi4E,GAAAA,WAAoBj4E,GAOH,+BACxB,OAAOi4E,GAAAA,wBAUmB,+BAAClC,GAC3B,OAAOkC,GAAAA,wBAAiClC,GAWpB,2BACpB,OAAO3oH,GAAQtjB,cAQQ,8BACvB,OAAOmuI,GAAAA,uBAQ6B,2CACpC,OAAOA,GAAAA,oCAOoC,kDAC3C,OAAOA,GAAAA,2CAOuB,mCAAChG,GAC/B,OAAOgG,GAAAA,4BAAqChG,GAUrB,4BAACC,GACxB,OAAO+F,GAAAA,qBAA8B/F,GAetB,oBAACj6I,GAChB,OAAO23J,GAAIC,iBAAiB5X,GAAAA,YAAqBhgJ,IAe9B,wBAAC4pH,GACpB,OAAOA,GAAyB,iBAAbA,GACC,YAAbA,EAQY,wBAACp9G,GACpBwzI,GAAAA,iBAA0BxzI,GAQR,uBAACuxI,GACnBiC,GAAAA,gBAAyBjC,GAOC,iCAC1B,OAAOiC,GAAAA,0BAMXzuD,qBACQ3hG,KAAK2lJ,WACL3lJ,KAAK2lJ,SAAS/O,QACd52I,KAAK2lJ,SAAW,KAEhB3lJ,KAAKmqC,eAAepP,GAAAA,QAAAA,uBAAkC/6B,KAAK0wK,uBAYnE/pE,cAAcxX,EAAKvoF,EAAM2qF,EAAYtB,GACjC,MAAM9X,EAAQgX,EAAImJ,eAAe1xF,GAE5BuxE,IAEOA,EAAMogB,gBAIPpgB,EAAM8X,YAAcA,GAC3B1rF,GAAOlD,MACF,GAAE82E,qBAAyB8X,EAAU,KAAO,kBAGrD9X,EAAMwuB,cAAcpV,EAAYpC,IAR5B5qF,GAAO2T,KAAM,6CAA4CtR,MAmBjEmsK,mBAAmB9zD,EAAIta,GACnB,IAAI3kG,KAAK2lJ,SAGL,MAAM,IAAI3hJ,MAAM,gCAFhBhE,KAAK2lJ,SAAS1uC,YAAYgI,EAAIta,GAWtCqiD,yBAAyBriD,GACjB3kG,KAAK2lJ,UAAY3lJ,KAAK2lJ,SAASc,UAC/BzmJ,KAAK2lJ,SAASqB,yBAAyBriD,GAU/CquE,SAAS7rK,GACDnH,KAAKqwK,SAAWlpK,IAChBnH,KAAKqwK,OAASlpK,EACVnH,KAAK2lJ,UAAY3lJ,KAAK2lJ,SAASc,UAC/BzmJ,KAAK2lJ,SAASyB,oBAAoBjgJ,GAEtCnH,KAAKwzF,aAAa37D,KAAKkD,GAAAA,QAAAA,oBAA+B5zB,IAU9DugG,UAAUriG,GACN,OAAQrF,KAAKswK,iBACNtwK,KAAKswK,gBAAgBjtK,QAAQgC,IAAO,EAU/Cg5J,qBAAqBj9B,GACjB,OAAQphI,KAAKuwK,mBACNvwK,KAAKuwK,kBAAkBltK,QAAQ+9H,IAAe,EAWzDyvC,iCAAiCxmB,GAC7B,MAAM4oB,EAAoBjzK,KAAKonK,gBAAgBtyE,GAAUqH,OAEzD,IAAK,MAAMhkB,KAAS86F,EAChB96F,EAAMw4E,eAAetG,cC3+BrBylB,GAAAA,EAAAA,oBAAAA,yBAAAA,EAAAA,qBAAAA,2BAAAA,KAAAA,GAAAA,KAcL,MAAMoD,GAAsBpD,GAAwBoD,oBAC9CC,GAAuBrD,GAAwBqD,qBCPtDx2I,GAAcnD,EAAQ,MACpBsD,UAASA,IAAKtD,EAAQ,MACtByD,WAAUA,IAAKzD,EAAQ,KAEzBj1B,IAAS2B,EAAAA,EAAAA,wDAcTktK,GAAoB,CACtB,CAAEx2I,MAAO,KACLC,OAAQ,KACRw2I,OAAQ,EACR78J,OAAQ,OACR88J,SAAU,KACd,CAAE12I,MAAO,KACLC,OAAQ,IACRw2I,OAAQ,EACR78J,OAAQ,OACR88J,SAAU,MACd,CAAE12I,MAAO,IACLC,OAAQ,IACRw2I,OAAQ,EACR78J,OAAQ,WACR88J,SAAU,KACd,CAAE12I,MAAO,IACLC,OAAQ,IACRw2I,OAAQ,EACR78J,OAAQ,WACR88J,SAAU,KACd,CAAE12I,MAAO,IACLC,OAAQ,IACRw2I,OAAQ,EACR78J,OAAQ,MACR88J,SAAU,MACd,CAAE12I,MAAO,IACLC,OAAQ,IACRw2I,OAAQ,EACR78J,OAAQ,MACR88J,SAAU,OAalB,IAAI7nD,GAAe,IAmEJ,MAAM8nD,GAOjBn6J,YAAYslF,EAAYlL,EAAczzF,GAAS,MAC3CC,KAAKwzF,aAAeA,EAKpBxzF,KAAKusG,YAAc7N,EAKnB1+F,KAAKwzK,YAAc,CACfC,kBAAmB,IACnBC,YAAQ3nK,GAMZ/L,KAAK2zK,8BAAgC,EAKrC3zK,KAAKwgH,SAAWzgH,EAMhBC,KAAK4zK,aAAe,GAMpB5zK,KAAK6zK,mBAAqB,EAM1B7zK,KAAK8zK,mBAAqB,GAGtB,UAAA9zK,KAAKwgH,SAAS/yG,cAAd,eAAsBg+G,cAAe,IACrCA,GAAezrH,KAAKwgH,SAAS/yG,OAAOg+G,cAKxC/sB,EAAWn0D,GACPwpI,GACA,KACI/zK,KAAKg0K,8BAA8B,GACnCh0K,KAAKwzF,aAAa37D,KACdi4I,GACA9vK,KAAKwzK,aACTxzK,KAAKi0K,0BAGbv1E,EAAW6C,KAAK3pE,YACZqF,GAAWi3I,8BACX,CAACzyE,EAAesJ,KACPtJ,EAAclS,OAAsB,cAAbwb,IACxB/qG,KAAK6zK,kBAAoBvxK,OAAOijG,YAAYt4C,UAQxDyxC,EAAWn0D,GACPwpI,IACA,CAAClyE,EAAa8C,KAxMC,UAyMPA,EAAQ/8F,MACR5H,KAAKm0K,mBACDtyE,EAAYsI,QAASxF,EAAQr7F,WAI7Co1F,EAAWn0D,GACPwpI,IACA,CAAClyE,EAAa8C,KACV3kG,KAAKm0K,mBAAmBtyE,EAAYsI,QAASxF,MAGrDjG,EAAWn0D,GACPwpI,IACA,CAAClyE,EAAa8C,KAjNa,sBAkNnBA,EAAQ/8F,MACR5H,KAAKwzF,aAAa37D,KACdk8I,GACAlyE,EAAYsI,QACZxF,MAKhBjG,EAAWa,WAAWnB,2BAA2Bp+F,KAAKo0K,kBAAkBxzK,KAAKZ,OAG7E0+F,EAAWn0D,GACPwpI,IACA57F,IACQA,EAAMqtB,iBACFrtB,EAAM+oB,UACNlhG,KAAK8zK,mBAAqB,EAE1B9zK,KAAKq0K,6BAIrB31E,EAAWn0D,GACPwpI,IACA57F,IACQA,EAAMqtB,iBAAmBrtB,EAAM+oB,WAC/BlhG,KAAKq0K,4BAGjB31E,EAAWgD,IAAIn3D,GACXxP,GAAAA,QAAAA,4CACAo9C,IACIn4E,KAAKwzK,YAAYpiB,qBAAuBj5E,EAAMi5E,wBAGtD1yD,EAAWn0D,GACPwpI,IACAO,IACIt0K,KAAKwzK,YAAYc,aAAeA,KAGxC51E,EAAWn0D,GACPwpI,IACAppF,IACI3qF,KAAKwzK,YAAYe,YACXzlK,QAAQ67E,GAAc,IAAI,oBAS5C0pF,yBACQr0K,KAAK8zK,kBAAoB,IACzB9zK,KAAK8zK,kBAAoBxxK,OAAOijG,YAAYt4C,OAWpDunH,4BAA4B/uE,EAAWvE,EAASuzE,GAI5C,MAAMl/E,EAAa54D,GAAY83I,GAE/B,IACI/+E,EADAg/E,EAAU,IA2Bd,GAtBI10K,KAAKwzK,YAAY99E,aACjBA,EAAa11F,KAAKwzK,YAAY99E,WAAWJ,OAgBrC4L,IACAxL,GAAc,KAIlBwL,IAAY3L,GAAckQ,IAAc3oE,GAAU63I,SAC/C30K,KAAK6zK,kBAAoB,GACzB7zK,KAAK8zK,kBAAoB,OAGT/nK,IAAf2pF,GACAnxF,GAAOlD,MAAM,6DAEbqzK,EAAU,KAEVA,EADOh/E,GAAc,EACX,IACHA,GAAc,EACX,GACHA,GAAc,EACX,GACHA,GAAc,EACX,GACHA,GAAc,GACX,GAEA,MAEX,CAEH,MAAMk/E,EAAY50K,KAAKusG,YAAYsoE,0BAEnC,GAAID,EAAW,SACX,MAAM7Z,EAAgB6Z,EAAU7Z,gBAC1B+Z,EAAuBF,EAAU/M,yBAGvCiN,EAAqBniG,MAAQiiG,EAAUthC,0BAGvC,MAAMyhC,EAAmBzyK,OAAOijG,YAAYt4C,MACtChjD,KAAKotB,IAAIr3B,KAAK8zK,kBAAmB9zK,KAAK6zK,mBACtCtgF,EAAa,oBAAGvzF,KAAKwgH,SAAS/yG,cAAjB,aAAG,EAAsB6vF,uBAAzB,QAA4C,IAG/D,IAAI9mF,EAxSpB,SAAmBwkJ,EAAWzlE,EAAYw/E,EAAkBD,GACxD,IAAIt+J,EAAS,EACTqmB,EAAS5yB,KAAK6uB,IAAIy8D,EAAW14D,OAAQ04D,EAAW34D,OAGhDo4I,EAAkB5B,GAAkB/qK,MAAK+rB,GAAKA,EAAEyI,QAAUA,IAE9D,GAAIm4I,GAAmBha,GAAa8Z,EAAqBniG,QAAUmsD,GAAAA,IAG/D,IAAKjiG,EAASm4I,EAAgBn4I,OAAQA,GAAU,IAAKA,GAAU,EAAG,CAC9D,MAAMo4I,EAAep4I,EAGrB,GADAm4I,EAAkB5B,GAAkB/qK,MAAK+rB,GAAKA,EAAEyI,SAAWo4I,KACvDD,EAKA,MAJAx+J,GAAU+uB,GAAQmhD,gBACZsuF,EAAgB1B,SAChBwB,EAAqBE,EAAgBx+J,aAK5Cw+J,IAGPx+J,EAAS+uB,GAAQmhD,gBACXsuF,EAAgB1B,SAChBwB,EAAqBE,EAAgBx+J,SAK/C,OAAOvM,KAAK6uB,IAAItiB,EAAS,IAS7B,SAAgBu+J,GACZ,OAAIA,EAAmB,IACZjmK,OAAOszD,iBAMXqpD,GAAexhH,KAAK2wB,IAAI,KAAMm6I,EAAmB,KAjBzBG,CAAOjrK,KAAKotB,IAAI,EAAG09I,EAAmB,OAwQ5CI,CAAUpa,EAAexlE,EAAYw/E,EAAkBD,GAEpEt+J,EAASvM,KAAK6uB,IAAItiB,EAxTP,MA2TPu+J,EAAmBxhF,IACnBmhF,EAAU,IAAM10K,KAAKwzK,YAAYp+E,QAAQE,OAAS9+E,GAKtDk/E,GAAcA,GAAc,KAC5Bg/E,EAAUzqK,KAAK6uB,IAAI47I,EAAS,KAKpC,GAAI10K,KAAK2zK,6BAA+B,EAAG,CACvC,MAAMyB,EAAuB,EACvBC,EAAwBr1K,KAAKwzK,YAAYC,kBACzC6B,GAAehzK,OAAOijG,YAAYt4C,MAAQjtD,KAAK2zK,8BAAgC,IAErFe,EAAUzqK,KAAK6uB,IAAI47I,EAASW,EAAyBC,EAAcF,GAGvE,OAAOnrK,KAAK6uB,IAAI,IAAK47I,GAOzBV,8BAA8B7sK,GAC1BnH,KAAKwzK,YAAYC,kBAAoBtsK,EACrCnH,KAAK2zK,6BAA+BrxK,OAAOijG,YAAYt4C,MAO3DgnH,uBAEI,MAAMx9J,EAAO,CACT2+E,QAASp1F,KAAKwzK,YAAYp+E,QAC1BM,WAAY11F,KAAKwzK,YAAY99E,WAC7B+9E,kBAAmBzzK,KAAKwzK,YAAYC,kBACpCC,OAAQ1zK,KAAKwzK,YAAYE,OACzBY,aAAct0K,KAAKwzK,YAAYc,aAC/BljB,qBAAsBpxJ,KAAKwzK,YAAYpiB,qBACvCp4D,eAAgBh5F,KAAKwzK,YAAYv6E,qBAGrC,IACIj5F,KAAKusG,YAAYy6C,yBAAyBvwI,GAC5C,MAAOgyB,KAYb2rI,kBAAkBjlF,EAAK14E,GAEnB,IAAK04E,EAAII,MAAO,CACZ,MAAMmkF,EACAj9J,EAAKrT,WACAqT,EAAKrT,UAAU1B,QAAU+U,EAAKrT,UAAU,GAAGs3F,IAEtD16F,KAAKwzK,YAAYE,OAASA,QAAkB3nK,EAKhD,GAAIojF,IAAQnvF,KAAKusG,YAAYsoE,0BACzB,OAGJ,IAAI3mK,EACJ,MAAMqnK,GACCv1K,KAAKusG,YAAYipE,0BAClBnS,EACArjK,KAAKusG,YAAY2pC,qBACjBzwC,EACA49D,EAAkBA,EAAgB59D,eAAY15F,EAC9Cm1F,GAAUmiE,GAAkBA,EAAgBniE,UAC5C3L,EAAa8tE,EACbp5J,KAAK6uB,IAAIuqI,EAAgB9tE,WAAY8tE,EAAgBjS,sBAAwB,KAOnF,IAAKljJ,KALAgzF,GACDlhG,KAAKq0K,yBAIG59J,EACJA,EAAKgC,eAAevK,KACpBlO,KAAKwzK,YAAYtlK,GAAOuI,EAAKvI,IAKjCqnK,GACAv1K,KAAKg0K,8BACDh0K,KAAKw0K,4BACD/uE,EACAvE,EACA3L,IAGZv1F,KAAKwzF,aAAa37D,KACdi4I,GACA9vK,KAAKwzK,aACTxzK,KAAKi0K,uBAQTE,mBAAmB9uK,EAAIoR,GAEnBzW,KAAK4zK,aAAavuK,GAAM,CACpB+vF,QAAS3+E,EAAK2+E,QACdM,WAAYj/E,EAAKi/E,WACjB+9E,kBAAmBh9J,EAAKg9J,kBACxBC,OAAQj9J,EAAKi9J,OACbY,aAAc79J,EAAK69J,aACnBljB,qBAAsB36I,EAAK26I,qBAC3Bp4D,eAAgBviF,EAAKuiF,gBAGzBh5F,KAAKwzF,aAAa37D,KACdi4I,GACAzqK,EACArF,KAAK4zK,aAAavuK,IAO1B8xF,WACI,OAAOn3F,KAAKwzK,aCrgBpB,MAAMjvK,IAAS2B,EAAAA,EAAAA,wDAaA,MAAMuvK,GAKjBr8J,YAAYslF,GACR1+F,KAAKusG,YAAc7N,EASvBg3E,kBACI,IAAK11K,KAAKusG,YAAYhL,KAClB,OAGJ,MAAM,mBAAE0zC,EAAF,iBAAsBpE,GAAqB7wI,KAAKusG,YAAYxsG,QAAQ0N,OACpEkoK,OAAiD,IAArB9kC,IAAqCA,EACjE9e,EAA6B/xH,KAAKusG,YAAYhL,KAAKwwB,6BACnD6jD,EAAyB7jD,IAA+B8e,EAO9D,GALAtsI,GAAOiH,KACA,mCAAuBypI,wBACFpE,qCACa9e,KAErC4jD,IAAwB9kC,IAAqB9e,GAA+BkjB,EAAoB,CAChG1wI,GAAOiH,KAAK,6CACZ,MAAM+sB,EAAS08G,EACTp7D,EACAA,EAIN,YAFA75E,KAAKusG,YAAY/Y,aAAa37D,KAAKqjD,EAAyC3iD,GAKhF,MAAMs9I,EAAgB71K,KAAKusG,YAAYtL,iBACjC60E,EAAkBD,GAAiBA,EAAc/5B,wBAElD+5B,EAE0B,cAApBC,EACPvxK,GAAOiH,KAAK,qDAEZjH,GAAOiH,KACA,mEAAasqK,+BACcF,KAC9BA,EACA51K,KAAKusG,YAAYtL,iBAAiBisC,WAC9B,KACI3oI,GAAOiH,KAAK,+CAEhBnK,IACIkD,GAAOlD,MAAO,8CAA6CA,EAAM2Z,aAClE,CACCud,OAAQ,qBACR+9G,kBAAmB,aACnBE,gBAAgB,EAChBJ,sBAAsB,IAG9Bp2I,KAAKusG,YAAYtL,iBAAiBqxC,6BArBtC/tI,GAAO2T,KAAK,8CA6BpB9V,QAUIpC,KAAKusG,YAAY7P,KAAKmiB,KAAK,MAAOj+D,MAC9B,KACS5gD,KAAK+1K,YACN/1K,KAAKg2K,kBAAoB1zK,OAAOE,YAAW,KACvCxC,KAAKg2K,uBAAoBjqK,EACzB/L,KAAK01K,oBACN,SAGXr0K,IACIkD,GAAOlD,MAAM,8CAA+CA,MAOxE4rE,SACIjtE,KAAK+1K,WAAY,EACjBzzK,OAAOC,aAAavC,KAAKg2K,oBCzH1B,IAAKC,aAAAA,GAAAA,EAAAA,sBAAAA,wBAAAA,EAAAA,yBAAAA,4BAAAA,EAAAA,eAAAA,0BAAAA,EAAAA,iBAAAA,6BAAAA,EAAAA,qBAAAA,uBAAAA,EAAAA,oBAAAA,gCAAAA,EAAAA,qBAAAA,kCAAAA,KAAAA,GAAAA,KAgEL,MAAMC,GAAwBD,GAAgBC,sBACxC/6F,GAA2B86F,GAAgB96F,yBAC3C2B,GAAiBm5F,GAAgBn5F,eACjCq5F,GAAmBF,GAAgBE,iBACnCC,GAAuBH,GAAgBG,qBACvCC,GAAsBJ,GAAgBI,oBACtCC,GAAuBL,GAAgBK,qBClDrC,MAAMC,WAA+B5sI,MAOhDvwB,YAAYslF,GACRxZ,QAEAllF,KAAKusG,YAAc7N,EACnB1+F,KAAKw2K,gBAAkB,KACvBx2K,KAAKy2K,eAAiB,KAEjBlxI,GAAQsjD,yBACT6V,EAAWa,WAAWvB,sBAAsBh+F,KAAK02K,YAAY91K,KAAKZ,OAEtE0+F,EAAWn0D,GAAG2wC,GAAmCl7E,KAAK22K,YAAY/1K,KAAKZ,OAM3E42K,uBACIr0K,aAAavC,KAAKw2K,iBAClBx2K,KAAKw2K,gBAAkB,KAU3BK,6BAA6BtlF,GAGzB,MAAMtC,EAAwB,IAAfsC,EAIa,OAAxBvxF,KAAKy2K,gBAA2Bz2K,KAAKy2K,iBAAmBxnF,IACxDjvF,KAAKy2K,eAAiBxnF,EACtBjvF,KAAK63B,KAAKo+I,GAA0Cj2K,KAAKy2K,iBAUjEK,6BAA6BvlF,GACrBvxF,KAAK+2K,cAIU,IAAfxlF,GAAqBvxF,KAAKw2K,gBAMJ,IAAfjlF,GAAoBvxF,KAAKw2K,iBAChCx2K,KAAK42K,uBANL52K,KAAKw2K,gBAAkBh0K,YAAW,KAC9BxC,KAAK+2K,aAAc,EAEnB/2K,KAAK63B,KAAKo+I,MAvEA,MAuFtBS,YAAYvnF,EAAKvoF,EAAM2qF,EAAYtB,GAE/B,IAAKA,IAAYjwF,KAAKg3K,YAClB,OAIJ,MAAMnS,EAAa11E,EAAI01E,WAAW7/I,IAAIhlB,KAAKg3K,YAAYnmB,OAIlDgU,GAAeA,EAAW/9J,MAAM22G,SAAS72G,KAM9C5G,KAAK62K,6BAA6BtlF,GAClCvxF,KAAK82K,6BAA6BvlF,IAStColF,YAAYx+F,GACJA,EAAMw3E,sBAEN3vJ,KAAKg3K,YAAc7+F,EACnBn4E,KAAK+2K,aAAc,EACnB/2K,KAAK42K,uBAGDrxI,GAAQsjD,0BACR1Q,EAAM5tC,GACF62D,IACA7P,IACIvxF,KAAK82K,6BAA6BvlF,MAG1CpZ,EAAM5tC,GACF62D,IACA7P,IACIvxF,KAAK82K,6BAA6BvlF,GAClCvxF,KAAK62K,6BAA6BtlF,SC/H3C,MAAM0lF,GAMjB79J,YAAYslF,GACR1+F,KAAK0+F,WAAaA,EAElBA,EAAWryD,iBACP6uC,GACAl7E,KAAK02K,YAAY91K,KAAKZ,OAE1BA,KAAKk3K,SAAWl3K,KAAK0+F,WAAWmG,WASpC6xE,YAAYrxK,EAAIksF,IAKPvxF,KAAK0+F,WAAW8J,eACdjX,GAtCiB,IAuChBlsF,IAAOrF,KAAKk3K,UACLl3K,KAAK0+F,WAAW+zE,qBAAqBvxE,WAIpDlhG,KAAK0+F,WAAWgD,IAAIlO,aAAa37D,KAC7BkD,GAAAA,QAAAA,yBACA11B,ICjDL,SAAS8xK,GAAmBp3K,GAC/B,MAAMq3K,EAAmB90K,OAAO2uF,cAAgB3uF,OAAO4uF,mBAEvD,GAAKkmF,EAIL,OAAO,IAAIA,EAAiBr3K,GCIjB,MAAMs3K,WAAwB1tI,MASzCvwB,YAAYk+J,EAAoBC,EAAcxhC,GAC1C7wD,QAKAllF,KAAKw3K,oBAAsBF,EAK3Bt3K,KAAKy3K,cAAgBF,EAKrBv3K,KAAK03K,YAAc3hC,EAKnB/1I,KAAK23K,eAAiB,IAAIC,aAAa,IAKvC53K,KAAK63K,cAAgBV,GAAmB,CAAEW,WAAYP,EAAaQ,4BAMnE/3K,KAAKg4K,eAAiBT,EAAaU,kBAMnCj4K,KAAKk4K,gBAAkBl4K,KAAKk4K,gBAAgBt3K,KAAKZ,MAEjDA,KAAKm4K,0BAeI,cAAC/qB,EAAakqB,EAAoBC,GAC3C,OAAOxP,GAAItb,+BAA+B,CACtClsE,QAAS,CAAE,SACX6sE,YAAAA,IACDxsG,MAAK+yF,IAEJ,IAAKA,EAAW,GACZ,MAAM,IAAI3vI,MAAO,qDAAoDopJ,KAGzE,OAAO,IAAIiqB,GAAgBC,EAAoBC,EAAc5jC,EAAW,OAYhFwkC,0BACIn4K,KAAKo4K,aAAep4K,KAAK63K,cAAcxlF,wBAAwBryF,KAAK03K,YAAYtnK,QAQhFpQ,KAAKq4K,qBAAuBr4K,KAAK63K,cAAcS,sBAAsBt4K,KAAKw3K,oBAAqB,EAAG,GActGU,gBAAgBK,GAEZ,MAAMC,EAASD,EAAWE,YAAYC,eAAe,GAC/CC,EAAiB,IAAK34K,KAAK23K,kBAAmBa,GAC9CI,EAAkBzzK,KAAK8nD,MAE7B,IAAIzrD,EAAI,EAER,KAAOA,EAAIxB,KAAKg4K,eAAiBW,EAAej3K,OAAQF,GAAKxB,KAAKg4K,eAAgB,CAC9E,MAAMa,EAAYF,EAAeh0K,MAAMnD,EAAGA,EAAIxB,KAAKg4K,gBAG7Cc,EAAW94K,KAAKy3K,cAAcsB,uBAAuBF,EAAUl0K,SAErE3E,KAAK63B,KAAKw+I,GAAqB,CAC3Bx0K,UAAW+2K,EACXI,MAAOF,EACPG,QAASJ,EACTxuB,SAAUrqJ,KAAK03K,YAAYpkB,gBAInCtzJ,KAAK23K,eAAiBgB,EAAeh0K,MAAMnD,EAAGm3K,EAAej3K,QAQjEw3K,qBACIl5K,KAAKq4K,qBAAqBc,eAAiBn5K,KAAKk4K,gBAChDl4K,KAAKo4K,aAAa9lF,QAAQtyF,KAAKq4K,sBAC/Br4K,KAAKq4K,qBAAqB/lF,QAAQtyF,KAAK63K,cAAcuB,aAQzDC,wBAIIr5K,KAAKq4K,qBAAqBc,eAAiB,OAC3Cn5K,KAAKq4K,qBAAqBxjF,aAC1B70F,KAAKo4K,aAAavjF,aAQtBykF,oBACIt5K,KAAKq5K,wBACLr5K,KAAK03K,YAAYtkB,aAQrBE,cACI,OAAOtzJ,KAAK03K,YAAYpkB,cAS5BvD,gBACI,OAAO/vJ,KAAK03K,YAAY6B,iBAQ5Bn3K,QACIpC,KAAKk5K,qBAQTn2K,OACI/C,KAAKq5K,wBACLr5K,KAAK23K,eAAiB,GAQ1B3G,UACQhxK,KAAKw5K,aAITx5K,KAAKs5K,oBACLt5K,KAAKw5K,YAAa,IClO1B,MAAMj1K,IAAS2B,EAAAA,EAAAA,oDAYA,MAAMuzK,WAAyB9vI,GAAAA,aAW1CvwB,YAAYslF,EAAYg7E,GACpBx0F,QAKAllF,KAAK25K,oBAAsBD,EAM3B15K,KAAK45K,YAAc,KAKnB55K,KAAK65K,sBAAuB,EAK5B75K,KAAK85K,mBAAqB,GAS1B95K,KAAK+5K,gBAAkBhwI,QAAQC,UAK/BhqC,KAAKg6K,iBAAmBh6K,KAAKg6K,iBAAiBp5K,KAAKZ,MAEnD0+F,EAAWn0D,GAAG2wC,GAAmCl7E,KAAK22K,YAAY/1K,KAAKZ,OACvE0+F,EAAWn0D,GAAG2wC,GAAqCl7E,KAAKi6K,cAAcr5K,KAAKZ,OAC3E0+F,EAAWn0D,GAAG2wC,GAA0Cl7E,KAAK6xG,kBAAkBjxG,KAAKZ,OAQxFk6K,uBAAuBC,GACnBn6K,KAAK85K,mBAAmB53K,KAAKi4K,GAC7BA,EAAW5vI,GAAG2rI,IAAuB,MAGVl2K,KAAK85K,mBAAmB/yK,QAAOqzK,IAAoC,IAAxBA,EAAStwE,aAKvDpoG,QAAU1B,KAAK65K,qBAC/B75K,KAAKq6K,kBACGr6K,KAAK65K,sBACb75K,KAAKs6K,sBASjBA,mBACQt6K,KAAK45K,cACL55K,KAAK45K,YAAYrvI,GAAG8rI,GAAqBr2K,KAAKg6K,kBAC9Ch6K,KAAK45K,YAAYx3K,QACjBpC,KAAK65K,sBAAuB,GAQpCQ,kBACQr6K,KAAK45K,cACL55K,KAAK45K,YAAYzvI,eAAeksI,GAAqBr2K,KAAKg6K,kBAC1Dh6K,KAAK45K,YAAY72K,QAErB/C,KAAK65K,sBAAuB,EAahCG,iBAAiBlB,GACb,IAAK,MAAMsB,KAAYp6K,KAAK85K,mBACxBM,EAASG,gBAAgBzB,GASjC0B,0BAA0Bt5E,GACtB,IAAK,MAAMk5E,KAAYp6K,KAAK85K,mBACxBM,EAASK,gBAAgBv5E,GAWjCy1E,YAAYx+F,GACJA,EAAMw3E,sBAGN3vJ,KAAK+5K,gBAAkB/5K,KAAK+5K,gBAAgBn5H,MAAK,IAAM5gD,KAAK25K,wBACvD/4H,MAAK22H,GACFF,GAAgBz4I,OAAOu5C,EAAMm7E,cAnJjB,KAmJyDikB,KAExE32H,MAAK85H,IACFn2K,GAAOynF,MAAM,kCAAmC7T,EAAM43E,iBAEtD/vJ,KAAK45K,YAAcc,EAInB16K,KAAKw6K,0BAA0BriG,EAAM+oB,cAExCl9C,OAAM3iD,IACHkD,GAAO2T,KAAK,mCAAoC7W,OAYhEwwG,kBAAkB15B,GACVA,EAAMw3E,sBAEN3vJ,KAAK+5K,gBAAkB/5K,KAAK+5K,gBAAgBn5H,MAAK,KAE7C5gD,KAAKw6K,0BAA0BriG,EAAM+oB,eAajD+4E,cAAc9hG,GACNA,EAAMw3E,sBAEN3vJ,KAAK+5K,gBAAkB/5K,KAAK+5K,gBAAgBn5H,MAAK,KAC7Cr8C,GAAOynF,MAAM,uCAAwC7T,EAAM43E,iBAGvD/vJ,KAAK45K,cACL55K,KAAKq6K,kBACLr6K,KAAK45K,YAAY5I,UACjBhxK,KAAK45K,YAAc,MAIvB,IAAK,MAAMQ,KAAYp6K,KAAK85K,mBACxBM,EAASp/H,aCnLd,MAAM2/H,WAA0BhxI,GAAAA,aAM3CvwB,cACI8rE,QAMAllF,KAAK46K,aAAc,EAKnB56K,KAAK66K,YAAc,GAKnB76K,KAAK86K,eAAiB,GAKtB96K,KAAK+6K,SAAU,EAEf/6K,KAAKg7K,qBAAuBh7K,KAAKg7K,qBAAqBp6K,KAAKZ,MAS/Dg7K,uBACI,MAAMC,EAAWtpF,GAAiB3xF,KAAK66K,aACjCK,EAAgBvpF,GAAiB3xF,KAAK86K,gBAExCG,EAxEoB,IAwEkBC,EAlEd,MAmExBl7K,KAAK63B,KAAKs+I,IAEVn2K,KAAKm7K,iBAAgB,IAIzBn7K,KAAKg7C,QASTogI,cAActC,EAAUuC,GACpBr7K,KAAK66K,YAAY34K,KAAK42K,GACtB94K,KAAK86K,eAAe54K,KAAKm5K,GAS7BF,gBAAgBhzB,GACZnoJ,KAAK+6K,QAAU5yB,EACfnoJ,KAAK63B,KAAKq+I,GAAuBl2K,KAAK+6K,SAQ1CN,gBAAgBv5E,GAEZlhG,KAAKm7K,iBAAiBj6E,GACtBlhG,KAAKg7C,QAQT8uD,WACI,OAAO9pG,KAAK+6K,QAQhB//H,QACIh7C,KAAK46K,aAAc,EACnB56K,KAAK66K,YAAc,GACnB76K,KAAK86K,eAAiB,GACtBv4K,aAAavC,KAAKs7K,iBAatBf,gBAAgBzB,GACZ,GAAK94K,KAAK+6K,QAKV,GAAI/6K,KAAK46K,YAAT,CAEI,MAAMW,EAAiB1pF,GAAqBinF,EAASG,SAErDj5K,KAAKo7K,cAActC,EAASE,MAAOrnF,GAAiB4pF,SAOxD,GAAIzC,EAASE,MAvJK,GAuJsB,CACpC,MACMqC,EAAc1pF,GADGE,GAAqBinF,EAASG,UAGjDoC,EArJkB,MAsJlBr7K,KAAK46K,aAAc,EACnB56K,KAAKo7K,cAActC,EAASE,MAAOqC,GAGnCr7K,KAAKs7K,gBAAkB94K,WAAWxC,KAAKg7K,qBApJpB,SCApB,MAAMQ,WAA8B7xI,GAAAA,aAK/CvwB,cACI8rE,QAMAllF,KAAK46K,aAAc,EAKnB56K,KAAK66K,YAAc,GAKnB76K,KAAK+6K,SAAU,EAEf/6K,KAAKy7K,mBAAqBz7K,KAAKy7K,mBAAmB76K,KAAKZ,MAQ3Dy7K,qBACkB9pF,GAAiB3xF,KAAK66K,aAxDlB,KA2Dd76K,KAAK63B,KAAKy+I,IAIVt2K,KAAKm7K,iBAAgB,IAIzBn7K,KAAKg7C,QASTmgI,gBAAgBhzB,GACZnoJ,KAAK+6K,QAAU5yB,EACfnoJ,KAAK63B,KAAKq+I,GAAuBl2K,KAAK+6K,SAQ1CN,gBAAgBv5E,GAEZlhG,KAAKm7K,gBAAgBj6E,GACrBlhG,KAAKg7C,QAQT8uD,WACI,OAAO9pG,KAAK+6K,QAYhBR,gBAAgBzB,GACP94K,KAAK+6K,UAKN/6K,KAAK46K,YACL56K,KAAK66K,YAAY34K,KAAK42K,EAASE,OAO/BF,EAASE,MArHG,KAsHZh5K,KAAK46K,aAAc,EACnB56K,KAAK66K,YAAY34K,KAAK42K,EAASE,OAG/Bh5K,KAAKs7K,gBAAkB94K,WAAWxC,KAAKy7K,mBA/GhB,OAwH/BzgI,QACIh7C,KAAK46K,aAAc,EACnB56K,KAAK66K,YAAc,GACnBt4K,aAAavC,KAAKs7K,kBCxJnB,IAAKI,aAAAA,GAAAA,EAAAA,gBAAAA,2BAAAA,KAAAA,GAAAA,KAQL,MAAMC,GAAkBD,GAAcC,gBCAvCp3K,IAAS2B,EAAAA,EAAAA,yCAMT01K,GAAmB,mBAMnBC,GAAoB,oBAK1B,MAAMC,GAOF1iK,YAAYyoF,EAAak6E,GAErB/7K,KAAK6hG,YAAcA,EAGnB7hG,KAAK+7K,QAAUA,EAGf/7K,KAAKqF,GAAKw8F,EAAYsI,QAGtBnqG,KAAKg8K,SAAW,GAIhBh8K,KAAKi8K,cAAgB,EAErBj8K,KAAKk8K,eAAiBl8K,KAAKk8K,eAAet7K,KAAKZ,MAC/CA,KAAKm8K,YAAcn8K,KAAKm8K,YAAYv7K,KAAKZ,MACzCA,KAAKo8K,eAAiBp8K,KAAKo8K,eAAex7K,KAAKZ,MAC/CA,KAAKq8K,mBAAqBr8K,KAAKq8K,mBAAmBz7K,KAAKZ,MACvDA,KAAK6gG,cAAgB7gG,KAAK6gG,cAAcjgG,KAAKZ,MAIzC+7K,EAAQO,mBACRt8K,KAAKm8K,cAGTn8K,KAAKu+G,aAAej8G,OAAOiwF,YACvBvyF,KAAKm8K,YAAaJ,EAAQQ,gBAC9Bv8K,KAAKw8K,kBAAoBl6K,OAAOE,WAC5BxC,KAAKq8K,mBAAoBr8K,KAAK+7K,QAAQU,qBAO9CP,iBACQl8K,KAAKu+G,cACLj8G,OAAO2wF,cAAcjzF,KAAKu+G,cAE1Bv+G,KAAKw8K,mBACLl6K,OAAO2wF,cAAcjzF,KAAKw8K,mBAQlCL,cACI,MAAMO,EAAY18K,KAAKi8K,gBACjBU,EAAiB,CACnB/0K,KAAMg0K,GACNv2K,GAAIq3K,GAGR18K,KAAK+7K,QAAQ9kE,YAAY0lE,EAAgB38K,KAAKqF,IAC9CrF,KAAKg8K,SAASU,GAAa,CACvBr3K,GAAIq3K,EACJE,SAAUt6K,OAAOijG,YAAYt4C,OAQrCmvH,eAAethE,GACX,MAAM2gC,EAAUz7I,KAAKg8K,SAASlhE,EAASz1G,IAEnCo2I,IACAA,EAAQ/gD,IAAMp4F,OAAOijG,YAAYt4C,MAAQwuF,EAAQmhC,SACjD58K,KAAK+7K,QAAQvoF,aAAa37D,KACtB6jJ,GACA17K,KAAK6hG,YACL45C,EAAQ/gD,MAGhB16F,KAAKq8K,qBASTA,qBACI,MAAMpvH,EAAM3qD,OAAOijG,YAAYt4C,MAI/B,IACIwuF,EAASihC,EADThiF,EAAM5yD,EAAAA,EAIV,IAAK40I,KAAa18K,KAAKg8K,SACfh8K,KAAKg8K,SAASvjK,eAAeikK,KAC7BjhC,EAAUz7I,KAAKg8K,SAASU,GAEpBjhC,EAAQmhC,SAAW3vH,EAAMjtD,KAAK+7K,QAAQU,2BAE/Bz8K,KAAKg8K,SAASU,GACdjhC,EAAQ/gD,MACfA,EAAMzwF,KAAK6uB,IAAI4hE,EAAK+gD,EAAQ/gD,OAKpCA,EAAM5yD,EAAAA,GACN9nC,KAAK6gG,cAAcnG,GAQ3BmG,cAAcnG,GACV+B,GAAWoE,cxGwJc,EAAErI,EAAwBwpD,EAAiBtnD,KAA3C,CAC7B76E,WAAY,CACR,eAAkB24E,EAClBwpD,OAAAA,EACAtnD,IAAAA,GAEJluF,KAAM,UACN5E,KAAMq5E,GAAgBC,mBwG/JO27F,CACrB78K,KAAKqF,GACLrF,KAAK6hG,YAAYwL,YAAY,UAC7B3S,KAmBG,MAAMoiF,GAMjB1jK,YAAYslF,EAAY3+F,EAASk3G,GAC7Bj3G,KAAK0+F,WAAaA,EAClB1+F,KAAKwzF,aAAekL,EAAWlL,aAC/BxzF,KAAKi3G,YAAcA,EAGnBj3G,KAAKu8K,eAAiB,IAGtBv8K,KAAKy8K,oBAAsB,IAG3Bz8K,KAAKwqG,aAAe,GAGpBxqG,KAAKs8K,mBAAoB,EAErBv8K,GAAWA,EAAQg8K,UACyB,iBAAjCh8K,EAAQg8K,QAAQx9D,eACvBv+G,KAAKu8K,eAAiBx8K,EAAQg8K,QAAQx9D,cAEO,iBAAtCx+G,EAAQg8K,QAAQS,oBACvBx8K,KAAKy8K,oBAAsB18K,EAAQg8K,QAAQS,mBAI3Cx8K,KAAKy8K,oBAAsB,GAAKz8K,KAAKy8K,oBACnCz8K,KAAKu8K,iBACPv8K,KAAKy8K,oBAAsBz8K,KAAKu8K,iBAGxCh4K,GAAOiH,KACF,uCACGxL,KAAKu8K,qCACLv8K,KAAKy8K,wBAEbz8K,KAAK+8K,kBAAoB/8K,KAAK+8K,kBAAkBn8K,KAAKZ,MACrD0+F,EAAWn0D,GACP2wC,GACAl7E,KAAK+8K,mBAET/8K,KAAKg9K,gBAAkBh9K,KAAKg9K,gBAAgBp8K,KAAKZ,MACjD0+F,EAAWn0D,GACP2wC,GACAl7E,KAAKg9K,iBAETh9K,KAAKi9K,gBAAkBj9K,KAAKi9K,gBAAgBr8K,KAAKZ,MACjD0+F,EAAWn0D,GACP2wC,GACAl7E,KAAKi9K,iBAETj9K,KAAKk9K,kBAAoBl9K,KAAKk9K,kBAAkBt8K,KAAKZ,MACrD0+F,EAAWn0D,GACP2wC,EACAl7E,KAAKk9K,mBAObA,oBACIl9K,KAAKs8K,mBAAoB,EASzB,IAAK,MAAMj3K,KAAMrF,KAAKwqG,aAClB,GAAIxqG,KAAKwqG,aAAa/xF,eAAepT,GAAK,CACtC,MAAM83K,EAAqBn9K,KAAKwqG,aAAanlG,GAE7C/C,OAAOE,WAAW26K,EAAmBhB,YAAa,MAW9Dc,gBAAgBp7E,EAAa8C,GAGrBA,EAAQ/8F,OAASg0K,GACjB57K,KAAKo9K,cAAcv7E,EAAYsI,QAASxF,GACjCA,EAAQ/8F,OAASi0K,IACxB77K,KAAKo8K,eAAev6E,EAAYsI,QAASxF,GAWjDo4E,kBAAkB13K,EAAIw8F,GACd7hG,KAAKu8K,gBAAkB,IAIvBv8K,KAAKwqG,aAAanlG,KAClBd,GAAOiH,KACF,0CAAyCnG,gBAC9CrF,KAAKwqG,aAAanlG,GAAI62K,wBACfl8K,KAAKwqG,aAAanlG,IAG7BrF,KAAKwqG,aAAanlG,GAAM,IAAIy2K,GAAmBj6E,EAAa7hG,OAQhEg9K,gBAAgB33K,GACRrF,KAAKu8K,gBAAkB,GAIvBv8K,KAAKwqG,aAAanlG,KAClBrF,KAAKwqG,aAAanlG,GAAI62K,wBACfl8K,KAAKwqG,aAAanlG,IAWjC+3K,cAAc5kF,EAAeijD,GAEzB,GAAIA,GAAWA,EAAQp2I,GAAI,CACvB,MAAMy1G,EAAW,CACblzG,KAAMi0K,GACNx2K,GAAIo2I,EAAQp2I,IAGhBrF,KAAKi3G,YAAY6D,EAAUtiB,QAE3Bj0F,GAAOiH,KACF,6CAA4CgtF,MAUzD4jF,eAAe5jF,EAAesiB,GAC1B,MAAMqiE,EAAqBn9K,KAAKwqG,aAAahS,GAEzC2kF,GACAA,EAAmBf,eAAethE,GAO1C/3G,OACIwB,GAAOiH,KAAK,oBAEZxL,KAAK0+F,WAAWrxD,IACZ6tC,GACAl7E,KAAK+8K,mBACT/8K,KAAK0+F,WAAWrxD,IACZ6tC,GACAl7E,KAAKg9K,iBACTh9K,KAAK0+F,WAAWrxD,IACZ6tC,GACAl7E,KAAKi9K,iBACTj9K,KAAK0+F,WAAWrxD,IACZ6tC,EACAl7E,KAAKk9K,mBAET,IAAK,MAAM73K,KAAMrF,KAAKwqG,aACdxqG,KAAKwqG,aAAa/xF,eAAepT,IACjCrF,KAAKwqG,aAAanlG,GAAI62K,iBAI9Bl8K,KAAKwqG,aAAe,ICrX5B,MAAMjmG,IAAS2B,EAAAA,EAAAA,oDAOA,MAAMm3K,GAKjBjkK,YAAYslF,GACR1+F,KAAKusG,YAAc7N,EASnB1+F,KAAKs9K,SAAU,EAEft9K,KAAKusG,YAAYlgE,iBACb6uC,IAAmC,IAAMl7E,KAAKu9K,mBAClDv9K,KAAKusG,YAAYlgE,iBACb6uC,IAAiC,IAAMl7E,KAAKu9K,mBAChDv9K,KAAKusG,YAAYlgE,iBACb6uC,IAAkC,IAAMl7E,KAAKu9K,mBAOrDA,iBACI,MAAMC,EAAYx9K,KAAKs9K,QACjBrzE,GACCjqG,KAAKusG,YAAY/D,eACbxoG,KAAKusG,YAAYkxE,uBAAyB,EAEjDD,IAAcvzE,IACdjqG,KAAKs9K,QAAUrzE,EACf1lG,GAAOynF,MAAO,iBAAgBwxF,QAAgBvzE,KAC9CjqG,KAAKusG,YAAY/Y,aAAa37D,KAC1BqjD,GAAqCsiG,EAAWvzE,KC5ChE,MAAM1lG,IAAS2B,EAAAA,EAAAA,+DASf,MAAMw3K,GAIFtkK,cAGIpZ,KAAK29K,oBAAsB,CAAE,UAdR,KAiBrB39K,KAAKqwK,QAhBW,EAmBhBrwK,KAAKwwK,gBArBc,KAwBnBxwK,KAAKywK,mBAAqB,GAE1BzwK,KAAKsxK,0BAA4B,CAC7B7wF,YAAa,GACbm9F,mBAAoB59K,KAAK49K,mBACzBv2B,MAAOrnJ,KAAKqwK,OACZwN,iBAAkB,GAClBr2B,kBAAmBxnJ,KAAKywK,oBAO5BhwF,kBAGA,OAFAzgF,KAAKsxK,0BAA0BjqB,MAAQrnJ,KAAKqwK,OAEvCrwK,KAAKywK,mBAAmB/uK,QAM7B1B,KAAKsxK,0BAA0B7wF,YAAc,GACzCzgF,KAAKywK,mBAAmB/uK,OAAS,GASjC1B,KAAKsxK,0BAA0BsM,mBAAqB,CAAE,UAAa59K,KAAKwwK,iBACxExwK,KAAKsxK,0BAA0BuM,iBAAmB,GAClD79K,KAAKsxK,0BAA0B9pB,kBAAoB,KAenDxnJ,KAAKsxK,0BAA0B7wF,YAAYzgF,KAAKywK,mBAAmB,IAAM,CACrE,UAAazwK,KAAKwwK,iBAEtBxwK,KAAKsxK,0BAA0BsM,mBAAqB59K,KAAK29K,oBACzD39K,KAAKsxK,0BAA0BuM,iBAAmB79K,KAAKywK,mBACvDzwK,KAAKsxK,0BAA0B9pB,kBAAoB,IAGhDxnJ,KAAKsxK,2BAxCDtxK,KAAKsxK,0BAiDpBwM,YAAY32K,GACR,MAAMwiK,EAAU3pK,KAAKqwK,SAAWlpK,EAOhC,OALIwiK,IACA3pK,KAAKqwK,OAASlpK,EACd5C,GAAOynF,MAAO,2CAA0C7kF,OAGrDwiK,EAUXoU,wBAAwBxoC,GACpB,MAAMo0B,EAAU3pK,KAAKwwK,kBAAoBj7B,EAOzC,OALIo0B,IACA3pK,KAAKwwK,gBAAkBj7B,EACvBhxI,GAAOynF,MAAO,oCAAmCupD,MAG9Co0B,EASXqU,+BAA+B11B,GAC3B,MAAMqhB,GAAW5yD,IAAAA,CAAQ/2G,KAAKsxK,0BAA2BhpB,GAOzD,OALIqhB,IACA3pK,KAAKsxK,0BAA4BhpB,EACjC/jJ,GAAOynF,MAAO,qCAAoC5qF,KAAKF,UAAUonJ,OAG9DqhB,EASXsU,wBAAwBlM,GACpBxtK,GAAOynF,MAAO,gCAA+B5qF,KAAKF,UAAU6wK,MAC5D/xK,KAAKywK,mBAAqBsB,GASnB,MAAMmM,GAQjB9kK,YAAYslF,EAAYgD,GAAK,QACzB1hG,KAAKusG,YAAc7N,EACnB1+F,KAAKm+K,KAAOz8E,EAEZ,MAAM,OAAEj0F,GAAWixF,EAAW3+F,QAG9BC,KAAKqwK,OAAL,UAAc5iK,MAAAA,OAAd,EAAcA,EAAQ2wK,kBAAtB,SAAqC3wK,MAAAA,OAAA,EAAAA,EAAQ4wK,gBAvK7B,EA0KhBr+K,KAAKwwK,gBA5Kc,KA+KY,UAAG/iK,MAAAA,OAAH,EAAGA,EAAQ6wK,yCAAX,UAG3Bt+K,KAAKsxK,0BAA4B,IAAIoM,GAChB19K,KAAKsxK,0BAA0BwM,YAAY99K,KAAKqwK,SAErDrwK,KAAKm+K,KAAKxM,+BAA+B3xK,KAAKsxK,0BAA0B7wF,cAExFzgF,KAAKm+K,KAAKnL,SAAShzK,KAAKqwK,QAI5BrwK,KAAKywK,mBAAqB,GAE1BzwK,KAAKusG,YAAYhiE,GACb2wC,IACA1zE,GAAWxH,KAAK0xG,uBAAuBlqG,KAW/CkqG,uBAAuBqzC,GACfA,EAAax1D,QAAUvvF,KAAKsxK,0BAC5BvsB,EAAatP,2BAA2Bz1I,KAAKwwK,kBAE7CxwK,KAAKsxK,0BAA0ByM,wBAAwB/9K,KAAKwwK,iBAC5DxwK,KAAKm+K,KAAKxM,+BAA+B3xK,KAAKsxK,0BAA0B7wF,cAShFoqB,WACI,OAAO7qG,KAAKqwK,OAUhByB,gBAAgBC,GAGZ,GAFA/xK,KAAKywK,mBAAqBsB,EAEtB/xK,KAAKsxK,0BAAT,CAEI,MAAMiN,EAAoBxM,EAAIhrK,QAAO1B,GAAMA,IAAOrF,KAAKusG,YAAY1H,aAC7D25E,EAAiBp9K,KAAKwJ,MAAMxJ,KAAKF,UAAUlB,KAAKsxK,0BAA0B7wF,cAEhF89F,EAAkB78K,QAAU1B,KAAKsxK,0BAA0B2M,wBAAwBM,GACnF,MAAME,EAAiBz+K,KAAKsxK,0BAA0B7wF,YAGjDs2B,IAAAA,CAAQ0nE,EAAgBD,IACzBx+K,KAAKm+K,KAAKxM,+BAA+B8M,QAKjDz+K,KAAKm+K,KAAKrM,gBAAgBC,GAU9BiB,SAAS7rK,GACL,GAAInH,KAAKqwK,SAAWlpK,EAAO,CAGvB,GAFAnH,KAAKqwK,OAASlpK,EAEVnH,KAAKsxK,0BAML,YALqBtxK,KAAKsxK,0BAA0BwM,YAAY32K,IAGhDnH,KAAKm+K,KAAKxM,+BAA+B3xK,KAAKsxK,0BAA0B7wF,cAI5FzgF,KAAKm+K,KAAKnL,SAAS7rK,IAU3Bu3K,kCAAkCnpC,GAC9Bv1I,KAAKwwK,gBAAkBj7B,EAEvB,IAAK,MAAM/tI,KAAWxH,KAAKusG,YAAY4F,mBAC/B3qG,EAAQ+nF,QAAUvvF,KAAKsxK,0BACvB/7B,GAAkB/tI,EAAQiuI,2BAA2BF,GAE3Bv1I,KAAKsxK,0BAA0ByM,wBAAwBxoC,IAG1Ev1I,KAAKm+K,KAAKxM,+BAA+B3xK,KAAKsxK,0BAA0B7wF,aAU3Fk+F,uBAAuBl+F,GACdzgF,KAAKsxK,4BACNtxK,KAAKsxK,0BAA4B,IAAIoM,IAGzC,MAAMkB,EAAoBx+K,OAAOC,KAAKogF,GAAag9B,SAAS,mBAAoB,qBAC1EohE,EAAkBz+K,OAAOC,KAAKogF,GAAag9B,SAAS,iBAAkB,mBAE5E,IAAK4Z,GAAAA,gCAA+CwnD,EAChD,MAAM,IAAI76K,MACN,kGAIR,GAAIqzH,GAAAA,gCAA+CunD,EAC/C,MAAM,IAAI56K,MACN,qGAKR,GAF2BhE,KAAKsxK,0BAA0B0M,+BAA+Bv9F,GAEjE,SACpBzgF,KAAKqwK,OAAL,UAAc5vF,EAAY4mE,aAA1B,QAAmCrnJ,KAAKqwK,OACxCrwK,KAAKywK,mBAAL,UAA0BhwF,EAAY+mE,yBAAtC,QAA2DxnJ,KAAKywK,mBAChEzwK,KAAKm+K,KAAKxM,+BAA+BlxF,GAEzC,MAAMq+F,EAAa9+K,KAAKusG,YAAY4F,mBAAmB9pG,MAAKb,GAAWA,EAAQ+nF,QAE/E,GAAIuvF,EAAY,OACZ,IAAIvpC,EAAc,UAAGn1I,OAAOkJ,OAAOm3E,EAAYA,aAAa,UAA1C,aAAG,EAA2Ck6C,UAE3C,MAAhB4a,IACDA,EAAc,UAAG90D,EAAYm9F,0BAAf,aAAG,EAAgCjjD,WAErD4a,GAAkBupC,EAAWrpC,2BAA2BF,MC3UxE,MAAMhxI,IAAS2B,EAAAA,EAAAA,4DAUA,MAAM64K,GAQjB3lK,YAAYslF,EAAYgD,GACpB1hG,KAAKusG,YAAc7N,EACnB1+F,KAAKg/K,6BAnBgB,KAoBrBh/K,KAAKm+K,KAAOz8E,EAOZ1hG,KAAKi/K,yBAA2B,IAAI54G,IACpCrmE,KAAKusG,YAAYhiE,GACb2wC,IACA1zE,GAAWxH,KAAK0xG,uBAAuBlqG,KAC3CxH,KAAKusG,YAAYhiE,GACb2wC,IACA,IAAMl7E,KAAKk/K,yCACfl/K,KAAKm+K,KAAK5zI,GACNxP,GAAAA,QAAAA,kCACAutH,GAAoBtoJ,KAAKm/K,6BAA6B72B,KAS9D42B,uCACI,GAAI7nD,GAAAA,+BACA,IAAK,MAAMl/C,KAASn4E,KAAKm+K,KAAKnoC,sBAAuB,CACjD,MAAM5U,EAAajpD,EAAM89D,gBAEzB7U,GAAcphI,KAAKo/K,6BAA6Bh+C,QAGpDphI,KAAKo/K,+BAYb1tE,uBAAuBqzC,GACnBA,EAAantH,YACT01G,GAAAA,kCACA9lI,IACQA,IAAYxH,KAAKusG,YAAY8yE,yBAC7Br/K,KAAKk/K,0CAYrBC,6BAA6B72B,GAAkB,MAC3C,GAAIjxB,GAAAA,+BAA6C,OAC7C,MAAM,UAAEsD,EAAF,WAAayG,GAAeknB,EAC5B3sD,EAAgB,UAAG37F,KAAKusG,YAAYypC,6BAApB,QAA6C,GAEnE,IAAK,MAAM79D,KAASwjB,EAEZxjB,EAAM89D,kBAAoB7U,GACrBphI,KAAKi/K,yBAAyB1/H,IAAI6hF,IACpCphI,KAAKi/K,yBAAyBj6J,IAAIo8G,KAAgBzG,IACrD36H,KAAKi/K,yBAAyB/5J,IAAIk8G,EAAYzG,GAC9Cp2H,GAAOynF,MAAO,iCAAgCo1C,0BAAmCzG,KACjF36H,KAAKo/K,6BAA6Bh+C,SAGnC,UAAAphI,KAAKs/K,+BAAL,eAA8BC,eAAgBj3B,EAAiBi3B,cACtEv/K,KAAKs/K,wBAA0Bh3B,EAC/BtoJ,KAAKo/K,gCAYbA,+BAAgD,IAAnBh+C,EAAmB,uDAAN,KACtC,GAAI/J,GAAAA,iCAAgD+J,EAChD,MAAM,IAAIp9H,MAAM,yEAEpB,MAAMw7K,EAAqBx/K,KAAKy/K,0BAA0Br+C,GACpDhtB,EAAW,GAEjB,GAAIorE,GAAsB,EACtB,IAAK,MAAMh4K,KAAWxH,KAAKusG,YAAY4F,mBACnCiC,EAASlyG,KAAKsF,EAAQsuI,yBAAyB0pC,EAAoBp+C,IAI3E,OAAOr3F,QAAQ8pG,IAAIz/B,GAWvBqrE,4BAA6C,UAAnBr+C,EAAmB,uDAAN,KACnC,GAAI/J,GAAAA,iCAAgD+J,EAChD,MAAM,IAAIp9H,MAAM,yEAEpB,MAAM07K,EAAqB1/K,KAAKusG,YAAY8yE,wBACtC/wC,EAA2BoxC,EAC3BA,EAAmBnwF,MACfmwF,EAAmBhuC,8BACnBtQ,EAAaphI,KAAKi/K,yBAAyBj6J,IAAIo8G,GAArC,UAAmDphI,KAAKs/K,+BAAxD,aAAmD,EAA8BC,iBAC/FxzK,EAEN,OAAI/L,KAAKg/K,8BAAgC,GAAK1wC,GAA4B,EAC/DrkI,KAAK6uB,IAAI94B,KAAKg/K,6BAA8B1wC,GAC5CA,GAA4B,EAC5BA,EAGJtuI,KAAKg/K,6BAShBW,+BAA+BpqC,GAG3B,GAFAv1I,KAAKg/K,6BAA+BzpC,EAEhCle,GAAAA,+BAA6C,CAC7C,MAAMjjB,EAAW,GAEjB,IAAK,MAAMgtB,KAAcphI,KAAKi/K,yBAAyB5+K,OACnD+zG,EAASlyG,KAAKlC,KAAKo/K,6BAA6Bh+C,IAGpD,OAAOr3F,QAAQyqE,WAAWJ,GAG9B,OAAOp0G,KAAKo/K,gCClLpB,UAQIQ,wBAAwBzuD,GACpB,MAAM0uD,EAAc1uD,GACbA,EAAS/sG,qBAAqB,0BAA0B,GAE/D,GAAKy7J,EAIL,MAAO,CACHx+K,MAAOw+K,EAAYr9J,aAAa,kBAChC2tH,UAAW0vC,EAAYr9J,aAAa,aACpCs9J,cAAeD,EAAYr9J,aAAa,kBACxCu9J,UAAWF,EAAYr9J,aAAa,cACpCysE,OAAQ4wF,EAAYr9J,aAAa,YAWzCw9J,sBAAsB7uD,GAClB,MAAM8uD,EACA9uD,EAAS/sG,qBAAqB,wBAAwB,GACtD87J,EAAoBD,GACnBA,EAA2B3nI,YAC5B6nI,EACAhvD,EAAS/sG,qBAAqB,QAAQ,GACtC2iI,EAAOo5B,GACNA,EAAc7nI,aACd6nI,EAAc7nI,YAAYnhB,cAC3BipJ,EACAjvD,EAAS/sG,qBAAqB,cAAc,GAIlD,MAAO,CACH87J,kBAAAA,EACAn5B,KAAAA,EACAg5B,UALEK,GAAsBA,EAAmB9nI,cAenD+nI,mBAAmBvlE,GACf,MAAMwlE,EAAQxlE,GAAYA,EAAS12F,qBAAqB,SAAS,GAEjE,OAAOk8J,GAASA,EAAM99J,aAAa,eASvC+9J,aAAapvD,GACT,MAAMqvD,EACArvD,EAAS/sG,qBAAqB,cAAc,GAGlD,OAFkBo8J,GAAsBA,EAAmBloI,aAW/DmoI,YAAYtvD,GACDA,EAAS3uG,aAAa,QAAQi7F,SAAS,UCpFvC,MAAMijE,GAMjBtnK,cAA0B,IAAdrZ,EAAc,uDAAJ,GAClBC,KAAK2gL,YAAc5gL,EAAQ+iG,WAC3B9iG,KAAK6lJ,MAAQ9lJ,EAAQgnJ,KAErB/mJ,KAAK4gL,cAAc7gL,EAAQggL,WAC3B//K,KAAK6gL,UAAU9gL,EAAQkvF,QAQ3BkV,WACI,OAAOnkG,KAAKktF,OAQhB4zF,QACI,OAAO9gL,KAAK+gL,WAQhBC,eACI,OAAOhhL,KAAKihL,WAQhBC,uBACI,OAAOlhL,KAAKmhL,mBAQhB99E,YACI,OAAOrjG,KAAK0kG,QAQhB08E,gBACI,OAAOphL,KAAKqhL,YAQhBC,UACI,OAAOthL,KAAK6lJ,MAUhB07B,SAASlgL,GACLrB,KAAKktF,OAAS7rF,EAUlBmgL,qBAAqBr5I,GACjBnoC,KAAKmhL,mBAAqBh5I,EAS9B04I,UAAU5xF,GACNjvF,KAAK0kG,QAAUzV,EAQnBsU,aAAa1B,GACT7hG,KAAKihL,WAAap/E,EAQtByB,cAAczB,GACV7hG,KAAKqhL,YAAcx/E,EAoBvBz/F,MAAM,GAAiD,IAAjD,QAAEq/K,EAAF,YAAWC,EAAX,YAAwBpzD,EAAxB,SAAqC0L,GAAY,EACnD,OAAO,IAAIjwF,SAAQ,CAACC,EAASC,KACzBjqC,KAAK2gL,YAAYt9D,OACbrjH,KAAK2hL,UAAU,CACXl6K,OAAQ,QACRg6K,QAAAA,EACAnzD,YAAAA,EACAozD,YAAAA,EACA1nD,SAAAA,KAEJ1gG,IAKIt5B,KAAK6gL,UAAU,WACf7gL,KAAK4gL,cACDgB,GAAkBvB,mBAAmB/mJ,IAEzC0Q,OAEJ3oC,IACIrB,KAAK6hL,gBAAgBxgL,GAErB4oC,EAAO5oC,SAcvB0B,KAAK,GAAiB,IAAjB,YAAEurH,GAAe,EAClB,OAAO,IAAIvkF,SAAQ,CAACC,EAASC,KACzBjqC,KAAK2gL,YAAYt9D,OACbrjH,KAAK2hL,UAAU,CACXl6K,OAAQ,OACR6mH,YAAAA,IAEJtkF,EACAC,MAqBZ03I,UAAU,GAAyD,IAAzD,OAAEl6K,EAAF,QAAUg6K,EAAV,YAAmBC,EAAnB,YAAgCpzD,EAAhC,SAA6C0L,GAAY,EAC/D,OAAOhb,EAAAA,GAAAA,KAAI,CACPC,GAAIqP,EACJ1mH,KAAM,QAETuF,EAAE,QAAS,CACR,MAAS,kCACT,OAAU1F,EACV,SAAYg6K,EACZ,eAAkBzhL,KAAK6lJ,MACvB,SAAY7rB,EACZ,sBAAyB0nD,IAE5B38D,KAUL88D,gBAAgBh1D,GACZ,MAAMxrH,EAAQwrH,EAAQzoG,qBAAqB,SAAS,GAEpDpkB,KAAKuhL,SAASlgL,EAAM89C,SAAS,GAAGjpC,SAUpC0qK,cAAcb,GACV//K,KAAK+gL,WAAahB,GCxP1B,MAAMx7K,IAAS2B,EAAAA,EAAAA,oDCET3B,IAAS2B,EAAAA,EAAAA,+DAWA,MAAM47K,GAOjB1oK,YAAYslF,GACR1+F,KAAKusG,YAAc7N,EACnB1+F,KAAK+hL,sBAAwB,GAC7B/hL,KAAKgiL,sBAAwB,GAC7BhiL,KAAKiiL,wBAA0B,GAC/BjiL,KAAKkiL,mCAAqC,GAC1CliL,KAAKmiL,0BAA4BniL,KAAKmiL,0BAA0BvhL,KAAKZ,MACrEA,KAAKoiL,4BAA8BpiL,KAAKoiL,4BAA4BxhL,KAAKZ,MACzEA,KAAKqiL,eAAiBriL,KAAKqiL,eAAezhL,KAAKZ,MAC/CA,KAAKusG,YAAYhiE,GAAGulI,GAA8C9vK,KAAKoiL,6BACvEpiL,KAAKusG,YAAYhN,WAAWnB,2BAA2Bp+F,KAAKmiL,2BAC5DniL,KAAKusG,YAAYhiE,GAAGwpI,GAA4B/zK,KAAKqiL,gBAUzDD,4BAA4Bt0F,EAAD,GAA6B,IAApB,eAAEkL,GAAkB,EACpD,MAAMspF,EAAmBtiL,KAAKkiL,mCAAmCp0F,GAAU,GAAM,EAIjF,GAFA9tF,KAAKkiL,mCAAmCp0F,GAAUw0F,GAEE,IAAhDtiL,KAAKgiL,sBAAsB3+K,QAAQyqF,IAAmBA,KAAU9tF,KAAKiiL,yBAC9DjpF,GAAkB,GAAKspF,EAAkB,EAChD,OAGJ,MAAMzgF,EAAc7hG,KAAKusG,YAAYzK,mBAAmBhU,GAExD,GAAI+T,GACeA,EAAY4J,qBAAqB3W,GAAUqH,OAE/Cz6F,OAAS,GAAKmgG,EAAYkM,eAIjC,OAIR,MAAMw0E,EAAmBviL,KAAK+hL,sBAAsBj0F,GAE/CppF,MAAMgD,QAAQ66K,KAAqBA,EAAiBv/J,OAAMuuE,GAA6B,IAAfA,MACzEvxF,KAAKiiL,wBAAwBn0F,GAAU,CACnC00F,kBAAmBxpF,EACnBupF,iBAAkB,KAY9BJ,0BAA0BhzF,EAAD,GAA0B,IAApB,eAAE6J,GAAkB,EAC3C7J,IAAQnvF,KAAKusG,YAAYsoE,4BAI7Bz0K,OAAOC,KAAK24F,GAAgBz4F,SAAQutF,IAChC,IAAoD,IAAhD9tF,KAAKgiL,sBAAsB3+K,QAAQyqF,GACnC,OAGJ,MAAMy0F,EAAmBviL,KAAK+hL,sBAAsBj0F,GAE/CppF,MAAMgD,QAAQ66K,GAERA,EAAiB7gL,QAxFR,GAyFhB6gL,EAAiBp1I,QAFjBntC,KAAK+hL,sBAAsBj0F,GAAU,GAKzC9tF,KAAK+hL,sBAAsBj0F,GAAQ5rF,KAAK82F,EAAelL,OAI3D1tF,OAAOC,KAAKL,KAAKiiL,yBAAyB1hL,SAAQutF,IAC9C,MAAM,iBAAEy0F,EAAF,kBAAoBC,GAAsBxiL,KAAKiiL,wBAAwBn0F,GAI7E,GAFAy0F,EAAiBrgL,KAAK82F,EAAelL,IAnGjB,IAqGhBy0F,EAAiB7gL,OAAoC,CACrD,GAAI6gL,EAAiBv/J,OAAMuuE,QAAoC,IAAfA,GAA6C,IAAfA,IAAmB,CAC7F,MAAMkxF,EAAyBrhL,KAAKF,UAAUqhL,GAE9C9lF,GAAWoE,c/GsXc,EAAE/S,EAAgBy0F,EAA2BC,KAA7C,CACzC56K,KAAMq5E,GAAgBC,iBACtBz5E,OAAQ,uBACRoY,WAAY,CACRiuE,OAAAA,EACAy0F,iBAAAA,EACAC,kBAAAA,K+G3XgBE,CAA8B50F,EAAQ20F,EAAwBD,IAClEj+K,GAAO2T,KAAM,yEACT41E,0BAA+B20F,2BAC/BD,KACJxiL,KAAKgiL,sBAAsB9/K,KAAK4rF,GAChC9tF,KAAKqiL,eAAev0F,UAGjB9tF,KAAKiiL,wBAAwBn0F,QAWhDu0F,eAAev0F,UACJ9tF,KAAK+hL,sBAAsBj0F,GAQtCxD,UACItqF,KAAKusG,YAAYl/D,IAAIyiI,GAA8C9vK,KAAKoiL,6BACxEpiL,KAAKusG,YAAYl/D,IAAI0mI,GAA4B/zK,KAAKqiL,gBACtDriL,KAAKusG,YAAYhN,WAAWlB,8BAA8Br+F,KAAKmiL,2BAC/DniL,KAAK+hL,2BAAwBh2K,EAC7B/L,KAAKiiL,6BAA0Bl2K,EAC/B/L,KAAKgiL,2BAAwBj2K,EAC7B/L,KAAKkiL,wCAAqCn2K,EAC1C/L,KAAKusG,iBAAcxgG,GC3I3B,MAAMxH,IAAS2B,EAAAA,EAAAA,wDAMf,MAAMy8K,GAMFvpK,YAAY5M,GACRxM,KAAKwM,KAAOA,EACZxM,KAAKiC,MAAQ,EACbjC,KAAK+rB,IAAM,EACX/rB,KAAK0yF,QAAU,GAQnBU,QAAQ1B,GACqB,iBAAdA,EACPntF,GAAOlD,MACF,GAAErB,KAAKwM,iCAAiCxM,KAAKiC,QAC9CyvF,GACIhoD,MAAMgoD,KACd1xF,KAAK+rB,KAAO2lE,EACZ1xF,KAAK0yF,QAAQxwF,KAAKwvF,GAClB1xF,KAAKiC,OAAS,GAStB2gL,YACI,OAAO5iL,KAAK+rB,IAAM/rB,KAAKiC,MAQ3B4gL,aAAar2F,GACTA,EAAQ,GAAExsF,KAAKwM,YAAcxM,KAAK4iL,YAClCp2F,EAAQ,GAAExsF,KAAKwM,gBAAkBpL,KAAKF,UAAUlB,KAAK0yF,SAOzD13C,QACIh7C,KAAK0yF,QAAU,GACf1yF,KAAK+rB,IAAM,EACX/rB,KAAKiC,MAAQ,GASrB,MAAM6gL,GAQF1pK,YAAY2pK,EAAqBxzF,EAAO1+E,GAKpC7Q,KAAKuvF,MAAQA,EAObvvF,KAAKgjL,GAAKnyK,EAQV7Q,KAAKijL,WAAa,EAMlBjjL,KAAKkjL,QAAU,IAAIP,GAAkB,OAYrC3iL,KAAKmjL,iBAAmB,IAAI98G,IAO5BrmE,KAAKojL,qBAAuBL,EAU5B/iL,KAAKqjL,oBAAiBt3K,EAEtB/L,KAAKsjL,mBAAqB,CAACn0F,EAAKyE,KACxB5zF,KAAKuvF,QAAUJ,EAAII,OACnBvvF,KAAKujL,mBAAmB3vF,IAIhC,MAAM8K,EAAaqkF,EAAoBx2E,YAEvC7N,EAAWa,WAAWnB,2BAClBp+F,KAAKsjL,oBAEJtjL,KAAKuvF,QACNvvF,KAAK6oG,YAAcxjG,GAAMrF,KAAKmjL,iBAAiB5yF,OAAOlrF,GACtDq5F,EAAWn0D,GAAGwpI,GAA4B/zK,KAAK6oG,aAE/C7oG,KAAKwjL,sBACC,CAACn+K,EAAIoR,IAASzW,KAAKyjL,oBAAoBp+K,EAAIoR,GACjDioF,EAAWn0D,GACPulI,GACA9vK,KAAKwjL,wBASjBD,mBAAmB9sK,GACf,GAAKA,GAcL,GARI8uB,GAAQujD,yBACJryE,EAAKrT,WAAaqT,EAAKrT,UAAU1B,QACjC1B,KAAKkjL,QAAQ9vF,QAAQ38E,EAAKrT,UAAU,GAAGs3F,KAI/C16F,KAAKijL,YAAc,EAEfjjL,KAAKijL,YAAcjjL,KAAKgjL,GAAI,CAC5B,GAAIz9I,GAAQujD,wBAAyB,CACjC,MAAM4V,EAAa1+F,KAAKojL,qBAAqB72E,YAEvCm3E,EAAc,CAChBrpF,IAAKr6F,KAAKuvF,MACV,gBAAmBmP,EAAW++E,uBAelC,GAZIhnK,EAAKrT,WAAaqT,EAAKrT,UAAU1B,QACjCtB,OAAOqmC,OAAOi9I,EAAa,CACvB,qBACIjtK,EAAKrT,UAAU,GAAGk3F,mBACtB,sBACI7jF,EAAKrT,UAAU,GAAGo3F,oBACtB,eAAkB/jF,EAAKrT,UAAU,GAAGwE,OAI5C5H,KAAKkjL,QAAQL,aAAaa,GAEtB1jL,KAAKuvF,MAAO,CAEZ,MAAMo0F,EAAgB3jL,KACjBojL,qBAAqBQ,gBAAgBP,eAErC35I,MAAMi6I,KAEPD,EAAW,SACL1jL,KAAKkjL,QAAQN,YAAce,OAElC,CAEH,MAAME,EAAe7jL,KAAK8jL,yBACpBC,EAAc/jL,KAAKkjL,QAAQN,YAEjC5iL,KAAKqjL,eAAiBU,EAAcF,EAE/Bn6I,MAAMq6I,IAAiBr6I,MAAMm6I,KAE9BH,EAAW,gBAAsB1jL,KAAKqjL,gBAI9C5mF,GAAWoE,cAAc3d,GAAoBwgG,IAGjD1jL,KAAKgkL,uBA5DLz/K,GAAOlD,MAAM,YAsErByiL,yBACI,IAAI7hL,EAAQ,EAAG8pB,EAAM,EAIrB,IAAK,MAAMk4J,KAAajkL,KAAKmjL,iBAAiB75K,SAAU,CACpD,MAAM46K,EAAMD,EAAUrB,YAEjBl5I,MAAMw6I,KACPn4J,GAAOm4J,EACPjiL,GAAS,EACTgiL,EAAUjpI,SAIlB,OAAOjvB,EAAM9pB,EAUjBwhL,oBAAoBp+K,EAAIoR,GACpB,MAAM0tK,EAAmC,iBAAhB1tK,EAAKi9J,OAC9B,IAAI0Q,EAASpkL,KAAKmjL,iBAAiBn+J,IAAI3f,IAElC++K,GAAUD,IACXC,EAAS,IAAIzB,GAAmB,GAAEt9K,cAClCrF,KAAKmjL,iBAAiBj+J,IAAI7f,EAAI++K,IAG9BD,EACAC,EAAOhxF,QAAQ38E,EAAKi9J,QACb0Q,GACPpkL,KAAKmjL,iBAAiB5yF,OAAOlrF,GAQrC2+K,iBACIhkL,KAAKkjL,QAAQloI,QACTh7C,KAAKmjL,kBACLnjL,KAAKmjL,iBAAiB/7G,QAE1BpnE,KAAKijL,WAAa,EAMtB34F,UAEI,MAAMoU,EAAa1+F,KAAKojL,qBAAqB72E,YAE7C7N,EAAWa,WAAWlB,8BAClBr+F,KAAKsjL,oBACJtjL,KAAKuvF,QACNmP,EAAWrxD,IACPyiI,GACA9vK,KAAKwjL,uBACT9kF,EAAWrxD,IACP0mI,GACA/zK,KAAK6oG,eAaN,MAAMw7E,GAOjBjrK,YAAYslF,EAAY7tF,GAOpB7Q,KAAKgjL,GAAKnyK,EAENA,EAAI,GACJtM,GAAOiH,KAAM,0CAAyCqF,aAc1D7Q,KAAKijL,WAAa,EAOlBjjL,KAAKusG,YAAc7N,EAQnB1+F,KAAKskL,mBACC,IAAI3B,GAAkB,wBAQ5B3iL,KAAKukL,qBACC,IAAI5B,GAAkB,0BAQ5B3iL,KAAKwkL,mBACC,IAAI7B,GAAkB,wBAQ5B3iL,KAAKykL,qBACC,IAAI9B,GAAkB,0BAQ5B3iL,KAAK0kL,gBACC,IAAI/B,GAAkB,oBAQ5B3iL,KAAK2kL,kBACC,IAAIhC,GAAkB,sBAQ5B3iL,KAAK4kL,oBACC,IAAIjC,GAAkB,qBAQ5B3iL,KAAK6kL,iBACC,IAAIlC,GAAkB,sBAQ5B3iL,KAAK8kL,mBACC,IAAInC,GAAkB,wBAO5B3iL,KAAK+kL,cAAgB,IAAIpC,GAAkB,oBAQ3C3iL,KAAKglL,oBACC,IAAIrC,GAAkB,2BAO5B3iL,KAAKilL,aAAe,IAAItC,GAAkB,mBAQ1C3iL,KAAKklL,mBACC,IAAIvC,GAAkB,0BAQ5B3iL,KAAKmlL,uBACC,IAAIxC,GAAkB,iBAQ5B3iL,KAAKolL,uBACC,IAAIzC,GAAkB,wBAO5B3iL,KAAKqlL,sBACC,IAAI1C,GAAkB,gBAQ5B3iL,KAAKslL,sBACC,IAAI3C,GAAkB,uBAQ5B3iL,KAAKulL,OAAS,IAAI5C,GAAkB,sBAEpC3iL,KAAKwlL,2BAAwBz5K,EAE7B/L,KAAKylL,qBAAuBhvK,IACxBzW,KAAKujL,mBAAmB9sK,GACxBzW,KAAK0lL,kCAAkCjvK,IAE3CioF,EAAWn0D,GACPulI,GACA9vK,KAAKylL,sBAETzlL,KAAK2lL,oBAAsB,KACvBphL,GAAOynF,MAAM,uCACbhsF,KAAKgkL,iBACLhkL,KAAK4jL,gBAAgBI,iBACrBhkL,KAAK4lL,gBAAgB5B,kBAEzBtlF,EAAWn0D,GACPwpI,GACA/zK,KAAK2lL,qBAET3lL,KAAK6lL,uBAAyB,CAACrI,EAAWvzE,MAIpB,IAAdA,IACA1lG,GAAOiH,KAAK,+BACZxL,KAAK8lL,sBAGbpnF,EAAWn0D,GACPwpI,GACA/zK,KAAK6lL,wBAET7lL,KAAK4jL,gBACC,IAAId,GAAmB9iL,MAAM,EAAiB6Q,GAEpD7Q,KAAK4lL,gBACC,IAAI9C,GAAmB9iL,MAAM,EAAgB6Q,IAtN/CtM,GAAOiH,KAAK,uCA+NpB+3K,mBAAmB9sK,GAEf,IAAKA,EAGD,YAFAlS,GAAOlD,MAAM,YAKjB,MAAMkuF,EAAQvvF,KAAKusG,YAAY/D,cACzBu9E,EAAW/lL,KAAKusG,YAAYkxE,sBAElC,IAAKluF,GAASw2F,EAAW,EAKrB,OAUJ,MAAM3wF,EAAU3+E,EAAK2+E,QACf7d,EAAY9gE,EAAK8gE,UACjBme,EAAaj/E,EAAKi/E,WAClB0F,EAAY3kF,EAAK++E,UACjBD,EAAa9+E,EAAK8+E,WAExB,GAAKH,EAIE,GAAK7d,EAIL,GAAKme,EAIL,GAAK0F,EAIL,GAAK7F,GA2DZ,GArDAv1F,KAAKskL,mBAAmBlxF,QAAQgC,EAAQ0D,MAAMxD,QAC9Ct1F,KAAKukL,qBAAqBnxF,QAAQgC,EAAQ0D,MAAMzD,UAEhDr1F,KAAKwkL,mBAAmBpxF,QAAQgC,EAAQxU,MAAM0U,QAC9Ct1F,KAAKykL,qBAAqBrxF,QAAQgC,EAAQxU,MAAMyU,UAE5C9vD,GAAQ4iD,gCACRnoF,KAAK0kL,gBAAgBtxF,QAAQ7b,EAAU+d,QACvCt1F,KAAK2kL,kBAAkBvxF,QAAQ7b,EAAU8d,WAG7Cr1F,KAAK6kL,iBAAiBzxF,QAAQsC,EAAWJ,QACzCt1F,KAAK8kL,mBAAmB1xF,QAAQsC,EAAWL,UAC3Cr1F,KAAK4kL,oBAAoBxxF,QAAQsC,EAAWqD,OAE5C/4F,KAAKulL,OAAOnyF,QAAQ38E,EAAKg9J,mBAErBr4E,IACAp7F,KAAK+kL,cAAc3xF,QACfpzF,KAAKgmL,sBACD5qF,GAAW,EAAoBt+D,GAAU,UAAVA,SACvC98B,KAAKglL,oBAAoB5xF,QACrBpzF,KAAKgmL,sBACD5qF,GAAW,EAAoBt+D,GAAU,UAAVA,UAEvC98B,KAAKilL,aAAa7xF,QACdpzF,KAAKgmL,sBACD5qF,GAAW,EAAkBt+D,GAAU,UAAVA,SACrC98B,KAAKklL,mBAAmB9xF,QACpBpzF,KAAKgmL,sBACD5qF,GAAW,EAAkBt+D,GAAU,UAAVA,WAGrCy4D,IACAv1F,KAAKmlL,uBAAuB/xF,QACxBpzF,KAAKimL,yBACD1wF,GAAY,EAAoBz4D,GAAU,UAAVA,SAExC98B,KAAKolL,uBAAuBhyF,QACxBpzF,KAAKimL,yBACD1wF,GAAY,EAAoBz4D,GAAU,UAAVA,UAExC98B,KAAKqlL,sBAAsBjyF,QACvBpzF,KAAKimL,yBACD1wF,GAAY,EAAkBz4D,GAAU,UAAVA,SAEtC98B,KAAKslL,sBAAsBlyF,QACvBpzF,KAAKimL,yBACD1wF,GAAY,EAAkBz4D,GAAU,UAAVA,WAG1C98B,KAAKijL,YAAc,EAEfjjL,KAAKijL,YAAcjjL,KAAKgjL,GAAI,CAE5B,MAAMU,EAAc,CAChBrpF,IAAK9K,EACL,gBAAmBw2F,GAGnBtvK,EAAKrT,WAAaqT,EAAKrT,UAAU1B,QACjCtB,OAAOqmC,OAAOi9I,EAAa,CACvB,qBACIjtK,EAAKrT,UAAU,GAAGk3F,mBACtB,sBACI7jF,EAAKrT,UAAU,GAAGo3F,oBACtB,eAAkB/jF,EAAKrT,UAAU,GAAGwE,OAI5C5H,KAAKskL,mBAAmBzB,aAAaa,GACrC1jL,KAAKukL,qBAAqB1B,aAAaa,GAEvC1jL,KAAKwkL,mBAAmB3B,aAAaa,GACrC1jL,KAAKykL,qBAAqB5B,aAAaa,GAEnCn+I,GAAQ4iD,gCACRnoF,KAAK0kL,gBAAgB7B,aAAaa,GAClC1jL,KAAK2kL,kBAAkB9B,aAAaa,IAExC1jL,KAAK6kL,iBAAiBhC,aAAaa,GACnC1jL,KAAK8kL,mBAAmBjC,aAAaa,GACrC1jL,KAAK4kL,oBAAoB/B,aAAaa,GAEtC1jL,KAAK+kL,cAAclC,aAAaa,GAC3Bh6I,MAAM1pC,KAAKglL,oBAAoBpC,cAChC5iL,KAAKglL,oBAAoBnC,aAAaa,GAE1C1jL,KAAKilL,aAAapC,aAAaa,GAC1Bh6I,MAAM1pC,KAAKklL,mBAAmBtC,cAC/B5iL,KAAKklL,mBAAmBrC,aAAaa,GAGzC1jL,KAAKmlL,uBAAuBtC,aAAaa,GACpCh6I,MAAM1pC,KAAKolL,uBAAuBxC,cACnC5iL,KAAKolL,uBAAuBvC,aAAaa,GAE7C1jL,KAAKqlL,sBAAsBxC,aAAaa,GACnCh6I,MAAM1pC,KAAKslL,sBAAsB1C,cAClC5iL,KAAKslL,sBAAsBzC,aAAaa,GAG5C1jL,KAAKulL,OAAO1C,aAAaa,GAEzBjnF,GAAWoE,cAAc3d,GAAoBwgG,IAE7C1jL,KAAKgkL,uBA/GLz/K,GAAOlD,MAAM,sBAJbkD,GAAOlD,MAAM,uBAJbkD,GAAOlD,MAAM,wBAJbkD,GAAOlD,MAAM,uBAJbkD,GAAOlD,MAAM,gBA8IrB4kL,yBAAyBC,EAAiBj2F,EAASwV,GAC/C,IAAI0gF,EAAgB,EAChBC,EAAY,EAChB,MAAMC,EAAOrmL,KAAKusG,YAAY1H,WAE9B,IAAK,MAAMyhF,KAAUlmL,OAAOC,KAAK6lL,GAC7B,GAAIj2F,EAAUq2F,IAAWD,EAAOC,IAAWD,EAAM,CAC7C,MAAMxkF,EACA5R,EACI,KACAjwF,KAAKusG,YAAYzK,mBAAmBwkF,GACxCC,EAAmBL,EAAgBI,GAGzC,IAAKr2F,GAAW4R,IAAgB0kF,EAAkB,CAC9C,MAAMC,EAAgBxmL,KAAKymL,6BACvBF,EAAkB1kF,EAAa4D,GAE9B/7D,MAAM88I,KACPL,GAAiBK,EACjBJ,GAAa,IAM7B,OAAOD,EAAgBC,EAc3BK,6BAA6BC,EAAQ7kF,EAAa4D,GAC9C,IAAI3+F,EAAQ1G,OAAOC,KAAKqmL,GAAQx/K,KAAIN,GAAQkI,OAAOlI,KAC/C4kG,EAAc,KAIlB,MAAMrc,EAAMnvF,KAAKusG,YAAYsoE,0BAEzBhzE,GACA2J,EAAc3J,EAAY4J,qBAAqB3W,GAAU2G,OACrD+P,IACA1kG,EACMA,EAAMC,QACJH,GAAQ4kG,EAAYnjG,MAChB8vE,IACKA,EAAM+oB,WACA/oB,EAAM6oF,YAAcp6J,GACpBuxE,EAAMstB,YAAcA,SAG/C+F,EAAcxrG,KAAKusG,YAAY3Q,eAAe9G,GAAU2G,OACxD30F,EACMA,EAAMC,QACJH,GAAQ4kG,EAAYnjG,MAChB8vE,IACKA,EAAM+oB,WACA/R,EAAI0M,aAAa1jB,KAAWvxE,GAC5BuxE,EAAMstB,YAAcA,OAG/C,IAAI0gF,EAAgB,EAChBQ,EAAgB,EAEpB,IAAK,MAAM//K,KAAQE,EAAO,CACtB,MAAM8/K,EACA93K,OAAO43K,EAAO9/K,GAAMi2B,QAAU/tB,OAAO43K,EAAO9/K,GAAMg2B,QAGnD8M,MAAMk9I,IAAmBA,EAAiB,IAC3CT,GAAiBS,EACjBD,GAAiB,GAIzB,OAAOR,EAAgBQ,EAa3BX,sBAAsB5qF,EAAWnL,EAASwV,GACtC,IAAIohF,EAAa,EACbT,EAAY,EAChB,MAAMC,EAAOrmL,KAAKusG,YAAY1H,WAE9B,IAAK,MAAMyhF,KAAUlmL,OAAOC,KAAK+6F,GAC7B,GAAInL,EAAUq2F,IAAWD,EAAOC,IAAWD,EAAM,CAC7C,MAAMxkF,EACA5R,EACI,KAAOjwF,KAAKusG,YAAYzK,mBAAmBwkF,GAC/CQ,EAAY1rF,EAAUkrF,GAG5B,IAAKr2F,GAAW4R,IAAgBilF,EAAW,CACvC,MAAMC,EACA/mL,KAAKgnL,0BACHF,EAAWjlF,EAAa4D,GAE3B/7D,MAAMq9I,KACPF,GAAcE,EACdX,GAAa,IAM7B,OAAOS,EAAaT,EAcxBY,0BAA0BN,EAAQ7kF,EAAa4D,GAC3C,IAAI3+F,EAAQ1G,OAAOC,KAAKqmL,GAAQx/K,KAAIN,GAAQkI,OAAOlI,KAC/C4kG,EAAc,KAIlB,MAAMrc,EAAMnvF,KAAKusG,YAAYsoE,0BAEzBhzE,GACA2J,EAAc3J,EAAY4J,qBAAqB3W,GAAU2G,OACrD+P,IACA1kG,EACMA,EAAMC,QACJH,GAAQ4kG,EAAYnjG,MAChB8vE,IAAUA,EAAM+oB,WACT/oB,EAAM6oF,YAAcp6J,GACpBuxE,EAAMstB,YAAcA,SAG3C+F,EAAcxrG,KAAKusG,YAAY3Q,eAAe9G,GAAU2G,OACxD30F,EACMA,EAAMC,QACJH,GAAQ4kG,EAAYnjG,MAChB8vE,IAAUA,EAAM+oB,WACT/R,EAAI0M,aAAa1jB,KAAWvxE,GAC5BuxE,EAAMstB,YAAcA,OAG3C,IAAIohF,EAAa,EACbF,EAAgB,EAEpB,IAAK,MAAM//K,KAAQE,EAAO,CACtB,MAAMmgL,EAAcn4K,OAAO43K,EAAO9/K,KAG7B8iC,MAAMu9I,IAAgBA,EAAc,IACrCJ,GAAcI,EACdN,GAAiB,GAIzB,OAAOE,EAAaF,EAUxBjB,kCAAkCjvK,GAC9B,IAAKA,IAASA,EAAKrT,YAAcqT,EAAKrT,UAAU1B,OAC5C,OAEJ,MAAMwlL,EAAiB,CACnB7sF,IAAK5jF,EAAKrT,UAAU,GAAGi3F,IACvB,qBAAwB5jF,EAAKrT,UAAU,GAAGk3F,mBAC1C,sBAAyB7jF,EAAKrT,UAAU,GAAGo3F,oBAC3C,eAAkB/jF,EAAKrT,UAAU,GAAGwE,MhHpdLiY,IAAAA,EgHud9B7f,KAAKwlL,uBAA0BzuE,IAAAA,CAAQmwE,EAAgBlnL,KAAKwlL,yBAC7DxlL,KAAKwlL,sBAAwB0B,EAC7BzqF,GAAWoE,ehHzdoBhhF,EgHydoBqnK,EhHzdtB,CACrCt/K,KAAMq5E,GAAgBC,iBACtBz5E,OAAQ,kBACRoY,WAAAA,MgHieAimK,oBACI9lL,KAAKgkL,iBACLhkL,KAAK4jL,gBAAgBI,iBAOzBA,iBACIhkL,KAAKskL,mBAAmBtpI,QACxBh7C,KAAKukL,qBAAqBvpI,QAE1Bh7C,KAAKwkL,mBAAmBxpI,QACxBh7C,KAAKykL,qBAAqBzpI,QAE1Bh7C,KAAK0kL,gBAAgB1pI,QACrBh7C,KAAK2kL,kBAAkB3pI,QAEvBh7C,KAAK6kL,iBAAiB7pI,QACtBh7C,KAAK8kL,mBAAmB9pI,QACxBh7C,KAAK4kL,oBAAoB5pI,QAEzBh7C,KAAK+kL,cAAc/pI,QACnBh7C,KAAKglL,oBAAoBhqI,QACzBh7C,KAAKilL,aAAajqI,QAClBh7C,KAAKklL,mBAAmBlqI,QAExBh7C,KAAKmlL,uBAAuBnqI,QAC5Bh7C,KAAKolL,uBAAuBpqI,QAC5Bh7C,KAAKqlL,sBAAsBrqI,QAC3Bh7C,KAAKslL,sBAAsBtqI,QAE3Bh7C,KAAKulL,OAAOvqI,QAEZh7C,KAAKijL,WAAa,EAMtB34F,UACItqF,KAAKusG,YAAYl/D,IACb0mI,GACA/zK,KAAK2lL,qBACT3lL,KAAKusG,YAAYl/D,IACbyiI,GACA9vK,KAAKylL,sBACTzlL,KAAKusG,YAAYl/D,IACb0mI,GACA/zK,KAAK6lL,wBACT7lL,KAAK4jL,gBAAgBt5F,UACrBtqF,KAAK4lL,gBAAgBt7F,WCz0B7B,SAvKA,MAkBIlxE,YAAY4mF,EAAQgM,EAAam7E,GAC7BnnL,KAAKonL,QAAUpnF,EACfhgG,KAAKqnL,eAAer7E,GACpBhsG,KAAKsnL,cAAgBH,IAAgB,EACrCnnL,KAAKunL,oBAAmB,GACxBvnL,KAAKwnL,yBAA2B,EAChCxnL,KAAKynL,sBAAwB,EAC7BznL,KAAK0nL,UAAW,EAChB1nL,KAAK2nL,mBAAqB,CACtBC,MAAO,EACPC,QAAS,EACTC,UAAW,EACXC,MAAO,EACPC,QAAS,EACTC,UAAW,EACXC,IAAK,GASbC,YACI,OAAOnoL,KAAKonL,QAQhB15E,iBACI,OAAO1tG,KAAKgsG,YAShBq7E,eAAee,GACXpoL,KAAKgsG,YAAco8E,EAQvBjB,eACI,OAAOnnL,KAAKsnL,cAQhBe,oBACI,OAAOroL,KAAKynL,sBAAwB,EAWxCF,mBAAmBe,GACf,IAAKtoL,KAAKqoL,qBAAuBC,EAC7BtoL,KAAKynL,sBAAwBtiL,KAAK8nD,WAC/B,GAAIjtD,KAAKqoL,sBAAwBC,EAAsB,CAC1D,MACMC,EADMpjL,KAAK8nD,MACSjtD,KAAKynL,sBAE/BznL,KAAKwnL,0BAA4Be,EACjCvoL,KAAKynL,sBAAwB,GASrCe,8BACI,IAAIzvF,EAAQ/4F,KAAKwnL,yBAMjB,OAJIxnL,KAAKqoL,sBACLtvF,GAAS5zF,KAAK8nD,MAAQjtD,KAAKynL,uBAGxB1uF,EAQX0vF,UACI,OAAOzoL,KAAK0nL,SAQhBgB,gBACI1oL,KAAK0nL,UAAW,EAChB1nL,KAAKunL,oBAAmB,GAQ5BoB,uBACI,OAAO3oL,KAAK2nL,mBAShBiB,qBAAqBC,GACjB7oL,KAAK2nL,mBAAqBkB,EAS9BC,oBAAoBplC,EAAkBtvD,GAClCp0F,KAAK2nL,mBAAmBjkC,IAAqBtvD,IAS9C,IAAK20F,aAAAA,GAAAA,EAAAA,MAAAA,QAAAA,EAAAA,QAAAA,UAAAA,EAAAA,UAAAA,YAAAA,EAAAA,MAAAA,QAAAA,EAAAA,QAAAA,UAAAA,EAAAA,UAAAA,YAAAA,EAAAA,IAAAA,OAAAA,KAAAA,GAAAA,KC1KG,MAAMC,GAQjB5vK,YAAYslF,GACR1+F,KAAK4zF,MAAQ,CACTgwD,MAAO,GAIPqlC,kBAAmB,MAGvB,MAAMjpF,EAAStB,EAAWmG,WAE1B7kG,KAAK4zF,MAAMgwD,MAAM5jD,GAAU,IAAIkpF,GAAalpF,EAAQ,MAAM,GAC1DhgG,KAAK0+F,WAAaA,EAElBA,EAAWryD,iBACP6uC,GACAl7E,KAAKmpL,mBAAmBvoL,KAAKZ,OACjC0+F,EAAWryD,iBACP6uC,GACAl7E,KAAKopL,YAAYxoL,KAAKZ,OAC1B0+F,EAAWryD,iBACP6uC,GACAl7E,KAAKqpL,aAAazoL,KAAKZ,OAC3B0+F,EAAWryD,iBACP6uC,EACAl7E,KAAKspL,qBAAqB1oL,KAAKZ,OACnC0+F,EAAWryD,iBACP6uC,GACAl7E,KAAKupL,uBAAuB3oL,KAAKZ,OACjC0+F,EAAWhC,MACXgC,EAAWhC,KAAK9kE,YACZqF,GAAW,WAAXA,uBACAj9B,KAAKwpL,aAAa5oL,KAAKZ,OAanCmpL,mBAAmBF,GACf,MAAMQ,EACAzpL,KAAK4zF,MAAMgwD,MAAM5jJ,KAAK4zF,MAAMq1F,mBAC5BS,EAAqB1pL,KAAK4zF,MAAMgwD,MAAMqlC,GAE5CQ,GAAsBA,EAAmBlC,oBAAmB,GAC5DmC,GAAsBA,EAAmBnC,oBAAmB,GAC5DvnL,KAAK4zF,MAAMq1F,kBAAoBA,EAWnCG,YAAYppF,EAAQ6B,GACZA,EAAY+L,YAIX5tG,KAAK4zF,MAAMgwD,MAAM5jD,KAClBhgG,KAAK4zF,MAAMgwD,MAAM5jD,GAAU,IAAIkpF,GAAalpF,EAAQ6B,EAAY6L,mBAYxE27E,aAAarpF,GACT,MAAM2pF,EAAY3pL,KAAK4zF,MAAMgwD,MAAM5jD,GAE/B2pF,GACAA,EAAUjB,gBAYlBY,qBAAqBtpF,EAAQooF,GACzB,MAAMuB,EAAY3pL,KAAK4zF,MAAMgwD,MAAM5jD,GAE/B2pF,GACAA,EAAUtC,eAAee,GAYjCmB,uBAAuBvpF,EAAQvpF,GAC3B,MAAMkzK,EAAY3pL,KAAK4zF,MAAMgwD,MAAM5jD,GAE/B2pF,GACAA,EAAUb,oBAAoBryK,EAAKitI,iBAAkBjtI,EAAK29E,UAUlE+C,WACI,OAAOn3F,KAAK4zF,MAAMgwD,MAStB4lC,aAAaI,GACT,IAAK,MAAM5pF,KAAU4pF,EAAU,CAC3B,IAAIC,EACJ,MAAMC,EAAiB9pL,KAAK0+F,WAAWoD,mBAAmB9B,GAGrD8pF,GAAmBA,EAAel8E,aAC/B5tG,KAAK4zF,MAAMgwD,MAAM5jD,IACjB6pF,EAAuB7pL,KAAK4zF,MAAMgwD,MAAM5jD,GAEnC6pF,EAAqBn8E,kBACtBm8E,EACKxC,eAAeuC,EAAS5pF,GAAQgM,eAGzC69E,EAAuB,IAAIX,GACvBlpF,EAAQ4pF,EAAS5pF,GAAQgM,aAC7BhsG,KAAK4zF,MAAMgwD,MAAM5jD,GAAU6pF,EAC3BA,EAAqBnB,kBAI7BmB,EAAqBrC,yBACfoC,EAAS5pF,GAAQwnF,yBAEvBqC,EAAqBjB,qBAAqBgB,EAAS5pF,GAAQ6oF,qBC5KxD,MAAMkB,GAOjB3wK,YAAY+3D,EAAM3kE,EAAMgoF,EAAWw1F,GAC/BhqL,KAAKmxE,KAAOA,EACZnxE,KAAKwM,KAAOA,EACZxM,KAAKw0F,UAAYA,EACjBx0F,KAAKgqL,UAAYA,GCbV,MAAMC,GAIjB7wK,YAAY++D,GAERn4E,KAAKm4E,MAAQA,EAGbn4E,KAAKkqL,SAAW,KAIhBlqL,KAAKyW,KAAO,KAIZzW,KAAKwM,KAAO,KAGZxM,KAAKw0F,UAAY,MCnBzB,MAAM21F,GAAa,aACbC,GAAY,YAOlB,SAASC,GAAcC,GACnB,QAA+Bv+K,IAA3Bu+K,EAAcJ,SACd,MAAM,IAAIlmL,MAAM,yEAGpBsmL,EAAcJ,SAAS9nL,QACvBkoL,EAAc91F,UAAY,IAAIrvF,KAQlC,SAASolL,GAAaD,GAClB,QAA+Bv+K,IAA3Bu+K,EAAcJ,SACd,MAAM,IAAIlmL,MAAM,wEAGpBsmL,EAAcJ,SAASnnL,OAO3B,SAASynL,KACL,GAAIC,cAAcC,gBAAgBP,IAC9B,OAAOA,GACJ,GAAIM,cAAcC,gBAAgBN,IACrC,OAAOA,GAEX,MAAM,IAAIpmL,MACN,6DASR,SAAS2mL,GAAcC,GAGnB5qL,KAAK6qL,UAAY,GAGjB7qL,KAAK8qL,SAAWN,KAGhBxqL,KAAK+qL,aAAc,EAGnB/qL,KAAK4qL,gBAAkBA,EAM3BD,GAAcH,yBAA2BA,GAOzCG,GAAc1pL,UAAU2yI,SAAW,SAASz7D,GACxC,GAAIA,EAAMogB,eAAgB,CAEtB,MAAM+xF,EAAgBtqL,KAAKgrL,yBAAyB7yG,GAIpDn4E,KAAK6qL,UAAU3oL,KAAKooL,GAGpBtqL,KAAKirL,cAIDjrL,KAAK+qL,aACLV,GAAcC,KAU1BK,GAAc1pL,UAAU+pL,yBAA2B,SAAS7yG,GACxD,MAAMmyG,EAAgB,IAAIL,GAAc9xG,GAGlC+yG,EAAiBZ,EAAcnyG,MAAMy3E,oBACrCx/I,EAAS,IAAIq9I,YAmBnB,OAjBAy9B,EAAexhC,iBAAiBnpJ,SAAQyE,GAAKoL,EAAOwjI,SAAS5uI,KAG7DslL,EAAcJ,SAAW,IAAIO,cAAcr6K,EACvC,CAAE4D,SAAUhU,KAAK8qL,WAIrBR,EAAc7zK,KAAO,GAGrB6zK,EAAcJ,SAASiB,gBAAkB,SAASC,GAC1CA,EAAU30K,KAAKuuD,KAAO,GACtBslH,EAAc7zK,KAAKvU,KAAKkpL,EAAU30K,OAInC6zK,GAaXK,GAAc1pL,UAAUmzJ,YAAc,SAASj8E,GAC3C,GAAIA,EAAMqtB,eACN,OAGJ,MAAMj7F,EAAQvK,KAAK6qL,UACnB,IAAIrpL,EAEJ,IAAKA,EAAI,EAAGA,EAAI+I,EAAM7I,OAAQF,IAC1B,GAAI+I,EAAM/I,GAAG22E,MAAMsgB,qBAAuBtgB,EAAMsgB,mBAAoB,CAChE,MAAM4yF,EAAmB9gL,EAAM/I,GAE3BxB,KAAK+qL,YACLR,GAAac,GAGb9gL,EAAM/G,OAAOhC,EAAG,GAM5BxB,KAAKirL,eAQTN,GAAc1pL,UAAUgqL,YAAc,WAClC,MAAMvsF,EAAa1+F,KAAK4qL,gBAExB5qL,KAAK6qL,UAAUtqL,SAAQ+pL,IACnB,GAAIA,EAAcnyG,MAAM8X,UACpBq6F,EAAc99K,KAAO,sBAClB,CACH,MAAMnH,EAAKilL,EAAcnyG,MAAMsgB,mBAEzB2vF,EADc1pF,EAAWoD,mBAAmBz8F,GACtBqoG,iBAEZ,cAAZ06E,IACAkC,EAAc99K,KAAO47K,QASrCuC,GAAc1pL,UAAUmB,MAAQ,WAC5B,GAAIpC,KAAK+qL,YACL,MAAM,IAAI/mL,MAAM,sCAKpBhE,KAAK+qL,aAAc,EAGnB/qL,KAAK6qL,UAAUtqL,SAAQ+pL,GAAiBD,GAAcC,KAGtDrnL,QAAQqB,IACH,2DACGtE,KAAK6qL,UAAUnpL,6BAM3BipL,GAAc1pL,UAAU8B,KAAO,WAE3B/C,KAAK+qL,aAAc,EAGnB/qL,KAAK6qL,UAAUtqL,SAAQ+pL,GAAiBC,GAAaD,KACrDrnL,QAAQqB,IAAI,sBAMhBqmL,GAAc1pL,UAAUo0F,SAAW,WAC/Br1F,KAAK6qL,UAAUtqL,SAAQ+pL,IACnB,MAAMn5G,EAAO,IAAIi/B,KAAKk6E,EAAc7zK,KAAM,CAAE7O,KAAM5H,KAAK8qL,WACjD3iJ,EAAMkoE,IAAIC,gBAAgBn/B,GAC1B9jE,EAAI4sB,SAAShX,cAAc,KAEjCgX,SAASitB,KAAKrzC,YAAYxG,GAC1BA,EAAEw5C,MAAQ,gBACVx5C,EAAEk6B,KAAOY,EACT96B,EAAEgoF,SAAY,QAAOr1F,KAAK8qL,SAAS5mL,MAAM,KAAK,KAC9CmJ,EAAEo/C,QACFnqD,OAAO+tG,IAAIi7E,gBAAgBnjJ,OASnCwiJ,GAAc1pL,UAAUsqL,oBAAsB,WAC1C,GAAIvrL,KAAK+qL,YACL,MAAM,IAAI/mL,MACN,kEAIRhE,KAAKirL,cAEL,MAAM1gL,EAAQ,GAUd,OARAvK,KAAK6qL,UAAUtqL,SACX2pL,GACI3/K,EAAMrI,KACF,IAAI6nL,GACA,IAAI35E,KAAK85E,EAASzzK,KAAM,CAAE7O,KAAM5H,KAAK8qL,WACrCZ,EAAS19K,KACT09K,EAAS11F,cAElBjqF,GAOXogL,GAAc1pL,UAAUuqL,YAAc,WAClC,OAAOxrL,KAAK8qL,UAMhB,YClRe,MAAMW,GAMjBryK,YAAYsyK,EAAMC,EAAO91J,GACrB71B,KAAK0rL,KAAOA,EACZ1rL,KAAK2rL,MAAQA,EACb3rL,KAAK61B,IAAMA,EAOf+1J,UACI,OAAO5rL,KAAK0rL,KAOhBG,eACI,OAAO7rL,KAAK2rL,MAOhBG,aACI,OAAO9rL,KAAK61B,KC7BL,MAAMk2J,WCNN,MAKX3yK,cACI,MAAM,IAAIpV,MAAM,0DAYpBs/G,KAAK0oE,EAAiBpvK,GAClB5c,KAAKm8K,YAAY6P,EAAgB76G,MAAM2pC,IAC/B96G,KAAKisL,OAAOnxE,GACZkxE,EAAgBhC,UAAYhqL,KAAKksL,eAAepxE,IAEhD73G,QAAQqB,IAAI,wDACZ0nL,EAAgBhC,UAAY,IAEhCptK,EAASovK,MAajB7P,YAAYgQ,EAAWvvK,GACnB,MAAM,IAAI5Y,MAAM,gDAkBpBkoL,eAAepxE,GACX,MAAM,IAAI92G,MAAM,2CASpBioL,OAAOnxE,GACH,MAAM,IAAI92G,MAAM,6CD3DpBoV,cACI8rE,QAGAllF,KAAKmoC,IAqGb,WACI,MAAMntB,EAAU,2DAEhB,QAAyBjP,IAArB0B,OAAO2+K,UACPnpL,QAAQqB,IAAI0W,OACT,CACH,MAAMqxK,EAAW5+K,OAAO2+K,UAExB,QAA0BrgL,IAAtBsgL,EAAS5uE,UAA0B4uE,EAAS5uE,SAAS,YACrD,OAAO4uE,EAEXppL,QAAQqB,IAAI0W,IAhHDsxK,GAUfnQ,YAAYoQ,EAAe3vK,GACvB3Z,QAAQqB,IAAK,6BAA4BtE,KAAKmoC,OAC9CllC,QAAQqB,IAAK,8BAA6BioL,KAC1C,MAAM9wC,EAAU,IAAI+wC,eAEpB/wC,EAAQgxC,mBAAqB,WACzB,GAAIhxC,EAAQjzG,aAAegkJ,eAAeE,MAChB,MAAnBjxC,EAAQxsD,OACXryE,EAAS6+H,EAAQkxC,mBACd,GAAIlxC,EAAQjzG,aAAegkJ,eAAeE,KAC7C,MAAM,IAAI1oL,MACL,yDAAwDy3I,EAAQxsD,WAK7EwsD,EAAQmxC,KAAK,OAAQ5sL,KAAKmoC,KAC1BszG,EAAQoxC,iBAAiB,eACrBC,GAActC,4BAClB/uC,EAAQn4B,KAAKipE,GACbtpL,QAAQqB,IAAK,QAAOioL,KASxBL,eAAepxE,GACX,MAAMxhF,EAASl4B,KAAKwJ,MAAMkwG,GAAUiyE,QAIpCzzJ,EAAO6T,QACP,MAAM5iC,EAAQ,GAMd,OAJA+uB,EAAO/4B,SACHmrL,GAAQA,EAAKsB,QACNziL,EAAMrI,KAAK,IAAIupL,GAAKC,EAAKA,KAAMA,EAAKtpL,MAAOspL,EAAK71J,QAEpDtrB,EAQX0hL,OAAOnxE,GAIH,GAHA73G,QAAQqB,IAAK,wBAAuBw2G,EAAS55F,cAGrB,iBAAb45F,EACP,OAAO,EAIX,IAAIlE,EAEJ,IACIA,EAAOx1G,KAAKwJ,MAAMkwG,GACpB,MAAOz5G,GAGL,OAFA4B,QAAQqB,IAAIjD,IAEL,EAIX,QAAqB0K,IAAjB6qG,EAAKm2E,QACL,OAAO,EAIX,MAAMxiL,EAAQqsG,EAAKm2E,QAEnB,SAAMxiL,EAAM,KAAMA,EAAM,GAAG,gBErGnC,MAAM0iL,GAAe,SACfC,GAAkB,YAClBC,GAAqB,eACrBC,GAAiB,WAYvB,SAASC,KAELrtL,KAAK8sL,cAAgB,IAAInC,GAGzB3qL,KAAKstL,qBAAuB,IAAIvB,GAGhC/rL,KAAKklI,QAAU,KAIfllI,KAAKw0F,UAAY,KAGjBx0F,KAAKutL,cAAgB,KAIrBvtL,KAAK4c,SAAW,KAIhB5c,KAAKywC,QAAU,GAGfzwC,KAAK6rC,MAAQohJ,GAIbjtL,KAAKwtL,WAAa,EA+DtB,SAASC,GAAaC,EAAaj1C,GAO/B,GANAx1I,QAAQqB,IAEG,0FAAoBm0I,EAAOuxC,UAAUtoL,UAI5C+2I,EAAOuxC,UAAUtoL,OAAS,EAAG,CAC7B,IAAI6iB,EAASk0H,EAAOjkD,UAAUm5F,qBACxBD,EAAYl5F,UAAUm5F,qBAIxBppK,EAAS,IACTA,EAAS,GAGb,IAAIha,EAAQ,IAEZkuI,EAAOuxC,UAAUzpL,SAAQqtL,IACrBA,EAAWjC,OAASpnK,EACpBqpK,EAAW/3J,KAAOtR,EAClBha,GAAU,GAAEqjL,EAAWlC,WAE3BnhL,GAAS,IACTtH,QAAQqB,IAAIiG,GAKZkuI,EAAOuxC,UAAUx9K,KAAOisI,EAAOjsI,KAInCkhL,EAAYj9I,QAAQvuC,KAAKu2I,EAAOuxC,WAChC0D,EAAYxoD,UACZjiI,QAAQqB,IAAK,oBAAmBopL,EAAYxoD,WAG5CwoD,EAAYG,aAkHhB,SAASC,GAAmBC,GACxB,IAAK,IAAIvsL,EAAI,EAAGA,EAAIusL,EAAoBrsL,OAAQF,IACN,IAAlCusL,EAAoBvsL,GAAGE,QACvBqsL,EAAoBvqL,OAAOhC,EAAG,GAItC,OAAOusL,EAAoBrsL,OAAS,EAvNxC2rL,GAAYpsL,UAAUmB,MAAQ,WAC1B,GAAIpC,KAAK6rC,QAAUohJ,GACf,MAAM,IAAIjpL,MACL,4FAEGhE,KAAK6rC,gBAEjB7rC,KAAK6rC,MAAQqhJ,GACbltL,KAAK8sL,cAAc1qL,QACnBpC,KAAKw0F,UAAY,IAAIrvF,MASzBkoL,GAAYpsL,UAAU8B,KAAO,SAAc6Z,GACvC,GAAI5c,KAAK6rC,QAAUqhJ,GACf,MAAM,IAAIlpL,MACL,8FAEGhE,KAAK6rC,gBAIjB5oC,QAAQqB,IAAI,8CACZtE,KAAK8sL,cAAc/pL,OAGnB,MAAMirL,EAAWP,GAAa7sL,KAAK,KAAMZ,MAEzCA,KAAK8sL,cAAcvB,sBAAsBhrL,SAAQyrL,IAC7ChsL,KAAKstL,qBAAqBhqE,KAAK0oE,EAAiBgC,GAChDhuL,KAAKklI,aAITllI,KAAK6rC,MAAQshJ,GAGbntL,KAAK4c,SAAWA,GA2DpBywK,GAAYpsL,UAAU4sL,WAAa,WAC3B7tL,KAAK6rC,QAAUshJ,IAAuC,IAAjBntL,KAAKklI,SAG1CllI,KAAKkvC,SAQbm+I,GAAYpsL,UAAUiuC,MAAQ,WAC1BjsC,QAAQqB,IACH,sDACGtE,KAAKywC,QAAQ/uC,UACrB1B,KAAKutL,cAAgB,GAOrB,MAAMU,EAASjuL,KAAKywC,QAGdy9I,EAAiB,GASvB,IANAJ,GAAmBG,GAGnBA,EAAO1tL,SAAQgK,GA6FnB,SAA+BA,EAAOmhL,GAClC,GAAqB,IAAjBnhL,EAAM7I,OACN6I,EAAMrI,KAAKwpL,OACR,CACH,GAAInhL,EAAMA,EAAM7I,OAAS,GAAGiqL,OAASD,EAAKC,MAGtC,YAFAphL,EAAMrI,KAAKwpL,GAKf,IAAK,IAAIlqL,EAAI,EAAGA,EAAI+I,EAAM7I,OAAQF,IAC9B,GAAIkqL,EAAKC,MAAQphL,EAAM/I,GAAGmqL,MAGtB,YAFAphL,EAAM/G,OAAOhC,EAAG,EAAGkqL,GAK3BnhL,EAAMrI,KAAKwpL,IA9GSyC,CAAsBD,EAAgB3jL,KAGvDujL,GAAmBG,IAAS,CAE/B,IAAIG,EAAkBH,EAAO,GAE7BA,EAAO1tL,SAAQypL,IACPA,EAAU,GAAG2B,MAAQyC,EAAgB,GAAGzC,QACxCyC,EAAkBpE,MAK1B,IAAIqE,EAAYD,EAAgBjhJ,QAMhC,IAJAntC,KAAKsuL,oBAAoBD,EAAWD,EAAgB5hL,MAI7C4hL,EAAgB1sL,OAAS,GAAG,CAC/B,IAAI6sL,GAAe,EACnB,MAAMC,EAAgBJ,EAAgB,GAAGzC,MASzC,GAPAsC,EAAO1tL,SAAQypL,IACPA,EAAU,GAAG2B,MAAQ6C,IACrBD,GAAe,MAKnBA,EACA,MAGJF,EAAYD,EAAgBjhJ,QAC5BntC,KAAKsuL,oBAAoBD,EAAW,OAM5CruL,KAAK6rC,MAAQuhJ,GACTptL,KAAK4c,UACL5c,KAAK4c,SAAS5c,KAAKutL,gBAU3BF,GAAYpsL,UAAUqtL,oBAAsB,SAAS5C,EAAMl/K,GACnDA,MAAAA,IACAxM,KAAKutL,eAAkB,KAAI/gL,KAC3BxM,KAAKwtL,WAAahhL,EAAK9K,OAAS,GAEhC1B,KAAKwtL,WAAa9B,EAAKA,KAAKhqL,OA/OJ,KAgPxB1B,KAAKutL,eAAiB,SACtBvtL,KAAKwtL,WAAa,GAEtBxtL,KAAKutL,eAAkB,IAAG7B,EAAKA,OAC/B1rL,KAAKwtL,YAAc9B,EAAKA,KAAKhqL,OAAS,GAwD1C2rL,GAAYpsL,UAAU2yI,SAAW,SAASz7D,GACtCn4E,KAAK8sL,cAAcl5C,SAASz7D,IAOhCk1G,GAAYpsL,UAAUmzJ,YAAc,SAASj8E,GACzCn4E,KAAK8sL,cAAc14B,YAAYj8E,IAQnCk1G,GAAYpsL,UAAUwtL,iBAAmB,WACrC,GAAIzuL,KAAK6rC,QAAUuhJ,GACf,MAAM,IAAIppL,MACL,qGAEGhE,KAAK6rC,gBAGjB,OAAO7rC,KAAKutL,eAMhBF,GAAYpsL,UAAU8rI,SAAW,WAC7B,OAAO/sI,KAAK6rC,OAOhBwhJ,GAAYpsL,UAAU+5C,MAAQ,WAC1Bh7C,KAAK6rC,MAAQohJ,GACbjtL,KAAKklI,QAAU,KACfllI,KAAKutL,cAAgB,KACrBvtL,KAAKw0F,UAAY,KACjBx0F,KAAK4c,SAAW,KAChB5c,KAAKywC,QAAU,GACfzwC,KAAKwtL,WAAa,GAGtB,YCpWMjpL,GAASi1B,EAAAA,IAAAA,mDAUA,SAASk1J,GAAmBhwF,GAEvC1+F,KAAK8+D,SAAW,GAEhB9+D,KAAK0+F,WAAaA,EAClB1+F,KAAK0+F,WAAWiwF,mBACZ,WAAY3uL,KAAK4uL,gBAAgBhuL,KAAKZ,OClBvC,IAAK6uL,GAkBAC,GA4BAC,GDzBZL,GAAmBztL,UAAU2tL,gBACvB,SAAS9vH,EAAUkwH,EAAan6D,GAC9B,IAAK70H,KAAK0+F,WAAWsyB,QAAQ6D,GAKzB,YAJAtwH,GAAO2T,KACF,8CAA6C4mD,IAC9C+1D,GAKR,MAAMvwH,EAAM,GAEZw6D,EAAS3f,SAAS5+C,SAAQwP,IAEtB,MAAMvD,EAAOuD,EAAU8P,WAAWrT,KAC5ByE,EAAUlB,EAAU5I,MAEtBnH,KAAK8+D,SAAStyD,KAAUyE,IACxBjR,KAAK8+D,SAAStyD,GAAQyE,EACtB1M,GAAOiH,KAAM,OAAMgB,cAAiByE,KAEpC3M,EAAIpC,KAAK,CACLmD,GAAI,oBACJ0K,UAAWvD,EACXyE,QAAAA,QAMR3M,EAAI5C,OAAS,GACb+6F,GAAW0D,QAAQ/+F,KAAKF,UAAUoD,KAW9CoqL,GAAmBztL,UAAUguL,oBAAsB,SAASC,GACxD,OAAOlvL,KAAK8+D,SAASowH,aChEbL,GAAAA,EAAAA,iBAAAA,YAAAA,EAAAA,iBAAAA,YAAAA,EAAAA,YAAAA,QAAAA,KAAAA,GAAAA,cAkBAC,GAAAA,EAAAA,SAAAA,KAAAA,EAAAA,UAAAA,MAAAA,EAAAA,cAAAA,UAAAA,EAAAA,eAAAA,WAAAA,EAAAA,aAAAA,UAAAA,KAAAA,GAAAA,cA4BAC,GAAAA,EAAAA,oBAAAA,sBAAAA,EAAAA,qBAAAA,gCAAAA,KAAAA,GAAAA,KAeL,MAAMI,GAAmBN,GAA0BM,iBAC7CC,GAAmBP,GAA0BO,iBAC7CC,GAAcR,GAA0BQ,YAExCC,GAAWR,GAAyBQ,SACpCC,GAAYT,GAAyBS,UACrCC,GAAgBV,GAAyBU,cACzCC,GAAiBX,GAAyBW,eAC1CC,GAAeZ,GAAyBY,aAExCC,GAAsBZ,GAAyBY,oBAC/CC,GAAuBb,GAAyBa,qBCjEvDrrL,IAAS2B,EAAAA,EAAAA,2DAMT2pL,GAAgB,gBAMP,MAAMC,WAA+BngF,GAWhDv2F,YAAY22K,EAAY/jF,EAAa1K,GACjCpc,QAEAllF,KAAK+vL,WAAaA,EAClB/vL,KAAKgsG,YAAcA,EACnBhsG,KAAKshG,SAAWA,EAShBthG,KAAK6rC,WAAQ9/B,EAMjBhJ,OACQ/C,KAAK6rC,QAAUmkJ,IACZhwL,KAAK6rC,QAAUmkJ,GAMtBhwL,KAAKiwL,aAAa,QALd1rL,GAAO2T,KAAK,mDAWpB9V,QAGQpC,KAAK6rC,QAAUmkJ,IACZhwL,KAAK6rC,QAAUmkJ,IACfhwL,KAAK6rC,QAAUmkJ,IACfhwL,KAAK6rC,QAAUmkJ,GAMtBhwL,KAAKiwL,aAAa,SALd1rL,GAAO2T,KAAK,yCAgBpBg4K,SAASnlF,EAAUolF,GACf,GAAIplF,IAAa/qG,KAAK6rC,MAClB,OAGJ,MAAMukJ,EAAWpwL,KAAK6rC,MAEtB7rC,KAAK6rC,MAAQk/D,EACb/qG,KAAKwzF,aAAa37D,KAAKg4J,GACnB,CACItiL,QAASvN,KAAK+vL,WACdI,cAAAA,EACAC,SAAAA,EACArlF,SAAU/qG,KAAK6rC,MACfmgE,YAAahsG,KAAKgsG,cAW9BqkF,iBAAiBvlJ,GACb9qC,KAAK43B,YAAYi4J,GAAe/kJ,GAQpCwlJ,oBAAoBxlJ,GAChB9qC,KAAKmqC,eAAe0lJ,GAAe/kJ,GASvCmlJ,aAAaxoL,GACT,MAAMoY,EAAa,CACf,MAAS,kCACT,OAAUpY,EACV8oL,WAAYvwL,KAAK+vL,YAGrBlwK,EAAW2wK,YAAcxwL,KAAKgsG,YAE9B,MAAM+S,GAAKC,EAAAA,GAAAA,KAAI,CACXC,GAAIj/G,KAAKshG,SAASgtB,YAClB1mH,KAAM,QACLuF,EAAE,QAAS0S,GACXklG,KAELxgH,GAAOynF,MAAO,GAAEvkF,yBAA+Bs3G,EAAG0xE,UAClDzwL,KAAKshG,SAASwB,WAAWugB,OACrBtE,GACA,SACA19G,IACIkD,GAAOlD,MACF,aAAYoG,kCAAwCpG,GACzDrB,KAAKkwL,SAASF,QCxJ9B,MAAMzrL,IAAS2B,EAAAA,EAAAA,+CAUA,MAAMwqL,GAOjBt3K,YAAYkoF,GACRthG,KAAKshG,SAAWA,EAChBthG,KAAKwzF,aAAe8N,EAAS9N,aAC7BjvF,GAAOynF,MAAM,uBACbhsF,KAAKu8I,SAAW,GAEhBv8I,KAAK2wL,2BAA6B3wL,KAAK4wL,oBAAoBhwL,KAAKZ,MAKhEshG,EAASsD,oBAAoB,uBACzB5kG,KAAK6wL,oBAAoBjwL,KAAKZ,OAStC6wL,oBAAoB59K,GAChB,MAAM4M,EAAa5M,EAAK4M,WAExB,IAAKA,EACD,OAGJtb,GAAOynF,MAAM,+BAAgCnsE,GAE7C,MAAMkrF,EAAWlrF,EAAWgsB,MAE5B,GAAIk/D,IAAa/qG,KAAK6rC,MAItB,OAAQk/D,GACR,KAAK+lF,GACL,KAAKA,GACL,KAAKA,GACL,KAAKA,GACL,KAAKA,GAAwB,CACzB,MAAMvjL,EAAUsS,EAAW0wK,WAE3B,IAAKhjL,EACD,OAIJ,MAAM/F,EAAUxH,KAAKu8I,SAAShvI,GAE1B/F,EACAA,EAAQ0oL,SAASnlF,EAAUlrF,EAAWkxK,gBAEtCxsL,GAAO2T,KAAK,kCAAmC3K,KAc3DyjL,wBAAwBjB,EAAY/jF,GAChC,GAAIhsG,KAAKu8I,SAASwzC,GAId,OAHAxrL,GAAO2T,KAAK,uDACR63K,GAEG,IAAI/rL,MAAM8sL,IAGrB,MAAMtpL,EAAU,IAAIsoL,GAChBC,EAAY/jF,EAAahsG,KAAKshG,UAMlC,OAJA95F,EAAQ6oL,iBAAiBrwL,KAAK2wL,4BAE9B3wL,KAAKu8I,SAASwzC,GAAcvoL,EAErBA,EASXopL,oBAAoBt4J,GAChB,MAAM/qB,EAAU+qB,EAAM/qB,QAEtB,GAAI+qB,EAAMyyE,WAAa+lF,IAChBx4J,EAAMyyE,WAAa+lF,GAAwB,CAC9C,MAAMtpL,EAAUxH,KAAKu8I,SAAShvI,GAE9B,IAAK/F,EAID,YAHAjD,GAAOlD,MAAM,6CACTkM,GAKR/F,EAAQ8oL,oBAAoBtwL,KAAK2wL,mCAC1B3wL,KAAKu8I,SAAShvI,GAGzBvN,KAAKwzF,aAAa37D,KACdoF,GAAW,WAAXA,mCACA3E,ICtHZ,MAAM/zB,IAAS2B,EAAAA,EAAAA,iDAEF+qL,GAA+B,aAM7B,MAAMC,WAA2Bp5B,GAI5C1+I,cACI8rE,QAUAllF,KAAKmxL,WAAa,IAAI9qH,IAMtBrmE,KAAKshG,SAAW,KAMhBthG,KAAKoxL,kBAAoB,GAMzBpxL,KAAKqxL,mBAAqB,GAU1BrxL,KAAKsxL,aAAe,IAAIjrH,IAS5BkrH,gCACI,QAAIvxL,KAAKshG,UACEthG,KAAKshG,SAASqZ,uBACjBs2E,GACA,CAAE9pL,MAAO/F,KAAKF,UAAUlB,KAAKoxL,qBAazCI,+BAA+B3nF,GAAY,MACvC,MAAMsnB,EAAQ,UAAGnxH,KAAKshG,gBAAR,aAAG,EAAem0B,gBAAgB5rB,GAEhD,OAAOviB,QAAQ6pC,GAAYA,EAAS9oH,MAAK4K,GAAQA,EAAKiD,UAAY+6K,MAOtEQ,YAAYlwF,GACR,MAAMmwF,EAAc1xL,KAAKshG,SAEzBthG,KAAKshG,SAAWC,EACZmwF,IACAA,EAAY/8D,uBACR,aAAc30H,KAAK2xL,mBACvBD,EAAY/8D,uBACR,aAAc30H,KAAK4xL,mBACvBF,EAAY/8D,uBACR,YAAa30H,KAAK6xL,mBAClBx6D,GAAAA,iCACAr3H,KAAK8xL,oBACEJ,EAAY/8D,uBACXs8D,GAA8BjxL,KAAK8xL,oBAC3C9xL,KAAK+xL,oBACEL,EAAYnlJ,oBACXtP,GAAW,WAAXA,gBAA4Bj9B,KAAK+xL,sBAG7CxwF,IACI81B,GAAAA,gCACAr3H,KAAKgyL,2BAA2BzwF,GAChCvhG,KAAKuxL,kCAKLvxL,KAAK2xL,kBAAoB,CAAC1+K,EAAM4rF,KAC5B7+F,KAAKwzF,aAAa37D,KACdy/H,GACAz4D,EAAM/J,GAAUqH,MAAsB,SAAflpF,EAAK9L,QAEpCo6F,EAAKqD,oBAAoB,aAAc5kG,KAAK2xL,mBAE5C3xL,KAAK4xL,kBAAoB,CAAC3+K,EAAM4rF,KAC5B7+F,KAAKwzF,aAAa37D,KACdy/H,GACAz4D,EAAM/J,GAAU2G,MAAsB,SAAfxoF,EAAK9L,QAEpCo6F,EAAKqD,oBAAoB,aAAc5kG,KAAK4xL,mBAE5C5xL,KAAK6xL,kBAAoB,CAAC5+K,EAAM4rF,KAC5B7+F,KAAKwzF,aAAa37D,KACdy/H,GACAz4D,EAAM5rF,EAAK9L,QAEnBo6F,EAAKqD,oBAAoB,YAAa5kG,KAAK6xL,qBAWvDG,2BAA2BzwF,GACvB,MAAM0wF,EAAsB,CAACpoF,EAAYjK,KACrC5/F,KAAKwzF,aAAa37D,KACdy/H,GACAztD,EACA/U,GAAUqH,MACVyD,IAEFsyF,EAAsB,CAACroF,EAAYjK,KACrC5/F,KAAKwzF,aAAa37D,KACdy/H,GACAztD,EACA/U,GAAU2G,MACVmE,IAIR5/F,KAAK2xL,kBAAoB,CAAC1+K,EAAM4rF,KACvB7+F,KAAKwxL,+BAA+B3yF,IACrCozF,EAAoBpzF,EAAqB,SAAf5rF,EAAK9L,QAGvCo6F,EAAKqD,oBAAoB,aAAc5kG,KAAK2xL,mBAE5C3xL,KAAK4xL,kBAAoB,CAAC3+K,EAAM4rF,KACvB7+F,KAAKwxL,+BAA+B3yF,IACrCqzF,EAAoBrzF,EAAqB,SAAf5rF,EAAK9L,QAGvCo6F,EAAKqD,oBAAoB,aAAc5kG,KAAK4xL,mBAE5C,MAAMO,EAAqB,CAACtoF,EAAYpE,KACpCzlG,KAAKwzF,aAAa37D,KACdy/H,GACAztD,EAAYpE,IAGpBzlG,KAAK6xL,kBAAoB,CAAC5+K,EAAM4rF,KACvB7+F,KAAKwxL,+BAA+B3yF,IACrCszF,EAAmBtzF,EAAM5rF,EAAK9L,QAIjCkwH,GAAAA,+BACD91B,EAAKqD,oBAAoB,YAAa5kG,KAAK6xL,mBAG/C7xL,KAAK8xL,mBAAqB,CAAC7+K,EAAMyiH,KAC7B,MAAM7rB,EAAa6rB,GACb,MAAEvuH,GAAU8L,EACZm/K,EAAiBhxL,KAAKwJ,MAAMzD,GAC5BkrL,EAAqBryL,KAAKwxL,+BAA+B3nF,GACzDyoF,EACAtyL,KAAKqxL,mBAAmBxnF,KAAgB7pG,KAAKqxL,mBAAmBxnF,GAAc,IAEpF,IAAK,MAAMu3B,KAAchhI,OAAOC,KAAK+xL,GAAiB,OAClD,MAAMnvG,EAAY00E,GAA2Bv2B,GACvCmxD,EAAgBjrG,QAAQ8qG,EAAehxD,GAAYxhC,OACnD4yF,EAAiBF,EAAoBlxD,KACnCkxD,EAAoBlxD,GAAc,CAAEA,WAAAA,IAExCoxD,EAAe5yF,QAAU2yF,IACzBC,EAAe5yF,MAAQ2yF,EACnBF,GAAsBpvG,IAAc6R,GAAUqH,MAC9C81F,EAAoBpoF,EAAY0oF,GAEhCL,EAAoBroF,EAAY0oF,IAKxC,MAAME,EAAexvG,IAAc6R,GAAU2G,MAAxB,UACf22F,EAAehxD,GAAY37B,iBADZ,QACyB3oE,GAAU,UAAVA,YACxC/wB,EAEFymL,EAAe/sF,YAAcgtF,IAC7BD,EAAe/sF,UAAYgtF,EAI3BJ,IACQh7D,GAAAA,+BACD86D,EAAmBtoF,EAAY4oF,IAK9C,MAAMC,EAAiBtyL,OAAOC,KAAK+xL,GAEnC,IAAK,MAAMhxD,KAAchhI,OAAOC,KAAKiyL,IACW,IAAxCI,EAAervL,QAAQ+9H,WAChBkxD,EAAoBlxD,IAIvC7/B,EAAKqD,oBAAoB,aAAc5kG,KAAK8xL,oBAG5C9xL,KAAK+xL,mBAAqB5uF,IACtB,MAAM0G,EAAa9H,GAAAA,QAAAA,mBAA2BoB,GAI9C,UAFOnjG,KAAKqxL,mBAAmBxnF,GAE3BwtB,GAAAA,+BACA,IAAK,MAAQnpH,EAAK/G,KAAWnH,KAAKmxL,WAAWhqH,UACrChgE,IAAU0iG,UACH7pG,KAAKsxL,aAAapjL,IAMzCqzF,EAAKl1D,iBAAiBpP,GAAW,WAAXA,gBAA4Bj9B,KAAK+xL,oBAU3DY,oCAAoC9oF,EAAY5mB,GAC5C,MAAM2vG,EAAoB5yL,KAAKqxL,mBAAmBxnF,GAElD,IAAK+oF,EACD,OAAO,KAGX,IAAK,MAAMp3C,KAAcp7I,OAAOkJ,OAAOspL,GAGnC,GAFmBj7B,GAA2Bnc,EAAWpa,cAEtCn+C,EACf,OAAOu4D,EAIf,OAAO,KAMX8J,iBAAiBpgG,EAAO+9B,GACpB,MAAM4vG,EAAyB,KAC3B,GAAI7yL,KAAKshG,SACL,OAAOthG,KAAKshG,SAAS8zB,qBAAqBlwE,EAAO+9B,GAErD1+E,GAAOlD,MAAM,mDAGjB,GAAIg2H,GAAAA,+BAA6C,CAC7C,MAAMy7D,EAAe9yL,KAAKshG,SAASm0B,gBAAgBvwE,GAEnD,IAAK4tI,EACD,MAAM,IAAI9uL,MAAO,8CAA6CkhD,KAGlE,IAAKllD,KAAKwxL,+BAA+BtsI,GACrC,OAAO2tI,IAMX,MAAME,EAAY,GACZC,EAAsBhzL,KAAK2yL,oCAAoCztI,EAAO+9B,GAK5E,GAAIA,IAAc6R,GAAUqH,MACxB42F,EAAUnzF,OAAQozF,GAAsBA,EAAoBpzF,UACzD,IAAI3c,IAAc6R,GAAU2G,MAU/B,MAAM,IAAIz3F,MAAO,2BAA0Bi/E,KAVL,CACtC8vG,EAAUnzF,OAAQozF,GAAsBA,EAAoBpzF,MAC5DmzF,EAAUttF,UAAYutF,EAAsBA,EAAoBvtF,eAAY15F,EAE5E,MAAMupH,EAAgBzH,GAA2BilE,EAAc,+BAE3Dx9D,EAAc5zH,OAAS,IACvBqxL,EAAUv9D,UAAYF,EAAc,GAAGnuH,QAM/C,OAAO4rL,EAGX,OAAOF,IAMX76B,kBAAkB9yG,EAAOk8E,GACrB,OAAOphI,KAAKqxL,mBAAmBnsI,GAASllD,KAAKqxL,mBAAmBnsI,GAAOk8E,QAAcr1H,EAMzFgsJ,aAAanxJ,GACT,OAAO5G,KAAKmxL,WAAWnsK,IAAIpe,GAS/BosI,aAAapsI,EAAMijG,GACf,GAAoB,iBAATjjG,EACP,MAAM,IAAImkC,UAAW,QAAOnkC,uBAKhC,MAAMqsL,EAAgBjzL,KAAKmxL,WAAWnsK,IAAIpe,GAEtCqsL,GAAiBA,IAAkBppF,GACnCtlG,GAAOlD,MAAO,+BAA8B4xL,QAAoBppF,KAEpE7pG,KAAKmxL,WAAWjsK,IAAIte,EAAMijG,GAU9BqpF,mBAAmB9xD,EAAYxhC,GAO3B,OANK5/F,KAAKoxL,kBAAkBhwD,KACxBphI,KAAKoxL,kBAAkBhwD,GAAc,IAGzCphI,KAAKoxL,kBAAkBhwD,GAAYxhC,MAAQA,IAEvC5/F,KAAKshG,UAIEthG,KAAKuxL,gCAYpB4B,kBAAkB/xD,EAAY37B,GAK1B,OAJKzlG,KAAKoxL,kBAAkBhwD,KACxBphI,KAAKoxL,kBAAkBhwD,GAAc,IAGrCphI,KAAKoxL,kBAAkBhwD,GAAY37B,YAAcA,IAEjDzlG,KAAKoxL,kBAAkBhwD,GAAY37B,UAAYA,IAAc3oE,GAAU,UAAVA,YAAmB/wB,EAAY05F,EAKrFzlG,KAAKuxL,iCASpBt5B,mBAAmBrxJ,GACf,OAAO5G,KAAKsxL,aAAatsK,IAAIpe,GASjCqsI,mBAAmBrsI,EAAMw6H,GACrB,GAAoB,iBAATx6H,EACP,MAAM,IAAImkC,UAAW,QAAOnkC,uBAKhC,MAAMwsL,EAAepzL,KAAKsxL,aAAatsK,IAAIpe,GAEvCwsL,GAAgBA,IAAiBhyD,GACjC78H,GAAOlD,MAAO,QAAOuF,kCAAqCwsL,QAAmBhyD,KAGjFphI,KAAKsxL,aAAapsK,IAAIte,EAAMw6H,IC/XpC,MAAM78H,IAAS2B,EAAAA,EAAAA,iCA+CA,SAASmtL,GAAgBtzL,GAAS,MAC7C,IAAKA,EAAQyM,MAAQzM,EAAQyM,KAAK2qB,gBAAkBp3B,EAAQyM,KAAK0U,WAAY,CACzE,MAAMo+F,EACA,8GAIN,MADA/6G,GAAOlD,MAAMi+G,GACP,IAAIt7G,MAAMs7G,GAKpB,GAHAt/G,KAAK8iG,WAAa/iG,EAAQ+iG,WAC1B9iG,KAAK08F,KAAL,UAAY18F,KAAK8iG,kBAAjB,aAAY,EAAiBpG,KAEzB18F,KAAK08F,KAAKi6B,cAAc52H,EAAQyM,KAAMzM,EAAQooH,cAAe,CAC7D,MAAM7I,EAAS,4DAKf,aAHOt/G,KAAK8iG,kBACL9iG,KAAK08F,KACZn4F,GAAOlD,MAAMi+G,GACP,IAAIt7G,MAAMs7G,GAEpBt/G,KAAKwzF,aAAe,IAAI7pD,MACxB3pC,KAAKD,QAAUA,EACfC,KAAKszL,aAAe,IAAIxyF,GAA4B9gG,MACpDA,KAAKwqG,aAAe,GAOpBxqG,KAAKysI,gBAAkB,IAAIykD,GAE3BlxL,KAAK2zG,MAAM5zG,GACXC,KAAKuzL,mBAAqB,IAAI7E,GAAmB1uL,MAMjDA,KAAKihG,iBAAmB,KACxBjhG,KAAKslG,oBAAsB,KAC3BtlG,KAAKwzL,YAAc,KACnBxzL,KAAKyzL,sBAAuB,EAC5BzzL,KAAKqkG,aAAc,EACnBrkG,KAAK8kG,iBAAkB,EACvB9kG,KAAK+kG,iBAAkB,EACvB/kG,KAAKilG,iBAAmB,CACpBnM,OAAO,EACPlY,OAAO,GAEX5gF,KAAKsiG,gBAAiB,EAGtBtiG,KAAKoiG,kBAAoB,KAEzBpiG,KAAKyiG,qBAAsB,EAG3BziG,KAAKuiG,uBAAyB,KAM9BviG,KAAK0zL,YAAa,EAGlB1zL,KAAK2qF,WAAa,GAOlB3qF,KAAKyzK,kBACC,IAAIF,GAAkBvzK,KAAMA,KAAKwzF,aAAczzF,GAMrDC,KAAK+iL,oBACC,IAAIsB,GAAoBrkL,KAAMD,EAAQ0N,OAAOkmL,cAAgB,IAM9D5zL,EAAQ0N,OAAO4vF,qBAChBr9F,KAAK4zL,4BAA8B,IAAI9R,GAA2B9hL,OAMtEA,KAAK2iG,4BAA6B,EAKlC3iG,KAAK6zL,sBAAwB,IAAI7K,GAAsBhpL,MAUvDA,KAAK8zL,qBAAuB,KAE5B,MAAMp8H,EACAjvD,SAAS1I,EAAQ0N,OAAO4sF,KAAOt6F,EAAQ0N,OAAO4sF,IAAI05F,eAAgB,IAOxE/zL,KAAK+zL,eAAiBrqJ,MAAMguB,GAAS,EAAIA,EACzCnzD,GAAOiH,KAAM,mBAAkBxL,KAAK+zL,kBAQpC/zL,KAAKg0L,4BAA6B,EAQlCh0L,KAAKq6F,KAAM,EAMXr6F,KAAKghG,iBAAmB,KAExBhhG,KAAKi0L,kBAAoB,IAAIvD,GAAW1wL,KAAKuhG,MAC7CvhG,KAAKk0L,iBAAmB,IjB/P5B,MAQI96K,YAAYkoF,GAIRthG,KAAKm0L,UAAY,GAEjBn0L,KAAKo0L,UAAY9yF,EAEjBthG,KAAKuwH,WAAavwH,KAAKuwH,WAAW3vH,KAAKZ,MAEvCA,KAAKo0L,UAAU5gG,aAAa57D,YACxBqF,GAAW,WAAXA,kBAA8Bj9B,KAAKuwH,YAS3C8jE,WAAWtU,GACP,OAAO//K,KAAKm0L,UAAUpU,GAe1BxvD,WAAW,GAAgC,IAAhC,iBAAEW,EAAF,SAAoBC,GAAY,EACnCywD,GAAkBnB,YAAYtvD,GAC9BnxH,KAAKs0L,qBAAqBnjE,GACnBD,GACPlxH,KAAKu0L,qBAAqBpjE,GAoBlCqjE,eAAez0L,GACX,MAAMyH,EAAU,IAAIk5K,GAAa,IAC1B3gL,EACH+iG,WAAY9iG,KAAKo0L,UAAUtxF,aAG/B,OAAOt7F,EAAQpF,MAAM,CACjBq/K,QAAS1hL,EAAQ0hL,QACjBC,YAAa3hL,EAAQ2hL,YACrBpzD,YAAatuH,KAAKo0L,UAAU9lE,YAC5B0L,SAAUj6H,EAAQi6H,WAEjBp5E,MAAK,KAKG5gD,KAAKq0L,WAAW7sL,EAAQs5K,WACzB9gL,KAAKy0L,YAAYjtL,GACjBxH,KAAK00L,mBAAmBltL,IAGrBA,KAEVw8C,OAAM3iD,IACHrB,KAAK00L,mBAAmBltL,GAEjBuiC,QAAQE,OAAO5oC,MAYlCszL,cAAc5U,GACV,MAAMv4K,EAAUxH,KAAKq0L,WAAWtU,GAEhC,OAAIv4K,EACOA,EAAQzE,KAAK,CAAEurH,YAAatuH,KAAKo0L,UAAU9lE,cAG/CvkF,QAAQE,OAAO,IAAIjmC,MAAM,2BASpCywL,YAAYjtL,GACRxH,KAAKm0L,UAAU3sL,EAAQs5K,SAAWt5K,EAYtCotL,eAAe7U,EAAW9wF,EAAQ83D,GAC9B,MAAMv/I,EAAU,IAAIk5K,GAAa,CAC7B59E,WAAY9iG,KAAKo0L,UAAUtxF,WAC3BwrB,YAAatuH,KAAKo0L,UAAU9lE,YAC5By4B,KAAAA,EACAg5B,UAAAA,EACA9wF,OAAAA,IAKJ,OAFAjvF,KAAKy0L,YAAYjtL,GAEVA,EASXktL,mBAAmBltL,EAAS2oI,GACxBnwI,KAAKo0L,UAAU5gG,aAAa37D,KACxBoF,GAAW,WAAXA,uBAAmCz1B,EAAS2oI,GAUpDmkD,qBAAqBnjE,GACjB,MAAM0uD,EAAc+B,GAAkBhC,wBAAwBzuD,GAE9D,IAAK0uD,EACD,OAGJ,MAAM,MAAEx+K,EAAF,UAAS8uI,EAAT,cAAoB2vC,EAApB,UAAmCC,EAAnC,OAA8C9wF,GAAW4wF,EAI/D,IAAIr4K,EAAUxH,KAAKq0L,WAAWtU,GAKzBv4K,GAAsB,QAAXynF,EAaZznF,GACGA,EAAQ67F,cAAgBpU,GACxBznF,EAAQ28F,aAAe9iG,EAC1BkD,GAAO2T,KAAK,uCACR9W,KAAKF,UAAU2+K,KAKlBr4K,IACDA,EAAUxH,KAAK40L,eAAe7U,EAAW9wF,EAAQ6wF,IAGrDt4K,EAAQq5K,UAAU5xF,GAEd5tF,GACAmG,EAAQ+5K,SAASlgL,GAGrBrB,KAAK00L,mBAAmBltL,EAAS2oI,IA/B7B5rI,GAAO2T,KACH,qCACA,2CAuCZq8K,qBAAqBpjE,GACjB,MAAM,kBAAE+uD,EAAF,KAAqBn5B,EAArB,UAA2Bg5B,GAC3B6B,GAAkB5B,sBAAsB7uD,GAE9C,IAAK4uD,EAID,YAHAx7K,GAAO2T,KACH,2DAKR,IAAI1Q,EAAUxH,KAAKq0L,WAAWtU,GAEzBv4K,IACDA,EAAUxH,KAAK40L,eAAe7U,EAAW,GAAIh5B,IAGjDv/I,EAAQg6K,qBAAqBtB,GAE7BlgL,KAAK00L,mBAAmBltL,KiBUiBxH,KAAKuhG,MAQlDvhG,KAAK60L,uCAAoC9oL,EAKrC/L,KAAK80L,oBACLvwL,GAAOiH,KAAK,sCAEZxL,KAAK+0L,eAAiB,IAAIj8E,GAAc94G,OAQ5CA,KAAKg1L,8BAA2BjpL,EAOhC/L,KAAKi1L,8BAA2BlpL,ECxRrB,SAASmpL,GAAgBC,EAAOp3I,EAAOh+C,GAClDC,KAAKm1L,MAAQA,EACbn1L,KAAK+9C,MAAQA,EACb/9C,KAAKD,QAAUA,EACfC,KAAK08F,KAAO,IAAIsxB,GAAKjuH,EAASg+C,GAG9B/9C,KAAKqsC,iBAAiB0iE,IAClB,CAACqmF,EAAS7zL,EAAKo/I,EAAab,KACxBrjD,GAAWkE,oBhIqOoB,EAAE00F,EAAoBC,EAAuBx1C,KAA7C,CACvCl4I,KAAMq5E,GAAgBC,iBACtBz5E,OAAQ,oBACRoY,WAAY,CACR,WAAcw1K,EACd,cAAiBC,KACdx1C,KgI1OKy1C,CAA4BH,EAAS7zL,EAAKu+I,OAItD9/I,KAAKqsC,iBAAiB0iE,IAClBxtG,IAMQA,GACAk7F,GAAWoE,cACP20F,GACA,CAAEx6K,QAASzZ,IAEnBk7F,GAAW0D,QACP/+F,KAAKF,UACD,CACImE,GAAImwL,GACJj0L,IAAAA,QC7CjB,IAAKk0L,GF2SZpC,GAAgBpyL,UAAUmY,YAAci6K,GAcxCA,GAAgBqC,gBAAkB,SAASvyF,EAAKwyF,GAC5C,IAAIhzC,EAEJ,GAAIgzC,EAEAhzC,EAAc1pH,KAAAA,gBAA2B,GAAG9B,kBACzC,OAIHwrH,EAAW,UAAG5gD,GAAAA,QAAAA,eAAuBoB,UAA1B,aAAG,EAA6B9+F,OAAO,EAAG,GAChD8yB,cAIL,MAAMy+J,EAAK,eAENjzC,GAAgBizC,EAAGrmL,KAAKozI,KACzBA,EAAc1pH,KAAAA,gBAA2B,GAAG9B,eAIpD,OAAOwrH,GAQX0wC,GAAgBpyL,UAAU0yG,MAAQ,WAAuB,IAAd5zG,EAAc,uDAAJ,GACjDC,KAAKszL,aAAa3tF,qBAElB,MAAM,OAAEl4F,GAAWzN,KAAKD,QAKlB81L,EAAgB,CAClBtxC,cAAe92I,EAAO8hI,aAChB9hI,EAAO8hI,aAAagV,cACpB92I,EAAO4sF,KAAO5sF,EAAO4sF,IAAIy1C,aAAehR,GAAAA,KAC9ComB,sBAAuBz3I,EAAO8hI,cAAgB9hI,EAAO8hI,aAAa2V,sBAClET,SAAWh3I,EAAO8hI,cAAgB9hI,EAAO8hI,aAAaQ,gBAC9CtiI,EAAOoiI,YAAc/Q,GAAAA,KAC7B4lB,SAAUj3I,EAAO4sF,IACX5sF,EAAO4sF,IAAI01C,gBAAmBtiI,EAAO4sF,IAAIw1C,YAAc/Q,GAAAA,KACvDA,GAAAA,KAGV9+H,KAAK81L,eAAiB,IAAIxxC,GAAetkJ,KAAM61L,GAC/C71L,KAAK+1L,gBAAkBtoL,EAAOuoL,aAAevoL,EAAOuoL,aAAe3rE,GAASX,kBAC5E1pH,KAAKuhG,KAAOvhG,KAAK08F,KAAK0rB,WAClBpoH,KAAKD,QAAQyM,KAAM,IACZiB,EACH0hH,QAASnvH,KAAK+1L,iBAElB1C,GAAgBqC,iBAGpB11L,KAAKysI,gBAAgBglD,YAAYzxL,KAAKuhG,MAGtCvhG,KAAKi2L,4BACCj2L,KAAKi2L,4BAA4Br1L,KAAKZ,MAC5CA,KAAKuhG,KAAK3pE,YACNqF,GAAW,WAAXA,uBAAmCj9B,KAAKi2L,6BAE5Cj2L,KAAKk2L,yBAA2Bl2L,KAAKk2L,yBAAyBt1L,KAAKZ,MACnEA,KAAKuhG,KAAK3pE,YACNqF,GAAW,WAAXA,oBAAgCj9B,KAAKk2L,0BAEzCl2L,KAAKm2L,4BACCn2L,KAAKm2L,4BAA4Bv1L,KAAKZ,MAC5CA,KAAKuhG,KAAK3pE,YACNqF,GAAW,WAAXA,uBAAmCj9B,KAAKm2L,6BAE5Cn2L,KAAKo2L,kBAAoBp2L,KAAKo2L,kBAAkBx1L,KAAKZ,MACrDA,KAAKuhG,KAAK3pE,YAAYqF,GAAW,WAAXA,8BAClBj9B,KAAKo2L,mBAETp2L,KAAKq2L,kCAAoCr2L,KAAKq2L,kCAAkCz1L,KAAKZ,MACrFA,KAAKuhG,KAAK3pE,YAAYqF,GAAW,WAAXA,eAA2Bj9B,KAAKq2L,mCAEtDr2L,KAAKs2L,2BAA6Bt2L,KAAKs2L,2BAA2B11L,KAAKZ,MACvEA,KAAKu2L,oBAAsBv2L,KAAKu2L,oBAAoB31L,KAAKZ,MACzDA,KAAKuhG,KAAK3pE,YAAYqF,GAAW,WAAXA,eAA2Bj9B,KAAKu2L,qBACtDv2L,KAAKuhG,KAAK3pE,YAAYqF,GAAW,WAAXA,WAAuBj9B,KAAKu2L,qBAClDv2L,KAAKuhG,KAAK3pE,YAAYqF,GAAW,WAAXA,iBAA6Bj9B,KAAKs2L,4BACxDt2L,KAAKuhG,KAAK3pE,YAAYqF,GAAW,WAAXA,cAA0Bj9B,KAAKu2L,qBAErDv2L,KAAK+7K,QAAU,IAAIe,GACf98K,KACAyN,GACA,CAACuN,EAASikG,KACN,IACIj/G,KAAKi3G,YACDj8F,EAASikG,GAAI,GACnB,MAAO59G,GACLkD,GAAO2T,KAAK,+CAAgD7W,GAASA,EAAME,SAIlFvB,KAAK0hG,MACN1hG,KAAK0hG,IAAM,IAAIqmE,GAAI/nK,KAAMD,GACzBC,KAAKszL,aAAapuF,oBACdmyB,GAAAA,gCACAr3H,KAAKw2L,sBAAsBx2L,KAAK0hG,MAIxC1hG,KAAKy2L,uBAAyB,IAAIvY,GAAuBl+K,KAAMA,KAAK0hG,KACpE1hG,KAAK02L,oBAAsB,IAAI3X,GAAoB/+K,KAAMA,KAAK0hG,KAE9D1hG,KAAK0rG,4BACC,IAAIlE,GACFxnG,KAAK0hG,IACL1hG,KACA,CAGIioG,kBAAmBx6F,EAAOg0J,6BAC1Bv5D,eAAgBz6F,EAAOi0J,8BACvB15D,kBAAmBv6F,EAAOk0J,mCAEtC3hK,KAAK0rG,4BAA4B9hE,OAGjC,IAAIizD,GAAkB,EAwCtB,GAtCIpvF,EAAO0rG,SAAW1rG,EAAO0rG,QAAQw9E,qBACjC95F,EAAmC,IAAhB5yF,KAAKE,UAAmBsD,EAAO0rG,QAAQw9E,oBAGzD32L,KAAKu/F,aACNv/F,KAAKu/F,WAAa,IAAI9C,GAAWz8F,KAAK08F,KAAM,CACxC3O,UAAW/tF,KAAK+1L,gBAChB/nG,SAAUvgF,EAAOmpL,sBAAwBnpL,EAAOmpL,sBAAwB52L,KAAK6kG,WAC7ExY,OAAQ5+E,EAAO4+E,QAAW,GAAErsF,KAAK8iG,WAAW/iG,QAAQqrH,MAAM1J,UAAU1hH,KAAKD,QAAQyM,OACjF8hF,OAAQ7gF,EAAO6gF,OACf0O,gBAAiBvvF,EAAOopL,yBACxB5oG,YAAaxgF,EAAOwgF,YACpBC,gBAAiBzgF,EAAOygF,gBACxB6O,iCAAkCtvF,EAAOsvF,iCACzCF,gBAAAA,EACAplE,SAAUz3B,KAAKD,QAAQyM,KACvB4hF,gBAAiB3gF,EAAO2gF,gBACxBK,mBAAoBhhF,EAAOghF,mBAC3BN,aAAc1gF,EAAOqpL,wBAEzBr6F,GAAWe,UAAUnT,uBAAuB,CACxC,eAAkBrqF,KAAK+1L,kBAIvBtoL,EAAO8vF,wBACPv9F,KAAKu/F,WAAWd,qBAAqBz+F,OAI7CA,KAAKszL,aAAajyF,yBAIlBrhG,KAAKszL,aAAa5sF,2BAIdj5F,EAAOspL,sBAAwBxxJ,GAAQukD,uBAGvC,GAAIr8E,EAAOisK,mBAAoB,CAC3Bn1K,GAAOiH,KAAK,8DAEPxL,KAAKg3L,iBACNh3L,KAAKg3L,eAAiB,IAAIvd,GAAiBz5K,KAAMyN,EAAOisK,qBAG5D,MAAMud,EAAwB,IAAIzb,GAElCyb,EAAsB1sJ,GAAG0rI,IAAsC,IAC3Dj2K,KAAKwzF,aAAa37D,KAAKqjD,MAE3Bl7E,KAAKg3L,eAAe9c,uBAAuB+c,QAE3C1yL,GAAO2T,KAAK,0FAMpB,GAAIzK,EAAOypL,yBAA2B3xJ,GAAQukD,uBAC1C,GAAIr8E,EAAOisK,mBAAoB,CACtB15K,KAAKg3L,iBACNh3L,KAAKg3L,eAAiB,IAAIvd,GAAiBz5K,KAAMyN,EAAOisK,qBAG5D,MAAMyd,EAAoB,IAAIxc,GAE9Bwc,EAAkB5sJ,GAAG0rI,IAAkC,IACnDj2K,KAAKwzF,aAAa37D,KAAKqjD,MAE3Bl7E,KAAKg3L,eAAe9c,uBAAuBid,QAE3C5yL,GAAO2T,KAAK,0FAKhBzK,EAAO2pL,yBACPp3L,KAAKq3L,wBAA0B,IAAI9gB,GAAuBv2K,MAC1DA,KAAKq3L,wBAAwB9sJ,GAAG0rI,IAAgC,KAC5Dj2K,KAAKwzF,aAAa37D,KAAKqjD,OAE3Bl7E,KAAKq3L,wBAAwB9sJ,GAAG0rI,IAA0CqhB,IACtEt3L,KAAKwzF,aAAa37D,KAAKqjD,EAAgDo8G,OAK3E,iBAAkB7pL,GAClBzN,KAAKgzK,SAASvlK,EAAO4wK,cAOzBr+K,KAAKu3L,aAAe,IAAIla,GAAqBr9K,MAG7CA,KAAKw3L,4BAA8B,IAAIvgB,GAA4Bj3K,MAE/DyN,GAAUA,EAAOoyI,gBAAkBpyI,EAAOoyI,eAAe43C,YACzDz3L,KAAKgyG,4BACD,SAAUvkG,EAAOoyI,eAAe43C,YAIxCz3L,KAAKgyG,4BAA4B,YAAahyG,KAAK81L,eAAetwC,qBAM9D/3I,GAAUA,EAAOiqL,uBAA0D,UAAjCjqL,EAAOiqL,uBACjD13L,KAAKgyG,4BAA4B,yBAA0BvkG,EAAOiqL,wBAU1ErE,GAAgBpyL,UAAUsI,KAAO,SAASsxC,GAAsC,IAA5BozE,EAA4B,wDACxEjuH,KAAKuhG,MACLvhG,KAAKuhG,KAAKh4F,KAAKsxC,EAAUozE,GAAoBrtE,MAAK,IAAM5gD,KAAK23L,wBAYrEtE,GAAgBpyL,UAAU+iJ,2BAA6B,SAASjkJ,GAC5D,OAAOikJ,GAA2Bp/I,KAAK5E,KAAM,IACtCD,EACH0iJ,iBAAkB4wC,GAAgBqC,mBAO1CrC,GAAgBpyL,UAAU22L,SAAW,WACjC,OAAO53L,KAAKuhG,MAAQvhG,KAAKuhG,KAAK0mB,QAOlCorE,GAAgBpyL,UAAU42L,aAAe,WACrC,OAAOvwG,QAAQtnF,KAAKD,QAAQ0N,OAAO4sF,KAAOr6F,KAAKD,QAAQ0N,OAAO4sF,IAAIoM,eAGxB,IAA5BzmG,KAAKD,QAAQ0N,OAAO4sF,KAQtCg5F,GAAgBpyL,UAAU62L,qBAAuB,WAC7C,OAAOxwG,QAAQtnF,KAAKD,QAAQ0N,OAAO0rG,SAC5Bn5G,KAAKD,QAAQ0N,OAAO0rG,QAAQ4+E,cAOvC1E,GAAgBpyL,UAAU8mH,MAAQpuF,iBA8C9B,GA7CI35B,KAAK0rG,8BACL1rG,KAAK0rG,4BAA4BphB,UACjCtqF,KAAK0rG,4BAA8B,MAEnC1rG,KAAK+iL,sBACL/iL,KAAK+iL,oBAAoBz4F,UACzBtqF,KAAK+iL,oBAAsB,MAG3B/iL,KAAK4zL,8BACL5zL,KAAK4zL,4BAA4BtpG,UACjCtqF,KAAK4zL,4BAA8B,MAGnC5zL,KAAK+7K,UACL/7K,KAAK+7K,QAAQh5K,OACb/C,KAAK+7K,QAAU,MAGnB/7K,KAAK47F,iBAAiBr7F,SAAQ43E,GAASn4E,KAAKg4L,oBAAoB7/G,KAEhEn4E,KAAK0hG,IAAIC,qBAET3hG,KAAKi4L,oCAEDj4L,KAAKu/F,YACLv/F,KAAKu/F,WAAWjV,UAGpBtqF,KAAKk4L,mBAAqBl4L,KAAKk4L,kBAAkBjrH,SAEjDjtE,KAAKm4L,8BACLn4L,KAAKo4L,uBAGDp4L,KAAKihG,mBACLjhG,KAAKihG,iBAAiB21C,QACtB52I,KAAKihG,iBAAmB,MAExBjhG,KAAKghG,mBACLhhG,KAAKghG,iBAAiB41C,QACtB52I,KAAKghG,iBAAmB,OAIvBhhG,KAAKuhG,KACN,MAAM,IAAIv9F,MAAM,wCAGpB,MAAMu9F,EAAOvhG,KAAKuhG,KA6BlB,IAAI82F,EA1BJ92F,EAAKp3D,eACDlN,GAAW,WAAXA,uBACAj9B,KAAKi2L,6BACT10F,EAAKp3D,eACDlN,GAAW,WAAXA,oBACAj9B,KAAKk2L,0BACT30F,EAAKp3D,eACDlN,GAAW,WAAXA,uBACAj9B,KAAKm2L,6BAET50F,EAAKp3D,eACDlN,GAAW,WAAXA,8BACAj9B,KAAKo2L,mBAET70F,EAAKp3D,eAAelN,GAAW,WAAXA,eAA2Bj9B,KAAKq2L,mCACpD90F,EAAKp3D,eAAelN,GAAW,WAAXA,eAA2Bj9B,KAAKu2L,qBACpDh1F,EAAKp3D,eAAelN,GAAW,WAAXA,WAAuBj9B,KAAKu2L,qBAChDh1F,EAAKp3D,eAAelN,GAAW,WAAXA,iBAA6Bj9B,KAAKs2L,4BACtD/0F,EAAKp3D,eAAelN,GAAW,WAAXA,cAA0Bj9B,KAAKu2L,qBAEnDv2L,KAAKszL,aAAa5tF,sBAElB1lG,KAAKysI,gBAAgBglD,YAAY,MAEjCzxL,KAAKuhG,KAAO,KAIZ,UACUA,EAAKwmB,QACb,MAAOt/E,GACL4vJ,EAAa5vJ,EAKbzoC,KAAKumG,kBAAkBhmG,SACnBshG,GAAe7hG,KAAK6jG,aAAahC,EAAY2E,YAOrD,GAJIxmG,KAAK0hG,KACL1hG,KAAK0hG,IAAIsvE,UAGTqnB,EACA,MAAMA,GASdhF,GAAgBpyL,UAAUo+K,sBAAwB,WAC9C,OAAOr/K,KAAKwoG,cAAgBxoG,KAAKghG,iBAAmBhhG,KAAKihG,kBAQ7DoyF,GAAgBpyL,UAAUkxG,iBAAmB,WACzC,MAAMoqC,EAAW,GAKjB,OAHAv8I,KAAKihG,kBAAoBs7C,EAASr6I,KAAKlC,KAAKihG,kBAC5CjhG,KAAKghG,kBAAoBu7C,EAASr6I,KAAKlC,KAAKghG,kBAErCu7C,GASX82C,GAAgBpyL,UAAUu1L,sBAAwB,SAAS90F,GACvDA,EAAI9pE,YAAYmD,GAAAA,QAAAA,mBAA6B,KACzC,IAAK,MAAM44G,KAAc3zI,KAAK0hG,IAAI2Q,YAC9BshC,EAAWnuC,gBAAkBxlG,KAAK4zJ,4BAA4BjgB,OAa1E0/C,GAAgBpyL,UAAU2yJ,4BAA8B,SAAS0kC,GAC7D,IAAI7yF,GAAa6yF,GAAcA,EAAWp3F,UAAY6vE,GAAuBunB,EAAW5oC,eAEpFjqD,IAAcsrE,IAA2B/wK,KAAKu4L,yBxE9vBjB,IwE+vB7B9yF,EAAYsrE,IAGZ15C,GAAAA,gCAA+CihE,EAC/Ct4L,KAAK0hG,IAAImwE,oBAAoBymB,EAAWriD,gBAAiBxwC,GACjD4xB,GAAAA,gCACRr3H,KAAK0hG,IAAIkwE,aAAansE,IAO9B4tF,GAAgBpyL,UAAUilF,QAAU,WAChC,OAAOlmF,KAAKD,QAAQyM,KAAK0U,YAM7BmyK,GAAgBpyL,UAAUw/I,cAAgB,WACtC,OAAOzgJ,KAAK8iG,YAMhBuwF,GAAgBpyL,UAAUu3L,cAAgB,WACtC,OAAOx4L,KAAKqkG,aAMhBgvF,GAAgBpyL,UAAUw3L,WAAa,WACnC,OAAOnxG,QAAQtnF,KAAKskG,eAMxB+uF,GAAgBpyL,UAAUy3L,aAAe,WACrC,OAAO14L,KAAKskG,cAMhB+uF,GAAgBpyL,UAAU0pH,sBAAwB,WAC9C,OAAO3qH,KAAKuhG,MAAQvhG,KAAKuhG,KAAKitB,UAAU7D,yBAS5C0oE,GAAgBpyL,UAAU03L,mBAAqB,SAASC,GACpD,OAAO,IAAI7uJ,SAAQ,CAACC,EAASC,KACpBjqC,KAAK2qH,wBAKNiuE,EACA54L,KAAKuhG,KAAKitB,UAAUlB,iBAAiBtjF,EAASC,GAE9CjqC,KAAKuhG,KAAKitB,UAAU1B,YAAY9iF,EAASC,GAPzCA,QAiBZopJ,GAAgBpyL,UAAU26F,eAAiB,SAAS3Y,GAChD,IAAIwkF,EAAS,GAMb,OAJIznK,KAAK0hG,MACL+lE,EAASznK,KAAK0hG,IAAI9F,eAAe3Y,IAG9BwkF,GAOX4rB,GAAgBpyL,UAAUwxK,mBAAqB,WAC3C,OAAOzyK,KAAK0hG,IAAM1hG,KAAK0hG,IAAI+wE,qBAAuB,MAOtD4gB,GAAgBpyL,UAAUi1I,mBAAqB,WAC3C,OAAOl2I,KAAK0hG,IAAM1hG,KAAK0hG,IAAIw0C,qBAAuB,MAOtDm9C,GAAgBpyL,UAAU+0I,oBAAsB,WAC5C,OAAOh2I,KAAK0hG,IAAM1hG,KAAK0hG,IAAIs0C,sBAAwB,MAOvDq9C,GAAgBpyL,UAAU43L,oBAAsB,WAC5C,MAAO,CACHC,eAAgB94L,KAAKu/F,WAAW1L,sBAaxCw/F,GAAgBpyL,UAAUspC,GAAK,SAASwuJ,EAAS1gK,GACzCr4B,KAAKwzF,cACLxzF,KAAKwzF,aAAajpD,GAAGwuJ,EAAS1gK,IAYtCg7J,GAAgBpyL,UAAUosC,IAAM,SAAS0rJ,EAAS1gK,GAC1Cr4B,KAAKwzF,cACLxzF,KAAKwzF,aAAarpD,eAAe4uJ,EAAS1gK,IAKlDg7J,GAAgBpyL,UAAUorC,iBAAmBgnJ,GAAgBpyL,UAAUspC,GACvE8oJ,GAAgBpyL,UAAUsrC,oBAAsB8mJ,GAAgBpyL,UAAUosC,IAQ1EgmJ,GAAgBpyL,UAAU0tL,mBAAqB,SAASqK,EAAS3gK,GACzDr4B,KAAKuhG,MACLvhG,KAAKuhG,KAAKqD,oBAAoBo0F,EAAS3gK,IAS/Cg7J,GAAgBpyL,UAAUg4L,sBAAwB,SAASD,EAAS3gK,GAC5Dr4B,KAAKuhG,MACLvhG,KAAKuhG,KAAKozB,uBAAuBqkE,EAAS3gK,IAUlDg7J,GAAgBpyL,UAAUi4L,gBAAkB,SAASl+K,GAA+B,IAAtBu3G,EAAsB,uDAAR,OACpEvyH,KAAKuhG,MACLvhG,KAAKuhG,KAAK0V,YAAYj8F,EAASu3G,IAWvC8gE,GAAgBpyL,UAAUk4L,uBAAyB,SAAS9zL,EAAI2V,GAA+B,IAAtBu3G,EAAsB,uDAAR,OAC/EvyH,KAAKuhG,MACLvhG,KAAKuhG,KAAKmmB,mBAAmBriH,EAAI2V,EAASu3G,IASlD8gE,GAAgBpyL,UAAUm4L,YAAc,SAAS5sL,EAAMlD,GAC/CtJ,KAAKuhG,KACLvhG,KAAKuhG,KAAKoZ,uBAAuBnuG,EAAMlD,IAAWtJ,KAAKuhG,KAAKkZ,eAE5Dl2G,GAAO2T,KAAK,iDAUpBm7K,GAAgBpyL,UAAUo4L,gBAAkB,SAAS7sL,EAAMlD,GACvDtJ,KAAKo5L,YAAY5sL,EAAMlD,GACvBtJ,KAAKs5L,cAAc9sL,IAOvB6mL,GAAgBpyL,UAAUq4L,cAAgB,SAAS9sL,GAC3CxM,KAAKuhG,MACLvhG,KAAKuhG,KAAKmZ,mBAAmBluG,IAQrC6mL,GAAgBpyL,UAAUomL,eAAiB,SAAS76K,GAChD,GAAIxM,KAAKuhG,KAAM,CACX,MAAMg4F,EAAU,OAGhB,IAAK/sL,IAASxM,KAAKuhG,KAAKmzB,gBAAgB6kE,GACpC,OAGJv5L,KAAKuhG,KAAKoZ,uBAAuB4+E,EAAS,CACtC15K,WAAY,CAAEzL,MAAO,mCACrBjN,MAAOqF,KACLxM,KAAKuhG,KAAKkZ,iBAQxB44E,GAAgBpyL,UAAUuxH,WAAa,SAASrM,GACxCnmH,KAAKuhG,MAAQvhG,KAAKgkG,cAClBhkG,KAAKuhG,KAAKixB,WAAWrM,GAErB5hH,GAAO2T,KAAM,0BAAyBlY,KAAKuhG,KAAO,GAAK,oBACnDvhG,KAAKgkG,cAAgB,GAAK,qCAQtCqvF,GAAgBpyL,UAAUu4L,eAAiB,WACvC,QAAyBztL,IAArB/L,KAAK0tL,YAA2B,CAChC1tL,KAAK0tL,YAAc,IAAIL,GAGvB,MAAMoM,EAAmBz5L,KAAK47F,eAAe9G,GAAUqH,OAEvD,IAAK,MAAMu2E,KAAc+mB,EACrBz5L,KAAK0tL,YAAY95C,SAAS8+B,GAI9B,MAAMO,EAAoBjzK,KAAK0hG,IAAI0lE,gBAAgBtyE,GAAUqH,OAE7D,IAAK,MAAMkO,KAAe4oE,EACtBjzK,KAAK0tL,YAAY95C,SAASvpC,GAIlC,OAAOrqG,KAAK0tL,aAQhB2F,GAAgBpyL,UAAUy4L,uBAAyB,WAC/C,OAAO15L,KAAKuhG,KAAK0tB,qBAUrBokE,GAAgBpyL,UAAU2yI,SAAW,SAASz7D,GAC1C,MAAM8K,EAAY9K,EAAMgpB,UAClBkR,EAAcryG,KAAK0hG,IAAI9F,eAAe3Y,GAG5C,GAAIovB,EAAY3wG,OAAS,EAAG,CAExB,GAAIy2E,IAAUk6B,EAAY,GACtB,OAAOtoE,QAAQC,QAAQmuC,GAG3B,GAAIk/C,GAAAA,+BAA8Cp0C,IAAc6R,GAAU2G,MAAO,CAC7E,MAAMk+F,EAAmB,GAKzB,OAHA35L,KAAKghG,kBAAoB24F,EAAiBz3L,KAAKlC,KAAKghG,iBAAiB4yC,SAASz7D,IAC9En4E,KAAKihG,kBAAoB04F,EAAiBz3L,KAAKlC,KAAKihG,iBAAiB2yC,SAASz7D,IAEvEpuC,QAAQ8pG,IAAI8lD,GACd/4I,MAAK,KACF5gD,KAAK45L,eAAezhH,IAGhBn4E,KAAKsiG,gBAAkBtiG,KAAKyiG,sBAC5BziG,KAAK65L,qBAAqB1hH,MAK1C,OAAOpuC,QAAQE,OAAO,IAAIjmC,MAAO,qBAAoBi/E,8BAGzD,OAAOjjF,KAAK24I,aAAa,KAAMxgE,IAQnCk7G,GAAgBpyL,UAAU64L,2BAA6B,SAASvoG,EAAYpC,GACxE,MAAM4qG,EAAY/5L,KAAK60K,0BAOlB1lF,GAAO4qG,IAAc5qG,GACtBnvF,KAAKwzF,aAAa37D,KACdqjD,GACAl7E,KAAK6kG,WAAYtT,IAQ7B8hG,GAAgBpyL,UAAU44L,qBAAuB,SAAS1hH,GActD,IAAImuB,EAEJ,GAdItmG,KAAKsiG,gBAAkBnqB,EAAMogB,iBAAmBpgB,EAAM+oB,WACtDlhG,KAAKsiG,gBAAiB,EAGtBtiG,KAAKuhG,KAAK60B,gBAAgBp2H,KAAKuhG,KAAKqmB,WAAW,EAAO9yB,GAAUqH,QACzDn8F,KAAKyiG,qBAAuBtqB,EAAMqtB,iBAAmBrtB,EAAM+oB,YAClElhG,KAAKyiG,qBAAsB,EAG3BziG,KAAKuhG,KAAK60B,gBAAgBp2H,KAAKuhG,KAAKqmB,WAAW,EAAO9yB,GAAU2G,QAKhEz7F,KAAKoiG,mBAAqBjqB,EAAMogB,eAAgB,CAChD,MAAMyhG,EAAUj4F,GAAAA,QAAAA,mBAA2B/hG,KAAKoiG,mBAEhDkE,EAAmBtmG,KAAKwqG,aAAawvF,QAClC,GAAIh6L,KAAKuiG,wBAA0BpqB,EAAMqtB,eAAgB,CAC5D,MAAMw0F,EAAUj4F,GAAAA,QAAAA,mBAA2B/hG,KAAKuiG,wBAEhD+D,EAAmBtmG,KAAKwqG,aAAawvF,GAKrC7hH,EAAMqtB,iBAAmBjgE,GAAQ0hD,+BACjCjnF,KAAK4zJ,4BAA4Bz7E,GAGrCn4E,KAAKwzF,aAAa37D,KAAKqjD,GAA0C/C,EAAOmuB,IAU5E+sF,GAAgBpyL,UAAUg5L,uBAAyB,WAK/C,OAAOj6L,KAAK47F,iBACP70F,QAAOoxE,IACJ,MAAM+hH,EAAY/hH,EAAMgpB,UAExB,QAAI+4F,IAAcplG,GAAUqH,OACfn8F,KAAKm6L,sBAAuB50J,GAAQ4hD,kBAAmB5hD,GAAQmhD,kBAEjEwzG,IAAcplG,GAAU2G,QAAUz7F,KAAKo6L,wBAY9D/G,GAAgBpyL,UAAU+2L,oBAAsB,SAAS7/G,GACrDA,EAAMu8E,cAAc,MACpB10J,KAAK0hG,IAAImxE,iBAAiB16F,GAC1BA,EAAM5rC,oBAAoB60D,GAAqCjpB,EAAMkiH,aACjEliH,EAAMogB,gBACNpgB,EAAM5rC,oBAAoB60D,GAA4CjpB,EAAMmiH,mBAM5EniH,EAAMqtB,gBAAkBrtB,EAAMstB,YAAc3oE,GAAU,UAAVA,SAC5C98B,KAAKu/F,WAAW1O,wBAAuB,GAG3C7wF,KAAKwzF,aAAa37D,KAAKqjD,GAAqC/C,IAShEk7G,GAAgBpyL,UAAUmzJ,YAAc,SAASj8E,GAC7C,OAAOn4E,KAAK24I,aAAaxgE,EAAO,OAYpCk7G,GAAgBpyL,UAAU03I,aAAe,SAASC,EAAUC,GACxD,MAAM0hD,EAAe3hD,MAAAA,OAAH,EAAGA,EAAU8W,eACzB+iC,EAAe55C,MAAAA,OAAH,EAAGA,EAAU6W,eAE/B,GAAIr4B,GAAAA,+BAA8CuhB,GAAYC,GAAY0hD,IAAiB9H,EACvF,MAAM,IAAIzuL,MAAO,kCAAiCu2L,+BAA0C9H,oCAGhG,MAAM+H,EAA8Bx6L,QAAS44I,MAAAA,OAAT,EAASA,EAAUl6C,YAEvD,OAAI87F,GAA+B5hD,EAAS3uD,UAGxC4uD,MAAAA,GAAAA,EAAU5uD,SAFHlgD,QAAQE,OAAO,IAAIq2C,GAAgBd,MAM1Co5D,IAAa4hD,GACbj2L,GAAO2T,KAAM,0CAAyC0gI,wCAInD54I,KAAKy6L,gBAAgBD,EAA8B5hD,EAAW,KAAMC,GACtEj4F,MAAK,KACF45I,GAA+Bx6L,KAAKg4L,oBAAoBp/C,GACxDC,GAAY74I,KAAK45L,eAAe/gD,IAG3B2hD,GAAAA,MAA+B5hD,GAAAA,EAAUpzC,gBAAmBqzC,MAAAA,GAAAA,EAAUrzC,iBACvExlG,KAAK4zJ,4BAA4B/a,GAIjC2hD,GAAAA,MAA+B5hD,GAAAA,EAAUpzC,kBAGpCozC,MAAAA,GAAAA,EAAUkY,sBAAwBjY,MAAAA,GAAAA,EAAUiY,uBACjD9wJ,KAAKu2L,oBAAoBv2L,KAAKq/K,yBAGjB,OAAbxmC,IAAsB74I,KAAKsiG,gBAAkBtiG,KAAKyiG,sBAClDziG,KAAK65L,qBAAqBhhD,GAGvB9uG,QAAQC,aAElBga,OAAM3iD,IACHkD,GAAOlD,MAAO,wBAAuBA,MAAAA,OAAxB,EAAwBA,EAAO4C,SAErC8lC,QAAQE,OAAO5oC,QAgBlCgyL,GAAgBpyL,UAAUw5L,gBAAkB,SAAS7hD,EAAUC,GAC3D,MAAM6hD,EAAuB,GAc7B,OAZI16L,KAAKihG,iBACLy5F,EAAqBx4L,KAAKlC,KAAKihG,iBAAiB03C,aAAaC,EAAUC,IAEvEt0I,GAAOiH,KAAK,0CAGZxL,KAAKghG,iBACL05F,EAAqBx4L,KAAKlC,KAAKghG,iBAAiB23C,aAAaC,EAAUC,IAEvEt0I,GAAOiH,KAAK,0CAGTu+B,QAAQ8pG,IAAI6mD,IAWvBrH,GAAgBpyL,UAAUq1L,2BAA6B,SAAS70F,EAAepgG,EAAO4hF,GAClF,IAAKwe,EACD,OAEJl9F,GAAO2T,KAAM,0BAAyBupF,cAA0BpgG,MAAAA,OAApD,EAAoDA,EAAOk3B,qBAAqBl3B,MAAAA,OAAhF,EAAgFA,EAAOE,QACnG,MAAM42E,EAAQn4E,KAAK47F,eAAe3Y,GAAW,GAE7CjjF,KAAKwzF,aAAa37D,KAAKqjD,GAA6C/C,IAOxEk7G,GAAgBpyL,UAAU24L,eAAiB,SAAS/gD,GAChD,MAAM51D,EAAY41D,EAAS13C,UAE3B,GAAI03C,EAAStgD,gBAAmBsgD,EAASrzC,gBAAkBqzC,EAASpzC,YAAc3oE,GAAU,UAAVA,QAAoB,CAElG,MACMstH,EADU2d,GAAIxZ,oCAEflmJ,MAAK2xB,GAAKA,EAAEu8C,OAAU,GAAEsiE,EAASiX,WAAWv5E,aAAev8C,EAAEuwH,QAAU1R,EAASiX,WAAWvF,QAE5FH,GACA3tD,GAAWqD,0BAA0BioE,GAAItZ,4BAA4BrE,IAK7E,GAAI/yB,GAAAA,iCAAgDwhB,EAAS5C,gBAAiB,OAC1E,MAAM7U,EAAaq2B,GACfz3J,KAAK6kG,WACL5hB,EAFyC,UAGzCjjF,KAAK47F,eAAe3Y,UAHqB,aAGzC,EAAgCvhF,QAEpCm3I,EAAS8b,cAAcvzB,GAG3BphI,KAAK0hG,IAAI4wE,cAAcz5B,GACvBA,EAAS6b,cAAc10J,MAGvB64I,EAASwhD,YAAcr6L,KAAK65L,qBAAqBj5L,KAAKZ,KAAM64I,GAC5DA,EAASxsG,iBAAiB+0D,GAAqCy3C,EAASwhD,aAEpExhD,EAAStgD,iBACTsgD,EAASyhD,kBAAoBt6L,KAAK85L,2BAA2Bl5L,KAAKZ,MAClE64I,EAASxsG,iBAAiB+0D,GAA4Cy3C,EAASyhD,oBAGnFt6L,KAAKwzF,aAAa37D,KAAKqjD,GAAmC29D,IAS9Dw6C,GAAgBpyL,UAAU05L,iBAAmB,SAASxiH,GAClD,IAAIyiH,GAAmB,EAMvB,GAJIvjE,GAAAA,gCAA+Cl/C,IAC/CyiH,EAAmB56L,KAAKysI,gBAAgB0mD,kBAAkBh7G,EAAM89D,gBAAiB99D,EAAMstB,aAGtF4xB,GAAAA,8BAA4C,CAC7C,MAAMwjE,EAAmB,YAInBC,EAAiB3iH,EAAQA,EAAMstB,UAAY3oE,GAAU,UAAVA,OAGjD,GAAIg+J,IAAmBh+J,GAAU,UAAVA,QAAoB98B,KAAKuhG,KAAKmzB,gBAAgBmmE,GAAmB,CAGpF,MAAME,EAAoB/6L,KAAKuhG,KAAKoZ,uBAAuBkgF,EAAkB,CAAE1zL,MAAO2zL,IAEtFF,EAAmBA,GAAoBG,GAI/C,OAAOH,GAWXvH,GAAgBpyL,UAAU+xJ,oBAAsB,SAAS/vE,EAAW0wD,EAAYzyC,GAC5E,IAAI85F,GAAkB,EAQtB,GANI3jE,GAAAA,gCAA+Csc,IAC/CqnD,EAAkBh7L,KAAKysI,gBAAgBymD,mBAAmBv/C,EAAWsC,gBAAiB/0C,KAKrFm2B,GAAAA,8BAA4C,CAC7C,IAAI4jE,EAAkBC,EAEtB,IAAKl7L,KAAKuhG,KACN,OAAO,EAGPte,IAAc6R,GAAUqH,MACxB8+F,EAAmBj7L,KAAKuhG,KAAKyzB,uBAAuB9zB,GAEpDg6F,EAAmBl7L,KAAKuhG,KAAK2zB,uBAAuBh0B,GAGxD85F,EAAkBA,GAAmBC,GAAoBC,EAG7D,OAAOF,GAYX3H,GAAgBpyL,UAAUmxJ,uBAAyB,SAASj6E,GACxD,MAAMgjH,EAAsB,GAc5B,OAZIn7L,KAAKihG,iBACLk6F,EAAoBj5L,KAAKlC,KAAKihG,iBAAiBu4C,iBAAiBrhE,IAEhE5zE,GAAOynF,MAAM,uEAGbhsF,KAAKghG,iBACLm6F,EAAoBj5L,KAAKlC,KAAKghG,iBAAiBw4C,iBAAiBrhE,IAEhE5zE,GAAOynF,MAAM,uEAGVjiD,QAAQyqE,WAAW2mF,IAU9B9H,GAAgBpyL,UAAU6xJ,wBAA0B,SAAS36E,GACzD,MAAMijH,EAAuB,GAa7B,OAXIp7L,KAAKihG,iBACLm6F,EAAqBl5L,KAAKlC,KAAKihG,iBAAiBy4C,kBAAkBvhE,IAElE5zE,GAAOynF,MAAM,+DAEbhsF,KAAKghG,iBACLo6F,EAAqBl5L,KAAKlC,KAAKghG,iBAAiB04C,kBAAkBvhE,IAElE5zE,GAAOynF,MAAM,+DAGVjiD,QAAQyqE,WAAW4mF,IAO9B/H,GAAgBpyL,UAAUgtG,QAAU,WAChC,OAAOjuG,KAAKuhG,KAAKhtB,MAUrB8+G,GAAgBpyL,UAAU2sG,SAAW,WACjC,OAAK5tG,KAAK8iG,WAIHf,GAAAA,QAAAA,iBAAyB/hG,KAAK8iG,WAAW0D,YACxCxmG,KAAKD,QAAQ0N,OAAOwjH,aAJjB,MAYfoiE,GAAgBpyL,UAAU+iG,YAAc,WACpC,OAAOhkG,KAAKuhG,KAAOvhG,KAAKuhG,KAAKyC,cAAgB,MAQjDqvF,GAAgBpyL,UAAUugD,KAAO,SAAS3G,GACtC,OAAK76C,KAAKgkG,cAIH,IAAIj6D,SAAQ,CAACC,EAASC,KACzBjqC,KAAKuhG,KAAK2yB,SACNr5E,GAAY,IACZ,IAAM7Q,MACNvB,GAAOwB,EAAOxB,KACd,IAAMwB,EAAO4vC,QARV9vC,QAAQE,OAAO,IAAIjmC,MAAM,4BAgBxCqvL,GAAgBpyL,UAAUo6L,OAAS,WAC/B,OAAOr7L,KAAKwhD,QAWhB6xI,GAAgBpyL,UAAUq6L,kBAAoB,SAAS9iG,GACnDx4F,KAAKu7L,mBAAmB,CAAE/iG,KAe9B66F,GAAgBpyL,UAAUs6L,mBAAqB,SAAS5xF,GACpD,IAAKjlG,MAAMgD,QAAQiiG,GACf,MAAM,IAAI3lG,MAAM,sDAGpBhE,KAAKy2L,uBAAuB3kB,gBAAgBnoE,IAOhD0pF,GAAgBpyL,UAAU4pG,SAAW,WACjC,OAAO7qG,KAAKy2L,uBAAuB5rF,YAOvCwoF,GAAgBpyL,UAAUsxK,oBAAsB,WAC5C,OAAOvyK,KAAK0hG,IAAI6wE,uBAWpB8gB,GAAgBpyL,UAAU+xK,SAAW,SAAS3rB,GAC1C,IAAKv4I,OAAO0sL,UAAUn0C,KAAWv4I,OAAOrG,SAAS4+I,EAAO,IACpD,MAAM,IAAIrjJ,MAAO,4BAA2BqjJ,KAEhD,MAAMx2I,EAAI/B,OAAOu4I,GAEjB,GAAIx2I,GAAK,EACL,MAAM,IAAI27B,WAAW,mCAMzB,GAJAxsC,KAAKy2L,uBAAuBzjB,SAASniK,GAIjC7Q,KAAKghG,iBAAkB,CACvB,MAAMy6F,EAAsB,IAAN5qL,EAEtB7Q,KAAKghG,iBACA+4C,wBAAuB,EAAM0hD,GAC7Bz3I,OAAM3iD,IACHkD,GAAOlD,MACF,2CAA0Co6L,KAC3Cp6L,QAepBgyL,GAAgBpyL,UAAUymG,UAAY,SAASlP,GAC3C,OAAOx4F,KAAK0hG,IAAIgG,UAAUlP,IAO9B66F,GAAgBpyL,UAAUslG,gBAAkB,WACxC,OAAOnmG,OAAOkJ,OAAOtJ,KAAKwqG,eAS9B6oF,GAAgBpyL,UAAUw8K,oBAAsB,WAA8B,IAArBie,EAAqB,wDACtElxF,EAAexqG,KAAKumG,kBAOxB,OALKm1F,IACDlxF,EAAeA,EAAazjG,QAAOiG,IAAMA,EAAE4gG,cAIxCpD,EAAa9oG,OAAS,GAQjC2xL,GAAgBpyL,UAAU6gG,mBAAqB,SAASz8F,GACpD,OAAOrF,KAAKwqG,aAAanlG,IAO7BguL,GAAgBpyL,UAAU06L,WAAa,SAASt2L,GAC5C,MAAMw8F,EAAc7hG,KAAK8hG,mBAAmBz8F,GAEvCw8F,GAGL7hG,KAAKuhG,KAAKwyB,eAAelyB,EAAY2E,SAAU,UAQnD6sF,GAAgBpyL,UAAU26L,YAAc,SAASv2L,GAC7C,MAAMw8F,EAAc7hG,KAAK8hG,mBAAmBz8F,GACtCw2L,EAAW77L,KAAK6kG,aAAex/F,EAC/BkvE,EAAOv0E,KAAK87L,gBAAkB,SAAW,OAE3CD,EACA77L,KAAKuhG,KAAKwyB,eAAe/zH,KAAKuhG,KAAKqmB,UAAWrzC,GACvCstB,GACP7hG,KAAKuhG,KAAKwyB,eAAelyB,EAAY2E,SAAUjyB,IAUvD8+G,GAAgBpyL,UAAU86L,gBAAkB,SAAS12L,EAAIkzB,GACrD,MAAMspE,EAAc7hG,KAAK8hG,mBAAmBz8F,GAEvCw8F,GAGL7hG,KAAKuhG,KAAK2nB,KAAKrnB,EAAY2E,SAAUjuE,IAQzC86J,GAAgBpyL,UAAUm3L,qBAAuB,WACzCp4L,KAAKg8L,0BACGh8L,KAAKihG,kBAAoBjhG,KAAKy9K,sBAAwB,KAC9Dn7K,OAAOC,aAAavC,KAAKg8L,yBACzBh8L,KAAKg8L,wBAA0B,OASvC3I,GAAgBpyL,UAAU02L,mBAAqB,YAEtC33L,KAAKihG,kBACCjhG,KAAKy9K,uBAAyB,IAC7Bz9K,KAAKg8L,0BACbh8L,KAAKg8L,wBAA0B15L,OAAOE,YAAW,KAC7CxC,KAAKg8L,wBAA0B,KAC/Bv/F,GAAWoE,cAAc/d,GACrBrB,GACA,CACI4Y,KAAK,EACLlzF,MAhqDM,gBA0qD1BksL,GAAgBpyL,UAAUm1H,gBAAkB,SAAS/wH,EAAI49E,GACrD,MAAMg5G,EAAgBh5G,GAAwB6R,GAAUqH,MAExD,GAAI8/F,IAAkBnnG,GAAUqH,OAAS8/F,IAAkBnnG,GAAU2G,MAGjE,YAFAl3F,GAAOlD,MAAO,2BAA0B46L,KAK5C,MAAMp6F,EAAc7hG,KAAK8hG,mBAAmBz8F,GAEvCw8F,GAGL7hG,KAAKuhG,KAAK60B,gBAAgBv0B,EAAY2E,UAAU,EAAMy1F,IAwB1D5I,GAAgBpyL,UAAU0iG,eAAiB,SACnCR,EAAKqlB,EAAMj0C,EAAMq5B,EAAU3B,EAAShd,EAAQid,EAAUwc,EAASwzE,EAASt6F,EAAUkvB,GACtF,MAAMzrH,EAAK08F,GAAAA,QAAAA,mBAA2BoB,GAEtC,GAAW,UAAP99F,GAAkBrF,KAAK6kG,aAAex/F,EACtC,OAGJ,MAAMw8F,EACA,IAAIkK,GAAiB5I,EAAKnjG,KAAMwoH,EAAM5a,EAAU3B,EAAShd,EAAQid,GAEvErK,EAAYqM,QAAQ35B,GACpBstB,EAAYgN,WAAW6Z,GACvB7mB,EAAYG,YAAYJ,GACxBC,EAAYuM,eAAe0iB,GAE3B9wH,KAAKwqG,aAAanlG,GAAMw8F,EACxB7hG,KAAKwzF,aAAa37D,KACdqjD,GACA71E,EACAw8F,GAEJ7hG,KAAKm8L,gBAAgBt6F,GAGjB7hG,KAAK43L,YACL53L,KAAKo8L,uBAGTp8L,KAAK23L,sBAYTtE,GAAgBpyL,UAAUyhG,aAAe,WACrC1iG,KAAKo8L,wBAST/I,GAAgBpyL,UAAUk7L,gBAAkB,SAASt6F,GACjDA,EAAY4M,cACP7tD,MAAKghD,IACFC,EAAY4K,cAAgB7K,EAASriD,IAAI,0BACzCv/C,KAAKq8L,oBAEDz6F,EAASriD,IAAI+/F,KACbz9C,EAAY9qC,YAAY,mBAAmB,GAG3C6qC,EAASriD,IAAI+0D,KACbzS,EAAY9qC,YAAY,iBAAiB,MAGhD/S,OAAM,KAAM,KASrBqvI,GAAgBpyL,UAAU2iG,wBAA0B,SAAST,EAAKulB,GAI9D,MACM4zE,EADQt8L,KAAKumG,kBACUl+F,MAAK2E,GAAKA,EAAEw5F,WAAarD,IAEtD,GAAIm5F,EAAgB,CAChBA,EAAeztF,WAAW6Z,GAC1B,MAAMrjH,EAAK08F,GAAAA,QAAAA,mBAA2BoB,GAEtCnjG,KAAKwzF,aAAa37D,KACdqjD,GACA71E,EACAqjH,GAOH4zE,EAAe3tF,cAChB3uG,KAAKo8L,wBAIb/I,GAAgBpyL,UAAU4iG,aAAe,SAASV,GAC9C,MAAM99F,EAAK08F,GAAAA,QAAAA,mBAA2BoB,GAEtC,GAAW,UAAP99F,GAAkBrF,KAAK6kG,aAAex/F,EACtC,OAGJ,MAAMw8F,EAAc7hG,KAAKwqG,aAAanlG,GAChCk3L,EAAgBv8L,KAAKmyG,mBAC3B,IAAIqqF,EAAoB,GAExB,IAAK,MAAMh1L,KAAW+0L,EAAe,CACjC,MAAM53B,EAAen9J,EAAQ+kF,eAAe66E,gBAAgB/hK,GAE5Ds/J,IAAiB63B,EAAoB,IAAKA,KAAsB73B,IAGhEn9J,EAAQ8vI,2BAA2BjyI,GAIvCm3L,EAAkBj8L,SAAQ43E,IACtBn4E,KAAKwzF,aAAa37D,KAAKqjD,GAAqC/C,MAG5D0pB,WACO7hG,KAAKwqG,aAAanlG,GACzBrF,KAAKwzF,aAAa37D,KAAKqjD,GAAiC71E,EAAIw8F,IAG9C,OAAd7hG,KAAKuhG,OACLvhG,KAAKo8L,sBAAqB,GAC1Bp8L,KAAKo4L,yBAkBb/E,GAAgBpyL,UAAUwiG,eAAiB,SACnCslB,EACAixE,EACAyC,EACAlkK,EACAu4F,GAIJ,GAAIkpE,IAAYh6L,KAAK6kG,WACjB,OAGJ,MAAMyB,EAAmBtmG,KAAKwqG,aAAawvF,GAE3C,GAAIjxE,EAMA,OALA/oH,KAAKwzF,aAAa37D,KACdqjD,GAA8BorB,EAAkB/tE,EAAQu4F,QAE5D9wH,KAAK+nH,QAKT,MAAM20E,EAAoB18L,KAAKwqG,aAAaiyF,GAE5CC,EAAkBpuF,cAAcwiB,GAEhC9wH,KAAKwzF,aAAa37D,KACdqjD,GAA0CorB,EAAkBo2F,EAAmBnkK,IAOvF86J,GAAgBpyL,UAAU8iG,mBAAqB,SAASxvB,GAEpDv0E,KAAKwzF,aAAa37D,KACdqjD,GAAyCl7E,KAAK6kG,WAAYtwB,IAGlE8+G,GAAgBpyL,UAAUmjG,kBAAoB,SAASjB,EAAK5uB,GACxD,MAAMlvE,EAAK08F,GAAAA,QAAAA,mBAA2BoB,GAChCtB,EAAc7hG,KAAK8hG,mBAAmBz8F,GAEvCw8F,IAGLA,EAAYqM,QAAQ35B,GACpBv0E,KAAKwzF,aAAa37D,KAAKqjD,GAAyC71E,EAAIkvE,KAGxE8+G,GAAgBpyL,UAAU6iG,qBAAuB,SAASX,EAAK6I,GAC3D,MAAM3mG,EAAK08F,GAAAA,QAAAA,mBAA2BoB,GAChCtB,EAAc7hG,KAAK8hG,mBAAmBz8F,GAEvCw8F,GAIDA,EAAY2K,eAAiBR,IAIjCnK,EAAY2K,aAAeR,EAC3BhsG,KAAKwzF,aAAa37D,KACdqjD,EACA71E,EACA2mG,KAQRqnF,GAAgBpyL,UAAUkkG,mBAAqB,SAAShtB,GACpD,GAAIA,EAAMoX,QAAUvvF,KAAKwoG,cAGrB,YAFAjkG,GAAOiH,KAAK,6DAGT,IAAK2sE,EAAMoX,OAASvvF,KAAKwoG,cAG5B,YAFAjkG,GAAOiH,KAAK,yDAKhB,MAAMnG,EAAK8yE,EAAMsgB,mBACXoJ,EAAc7hG,KAAK8hG,mBAAmBz8F,GAE5C,IAAKw8F,EAGD,YAFAt9F,GAAOlD,MAAO,gCAA+BgE,KAMjDw8F,EAAY6K,QAAQxqG,KAAKi2E,GAErBn4E,KAAK0tL,aACL1tL,KAAK0tL,YAAY95C,SAASz7D,GAG9B,MAAMruC,EAAU9pC,KAAKwzF,aAErBrb,EAAM9rC,iBACF+0D,IACA,IAAMt3D,EAAQjS,KAAKqjD,GAA0C/C,KACjEA,EAAMogB,gBAAkBpgB,EAAM9rC,iBAC1B+0D,IACA,CAAC7P,EAAYpC,KACSnvF,KAAK60K,4BAEL1lF,GACdrlD,EAAQjS,KAAKqjD,GAAiD71E,EAAIksF,MAK9EznD,EAAQjS,KAAKqjD,GAAmC/C,IAUpDk7G,GAAgBpyL,UAAU6kG,eAAiB,SAASt+F,EAASixI,GACrDz4I,KAAKghG,mBAAqBx5F,IAC1BjD,GAAOiH,KAAK,iBAEZxL,KAAKghG,iBAAiBkzC,UAAUuE,GAChCz4I,KAAKwzF,aAAa37D,KAAKqjD,GAA8Cl7E,KAAKghG,oBAYlFqyF,GAAgBpyL,UAAU8kG,gBAAkB,SAASv+F,EAASm1L,GACtD38L,KAAKghG,mBAAqBx5F,IAC1BjD,GAAOiH,KAAK,wBACZxL,KAAKghG,iBAAiB8rC,iBAAiB6vD,KAU/CtJ,GAAgBpyL,UAAUmkG,qBAAuB,SAASw3F,GACtD58L,KAAKumG,kBAAkBhmG,SAAQshG,IAC3B,MAAM4lE,EAAS5lE,EAAYyL,YAE3B,IAAK,IAAI9rG,EAAI,EAAGA,EAAIimK,EAAO/lK,OAAQF,IAC/B,GAAIimK,EAAOjmK,KAAOo7L,EAAc,CAG5B/6F,EAAY6K,QAAQlpG,OAAOhC,EAAG,GAE9BxB,KAAKwzF,aAAa37D,KAAKqjD,GAAqC0hH,GAExD58L,KAAK0tL,aACL1tL,KAAK0tL,YAAYt5B,YAAYwoC,GAGjC,SAGT58L,OAMPqzL,GAAgBpyL,UAAU47L,mBAAqB,SAASp7F,EAAe8xC,GAEnE,IAAIupD,GAEE98L,KAAK63L,iBAAmB73L,KAAK83L,wBAA2BvyJ,GAAQ8gD,aAAe9gD,GAAQ4hD,gBACzF21G,EAAe,CACXvkK,OAAQ,UACR+9G,kBAAmB,eACnB9pB,SAAU,iEAEPxsH,KAAKghG,iBAEZ87F,EAAe,CACXvkK,OAAQ,OACR+9G,kBAAmB,0BACnB9pB,SAAU,qCAENxsH,KAAK+8L,uBACbD,EAAe,CACXvkK,OAAQ,UACR+9G,kBAAmB,2BACnB9pB,SAAU,kEAEd/vB,GAAWoE,cAAc/d,GAAkBjB,MAG3Ci7G,EACA98L,KAAKg9L,oBAAoBv7F,EAAeq7F,GAExC98L,KAAKi9L,uBAAuBx7F,EAAe8xC,IAOnD8/C,GAAgBpyL,UAAU4kG,eAAiB,SAASpE,EAAe8xC,EAAatmF,GAE5E,GAAIw0C,EAAclS,MACdvvF,KAAK68L,mBAAmBp7F,EAAe8xC,OACpC,CACH,IAAKvzI,KAAKgxH,QAAQvvB,EAAc2d,WAAY,CACxC,MAAMtpC,EAAc,6CASpB,YAPA91E,KAAKg9L,oBACDv7F,EAAe,CACXlpE,OAAQ,iBACR+9G,kBAAmBxgE,EACnB02C,SAAU12C,IAKtB91E,KAAKk9L,uBAAuBz7F,EAAe8xC,EAAatmF,KAOhEomI,GAAgBpyL,UAAUi8L,uBAAyB,SAASz7F,EAAe8xC,EAAatmF,GAGpFjtD,KAAKihG,iBAAmBQ,EACxBzhG,KAAKuhG,KAAKqB,gBAAgB,oBAAsB31C,EAChDjtD,KAAKq2L,oCAEDr2L,KAAK0zL,YACLj3F,GAAWkE,oBAAoB7d,GAAkBxB,GAAuB,CAAE+Y,KAAK,KAGnF,MAAMi6E,EACA/1G,IAAAA,CAAEg1E,GACClrI,KAAK,4DACLqN,KAAK,UAEd1V,KAAKwzF,aAAa37D,KAAKqjD,GAA6Co5F,GAEpEt0K,KAAKo4L,uBACL37F,GAAWoE,cAAc/d,GACrBtB,GACA,CACI6Y,KAAK,EACLlzF,MAAO8lD,KAGf,IACIw0C,EAAclT,WACVvuF,KAAKuhG,KACLvhG,KAAK0hG,IACL1hG,KAAKysI,gBACL,IACOzsI,KAAKD,QAAQ0N,OAChB6hI,wBAAyBtvI,KAAKg3G,kBAExC,MAAO31G,GAIL,OAHAm3B,KAAAA,iBAAsCn3B,QACtCkD,GAAOlD,MAAMA,GAMjBrB,KAAKkiG,kBAAkBqxC,EAAa9xC,EAAclV,gBAElD,MAAM8lB,EAAcryG,KAAKi6L,yBAEzB,IACIx4F,EAAc2rC,YACVmG,GACA,KAIQvzI,KAAKwoG,eAAiBxoG,KAAKihG,kBAC3BjhG,KAAKm9L,wCAGTn9L,KAAKwzF,aAAa37D,KAAKqjD,GAA8CumB,GAChEzhG,KAAKwoG,eACNxoG,KAAKwzF,aAAa37D,KAAKqjD,GAAqDumB,MAGpFpgG,IACIm3B,KAAAA,iBAAsCn3B,GACtCkD,GAAOlD,MAAM,2CAA4CA,KAE7DgxG,GAIJryG,KAAKu4L,0BACE92F,EAAclV,eAAe2uC,2BAA2Bl7H,KAAKu4L,0BAMpEh0L,GAAOiH,KAAK,4CACZxL,KAAKu/F,WAAWJ,eACZn/F,KAAKihG,iBAAiB1U,eACtB,SACJvsF,KAAKu/F,WAAW9B,iBAAiBz9F,KAAKihG,iBAAiB1U,gBACzD,MAAOx/E,GACLyrB,KAAAA,iBAAsCzrB,GACtCxI,GAAOlD,MAAM0L,KAarBsmL,GAAgBpyL,UAAUihG,kBAAoB,SAASD,EAASrV,GAC5D,IAAI84D,EAAQ,KACZ,MAAM03C,EACA7+H,IAAAA,CAAE0jC,GACC55F,KAAK,iCACLinC,QAEgB,IAArB8tJ,EAAU17L,SACVgkJ,EAAQ03C,EAAU,GAAG56K,aAAa,QAGlCkjI,EAEA1lJ,KAAK0hG,IAAIyvE,wBAAwB,KAAMzrB,GAGvC1lJ,KAAK0hG,IAAIyvE,wBAAwBvkF,EAAI,OAgB7CymG,GAAgBpyL,UAAU+7L,oBAAsB,SAASv7F,EAAe1hG,GAChEA,GAAWA,EAAQysH,UACnBh0F,KAAAA,iBAAsC,IAAIx0B,MAAMjE,EAAQysH,WAI5D/qB,EAAcyrC,UACV,MACA7rI,IACIkD,GAAO2T,KACH,qEACiC7W,KACtC,CACCk3B,OAAQx4B,GAAWA,EAAQw4B,OAC3B+9G,kBAAmBv2I,GAAWA,EAAQu2I,kBACtCF,sBAAsB,KAclCi9C,GAAgBpyL,UAAU+kG,YAAc,SAASvE,EAAei1C,EAAiBC,GAI7E,GAHApyI,GAAOiH,KACF,eAAckrI,OAAqBC,UAChCl1C,EAAclS,SAClBkS,IAAkBzhG,KAAKihG,iBACvBjhG,KAAK0zL,YAAa,EAElBj3F,GAAWoE,cACP/d,GAAkBpB,GAAyB,CAAE2Y,KAAK,KAGlDr6F,KAAKu/F,aACLv/F,KAAKu/F,WAAW7B,gBACZ19F,KAAKihG,iBAAiB1U,gBAC1BhoF,GAAOiH,KAAK,0BACZxL,KAAKu/F,WAAWR,cACZ/+F,KAAKihG,iBAAiB1U,iBAI9BvsF,KAAKihG,iBAAmB,KAGxBjhG,KAAK0hG,IAAIsE,mBACN,GAAIvE,IAAkBzhG,KAAKghG,iBAAkB,CAChD,MAAMq8F,EAAc,GAII,YAApB3mD,GAAgD,iBAAfC,GACjCpyI,GAAOiH,KAAK,6BACZixF,GAAWe,UAAUnT,uBAAuB,CAAEizG,aAAa,KAChC,uBAApB5mD,GACW,eAAfC,EAIHl6C,GAAWe,UAAUnT,uBAAuB,CAAEkzG,WAAW,IAC9B,YAApB7mD,GAAgD,YAAfC,IAGxC0mD,EAAY7mD,gBAAiB,GAEjCx2I,KAAKw9L,gBAAgBH,QAErB94L,GAAOlD,MACH,2CACAogG,EAAcugB,IACdvgB,EAAc2d,UACds3B,EACAC,IAQZ08C,GAAgBpyL,UAAUyiG,kBAAoB,SAASjC,GAC9CA,EAAclS,QACfvvF,KAAK+nH,QACL/nH,KAAKwzF,aAAa37D,KAAKqjD,MAI/Bm4G,GAAgBpyL,UAAUo7L,kBAAoB,WAC1C,IAAI5I,GAAuB,EAC3B,MAAMjpF,EAAexqG,KAAKumG,kBAG1B,IAAK,IAAI/kG,EAAI,EAAGA,EAAIgpG,EAAa9oG,OAAQF,GAAK,EAC1C,GAAIgpG,EAAahpG,GAAGgtG,eAAgB,CAChCilF,GAAuB,EACvB,MAGJA,IAAyBzzL,KAAKyzL,uBAC9BzzL,KAAKyzL,qBAAuBA,EAC5BzzL,KAAKwzF,aAAa37D,KACdqjD,GACAu4G,KASZJ,GAAgBpyL,UAAUw8L,gBAAkB,WACxC,OAAOz9L,KAAKyzL,sBAOhBJ,GAAgBpyL,UAAU4jG,SAAW,WACjC,OACI7kG,KAAKuhG,MAAQvhG,KAAKuhG,KAAKqmB,UACjB7lB,GAAAA,QAAAA,mBAA2B/hG,KAAKuhG,KAAKqmB,WACrC,MAGdyrE,GAAgBpyL,UAAU6sK,UAAY,SAASC,EAAO35E,EAAUq1C,GAC5D,MAAMi0D,EAAiB19L,KAAK60K,0BAExB6oB,EACAA,EAAe5vB,UAAUC,EAAO35E,EAAUq1C,GAE1CllI,GAAO2T,KAAK,yCAWpBm7K,GAAgBpyL,UAAUuzL,eAAiB,SAASz0L,GAChD,OAAIC,KAAKuhG,KACEvhG,KAAKk0L,iBAAiBM,eAAez0L,GAGzCgqC,QAAQE,OAAO,IAAIjmC,MAAM,wCAUpCqvL,GAAgBpyL,UAAU0zL,cAAgB,SAAS5U,GAC/C,OAAI//K,KAAKuhG,KACEvhG,KAAKk0L,iBAAiBS,cAAc5U,GAGxCh2I,QAAQE,OAAO,IAAIjmC,MAAM,wCAMpCqvL,GAAgBpyL,UAAU00H,sBAAwB,WAC9C,QAAI31H,KAAKuhG,MACEvhG,KAAKuhG,KAAKo0B,yBAUzB09D,GAAgBpyL,UAAU20H,KAAO,SAASnkC,GACtC,OAAIzxF,KAAKuhG,KACEvhG,KAAKuhG,KAAKq0B,KAAKnkC,GAGnB,IAAI1nD,SAAQ,CAACC,EAASC,KACzBA,EAAO,IAAIjmC,MAAM,2CAOzBqvL,GAAgBpyL,UAAU60H,OAAS,WAC/B,OAAI91H,KAAKuhG,KACEvhG,KAAKuhG,KAAKu0B,SAGd,IAAI/rF,SAAQ,CAACC,EAASC,KACzBA,EAAO,IAAIjmC,MAAM,2CAOzBqvL,GAAgBpyL,UAAU08L,iBAAmB,WACzC,OAAO39L,KAAK41H,KAAK,0BAOrBy9D,GAAgBpyL,UAAU28L,gBAAkBvK,GAAgBpyL,UAAU60H,OAKtEu9D,GAAgBpyL,UAAUg1H,eAAiB,WACvC,OAAIj2H,KAAKuhG,KACEvhG,KAAKuhG,KAAK00B,iBAGd,MAMXo9D,GAAgBpyL,UAAUi1H,YAAc,WACpC,OAAIl2H,KAAKuhG,KACEvhG,KAAKuhG,KAAK20B,cAGd,MAQXm9D,GAAgBpyL,UAAU48L,mBAAqB,WAC3C,GAAI79L,KAAKuhG,KACL,OAAOvhG,KAAKuhG,KAAK40B,gBAYzBk9D,GAAgBpyL,UAAU4zK,wBAA0B,WAChD,MAAMrtK,EAAUxH,KAAKwoG,cAAgBxoG,KAAKghG,iBAAmBhhG,KAAKihG,iBAElE,OAAOz5F,EAAUA,EAAQ+kF,eAAiB,MAW9C8mG,GAAgBpyL,UAAU86I,mBAAqB,WAC3C,MAAM2hD,EAAiB19L,KAAK60K,0BAE5B,OAAO6oB,EAAiBA,EAAe3hD,qBAAuB,MASlEs3C,GAAgBpyL,UAAU68L,oBAAsB,SAASC,GAChD/9L,KAAKgkG,eAMVhkG,KAAKilG,iBAAmB84F,EACxB/9L,KAAKuhG,KAAKoZ,uBAAuB,aAAc,CAC3C96F,WAAY,CACRi5E,MAAOilG,EAAOjlG,MACdlY,MAAOm9G,EAAOn9G,MACdxsE,MAAO,2CAETpU,KAAKuhG,KAAKkZ,gBAZZl2G,GAAO2T,KAAM,qCAAoClY,KAAKuhG,KAAO,GAAK,oBAC9DvhG,KAAKgkG,cAAgB,GAAK,qCAkBtCqvF,GAAgBpyL,UAAU+8L,oBAAsB,WAC5C,OAAOh+L,KAAKilG,kBAMhBouF,GAAgBpyL,UAAUk5L,kBAAoB,WAC1C,OAAOn6L,KAAK8kG,iBAMhBuuF,GAAgBpyL,UAAUm5L,kBAAoB,WAC1C,OAAOp6L,KAAK+kG,iBAMhBsuF,GAAgBpyL,UAAUkgK,mBAAqB,WAC3C,OAAOnhK,KAAKuhG,KAAKqB,iBAMrBywF,GAAgBpyL,UAAU+wG,4BAA8B,SAASxlG,EAAMrF,GACnEnH,KAAKo5L,YAAa,qBAAoB5sL,IAAQ,CAAErF,MAAAA,KAMpDksL,GAAgBpyL,UAAUg9L,+BAAiC,SAASzxL,GAChExM,KAAKs5L,cAAe,qBAAoB9sL,KACxCxM,KAAKuhG,KAAKkZ,gBASd44E,GAAgBpyL,UAAUi9L,4BAA8B,SAAS1xL,GAC7D,MAAM2xL,EAAWn+L,KAAKuhG,KAAK2sB,QAAQ/kE,MAAM9gD,MAAK8jB,GAC1CA,EAAKjW,UAAa,qBAAoB1J,MAG1C,OAAO2xL,EAAWA,EAASh3L,WAAQ4E,GAWvCsnL,GAAgBpyL,UAAUs/F,aAAe,SAAS69F,EAAiBC,GAC/D,OAAOr+L,KAAKu/F,WAAWgB,aAAa69F,EAAiBC,IAUzDhL,GAAgBpyL,UAAUu+F,mBAAqB,WAC3C,OAAOx/F,KAAKu/F,WAAWC,sBAS3B6zF,GAAgBpyL,UAAUq9L,eAAiB,SAASnmH,GAAO,MACvD,OAAOA,EAAM8X,UAAN,UAAkBjwF,KAAK60K,iCAAvB,aAAkB,EAAgCh5E,aAAa1jB,GAASA,EAAM6oF,WASzFqyB,GAAgBpyL,UAAUkvJ,eAAiB,SAASh4E,EAAO3lB,GACvD,MAAMy9B,EAAU9X,EAAM8X,UACtB,IAAIrpF,EAAO,KACX,MAAM2oF,EAAQpX,EAAMoX,MACdgvG,EAAehvG,EAAQpX,EAAMsgB,mBAAqB,QAClDilG,EACAnuG,EACIvvF,KAAKghG,kBAAoBhhG,KAAKghG,iBAAiBzU,eAC/CvsF,KAAKihG,kBAAoBjhG,KAAKihG,iBAAiB1U,eAErD0D,EAEIytG,IACA92L,EAAO82L,EAAe7hG,aAAa1jB,IAGvCvxE,EAAOuxE,EAAM6oF,UAEZxuG,EAAUntD,IAAOuB,GAAS82L,GAI/B19L,KAAKu/F,WAAWvP,4BACZ0tG,EACA92L,EACAqpF,EACAsuG,EACApmH,EAAM83E,gBACNz9F,EAAUntD,KAUlBguL,GAAgBpyL,UAAUq/F,mBAAqB,SAAStlF,GACpDyhF,GAAW0D,QAAQnlF,IAUvBq4K,GAAgBpyL,UAAU+vH,QAAU,SAAS6D,GACzC,OAAO70H,KAAKuhG,KAAOvhG,KAAKuhG,KAAKyvB,QAAQ6D,GAAU,MAMnDw+D,GAAgBpyL,UAAUu9L,+BAAiC,WACvDx+L,KAAKwzF,aAAa37D,KAAKqjD,EACnBrB,IAWRw5G,GAAgBpyL,UAAUw9L,oBAAsB,SAASx/E,EAAIta,GACzD3kG,KAAK0hG,IAAIqxE,mBAAmB9zD,EAAIta,IAQpC0uF,GAAgBpyL,UAAU+lJ,yBAA2B,SAASriD,GAC1D3kG,KAAK0hG,IAAIslD,yBAAyBriD,IAStC0uF,GAAgBpyL,UAAUy9L,yBAA2B,SAAS/5F,GAC1D3kG,KAAKy+L,oBAAoB,GAAI95F,IAiBjC0uF,GAAgBpyL,UAAUg2G,YAAc,SAASj8F,GAAkD,IAAzCikG,EAAyC,uDAApC,GAAI0/E,EAAgC,wDAC/F,MAAMC,SAAqB5jL,EAK3B,GAAoB,WAAhB4jL,IACQD,GAA0C,WAAhBC,EAMtC,GAAID,EACA3+L,KAAKy+L,oBAAoBx/E,EAAIjkG,OAC1B,CACH,IAAI6jL,EAAgB7jL,EAIhBu3G,EAAc,OAElB,GAAoB,WAAhBqsE,EAA0B,CAC1BrsE,EAAc,eAGTssE,EAAcpmL,eAAeq8F,MAC9B+pF,EAAc/pF,IAAuB,IAGzC,IACI+pF,EAAgBz9L,KAAKF,UAAU29L,GACjC,MAAO9xL,GAGL,YAFAxI,GAAOlD,MAAM,6CAA8C0L,IAM/DkyG,EACAj/G,KAAKm5L,uBAAuBl6E,EAAI4/E,EAAetsE,GAG/CvyH,KAAKk5L,gBAAgB2F,EAAetsE,QAnCxChuH,GAAOlD,MAAO,kCAAiCu9L,MAyCvDvL,GAAgBpyL,UAAUu0K,wBAA0B,WAChD,OAAOx1K,KAAKwoG,cACNxoG,KAAKg0L,2BAA6Bh0L,KAAK2iG,4BASjD0wF,GAAgBpyL,UAAU4hG,uBAAyB,SAASr7F,IACnDA,EAAQ+nF,OAASvvF,KAAKD,QAAQ0N,OAAOwnI,oBACtCj1I,KAAKwzF,aAAa37D,KAAKqjD,EAAyCrB,IASxEw5G,GAAgBpyL,UAAUg1L,4BAA8B,SAASzuL,GACzDA,EAAQ+nF,MACRvvF,KAAKg0L,4BAA6B,EAElCh0L,KAAK2iG,4BAA6B,EAElCn7F,EAAQ+nF,QAAUvvF,KAAKwoG,eACvBxoG,KAAKwzF,aAAa37D,KAAKqjD,IAS/Bm4G,GAAgBpyL,UAAUiiG,uBAAyB,SAAS17F,GAGpDA,EAAQ+nF,OAGRkN,GAAWe,UAAUnT,uBAAuB,CAAEkzG,WAAW,IAErDv9L,KAAKghG,kBACLvE,GAAWkE,oBACP5d,GACIhB,GACA,CACIouD,UAAWnwI,KAAKghG,iBAAiBsrC,eAIjDtsI,KAAKw9L,gBAAgB,CACjBjlK,OAAQ,qBACR+9G,kBAAmB,gBAEhB9uI,GAAWxH,KAAKihG,mBAAqBz5F,IAC5CxH,KAAKk4L,kBAAoB,IAAIziB,GAAkBz1K,MAC/CA,KAAKk4L,kBAAkB91L,MAAMoF,KASrC6rL,GAAgBpyL,UAAUi1L,yBAA2B,SAAS1uL,GACtDA,EAAQ+nF,MACRvvF,KAAKg0L,4BAA6B,GAElCh0L,KAAK2iG,4BAA6B,EAClC3iG,KAAKk4L,mBAAqBl4L,KAAKk4L,kBAAkBjrH,UAGjDzlE,EAAQ+nF,QAAUvvF,KAAKwoG,eACvBxoG,KAAKwzF,aAAa37D,KAAKqjD,IAU/Bm4G,GAAgBpyL,UAAUg8L,uBAAyB,SAASx7F,EAAe8xC,GACvEvzI,KAAKg0L,4BAA6B,EAGlCh0L,KAAKghG,iBAAmBS,EACxBzhG,KAAKq2L,oCAELr2L,KAAKghG,iBAAiBzS,WAClBvuF,KAAKuhG,KACLvhG,KAAK0hG,IACL1hG,KAAKysI,gBACL,IACOzsI,KAAKD,QAAQ0N,OAChB6hI,wBAAyBtvI,KAAKg3G,kBAGtCzyG,GAAOiH,KAAK,4CAEZ,IAAIszL,EAAW/8F,GAAAA,QAAAA,mBAA2B/hG,KAAKghG,iBAAiBoe,WAEhE,MAAMvd,EAAc7hG,KAAKwqG,aAAas0F,GAElCj9F,IACAi9F,EAAWj9F,EAAY8L,cAAgBmxF,GAG3C9+L,KAAKu/F,WAAWJ,eACZn/F,KAAKghG,iBAAiBzU,eACtBuyG,GAEJ,MAAMzsF,EAAcryG,KAAK47F,iBAEzB57F,KAAKghG,iBAAiBosC,YAClBmG,GACA,KACIhvI,GAAOynF,MAAM,uCAEbhsF,KAAKwzF,aAAa37D,KACdqjD,GACAumB,MAERpgG,IACIkD,GAAOlD,MACH,+CAAgDA,KAExDgxG,IAORghF,GAAgBpyL,UAAU89L,oBAAsB,WAC5C/+L,KAAKg/L,iBAAiB,MAAOh/L,KAAKihG,iBAAiB1U,eAAe66E,oBAOtEisB,GAAgBpyL,UAAUg+L,oBAAsB,WAC5Cj/L,KAAKg/L,iBAAiB,MAAOh/L,KAAKghG,iBAAiBzU,eAAe66E,oBAUtEisB,GAAgBpyL,UAAU+9L,iBAAmB,SAASlwB,EAASnK,GAC3D,IAAK,MAAMxsF,KAASwsF,EAChBpgK,GAAOiH,KAAM,iBAAgBsjK,YAAkB32F,KAC/Cn4E,KAAKmlG,mBAAmBhtB,IAWhCk7G,GAAgBpyL,UAAUk1L,4BAA8B,SAAS10F,GAC/B,OAA1BzhG,KAAKghG,mBAILhhG,KAAKk/L,yBACCl/L,KAAKghG,iBAAiBytC,uBAGF,OAA1BzuI,KAAKihG,mBACLjhG,KAAKm/L,yBACCn/L,KAAKihG,iBAAiBwtC,uBAGhC,IAAIt8F,GAAO,EACX,MAAMitJ,EAAmBp/L,KAAKD,QAAQ0N,OAAO2xL,iBAsB7C,GAnBK39F,EAAclS,MAERvvF,KAAKghG,mBAAqBS,GACjCl9F,GAAOlD,MAAM,0DAEb8wC,GAAO,IACCsvD,EAAc6qC,aACS,iBAArB8yD,GACPn1L,KAAKE,SAAWi1L,IACnB76L,GAAOiH,KAAM,+BAA8B4zL,SAC3C3iG,GAAWe,UAAUnT,uBAAuB,CAAEizG,aAAa,IAC3Dt9L,KAAKw9L,gBAAgB,CACjBjlK,OAAQ,UACR+9G,kBAAmB,iBAGvBnkG,GAAO,GAfPA,GAAO,GAkBNzI,MAAM1pC,KAAKk/L,4BACRx1J,MAAM1pC,KAAKm/L,0BAA2B,CAC1C,MAAME,EACAr/L,KAAKk/L,yBAA2Bl/L,KAAKm/L,yBAE3C1iG,GAAWoE,cACPxe,GACA,CAAEl7E,MAAOk4L,IAGb59F,EAAclS,QAAUvvF,KAAKwoG,eAC7BxoG,KAAKwzF,aAAa37D,KAAKqjD,GAGvB/oC,IAMJnyC,KAAKs/L,eAAc,GAGft/L,KAAKihG,iBACLjhG,KAAKu/L,yBAELh7L,GAAOiH,KAAK,mDAGhBxL,KAAKi/L,sBAGDj/L,KAAKihG,kBACLjhG,KAAKm9L,wCAGT54L,GAAOiH,KAAK,6CACZxL,KAAKu/F,WAAW9B,iBAAiBz9F,KAAKghG,iBAAiBzU,gBAEvDkQ,GAAWkE,oBACP5d,GACIjB,GACA,CACIquD,UAAWnwI,KAAKghG,iBAAiBsrC,iBAajD+mD,GAAgBpyL,UAAUm1L,kBAAoB,WAA0B,IAAjBzrG,EAAiB,uDAAJ,GAChE,MAAMg/E,GAAW5yD,IAAAA,CAAQpsB,EAAY3qF,KAAK2qF,YAG1C,GADA3qF,KAAK2qF,WAAaA,EACdg/E,EAAS,CACT3pK,KAAKwzF,aAAa37D,KAAKqjD,GAA0Cl7E,KAAK2qF,YAEtE,MAAM60G,EAA+D,SAA3Cx/L,KAAK2qF,WAAW,uBACpC80G,EAA+D,SAA3Cz/L,KAAK2qF,WAAW,uBAEtC3qF,KAAKg1L,2BAA6BwK,IAClCx/L,KAAKg1L,yBAA2BwK,EAChCx/L,KAAKwzF,aAAa37D,KAAKqjD,EAAwDskH,GAC/Ej7L,GAAOiH,KAAM,6CAA4Cg0L,MAGzDx/L,KAAKi1L,2BAA6BwK,IAClCz/L,KAAKi1L,yBAA2BwK,EAChCz/L,KAAKwzF,aAAa37D,KAAKqjD,GAAwDukH,GAC/El7L,GAAOiH,KAAM,6CAA4Ci0L,MAIvC,CAIlB,eAGA,cAGUl/L,SAAQ2N,SACMnC,IAApB4+E,EAAWz8E,IACXuuF,GAAWe,UAAUnT,uBAAuB,CACxC,CAACn8E,EAAIuC,QAAQ,IAAK,MAAOk6E,EAAWz8E,UAaxDmlL,GAAgBpyL,UAAUosG,YAAc,SAASn/F,GAC7C,OAAOlO,KAAK2qF,WAAWz8E,IAO3BmlL,GAAgBpyL,UAAUk3L,4BAA8B,WAChDn4L,KAAK8zL,uBACLvvL,GAAOiH,KAAK,mCACZjJ,aAAavC,KAAK8zL,sBAClB9zL,KAAK8zL,qBAAuB,OASpCT,GAAgBpyL,UAAUs+L,uBAAyB,WAC/Cv/L,KAAK0/L,oBACD,MAAO1/L,KAAKihG,iBAAiB1U,eAAe66E,oBAQpDisB,GAAgBpyL,UAAU0+L,uBAAyB,WAC/C3/L,KAAK0/L,oBACD,MAAO1/L,KAAKghG,iBAAiBzU,eAAe66E,oBAUpDisB,GAAgBpyL,UAAUy+L,oBAAsB,SAASE,EAAiBj7B,GACtE,IAAK,MAAMxsF,KAASwsF,EAChBpgK,GAAOiH,KAAM,mBAAkBo0L,YAA0BznH,KACzDn4E,KAAKolG,qBAAqBjtB,IAQlCk7G,GAAgBpyL,UAAU4+L,qCAAuC,WAC7Dt7L,GAAOiH,KAAK,sDACZxL,KAAKihG,iBAAiB84C,wBAAuB,GAAM,GAAMn5F,MACrD,KACIr8C,GAAOiH,KAAK,sDAEhBnK,IACIkD,GAAOlD,MACH,2DACAA,OAWhBgyL,GAAgBpyL,UAAUq+L,cAAgB,SAASr1F,GAC/C,GAAIjqG,KAAKq6F,MAAQ4P,EAAjB,CAMA,GADAjqG,KAAKq6F,IAAM4P,EACPA,EAAW,CACX1lG,GAAOiH,KAAK,wCAIZixF,GAAWe,UAAUnT,uBAAuB,CACxCkzG,WAAW,EACXD,aAAa,IAKjB,MAAM7B,EAAoC,IAApBz7L,KAAK6qG,WAE3B7qG,KAAKghG,iBACA+4C,wBAAuB,EAAM0hD,GAC7Bz3I,OAAM3iD,IACHkD,GAAOlD,MAEI,+CAAGo6L,KAAkBp6L,WAGxCkD,GAAOiH,KAAK,mCAIZxL,KAAKihG,kBACLjhG,KAAKu/F,WAAWE,gCACZz/F,KAAKihG,iBAAiB1U,gBAAiB0d,GAI/CjqG,KAAKwzL,YAAc,KAGnBxzL,KAAKwzF,aAAa37D,KACdqjD,GACAl7E,KACAA,KAAKq6F,KACTr6F,KAAKwzF,aAAa37D,KAAKqjD,GAAqDl7E,KAAKq/K,yBAGjFr/K,KAAKwzF,aAAa37D,KACd73B,KAAKw1K,0BACCt6F,EACAA,QAlDN32E,GAAOynF,MAAO,8CAA6Cie,MA0DnEopF,GAAgBpyL,UAAU6+L,iBAAmB,SAAS1gF,GAElD,GADAp/G,KAAKm4L,8BACDn4L,KAAKghG,iBAGL,YAFAz8F,GAAOlD,MAAM,gCAKjBrB,KAAKg0L,4BAA6B,EAClCh0L,KAAKghG,iBACChhG,KAAK08F,KAAKoG,WAAW20B,OAAOgmB,oBAC1Bz9I,KAAKuhG,KAAKqmB,UACVxI,GACR76G,GAAOiH,KACH,gCAAiCxL,KAAKuhG,KAAKqmB,UAAWxI,GAC1Dp/G,KAAKq2L,oCAELr2L,KAAKghG,iBAAiBzS,WAClBvuF,KAAKuhG,KACLvhG,KAAK0hG,IACL1hG,KAAKysI,gBACL,IACOzsI,KAAKD,QAAQ0N,OAChB6hI,wBAAyBtvI,KAAKg3G,kBAGtCzyG,GAAOiH,KAAK,4CAEZ,IAAIszL,EAAW/8F,GAAAA,QAAAA,mBAA2B/hG,KAAKghG,iBAAiBoe,WAEhE,MAAMvd,EAAc7hG,KAAKwqG,aAAas0F,GAElCj9F,IACAi9F,EAAWj9F,EAAY8L,cAAgBmxF,GAG3C9+L,KAAKu/F,WAAWJ,eACZn/F,KAAKghG,iBAAiBzU,eACtBuyG,GAEJ,MAAMzsF,EAAcryG,KAAK47F,iBAEzB57F,KAAKghG,iBAAiBuyB,OAAOlhB,IAOjCghF,GAAgBpyL,UAAUk8L,sCAAwC,WAC9D54L,GAAOiH,KAAK,wDACZxL,KAAKihG,iBAAiB84C,wBAAuB,GAAO,GAAOn5F,MACvD,KACIr8C,GAAOiH,KAAK,yDAEhBnK,IACIkD,GAAOlD,MACH,4DACAA,OAWhBgyL,GAAgBpyL,UAAUm7L,qBAAuB,SAAS2D,GACtD,IAAK//L,KAAK63L,gBACC73L,KAAK83L,wBACLvyJ,GAAQ8gD,aACR9gD,GAAQ4hD,iBACRnnF,KAAKg3G,gBAGZ,YAFAzyG,GAAOiH,KAAK,qBAIhB,MAAMw0L,EAAQhgM,KAAKumG,kBACb6/E,EAAY4Z,EAAMt+L,OAGlBu+L,EAAgBjgM,KAAK+8L,qBAQ3B,IALKkD,GAAiBjgM,KAAK8zL,sBACvB9zL,KAAKm4L,+BAIJn4L,KAAKghG,kBAAoBi/F,EAAe,CACzC,MAAMxwG,EAAO22F,GAAa4Z,EAAM,GAG1BE,EAAOlgM,KAAK6kG,WACZs7F,EAAU1wG,EAAK0a,QAErB,GAAI+1F,EAAOC,EAKP,YAJA57L,GAAOynF,MACH,2DACqCk0G,EAAMC,GAG5C,GAAID,IAASC,EAGhB,YAFA57L,GAAOlD,MAAM,kBAAmB6+L,EAAMC,GAK1C,MAAMh9F,EAAM1T,EAAK+W,SAEjB,GAAIu5F,EAAe,CACf,GAAI//L,KAAK8zL,qBAGL,YAFAvvL,GAAOlD,MAAM,+CAIjBkD,GAAOiH,KACF,wBAAuB23F,WACpBnjG,KAAK+zL,6BACb/zL,KAAK8zL,qBAAuBtxL,WACxBxC,KAAK8/L,iBAAiBl/L,KAAKZ,KAAMmjG,GACX,IAAtBnjG,KAAK+zL,qBAETxvL,GAAOiH,KAAM,wBAAuB23F,KACpCnjG,KAAK8/L,iBAAiB38F,QAEnBnjG,KAAKghG,mBAAqBi/F,IACjC17L,GAAOiH,KAAM,uBAAsBxL,KAAKghG,iBAAiBoe,aAGrDp/G,KAAKghG,iBAAiBsrC,aAAe85C,EAAY,GACjD3pF,GAAWkE,oBACP5d,GAAef,KAEvBhiF,KAAKw9L,oBAUbnK,GAAgBpyL,UAAU87L,mBAAqB,WAC3C,MAAMiD,EAAQhgM,KAAKumG,kBACb6/E,EAAY4Z,EAAMt+L,OAClB0+L,OAAmGr0L,IAAtFi0L,EAAM33L,MAAK2E,GAAwB,gBAAnBA,EAAE2hG,cAAkC3hG,EAAEyU,WAAW69H,MAC9E2gD,EAA8B,IAAd7Z,IAAoBga,EAI1C,OAFA77L,GAAOynF,MAAO,mBAAkBo6F,kBAA0Bga,QAAiBH,KAEpEA,GAcX5M,GAAgBpyL,UAAUu8L,gBAAkB,WAAuB,IAAdz9L,EAAc,uDAAJ,GAC3D,MAAM,OACFw4B,EAAS,UADP,kBAEF+9G,EAAoB,0BAFlB,eAGFE,GAAiB,GACjBz2I,EAEJ,IAAKC,KAAKghG,iBAGN,YAFAz8F,GAAOlD,MAAM,iCAKjB,MAAMg/L,EAAoBrgM,KAAKwoG,cAG3B63F,IACIrgM,KAAKihG,mBAAqBu1C,GAC1Bx2I,KAAK6/L,uCAIT7/L,KAAK2/L,0BAITp7L,GAAOiH,KAAK,4CACZxL,KAAKu/F,WAAW7B,gBAAgB19F,KAAKghG,iBAAiBzU,gBACtDhoF,GAAOiH,KAAK,yCACZxL,KAAKu/F,WAAWR,cAAc/+F,KAAKghG,iBAAiBzU,gBAEpDvsF,KAAKghG,iBAAiBksC,WAClB,KACI3oI,GAAOiH,KAAK,mCAEhBnK,IAemB,YAAXk3B,GACAh0B,GAAOlD,MAAM,iEAAkEA,KAEpF,CACCk3B,OAAAA,EACA+9G,kBAAAA,EACAF,qBAAsBp2I,KAAKuhG,MACpBvhG,KAAK8hG,mBACJC,GAAAA,QAAAA,mBAA2B/hG,KAAKghG,iBAAiBoe,cAGjEp/G,KAAKghG,iBAAmB,KAGxBhhG,KAAKs/L,eAAc,GAEfe,IAEIrgM,KAAKihG,mBAAqBu1C,EAC1Bx2I,KAAK++L,sBAELx6L,GAAOiH,KAAK,mDAWxB6nL,GAAgBpyL,UAAUs1L,oBAAsB,SAAS90F,EAAe85C,GACpE,IAAK95C,EACD,OAIJ,GAAI85C,EAAK,CACL,GAAIA,EAAIpgG,KACJ,OAEJogG,EAAIpgG,MAAO,EAGf,IACImlJ,EAAmB1F,EADnBI,GAAkB,EAEtB,MAAM3oF,EAAcryG,KAAK47F,iBAGzB,IAAK,MAAMzjB,KAASk6B,EAChBiuF,EAAoBtgM,KAAKgzJ,oBAAoB76E,EAAMgpB,UAAWhpB,EAAOA,EAAM+oB,WACvE/oB,EAAMgpB,YAAcrM,GAAU2G,QAC9Bm/F,EAAmB56L,KAAK26L,iBAAiBxiH,IAE7C6iH,EAAkBA,GAAmBsF,GAAqB1F,EAI9D,IAAKvoF,EAAY3wG,SAAW21H,GAAAA,8BAA4C,CACpE,MAAMkpE,EAAyBvgM,KAAKgzJ,oBAAoBl+D,GAAUqH,WAAOpwF,GAAW,GAC9Ey0L,EAAyBxgM,KAAKgzJ,oBAAoBl+D,GAAU2G,WAAO1vF,GAAW,GAEpF6uL,EAAmB56L,KAAK26L,mBACxBK,EAAkBuF,GAA0BC,GAA0B5F,EAG1EI,GAAmBh7L,KAAKuhG,KAAKkZ,gBASjC44E,GAAgBpyL,UAAUunG,YAAc,WACpC,OAAOxoG,KAAKq6F,KAShBg5F,GAAgBpyL,UAAUw/L,sBAAwB,WAC9C,OAAIzgM,KAAKwoG,cACExoG,KAAKghG,iBAAiBzU,eAAewvD,qBAGzC,MASXs3C,GAAgBpyL,UAAUi6H,2BAA6B,SAASC,GAC5D,MAAsB,iBAAXA,GAAuBzxF,MAAMyxF,IACpC52H,GAAOlD,MAAO,iBAAgB85H,+CAEvB,IAGXn7H,KAAKu4L,yBAA2Bp9D,EAGhCn7H,KAAKihG,kBAAoBjhG,KAAKihG,iBAAiB1U,eAAe2uC,2BAA2BC,GAGzFn7H,KAAK0hG,IAAIw5B,2BAA2BC,IAE7B,IAMXk4D,GAAgBpyL,UAAUy/L,gBAAkB,WACxC,MAAMV,EAAQhgM,KAAKumG,kBAGnB,GAAqB,IAAjBy5F,EAAMt+L,OAKN,MAAM,IAAIsC,MACN,kEANgB,CACpB,MAAM+wH,EAAUirE,EAAM,GAAGx5F,SAEzBxmG,KAAK8/L,iBAAiB/qE,KAU9Bs+D,GAAgBpyL,UAAU0/L,eAAiB,SAAS5gM,GAChDC,KAAKw9L,gBAAgBz9L,IAOzBszL,GAAgBpyL,UAAU2/L,gBAAkB,WACxC,OAAO5gM,KAAK6zL,sBAAsB18F,YAOtCk8F,GAAgBpyL,UAAU4/L,qBAAuB,SAASl8F,GACtD3kG,KAAK08F,KAAK8mD,0BAA0BxjJ,KAAKuhG,KAAK0B,QAAS0B,IAoB3D0uF,GAAgBpyL,UAAU09K,uBAAyB,SAASr2B,GACxDtoJ,KAAKy2L,uBAAuB9X,uBAAuBr2B,IAWvD+qC,GAAgBpyL,UAAUw0I,2BAA6B,SAASF,GAC5Dv1I,KAAKy2L,uBAAuB/X,kCAAkCnpC,IAUlE89C,GAAgBpyL,UAAU60I,yBAA2B,SAASP,GAC1D,OAAOv1I,KAAK02L,oBAAoB/W,+BAA+BpqC,IAgBnE89C,GAAgBpyL,UAAU+vL,wBAA0B,SAASjB,EAAY/jF,GACrE,OAAKhsG,KAAKuhG,KAIHvhG,KAAKi0L,kBACPjD,wBAAwBjB,EAAY/jF,GAJ9B,IAAIhoG,MAAMgsL,KAYzBqD,GAAgBpyL,UAAUo1L,kCAAoC,WAC1D,MAAMpmE,EAAYjwH,KAAK69L,sBAEnB79L,KAAK60L,mCAAsC5kE,GAAgD,OAAnCjwH,KAAK60K,4BAIjEp4E,GAAWoE,cAAcpe,GAAsB,SAAU,CACrDwtC,UAAAA,EACAz3B,cAAgB,GAAEy3B,KAAajwH,KAAK+1L,qBAExC/1L,KAAK60L,kCAAoC1vL,KAAK8nD,QAOlDomI,GAAgBpyL,UAAUg3L,kCAAoC,WAC1D,MAAMhoE,EAAYjwH,KAAK69L,qBAElB5tE,GAAcjwH,KAAK60L,mCAKxBp4F,GAAWoE,cAAcpe,GAAsB,OAAQ,CACnDwtC,UAAAA,EACAz3B,cAAgB,GAAEy3B,KAAajwH,KAAK+1L,kBACpCniG,MAAO,CACHQ,SAAUnqF,KAAKC,OAAO/E,KAAK8nD,MAAQjtD,KAAK60L,mCAAqC,KAC7EiM,KAAM9gM,KAAK64L,2BAUvBxF,GAAgBpyL,UAAUgxG,sBAAwB,WAC1CjyG,KAAKghG,kBACLhhG,KAAKw9L,gBAAgB,CACjBlnD,kBAAmB,UACnBE,gBAAgB,IAIpBx2I,KAAKihG,kBACLjhG,KAAKihG,iBAAiBisC,UAClB,MACA7rI,IACIkD,GAAO2T,KAAK,8DAA+D7W,KAC5E,CACCk3B,OAAQ,UACR+9G,kBAAmB,mBACnBE,gBAAgB,EAChBJ,sBAAsB,IAIlCp2I,KAAKo8L,sBAAqB,IAQ9B/I,GAAgBpyL,UAAU+1G,cAAgB,WACtC,OAAO1vB,QAAQtnF,KAAK+0L,gBAAkB/0L,KAAK+0L,eAAejjF,cAS9DuhF,GAAgBpyL,UAAU6zL,gBAAkB,WACxC,OAAOh8E,GAAc72F,YAAYjiB,KAAKD,QAAQ0N,SASlD4lL,GAAgBpyL,UAAU8/L,WAAa,SAASt6F,GACvCzmG,KAAK80L,kBAMV90L,KAAK+0L,eAAez7E,WAAW7S,GAL3BliG,GAAO2T,KAAK,6DAepBm7K,GAAgBpyL,UAAU+/L,sBAAwB,SAASvuF,GACvDzyG,KAAK+0L,eAAe7iF,iBAAiBO,IAQzC4gF,GAAgBpyL,UAAUggM,iBAAmB,WACzC,OAAO35G,QAAQtnF,KAAKuhG,MAAQvhG,KAAKuhG,KAAKw0B,WAAW9zG,gBAQrDoxK,GAAgBpyL,UAAU66L,cAAgB,WACtC,OAAOx0G,QAAQtnF,KAAKuhG,MAAQvhG,KAAKuhG,KAAKkmB,qBAQ1C4rE,GAAgBpyL,UAAUsnH,YAAc,WACpC,OAAIvoH,KAAKuhG,MAAQvhG,KAAKgkG,cACXhkG,KAAKuhG,KAAKw0B,WAAWhT,SAGzBh5E,QAAQE,OACX,IAAIjmC,MAAM,yDAQlBqvL,GAAgBpyL,UAAUigM,aAAe,WACjClhM,KAAKuhG,MAAQvhG,KAAKgkG,cAClBhkG,KAAKuhG,KAAKw0B,WAAWx0E,UAErBh9C,GAAO2T,KAAM,4BAA2BlY,KAAKuhG,KAAO,GAAK,oBACrDvhG,KAAKgkG,cAAgB,GAAK,qCAWtCqvF,GAAgBpyL,UAAUkgM,UAAY,SAASn1F,EAAakc,GACxD,OAAIloH,KAAKuhG,KACEvhG,KAAKuhG,KAAKw0B,WAAWxsH,KAAKyiG,EAAakc,GAG3Cn+E,QAAQE,OAAO,IAAIjmC,MAAM,gCAUpCqvL,GAAgBpyL,UAAUmgM,cAAgB,WACtC,GAAIphM,KAAKuhG,KACL,OAAOvhG,KAAKuhG,KAAKw0B,WAAWpO,cAapC0rE,GAAgBpyL,UAAUogM,iBAAmB,SAASrmL,EAAS3V,GAC3D,GAAIrF,KAAKuhG,KACL,OAAIl8F,EACOrF,KAAKuhG,KAAKw0B,WAAWrO,mBAAmBriH,EAAI2V,GAGhDhb,KAAKuhG,KAAKw0B,WAAW9e,YAAYj8F,IAWhDq4K,GAAgBpyL,UAAUqgM,wBAA0B,SAASx2J,GACzD,GAAI9qC,KAAKuhG,KACL,OAAOvhG,KAAKuhG,KAAKw0B,WAAWlO,mBAAmB/8E,IAUvDuoJ,GAAgBpyL,UAAUsgM,0BAA4B,SAASlpK,GAC3D,GAAIr4B,KAAKuhG,KACL,OAAOvhG,KAAKuhG,KAAKw0B,WAAWjO,qBAAqBzvF,IAQzDg7J,GAAgBpyL,UAAUugM,gBAAkB,SAASn8L,GAC7CrF,KAAKuhG,MACLvhG,KAAKuhG,KAAKw0B,WAAW9M,WAAW5jH,IASxCguL,GAAgBpyL,UAAUwgM,mBAAqB,SAASp8L,GAChDrF,KAAKuhG,MACLvhG,KAAKuhG,KAAKw0B,WAAW5M,cAAc9jH,IAS3CguL,GAAgBpyL,UAAUygM,wBAA0B,WAChD,OAAOp6G,QAAQtnF,KAAKuhG,MAAQvhG,KAAKuhG,KAAKy0B,kBAAkB/zG,gBAO5DoxK,GAAgBpyL,UAAU0gM,mBAAqB,SAAS1+G,GAChDjjF,KAAKuhG,MAAQvhG,KAAKgkG,gBACd/gB,IAAc6R,GAAUqH,OAASlZ,IAAc6R,GAAU2G,OAC7Dz7F,KAAKuhG,KAAKy0B,kBAAkBjT,QAAO,EAAM9/B,GAEzC1+E,GAAO2T,KAAM,mCAAkClY,KAAKuhG,KAAO,GAAK,oBAC5DvhG,KAAKgkG,cAAgB,GAAK,qCAC1BhkG,KAAKuhG,MAAQvhG,KAAKgkG,cAAgB,0BAA4B,OAQ1EqvF,GAAgBpyL,UAAU2gM,oBAAsB,SAAS3+G,GACjDjjF,KAAKuhG,MAAQvhG,KAAKgkG,gBACd/gB,IAAc6R,GAAUqH,OAASlZ,IAAc6R,GAAU2G,OAC7Dz7F,KAAKuhG,KAAKy0B,kBAAkBjT,QAAO,EAAO9/B,GAE1C1+E,GAAO2T,KAAM,oCAAmClY,KAAKuhG,KAAO,GAAK,oBAC7DvhG,KAAKgkG,cAAgB,GAAK,qCAC1BhkG,KAAKuhG,MAAQvhG,KAAKgkG,cAAgB,0BAA4B,OAU1EqvF,GAAgBpyL,UAAU4gM,oBAAsB,SAAS5+G,EAAW59E,GAChE,GAAIrF,KAAKuhG,MAAQvhG,KAAKgkG,gBACd/gB,IAAc6R,GAAUqH,OAASlZ,IAAc6R,GAAU2G,OAAQ,CAErE,MAAMoG,EAAc7hG,KAAK8hG,mBAAmBz8F,GAE5C,IAAKw8F,EACD,OAGJ7hG,KAAKuhG,KAAKy0B,kBAAkBhR,QAAQ/hC,EAAW4e,EAAY2E,eAE3DjiG,GAAO2T,KAAM,mCAAkClY,KAAKuhG,KAAO,GAAK,oBAC5DvhG,KAAKgkG,cAAgB,GAAK,qCAC1BhkG,KAAKuhG,MAAQvhG,KAAKgkG,cAAgB,0BAA4B,OAU1EqvF,GAAgBpyL,UAAU6gM,mBAAqB,SAAS7+G,EAAW59E,GAC/D,GAAIrF,KAAKuhG,MAAQvhG,KAAKgkG,gBACd/gB,IAAc6R,GAAUqH,OAASlZ,IAAc6R,GAAU2G,OAAQ,CAErE,MAAMoG,EAAc7hG,KAAK8hG,mBAAmBz8F,GAE5C,IAAKw8F,EACD,OAGJ7hG,KAAKuhG,KAAKy0B,kBAAkB/rF,OAAOg5C,EAAW4e,EAAY2E,eAE1DjiG,GAAO2T,KAAM,kCAAiClY,KAAKuhG,KAAO,GAAK,oBAC3DvhG,KAAKgkG,cAAgB,GAAK,qCAC1BhkG,KAAKuhG,MAAQvhG,KAAKgkG,cAAgB,0BAA4B,OAS1EqvF,GAAgBpyL,UAAU2nH,iBAAmB,WAAW,MACpD,iBAAO5oH,KAAKuhG,YAAZ,aAAO,EAAWqnB,oBC5/HtBssE,GAAgBj0L,UAAUqxF,QAAU,WAAuB,IAAdvyF,EAAc,uDAAJ,GACnDC,KAAK08F,KAAKpK,QAAQvyF,EAAQsF,GAAItF,EAAQ86C,WAU1Cq6I,GAAgBj0L,UAAU8gH,OAAS,SAAShiH,GACxCC,KAAK08F,KAAKqlB,OAAOhiH,IAOrBm1L,GAAgBj0L,UAAU4zF,WAAa,WAKnC,OAAO70F,KAAK08F,KAAK7H,cAAc,YAQnCqgG,GAAgBj0L,UAAUulG,OAAS,WAC/B,OAAOxmG,KAAK08F,KAAK8J,UAOrB0uF,GAAgBj0L,UAAU8gM,SAAW,SAAShkJ,GAC1C/9C,KAAK+9C,MAAQA,GAWjBm3I,GAAgBj0L,UAAU+gM,oBAAsB,SAASx1L,EAAMzM,GAC3D,OAAO,IAAIszL,GAAgB,CACvB7mL,KAAAA,EACAiB,OAAQ1N,EACR+iG,WAAY9iG,QASpBk1L,GAAgBj0L,UAAUorC,iBAAmB,SAAS/T,EAAOwS,GACzD9qC,KAAK08F,KAAK9kE,YAAYU,EAAOwS,IAQjCoqJ,GAAgBj0L,UAAUsrC,oBAAsB,SAASjU,EAAOwS,GAC5D9qC,KAAK08F,KAAKvyD,eAAe7R,EAAOwS,IAMpCoqJ,GAAgBj0L,UAAUkgK,mBAAqB,WAC3C,OAAOnhK,KAAK08F,KAAKkG,iBAUrBsyF,GAAgBj0L,UAAUm5G,WAAa,SAAS14F,GAAyB,IAAhBq5B,EAAgB,wDACrE/6C,KAAK08F,KAAKlmB,KAAK4jC,WAAW14F,EAASq5B,GAAQ,IAU/Cm6I,GAAgBj0L,UAAUu5G,cAAgB,SAAS94F,GAAyB,IAAhBq5B,EAAgB,wDACxE/6C,KAAK08F,KAAKlmB,KAAKgkC,cAAc94F,EAASq5B,GAAQ,IAMlDm6I,GAAgBj0L,UAAUghM,QAAU,WAChC,MAAMxrL,EAAOzW,KAAK08F,KAAKmmD,eAEjBsO,EAAW,GAEjBA,EAASx5F,KAAO,IAAIxyD,KACpBgsJ,EAAShpH,IAAM7lC,OAAO0M,SAASu4B,KAC/B4pH,EAASnnE,GAAK3F,UAAUD,UAExB,MAAM9/E,EAAMtE,KAAK08F,KAAKomD,aAQtB,OANIx+I,IACA6sJ,EAASz0D,KAAOp4F,GAGpBmS,EAAK06I,SAAWA,EAET16I,YCtLCg/K,GAAAA,EAAAA,oBAAAA,4BAAAA,EAAAA,oBAAAA,0BAAAA,EAAAA,2BAAAA,uCAAAA,EAAAA,oBAAAA,iCAAAA,KAAAA,GAAAA,KAiCL,MAAMr5J,GAAsBq5J,GAAwBr5J,oBAC9Cb,GAAsBk6J,GAAwBl6J,oBAC9C2mK,GAA6BzM,GAAwByM,2BACrDC,GAAsB1M,GAAwB0M,oBC/BrDC,GAAwB,aAExBC,GAAwB,SA0T9B,OArTA,MAKIjpL,cACIpZ,KAAK4lJ,cAAgB,IAAIj8G,MACzB3pC,KAAKsiM,aAAe,GAEpBv6B,GAAInwI,YACAmD,GAAAA,QAAAA,qBACAwlD,GACIvgF,KAAK4lJ,cAAc/tH,KACf49J,GACAl1G,KACZwnF,GAAInwI,YACAmD,GAAAA,QAAAA,uBACAwlD,GACIvgF,KAAKuiM,iBACDviM,KAAKurJ,uBACLhrE,KAGZwnF,GAAInwI,YACAmD,GAAAA,QAAAA,qBACAynK,GAAexiM,KAAKyiM,yBAAyBD,KAIjDxiM,KAAK0iM,yBAA2B,IAAI34J,SAAQC,IACxC,IAAKq6C,UAAUm+G,YAGX,YAFAx4J,GAAQ,GAKZ,MAAMrqC,EAAOK,KAEPo0G,EAAW,GAEjBA,EAASlyG,KAAKmiF,UAAUm+G,YAAYG,MAAM,CAAEn2L,KAAM61L,KAC7CzhJ,MAAKquC,IACFjvF,KAAKyiM,yBAAyB,CAC1B,CAAC3tG,GAAU2G,OAAQz7F,KAAK4iM,sBAAsB3zG,KAElDA,EAAO4zG,SAAW,WACd,IACIljM,EAAK8iM,yBAAyB,CAC1B,CAAC3tG,GAAU2G,OAAQ97F,EAAKijM,sBAAsB5iM,QAEpD,MAAOqB,OAKN,KAEV2iD,OAAM,KAAM,KAEjBowD,EAASlyG,KAAKmiF,UAAUm+G,YAAYG,MAAM,CAAEn2L,KAAM41L,KAC7CxhJ,MAAKquC,IACFjvF,KAAKyiM,yBAAyB,CAC1B,CAAC3tG,GAAUqH,OAAQn8F,KAAK4iM,sBAAsB3zG,KAElDA,EAAO4zG,SAAW,WACd,IACIljM,EAAK8iM,yBAAyB,CAC1B,CAAC3tG,GAAUqH,OAAQx8F,EAAKijM,sBAAsB5iM,QAEpD,MAAOqB,OAKN,KAEV2iD,OAAM,KAAM,KAEjBja,QAAQ8pG,IAAIz/B,GAAUxzD,MAAKnQ,GAAWzG,EAAQyG,EAAQztB,OAAM8/K,GAAaA,UAajFF,wBAA6C,IAAvBG,EAAuB,uDAAJ,GAIrC,MAAM9zG,EAAS8zG,EAAiBl3J,OAASk3J,EAAiB9zG,OAE1D,GAAsB,iBAAXA,EACP,MAAM,IAAIlkD,UAGd,MA3G0B,YA2GnBkkD,EAUXwzG,yBAAyBD,GAEf,CAAE1tG,GAAUqH,MAAOrH,GAAU2G,OAC1B7vF,MAAKhE,GAAQA,KAAQ46L,GAAeA,EAAY56L,KAAU5H,KAAKsiM,aAAa16L,OAGjF5H,KAAKsiM,aAAe,IACbtiM,KAAKsiM,gBACLE,GAEPxiM,KAAK4lJ,cAAc/tH,KAAK49J,GAA6Cz1L,KAAKsiM,eAEtEtiM,KAAKsiM,aAAaxtG,GAAUqH,QAAUn8F,KAAKsiM,aAAaxtG,GAAU2G,SAIlEz7F,KAAK6rJ,kBAAiB,UAUlC02C,iBAAiBS,EAAUziH,GACvB,MAAM6pE,EACA7pE,EAAQl4E,MACN2xB,GAAgB,gBAAXA,EAAEu8C,MAA0Bv8C,EAAEqwH,WAAa24C,IAEpD54C,GACA3tD,GAAWqD,0BACPioE,GAAItZ,4BAA4BrE,IAQ5CyB,iBAAiBjvI,GACbmrJ,GAAIlc,iBAAiBjvI,GASzBgvI,wBACI,OAAOmc,GAAInc,wBAUfN,wBAAwB4C,GACpB,OAAO6Z,GAAIzc,wBAAwB4C,GAUvC+0C,0BAA0Br7L,GACtB,OAAO,IAAImiC,SAAQC,IAGXpiC,KAAQ5H,KAAKsiM,aACbt4J,EAAQhqC,KAAKsiM,aAAa16L,IAM9B5H,KAAK0iM,yBAAyB9hJ,MAAKkiJ,IAC/B,IAAKA,EAGD,YAFA94J,GAAQ,GAKZ,MAAMoqE,EAAW,GAEjB,OAAQxsG,GACR,KAAKktF,GAAU2G,MACX2Y,EAASlyG,KACLmiF,UAAUm+G,YAAYG,MAAM,CACxBn2L,KAAM61L,MAEd,MACJ,KAAKvtG,GAAUqH,MACXiY,EAASlyG,KACLmiF,UAAUm+G,YAAYG,MAAM,CACxBn2L,KAAM41L,MAEd,MACJ,QACIhuF,EAASlyG,KACLmiF,UAAUm+G,YAAYG,MAAM,CACxBn2L,KAAM61L,MAEdjuF,EAASlyG,KACLmiF,UAAUm+G,YAAYG,MAAM,CACxBn2L,KAAM41L,MAIlBr4J,QAAQ8pG,IAAIz/B,GAAUxzD,MAClBnQ,GAAWzG,EAAQyG,EAAQztB,OAAM+/K,IAC7B,IACI,OAAO/iM,KAAK4iM,sBAAsBG,GACpC,MACE,OAAO,SAGf,IAAM/4J,GAAQ,WAW9Bk5J,gCACI,QAAS39J,GAAQ8gD,aAAe9gD,GAAQ6hD,gBAQ5CmkE,uBACI,OAAOwc,GAAIxc,uBAWf+C,qBAAqBjE,GAWjB,OAVyB0d,GAAIxZ,oCAER7sJ,OAAS,GAI1B1B,KAAKuiM,iBACDl4C,EAAU0d,GAAIxZ,qCAGfwZ,GAAIzZ,qBAAqBjE,GAQpCh+G,iBAAiB/T,EAAOD,GACpBr4B,KAAK4lJ,cAAchuH,YAAYU,EAAOD,GAQ1CkU,oBAAoBjU,EAAOD,GACvBr4B,KAAK4lJ,cAAcz7G,eAAe7R,EAAOD,GAO7C8qK,UAAU7qK,GAAgB,2BAAN7zB,EAAM,iCAANA,EAAM,kBACtBzE,KAAK4lJ,cAAc/tH,KAAKS,KAAU7zB,KC1TpCF,IAAS2B,EAAAA,EAAAA,wDAwFf,SAASk9L,GAAkBr5C,GACvB,IAAK,MAAMK,KAAUL,EACjBK,EAAOgJ,aC7FR,IAAKiwC,aAAAA,GAAAA,EAAAA,OAAAA,iBAAAA,EAAAA,iBAAAA,+BAAAA,EAAAA,SAAAA,mBAAAA,EAAAA,UAAAA,oBAAAA,EAAAA,eAAAA,iBAAAA,EAAAA,YAAAA,eAAAA,KAAAA,GAAAA,KCOZ,MAAM9+L,IAAS2B,EAAAA,EAAAA,2DASA,MAAMo9L,GAgBjBlqL,cAA0B,IAAdrZ,EAAc,uDAAJ,GAClBC,KAAKwgH,SAAW,CACZ6rB,SAAU,GACVC,aAAa,EACbi3D,cAAc,EACdC,cAAc,KACXzjM,GASPC,KAAK0sG,QAAU,GAOf1sG,KAAKyjM,gBAAkB,KAGvBzjM,KAAK0jM,SAAW1jM,KAAK0jM,SAAS9iM,KAAKZ,MACnCA,KAAK2jM,gBAAkB3jM,KAAK2jM,gBAAgB/iM,KAAKZ,MACjDA,KAAK4jM,eAAiB5jM,KAAK4jM,eAAehjM,KAAKZ,MASnD6jM,aACI,OAAO7jM,KAAKwgH,SAASuU,QAUzB+uE,eAAeC,GACX,OAAQA,EAAQruL,KAAK,WACrB,KAAK2tL,GAAQW,OACThkM,KAAKikM,iBAAiBF,GACtB,MAEJ,KAAKV,GAAQa,SACTlkM,KAAKmkM,mBAAmBJ,GACxB,MAEJ,KAAKV,GAAQe,UACTpkM,KAAKqkM,oBAAoBN,GACzB,MAEJ,KAAKV,GAAQiB,eACTtkM,KAAKukM,iBAAiBR,IAa9B3hM,QAAwB,IAAlBiwG,EAAkB,uDAAJ,GACZryG,KAAKyjM,kBAITzjM,KAAK0sG,QAAU1sG,KAAK0sG,QAAQ3nG,OAAOstG,GAEnCryG,KAAKyjM,gBAAkBzjM,KAAKwkM,wBAE5BxkM,KAAKyjM,gBAAgBlwE,OAAOlhB,IAShCtvG,OACQ/C,KAAKyjM,iBACLzjM,KAAKyjM,gBAAgBv2D,YAGzBltI,KAAKqkM,sBAUTG,wBAOI,MAWMC,EAAiB,CAGnB/mF,WAAW,EACX+Z,OAAQ,CACJyV,UAAW,QAEf7pB,OAAQrjH,KAAK4jM,eAIbv3J,iBAAkB,IAAM,QAWtBq4J,EAAe,CACjBtmD,WAAYiB,MACTr/I,KAAKwgH,SAAS6rB,UAgCfs4D,EAAW,CACb//F,oBAAqB,OACrBhC,gBAAiB,GACjBpP,aAAc,CAAE37D,KApBJS,IACZ,OAAQA,GACR,KAAK2E,GAAW,WAAXA,sBACL,KAAKA,GAAW,WAAXA,kBACDj9B,KAAK0jM,SAASL,GAAQlpH,iBAAkB7hD,MAiB5C88F,qBAAsB,KAGX,IAEXT,uBAAwB,OACxB5C,2BAA4B,KAAM,GAiBtC/xH,KAAKm+K,KAAO,IAAIpW,GAVO,CACnBljE,SAAU,IAAM,IASgB,IAOpC7kG,KAAKm+K,KAAKvmJ,YACNmD,GAAAA,QAAAA,mBACA/6B,KAAK2jM,iBAGT,MAAMjG,EAAiB,IAAIlwD,QACvBzhI,OACAA,EACA/L,KAAKwgH,SAASuU,QACd0vE,EACA,CACI9nD,oBAAqB38I,KAAKwgH,SAAS+iF,aACnC3mD,oBAAqB58I,KAAKwgH,SAASgjF,cAEvCkB,GACA,EACA1kM,KAAKwgH,SAAS8rB,aAGZM,EAAiB,IAAIskD,GAU3B,OARAtkD,EAAe6kD,YAAYkT,GAM3BjH,EAAenvG,WAAWo2G,EAAU3kM,KAAKm+K,KAAMvxC,EAhI5B,IAkIZ8wD,EAYXgG,SAASrO,GAAyB,IAAdv1C,EAAc,uDAAJ,GAC1B9/I,KAAKwgH,SAAS4T,QAAQp0H,KAAKwgH,SAASuU,QAASsgE,EAAWv1C,GAY5D6jD,gBAAgBiB,GACZ5kM,KAAK0sG,QAAQxqG,KAAK0iM,GAElB5kM,KAAKwgH,SAASqkF,eAAeD,GAWjChB,eAAe7kF,GACX/+G,KAAKwgH,SAASskF,cAAc9kM,KAAKwgH,SAASuU,QAAShW,GAYvDklF,iBAAiBF,GACR/jM,KAAKyjM,gBAMVzjM,KAAKyjM,gBAAgBvvD,UAAU6vD,GAL3Bx/L,GAAOlD,MAAM,sDAgBrB8iM,mBAAmBJ,GACX/jM,KAAKyjM,gBACLl/L,GAAOlD,MAAM,sDAKjBrB,KAAKyjM,gBAAkBzjM,KAAKwkM,wBAE5BxkM,KAAKyjM,gBAAgBr2D,YACjB22D,GACA,SACA,IAAM/jM,KAAK0jM,SACP1jM,KAAKwgH,SAASuU,QACdsuE,GAAQlpH,iBACR,6BAYZkqH,sBACIrkM,KAAK0sG,QAAQnsG,SAAQ43E,GAASA,EAAMmS,YACpCtqF,KAAK0sG,QAAU,GAEX1sG,KAAKyjM,iBACLzjM,KAAKyjM,gBAAgBhtD,eAGrBz2I,KAAKm+K,OACLn+K,KAAKm+K,KAAKh0I,eACNpP,GAAAA,QAAAA,mBACA/6B,KAAK2jM,iBAGT3jM,KAAKm+K,KAAKnN,WAYlBuzB,iBAAiBR,GACb/jM,KAAKyjM,gBAAgB32D,iBAAiBi3D,IC1Y9C,MAAMx/L,IAAS2B,EAAAA,EAAAA,gECHT6+L,GAAuB,qBACvBj7J,GAAU,IAAIH,MACpB,IAAIq7J,IAAe,EACfC,GAAM,KAsHV,UACIr7J,KAtDGjQ,eAAoB55B,GACvB,GAAIilM,GACA,MAAM,IAAIhhM,MAAM,oCAGpB,MAAM,YAAEiqF,EAAF,gBAAeC,EAAf,0BAAgC4O,GAA8B/8F,EAEpE,IAAKkuF,IAAgBC,GAAmB4O,EACpC,MAAM,IAAI94F,MAAM,yBAOpB,aAzEJ,SAAqBjE,GACjB,IAAIwlC,GAAQmhD,gBAIZ,OAAO,IAAI38C,SAAQC,IACfvQ,KAAAA,WACI15B,EAAQ82L,0BAA4Bt3G,IACxB,GACE,OACIxzE,EACCi+B,MA0DrBk7J,CAAYnlM,GAElBklM,GAAM,IAAI3iM,OAAOsrF,UA1CrB,SAAqB7tF,GACjB,OAAO,IAAIgqC,SAAQ,CAACC,EAASC,KACzB,MAAMk7J,EAAQplM,EAAQkuF,YAChBm3G,EAAYrlM,EAAQmuF,gBACpB8R,EAASjgG,EAAQi2L,cAAgBj2L,EAAQ62L,uBAAyBvsE,GAASX,kBAEjFu7E,GAAI12G,WAAW42G,EAAOC,EAAWplG,GAAQ,CAAC/Q,EAAQj0E,KAC/B,YAAXi0E,GACAg2G,GAAI16J,GAAGw6J,IAAsB,WAAa,2BAATtgM,EAAS,yBAATA,EAAS,gBACtCqlC,GAAQjS,KAAKktK,MAAyBtgM,MAE1CugM,IAAe,EACfh7J,KAEAC,EAAO,CACHglD,OAAAA,EACAj0E,QAAAA,MAGT,KAAM,CAAEqqL,oBAAoB,OAyB5BC,CAAYvlM,IAwCnBwlM,QAxBG,WACH,OAAKP,GAIE,IAAIj7J,SAAQ,CAACC,EAASC,KACzBH,GAAQS,GAAGw6J,IAAsB,CAAC91G,EAAQ0V,KACvB,YAAX1V,EACAjlD,EAAQ26D,GAER16D,EAAO,CACHglD,OAAAA,EACA0V,QAAAA,OAMZsgG,GAAIO,qBAhBGz7J,QAAQE,OAAO,4CCzG9B,MAAM1lC,IAAS2B,EAAAA,EAAAA,6CAMA,MAAMu/L,GAIjBrsL,cACIpZ,KAAK0lM,UAAW,EAChB1lM,KAAK2lM,cAAgB,GACrB3lM,KAAK4lM,gBAAkB,GAQ3BC,eAAez1L,GACNA,EAAOs5I,kBACRnlJ,GAAO2T,KAAK,mDAGhBlY,KAAK2lM,cAAczjM,KAAKkO,GAU5BhO,QAEI,GAAIpC,KAAK0lM,SACL,OAAO1lM,KAAK8lM,UAAU11L,OAK1B,GAFApQ,KAAK63K,cAAgBV,MAEhBn3K,KAAK2lM,cAAcjkM,OAGpB,OAFA6C,GAAO2T,KAAK,8DAEL,KAGXlY,KAAK0lM,UAAW,EAEhB1lM,KAAK8lM,UAAY9lM,KAAK63K,cAAckuB,+BAEpC,IAAK,MAAM31L,KAAUpQ,KAAK2lM,cAAe,CACrC,MAAMK,EAAYhmM,KAAK63K,cAAcxlF,wBAAwBjiF,GAE7D41L,EAAU1zG,QAAQtyF,KAAK8lM,WAGvB9lM,KAAK4lM,gBAAgB1jM,KAAK8jM,GAG9B,OAAOhmM,KAAK8lM,UAAU11L,OAQ1B4qC,QACIh7C,KAAK0lM,UAAW,EAChB1lM,KAAK2lM,cAAgB,GAGrB,IAAK,MAAMK,KAAahmM,KAAK4lM,gBACzBI,EAAUnxG,aAGd70F,KAAK4lM,gBAAkB,GAEnB5lM,KAAK63K,gBACL73K,KAAK63K,mBAAgB9rK,IC9CjC,MAAMxH,GAAS3E,IAAAA,4BAef,SAASqmM,GAAkClmM,GACvC,MAAM8f,EAAa,CACf,gBACI9f,EAAQwgF,QAAQk9B,SAAS,SAC7B,gBACI19G,EAAQwgF,QAAQk9B,SAAS,SAC7B,yBACI19G,EAAQwgF,QAAQk9B,SAAS,YAOjC,OAJI59F,EAAWqmL,kBACXrmL,EAAW01E,WAAax1F,EAAQw1F,YAG7B11E,EAiCX,SAVA,SAAkCrgB,GAC9B,MACkC,iBAAvB8C,OAAO6jM,YACR/lM,OAAOqmC,OAAO,GAAInkC,OAAO6jM,YAAa3mM,GACtCA,EAMd,CAAwC,CAEpCyR,QAAS,WAETikL,gBAJoC,GAapCkR,uBHlGW,MAeXhtL,cAA0B,IAAdrZ,EAAc,uDAAJ,GAClB,MAAM,gBACFsmM,KACG35C,GACH3sJ,EAOJC,KAAKwgH,SAAW,CACZ6rB,SAAUg6D,GAAmBA,EAAgB3pG,KAAKoG,WAAW20B,OAAOilB,gBACjEgQ,GAQP1sJ,KAAKyjM,gBAAkB,KAGvBzjM,KAAKsmM,cAAgBtmM,KAAKsmM,cAAc1lM,KAAKZ,MAC7CA,KAAK4jM,eAAiB5jM,KAAK4jM,eAAehjM,KAAKZ,MAC/CA,KAAK2jM,gBAAkB3jM,KAAK2jM,gBAAgB/iM,KAAKZ,MAiBrD8jM,eAAe9oL,GACX,MAAM+5G,EAAU/5G,EAAQ6jF,KAExB,IAAKk2B,EACD,OAMJ,GAAI/0H,KAAKyjM,iBACFzjM,KAAKyjM,gBAAgBI,eAAiB9uE,EAOzC,YANA/0H,KAAKsmM,cACDvxE,EACAsuE,GAAQlpH,iBACR,YAMR,MAAM4kC,EAAK/+G,KAAKumM,oBAAoBvrL,EAAQvE,KAAKsoG,IAC3CglF,EAAUhlF,GAAMA,EAAG12G,KAAK,UACxBZ,EAASs8L,GAAWA,EAAQruL,KAAK,UAEnCjO,IAAW47L,GAAQa,WACnBlkM,KAAKyjM,gBAAkBzjM,KAAKwkM,sBAAsBzvE,EAAS,CACvDuX,aAAa,EACbk3D,cAAc,KAMlBxjM,KAAKyjM,iBACLzjM,KAAKyjM,gBAAgBK,eAAeC,GAKpCt8L,IAAW47L,GAAQlpH,kBAChB1yE,IAAW47L,GAAQmD,aACnB/+L,IAAW47L,GAAQe,WACtBpkM,KAAKymM,uBAebrkM,MAAM2yH,GAA2B,IAAlB1iB,EAAkB,uDAAJ,GACzBryG,KAAKyjM,gBAAkBzjM,KAAKwkM,sBAAsBzvE,EAAS,CACvDuX,aAAa,EACbk3D,cAAc,IAGlBxjM,KAAKyjM,gBAAgBrhM,MAAMiwG,GAQ/BtvG,OACQ/C,KAAKyjM,iBACLzjM,KAAKyjM,gBAAgB1gM,OAGzB/C,KAAKyjM,gBAAkB,KAW3B8C,oBAAoBzxL,GAChB,IACI,MAAM4xL,GAAS,IAAI9zL,WAAYmB,gBAAgBe,EAAK,YAEpD,OAAOypD,IAAAA,CAAEmoI,GACX,MAAO35L,GAGL,OAFAxI,GAAOlD,MAAM,kDAEN,MAefmjM,sBAAsBzvE,GAAuB,IAAdh1H,EAAc,uDAAJ,GACrC,IAAKg1H,EACD,MAAM,IAAI/wH,MAAM,mDAGpB,MAAMkrI,EAAY,CACd7C,SAAUrsI,KAAKwgH,SAAS6rB,SACxBjY,QAASp0H,KAAKsmM,cACdzB,eAAgB7kM,KAAK2jM,gBACrBmB,cAAe9kM,KAAK4jM,eACpB7uE,QAAAA,KACGh1H,GAGP,OAAO,IAAIujM,GAAkBp0D,GAiBjCo3D,cAAcvxE,EAASsgE,GAAyB,IAAdv1C,EAAc,uDAAJ,GACxCv7I,GAAOlD,MACH,oCAAqC0zH,EAASsgE,EAAWv1C,GAE7D,MAAM/gC,GAAKC,EAAAA,GAAAA,KAAI,CACXC,GAAI8V,EACJntH,KAAM,QAELuF,EAAE,SAAU,CACTiH,MAAO,oBACP3M,OAAQ4tL,IAEXloL,EAAE,WACFnI,EAAE86I,GACF/6B,KAEL/kH,KAAK4jM,eAAe7uE,EAAShW,GAEzB/+G,KAAKyjM,iBACFzjM,KAAKyjM,gBAAgBI,eAAiB9uE,GACzC/0H,KAAKymM,uBAeb9C,gBAAgBiB,GACZ,IAAK5kM,KAAKwgH,SAASqkF,eAIf,OAHAtgM,GAAOlD,MAAM,gDACbujM,EAAiBt6G,UAKrB,MAAMq8G,EAAU/B,EAAiBp/F,eACjC,IAAIC,EAEAkhG,IACAlhG,EAAYzlG,KAAKwgH,SAASomF,sBACpB9pK,GAAU,UAAVA,QAAoBA,GAAU,UAAVA,QAK9B,MAAMqxH,EAAcy2C,EAAiBh1C,oBAC/Bi3C,EAAmB9+B,GAAI++B,kBACzB,CACI,CACIz8C,SACK,SAAQrqJ,KAAKyjM,gBAAgBI,eAClC5gH,UAAW0jH,EAAU7xG,GAAU2G,MAAQ3G,GAAUqH,MACjD0+B,WAAY,QACZzqH,OAAQ+9I,EACRh2E,MAAOg2E,EAAYvE,iBAAiB,GACpCnkD,UAAAA,KAIZzlG,KAAKwgH,SAASqkF,eAAegC,EAAiB,IAWlDjD,eAAe7uE,EAAShW,GACpB,GAAK/+G,KAAKwgH,SAASskF,cAInB,IACI,MAAMiC,GACA,IAAI3uL,eAAgBoH,kBAAkBu/F,EAAG0xE,UAAY1xE,GAE3D/+G,KAAKwgH,SAASskF,cAAc/vE,EAAS,CAAEhW,GAAIgoF,IAC7C,MAAOh6L,GACLxI,GAAOlD,MAAM,mDAUrBolM,uBACIzmM,KAAK+C,OAEL/C,KAAKwgH,SAASwmF,oBACPhnM,KAAKwgH,SAASwmF,uBG3MzBC,UAAW,CACPv7F,4BAA6BvE,GAC7B+/F,UCxHR,CACI7lM,MAAO,CACH8lM,KAAM,OACNvlM,MAAO,QACPwlM,oBAAqB,sBACrBC,mBAAoB,qBACpBC,oBAAqB,uBAEzBvgD,KAAM,CACFwgD,KAAM,OACNC,OAAQ,UAEZv4G,OAAQ,CACJo1B,IAAK,MACLD,GAAI,KACJ4nB,QAAS,YD0GTy7D,WAAYzX,EACZ/gE,oBAAqB9K,EACrBi7C,qBAAsBjB,IAE1BhzH,OAAQ,CACJuzD,WAAYxjB,EACZ4nB,WAAYiM,EACZ24F,UAAWzxB,EACX99F,MAAOipB,EACP7Z,aAAckuG,EACdhiB,kBAAmB3D,EACnBiM,QAASL,GAEbisB,OAAQ,CACJjpG,WAAY7kB,EACZipB,WAAYqM,EACZh3B,MAAOqH,GAEXooH,WAAY,CACRtnH,gBAAeA,IAEnBunH,UAAWjoM,IAAAA,OACX2nF,aAAcugH,GACdtqG,UAAWf,GAAWe,UACtB5zD,OAAmB,IAAd7pC,EAAc,uDAAJ,GAuBX,GAtBAsqH,GAASzgF,KAAK7pC,EAAQ0pH,iBACtBhtB,GAAW7yD,KAAK7pC,GAGhBs3H,GAAAA,KAAkBt3H,EAAQuqC,OAAS,IAI9BhoC,OAAOsgG,kBACRtgG,OAAOsgG,gBAAkB,KAGU,IAAnC7iG,EAAQgoM,yBACRxjM,GAAO2T,KAAK,kCACZlY,KAAKw9F,UAAUlT,WAGfvqF,EAAQioM,4BACRxvK,KAAAA,WACIx4B,KAAKioM,wBAAwBrnM,KAAKZ,OAGtCA,KAAKiR,QAAS,CACd,MAAMizF,EAAY,CACd7+F,GAAI,oBACJ0K,UAAW,iBACXkB,QAASjR,KAAKiR,SAGlBwrF,GAAW0D,QAAQ/+F,KAAKF,UAAUgjG,IAGtC,OAAO6jE,GAAIn+H,KAAK7pC,IAQpBsuJ,wBAAuB,IACZ0Z,GAAI1Z,0BAWf65C,kBAAiB,IACNngC,GAAImgC,oBAGf7hM,YAAY7B,GACR5E,IAAAA,YAAmB4E,IAWvB4B,gBAAgB5B,EAAOa,GACnBzF,IAAAA,gBAAuB4E,EAAOa,IASlC8iM,sBAAsBC,GAClBxoM,IAAAA,mBAA0BwoM,IAS9BC,yBAAyBD,GACrBxoM,IAAAA,sBAA6BwoM,IAUjCE,oBAAoBvoM,GAChBH,IAAAA,iBAAwBG,IAyC5B+mM,oBAAqE,IAAnD/mM,EAAmD,uDAAzC,GAAIwoM,EAAqC,uCAC7DC,GAAmB,EAEvB,MAAM,iCAAEC,EAAF,qBAAoCC,KAAyBC,GAAgB5oM,EAqBnF,OApB6B0oM,IAAoCF,GAEpCxgC,GAAIvZ,2CAItBk6C,GACPpmM,OAAOE,YAAW,KACTgmM,GACDV,GAAAA,UAA4BrS,MA7PR,KAuP5BqS,GAAAA,UACIrS,GACAlwJ,GAAQ2gD,WASX5jF,OAAOsgG,kBACRtgG,OAAOsgG,gBAAkB,IAE7BtgG,OAAOsgG,gBAAgB,2BACjBtgG,OAAOijG,YAAYt4C,MAElB86G,GAAItb,+BAA+Bk8C,GACrC/nJ,MAAK6mH,IAWF,GAVA+gC,GAAmB,EAEnBlmM,OAAOsgG,gBAAgB,yBACjBtgG,OAAOijG,YAAYt4C,MAEzBwvC,GAAWoE,cACPhe,GACI,UACAojH,GAAkC0C,MAErC5gC,GAAIhoK,QAAQs9F,mBACb,IAAK,IAAI77F,EAAI,EAAGA,EAAIimK,EAAO/lK,OAAQF,IAAK,CACpC,MAAM22E,EAAQsvF,EAAOjmK,GACfonM,EAAUzwH,EAAMy3E,oBAElBz3E,EAAMgpB,YAAcrM,GAAUqH,QAC9BM,GAAWqB,gBAAgB8qG,EACvBzwH,EAAMwuB,cAAc/lG,KAAKu3E,IAC7BA,EAAM9rC,iBACF+0D,IACA,KACI3E,GAAWyC,eAAe0pG,OAO9C,MAAMC,EACA9gC,GAAIxZ,oCAEV,GAAIs6C,EACA,IAAK,IAAIrnM,EAAI,EAAGA,EAAIimK,EAAO/lK,OAAQF,IACjBimK,EAAOjmK,GAEfwwJ,+BACF62C,GAMZ,IAAK,MAAM1wH,KAASsvF,EACZtvF,EAAMvwE,OAASktF,GAAU2G,OACF,YAApBtjB,EAAMstB,WACTzlG,KAAK8oM,0BAA0B3wH,EAAMA,MAAO,UAIpD,OAAOsvF,KAEVzjH,OAAM3iD,IAGH,GAFAmnM,GAAmB,EAEfnnM,EAAMmL,OAASgzE,GAA8C,CAI7D,MAAM0kB,EAAY,CACd7+F,GAAI,8BACJ2V,QAAS3Z,EAAM2Z,SAGnByhF,GAAW0D,QAAQ/+F,KAAKF,UAAUgjG,IAElCzH,GAAWoE,cACPhe,GACI,UACA,CACItqD,OAAQ,0CAEjB,GAAIl3B,EAAMmL,OAASgzE,GAA4B,CAElD,MAAM0kB,EAAY,CACd7+F,GAAI,2BACJ4pF,OAAQ5tF,EAAMm/E,IAAID,SAGtBkc,GAAW0D,QAAQ/+F,KAAKF,UAAUgjG,IAElC,MAAMrkF,EACAomL,GAAkClmM,GAExC8f,EAAW0Y,OAAS,mBACpB1Y,EAAW0gE,QAAUl/E,EAAMm/E,IAAID,QAAQh3E,KAAK,KAC5CkzF,GAAWoE,cACPhe,GAAwB,QAAShjE,QAClC,CAEH48E,GAAWwD,uBAAuB5+F,GAElC,MAAMwe,EACAomL,GAAkClmM,GAExC8f,EAAW0Y,OAASl3B,EAAMmL,KAC1BiwF,GAAWoE,cACPhe,GAAwB,QAAShjE,IAMzC,OAHAvd,OAAOsgG,gBAAgB,yBACjBtgG,OAAOijG,YAAYt4C,MAElBljB,QAAQE,OAAO5oC,OAoBlC0nM,sBAAqB,CAACC,EAAoBlxB,EAAYP,IAC3CF,GAAgBz4I,OAAOoqK,EAAoBlxB,EAAYP,GASlE0xB,iBAAgB,IACL,IAAIxD,GAQfyD,qBAAoB,INjbb,IAAIn/J,SAAQC,IACf+9H,GAAIlc,kBAAiBtrE,IACjB,MAAM4oH,EAAe5oH,EAAQx5E,QAAOqjJ,GAA0B,eAAhBA,EAAO7zE,OAC/C6yH,EAAqB,GAG3B,IAAK,MAAMC,KAAaF,EAAc,CAClC,MAAMG,EAAgBvhC,GAAItb,+BAA+B,CAAElsE,QAAS,CAAE,SAClE6sE,YAAai8C,EAAUh/C,WAAYzpG,MAAK6mH,IAIxC,MAAMtvF,EAAQsvF,EAAO,GACfyjB,EAAiB/yG,EAAMy3E,oBAO7B,OALAnzD,GAAWqB,gBAAgBotF,EAAgB/yG,EAAMwuB,cAAc/lG,KAAKu3E,IACpEA,EAAM9rC,iBAAiB+0D,IAAsC,KACzD3E,GAAWyC,eAAegsF,MAGvB/yG,KAGXixH,EAAmBlnM,KAAKonM,GAG5Bv/J,QAAQyqE,WAAW40F,GAAoBxoJ,MAAK2oJ,IACxC,MAAMC,EAAqBD,EAAaxiM,QAAOiG,GAAkB,cAAbA,EAAEiiF,SAChDw6G,EAAmBF,EAAaxiM,QAAOiG,GAAkB,aAAbA,EAAEiiF,SAG9Co6D,EAAmBmgD,EAAmBtiM,KAAI8F,GAAKA,EAAE7F,QACjDuiM,EAAgBD,EAAiBviM,KAAI8F,GAAKA,EAAE7F,QAElD,IAAK,MAAMoxB,KAAUmxK,EACjBnlM,GAAOlD,MAAM,8CAA+Ck3B,GAIhE,IAAK,MAAM6xH,KAAUf,EACjBe,EAAO7/G,GAAG62D,IAA4C7P,IAK9CA,EAAa,OACb6xG,GAAkB/5C,GAClBr/G,EAAQ,CAAEqgH,SAAUD,EAAOC,SACvBs/C,YAAav/C,EAAOjyE,MAAMoyE,YAM1C/nJ,YAAW,KACP4gM,GAAkB/5C,GAClBr/G,EAAQ,CACJqgH,SAAU,GACVs/C,YAAa,OApEX,cMuctB/9C,wBAII,OAHArnJ,GAAO2T,KAAK,yFAGLlY,KAAKunF,aAAaqkE,yBAY7BN,wBAAwB4C,GAIpB,OAHA3pJ,GAAO2T,KAAK,2FAGLlY,KAAKunF,aAAa+jE,wBAAwB4C,IAUrDg1C,gCACI,OAAOljM,KAAKunF,aAAa27G,iCAQ7B0G,uBAAsB,IACXntG,GAAWW,oBACXjM,GAAoBY,wBAS/B85D,iBAAiBjvI,GACbrY,GAAO2T,KAAK,oFAEZlY,KAAKunF,aAAaskE,iBAAiBjvI,IAWvCqrL,wBAAwBjtL,EAAS3O,EAAQw9L,EAAQC,EAAOzoM,GACpDkD,GAAOlD,MACF,mBAAkB2Z,IAClB,WAAU3O,IACV,SAAQw9L,IACR,WAAUC,IACX,eAAgBzoM,GACpBo7F,GAAWiE,kBAAkBr/F,IASjC0oM,eAAe,GAAc,IAAd,SAAEruF,GAAY,EACzBW,GAAAA,kBAA8B,CAAEX,SAAAA,KAUpCotF,0BAA0B3wH,EAAO6xH,GACzB,gBAAiB7xH,GACjBA,EAAM8xH,YAAcD,EAChB7xH,EAAM8xH,cAAgBD,GACtBzlM,GAAOynF,MAAM,oCAGjBznF,GAAOynF,MAAM,yDAIrBk+G,YAjdoC,GAydpCC,KAAM,CACFC,SADE,KAEF3wK,WAFE,KAGF8L,QAAOA,4BE/jBN,SAAWhmC,GAAW,aAEnB,IAAI8qM,OAA6B,IAAX,EAAAtrI,EAAyB,EAAAA,EAAyB,oBAATp/D,KAAuBA,KAAyB,oBAAX2C,OAAyBA,OAAS,GAwCtI,MAAMi/G,EAdN,WACE,IAAI+oF,EAA0BD,EAAS9oF,UAEvC,QAAuC,IAA5B+oF,EACT,IACEA,EAA0B,EAAQ,IAClC,MAAO7hK,GACP,MAAM,IAAIzkC,MAAM,+DAIpB,OAAOsmM,EAGSC,GA4BlB,MAAM33L,EAdN,WACE,IAAI43L,EAA0BH,EAASz3L,UAEvC,QAAuC,IAA5B43L,EACT,IACEA,EAA0B,iBAC1B,MAAO/hK,GACP,MAAM,IAAIzkC,MAAM,2EAIpB,OAAOwmM,EAGSC,GAiClB,SAASC,IAEP,GAAwB,oBAAbzwK,SACT,IAGE,OAAO,IAAIxnB,EAFe,WAEKuC,eAAe,gBAAiB,UAAW,MAC1E,MAAOyzB,GACP,MAAM,IAAIzkC,MAAM,2EAKpB,QAA+C+H,IAA3CkuB,SAASpiB,eAAe7C,gBAAgCilB,SAASpiB,eAAe7C,gBAAkBilB,SAAS0wK,cAAgB1wK,SAAS0wK,aAAe,GAAI,CACzJ,MAAM72L,EArCV,WACE,MAAM82L,EAAa,CAAC,yBAA0B,yBAA0B,yBAA0B,yBAA0B,qBAAsB,oBAAqB,oBAEvK,IAAK,IAAI5wK,EAAI,EAAGA,EAAI4wK,EAAWlpM,OAAQs4B,IACrC,IAGE,OADY,IAAI6wK,cAAcD,EAAW5wK,IAEzC,MAAOjtB,KA6BG+9L,GAGZ,OADAh3L,EAAID,YAAYC,EAAImP,cAAc,YAC3BnP,EAIT,OAAOmmB,SAASpiB,eAAe7C,eAAe,gBAAiB,UAAW,MAoB5E,MAAM+1L,EAAa,SAAUr6L,EAAGs6L,GAC9B,MAAMC,GAAW,MAAJv6L,IAAmB,MAAJs6L,GAE5B,OADat6L,GAAK,KAAOs6L,GAAK,KAAOC,GAAO,KAC9B,GAAW,MAANA,GAefC,EAAW,SAAUv9L,GACzB,GAAmB,iBAARA,EACT,MAAM,IAAI3J,MAAM,oCAGlB,MAAMmnM,EAAM,GAEZ,IAAK,IAAI3pM,EAAI,EAAGA,EAAiB,EAAbmM,EAAIjM,OAAYF,GAAK,EACvC2pM,EAAI3pM,GAAK,KAA+B,IAAxBmM,EAAI+O,WAAWlb,EAAI,KAAaA,EAAI,GAGtD,OAAO2pM,GAoCHC,EAAU,SAAUziE,EAAGt7H,EAAGD,EAAGsD,EAAG7D,EAAG7H,GACvC,OAAO+lM,GAxDiBzsK,EAwDEysK,EAAWA,EAAW19L,EAAGs7H,GAAIoiE,EAAWr6L,EAAG1L,OAxDxCqmM,EAwD6Cx+L,GAvDtDyxB,IAAQ,GAAK+sK,EAuD6Cj+L,GAxDhE,IAAUkxB,EAAK+sK,GA2DzBC,EAAS,SAAUj+L,EAAGD,EAAGD,EAAG6sB,EAAGtpB,EAAG7D,EAAG7H,GACzC,OAAOomM,EAAQh+L,EAAID,GAAKC,EAAI4sB,EAAG3sB,EAAGD,EAAGsD,EAAG7D,EAAG7H,IAGvCumM,EAAS,SAAUl+L,EAAGD,EAAGD,EAAG6sB,EAAGtpB,EAAG7D,EAAG7H,GACzC,OAAOomM,EAAQh+L,EAAI4sB,EAAI7sB,GAAK6sB,EAAG3sB,EAAGD,EAAGsD,EAAG7D,EAAG7H,IAGvCwmM,EAAS,SAAUn+L,EAAGD,EAAGD,EAAG6sB,EAAGtpB,EAAG7D,EAAG7H,GACzC,OAAOomM,EAAQh+L,EAAID,EAAI6sB,EAAG3sB,EAAGD,EAAGsD,EAAG7D,EAAG7H,IAGlCymM,EAAS,SAAUp+L,EAAGD,EAAGD,EAAG6sB,EAAGtpB,EAAG7D,EAAG7H,GACzC,OAAOomM,EAAQj+L,GAAKC,GAAK4sB,GAAI3sB,EAAGD,EAAGsD,EAAG7D,EAAG7H,IAOrC0mM,EAAW,SAAUh7L,EAAGjP,GAE5BiP,EAAEjP,GAAO,IAAM,KAAQA,EAAM,GAC7BiP,EAA0B,IAAvBjP,EAAM,KAAO,GAAK,IAAWA,EAChC,IAIIkqM,EAAMC,EAAMC,EAAMC,EAJlBz+L,EAAI,WACJD,GAAK,UACLD,GAAK,WACL6sB,EAAI,UAGR,IAAK,IAAIx4B,EAAI,EAAGA,EAAIkP,EAAEhP,OAAQF,GAAK,GACjCmqM,EAAOt+L,EACPu+L,EAAOx+L,EACPy+L,EAAO1+L,EACP2+L,EAAO9xK,EACP3sB,EAAIi+L,EAAOj+L,EAAGD,EAAGD,EAAG6sB,EAAGtpB,EAAElP,EAAI,GAAI,GAAI,WACrCw4B,EAAIsxK,EAAOtxK,EAAG3sB,EAAGD,EAAGD,EAAGuD,EAAElP,EAAI,GAAI,IAAK,WACtC2L,EAAIm+L,EAAOn+L,EAAG6sB,EAAG3sB,EAAGD,EAAGsD,EAAElP,EAAI,GAAI,GAAI,WACrC4L,EAAIk+L,EAAOl+L,EAAGD,EAAG6sB,EAAG3sB,EAAGqD,EAAElP,EAAI,GAAI,IAAK,YACtC6L,EAAIi+L,EAAOj+L,EAAGD,EAAGD,EAAG6sB,EAAGtpB,EAAElP,EAAI,GAAI,GAAI,WACrCw4B,EAAIsxK,EAAOtxK,EAAG3sB,EAAGD,EAAGD,EAAGuD,EAAElP,EAAI,GAAI,GAAI,YACrC2L,EAAIm+L,EAAOn+L,EAAG6sB,EAAG3sB,EAAGD,EAAGsD,EAAElP,EAAI,GAAI,IAAK,YACtC4L,EAAIk+L,EAAOl+L,EAAGD,EAAG6sB,EAAG3sB,EAAGqD,EAAElP,EAAI,GAAI,IAAK,UACtC6L,EAAIi+L,EAAOj+L,EAAGD,EAAGD,EAAG6sB,EAAGtpB,EAAElP,EAAI,GAAI,EAAG,YACpCw4B,EAAIsxK,EAAOtxK,EAAG3sB,EAAGD,EAAGD,EAAGuD,EAAElP,EAAI,GAAI,IAAK,YACtC2L,EAAIm+L,EAAOn+L,EAAG6sB,EAAG3sB,EAAGD,EAAGsD,EAAElP,EAAI,IAAK,IAAK,OACvC4L,EAAIk+L,EAAOl+L,EAAGD,EAAG6sB,EAAG3sB,EAAGqD,EAAElP,EAAI,IAAK,IAAK,YACvC6L,EAAIi+L,EAAOj+L,EAAGD,EAAGD,EAAG6sB,EAAGtpB,EAAElP,EAAI,IAAK,EAAG,YACrCw4B,EAAIsxK,EAAOtxK,EAAG3sB,EAAGD,EAAGD,EAAGuD,EAAElP,EAAI,IAAK,IAAK,UACvC2L,EAAIm+L,EAAOn+L,EAAG6sB,EAAG3sB,EAAGD,EAAGsD,EAAElP,EAAI,IAAK,IAAK,YACvC4L,EAAIk+L,EAAOl+L,EAAGD,EAAG6sB,EAAG3sB,EAAGqD,EAAElP,EAAI,IAAK,GAAI,YACtC6L,EAAIk+L,EAAOl+L,EAAGD,EAAGD,EAAG6sB,EAAGtpB,EAAElP,EAAI,GAAI,GAAI,WACrCw4B,EAAIuxK,EAAOvxK,EAAG3sB,EAAGD,EAAGD,EAAGuD,EAAElP,EAAI,GAAI,GAAI,YACrC2L,EAAIo+L,EAAOp+L,EAAG6sB,EAAG3sB,EAAGD,EAAGsD,EAAElP,EAAI,IAAK,GAAI,WACtC4L,EAAIm+L,EAAOn+L,EAAGD,EAAG6sB,EAAG3sB,EAAGqD,EAAElP,EAAI,GAAI,IAAK,WACtC6L,EAAIk+L,EAAOl+L,EAAGD,EAAGD,EAAG6sB,EAAGtpB,EAAElP,EAAI,GAAI,GAAI,WACrCw4B,EAAIuxK,EAAOvxK,EAAG3sB,EAAGD,EAAGD,EAAGuD,EAAElP,EAAI,IAAK,EAAG,UACrC2L,EAAIo+L,EAAOp+L,EAAG6sB,EAAG3sB,EAAGD,EAAGsD,EAAElP,EAAI,IAAK,IAAK,WACvC4L,EAAIm+L,EAAOn+L,EAAGD,EAAG6sB,EAAG3sB,EAAGqD,EAAElP,EAAI,GAAI,IAAK,WACtC6L,EAAIk+L,EAAOl+L,EAAGD,EAAGD,EAAG6sB,EAAGtpB,EAAElP,EAAI,GAAI,EAAG,WACpCw4B,EAAIuxK,EAAOvxK,EAAG3sB,EAAGD,EAAGD,EAAGuD,EAAElP,EAAI,IAAK,GAAI,YACtC2L,EAAIo+L,EAAOp+L,EAAG6sB,EAAG3sB,EAAGD,EAAGsD,EAAElP,EAAI,GAAI,IAAK,WACtC4L,EAAIm+L,EAAOn+L,EAAGD,EAAG6sB,EAAG3sB,EAAGqD,EAAElP,EAAI,GAAI,GAAI,YACrC6L,EAAIk+L,EAAOl+L,EAAGD,EAAGD,EAAG6sB,EAAGtpB,EAAElP,EAAI,IAAK,GAAI,YACtCw4B,EAAIuxK,EAAOvxK,EAAG3sB,EAAGD,EAAGD,EAAGuD,EAAElP,EAAI,GAAI,GAAI,UACrC2L,EAAIo+L,EAAOp+L,EAAG6sB,EAAG3sB,EAAGD,EAAGsD,EAAElP,EAAI,GAAI,GAAI,YACrC4L,EAAIm+L,EAAOn+L,EAAGD,EAAG6sB,EAAG3sB,EAAGqD,EAAElP,EAAI,IAAK,IAAK,YACvC6L,EAAIm+L,EAAOn+L,EAAGD,EAAGD,EAAG6sB,EAAGtpB,EAAElP,EAAI,GAAI,GAAI,QACrCw4B,EAAIwxK,EAAOxxK,EAAG3sB,EAAGD,EAAGD,EAAGuD,EAAElP,EAAI,GAAI,IAAK,YACtC2L,EAAIq+L,EAAOr+L,EAAG6sB,EAAG3sB,EAAGD,EAAGsD,EAAElP,EAAI,IAAK,GAAI,YACtC4L,EAAIo+L,EAAOp+L,EAAGD,EAAG6sB,EAAG3sB,EAAGqD,EAAElP,EAAI,IAAK,IAAK,UACvC6L,EAAIm+L,EAAOn+L,EAAGD,EAAGD,EAAG6sB,EAAGtpB,EAAElP,EAAI,GAAI,GAAI,YACrCw4B,EAAIwxK,EAAOxxK,EAAG3sB,EAAGD,EAAGD,EAAGuD,EAAElP,EAAI,GAAI,GAAI,YACrC2L,EAAIq+L,EAAOr+L,EAAG6sB,EAAG3sB,EAAGD,EAAGsD,EAAElP,EAAI,GAAI,IAAK,WACtC4L,EAAIo+L,EAAOp+L,EAAGD,EAAG6sB,EAAG3sB,EAAGqD,EAAElP,EAAI,IAAK,IAAK,YACvC6L,EAAIm+L,EAAOn+L,EAAGD,EAAGD,EAAG6sB,EAAGtpB,EAAElP,EAAI,IAAK,EAAG,WACrCw4B,EAAIwxK,EAAOxxK,EAAG3sB,EAAGD,EAAGD,EAAGuD,EAAElP,EAAI,GAAI,IAAK,WACtC2L,EAAIq+L,EAAOr+L,EAAG6sB,EAAG3sB,EAAGD,EAAGsD,EAAElP,EAAI,GAAI,IAAK,WACtC4L,EAAIo+L,EAAOp+L,EAAGD,EAAG6sB,EAAG3sB,EAAGqD,EAAElP,EAAI,GAAI,GAAI,UACrC6L,EAAIm+L,EAAOn+L,EAAGD,EAAGD,EAAG6sB,EAAGtpB,EAAElP,EAAI,GAAI,GAAI,WACrCw4B,EAAIwxK,EAAOxxK,EAAG3sB,EAAGD,EAAGD,EAAGuD,EAAElP,EAAI,IAAK,IAAK,WACvC2L,EAAIq+L,EAAOr+L,EAAG6sB,EAAG3sB,EAAGD,EAAGsD,EAAElP,EAAI,IAAK,GAAI,WACtC4L,EAAIo+L,EAAOp+L,EAAGD,EAAG6sB,EAAG3sB,EAAGqD,EAAElP,EAAI,GAAI,IAAK,WACtC6L,EAAIo+L,EAAOp+L,EAAGD,EAAGD,EAAG6sB,EAAGtpB,EAAElP,EAAI,GAAI,GAAI,WACrCw4B,EAAIyxK,EAAOzxK,EAAG3sB,EAAGD,EAAGD,EAAGuD,EAAElP,EAAI,GAAI,GAAI,YACrC2L,EAAIs+L,EAAOt+L,EAAG6sB,EAAG3sB,EAAGD,EAAGsD,EAAElP,EAAI,IAAK,IAAK,YACvC4L,EAAIq+L,EAAOr+L,EAAGD,EAAG6sB,EAAG3sB,EAAGqD,EAAElP,EAAI,GAAI,IAAK,UACtC6L,EAAIo+L,EAAOp+L,EAAGD,EAAGD,EAAG6sB,EAAGtpB,EAAElP,EAAI,IAAK,EAAG,YACrCw4B,EAAIyxK,EAAOzxK,EAAG3sB,EAAGD,EAAGD,EAAGuD,EAAElP,EAAI,GAAI,IAAK,YACtC2L,EAAIs+L,EAAOt+L,EAAG6sB,EAAG3sB,EAAGD,EAAGsD,EAAElP,EAAI,IAAK,IAAK,SACvC4L,EAAIq+L,EAAOr+L,EAAGD,EAAG6sB,EAAG3sB,EAAGqD,EAAElP,EAAI,GAAI,IAAK,YACtC6L,EAAIo+L,EAAOp+L,EAAGD,EAAGD,EAAG6sB,EAAGtpB,EAAElP,EAAI,GAAI,EAAG,YACpCw4B,EAAIyxK,EAAOzxK,EAAG3sB,EAAGD,EAAGD,EAAGuD,EAAElP,EAAI,IAAK,IAAK,UACvC2L,EAAIs+L,EAAOt+L,EAAG6sB,EAAG3sB,EAAGD,EAAGsD,EAAElP,EAAI,GAAI,IAAK,YACtC4L,EAAIq+L,EAAOr+L,EAAGD,EAAG6sB,EAAG3sB,EAAGqD,EAAElP,EAAI,IAAK,GAAI,YACtC6L,EAAIo+L,EAAOp+L,EAAGD,EAAGD,EAAG6sB,EAAGtpB,EAAElP,EAAI,GAAI,GAAI,WACrCw4B,EAAIyxK,EAAOzxK,EAAG3sB,EAAGD,EAAGD,EAAGuD,EAAElP,EAAI,IAAK,IAAK,YACvC2L,EAAIs+L,EAAOt+L,EAAG6sB,EAAG3sB,EAAGD,EAAGsD,EAAElP,EAAI,GAAI,GAAI,WACrC4L,EAAIq+L,EAAOr+L,EAAGD,EAAG6sB,EAAG3sB,EAAGqD,EAAElP,EAAI,GAAI,IAAK,WACtC6L,EAAI09L,EAAW19L,EAAGs+L,GAClBv+L,EAAI29L,EAAW39L,EAAGw+L,GAClBz+L,EAAI49L,EAAW59L,EAAG0+L,GAClB7xK,EAAI+wK,EAAW/wK,EAAG8xK,GAGpB,MAAO,CAACz+L,EAAGD,EAAGD,EAAG6sB,IASb+xK,EAAM,CACVC,UAAW,SAAUn/L,GACnB,OAvIa,SAAUo/L,GACzB,MAAMC,EAAU,mBAChB,IAAIv+L,EAAM,GAEV,IAAK,IAAInM,EAAI,EAAGA,EAAsB,EAAlByqM,EAASvqM,OAAYF,IACvCmM,GAAOu+L,EAAQp3K,OAAOm3K,EAASzqM,GAAK,IAAMA,EAAI,EAAI,EAAI,EAAI,IAAO0qM,EAAQp3K,OAAOm3K,EAASzqM,GAAK,IAAMA,EAAI,EAAI,EAAI,IAGlH,OAAOmM,EA+HEw+L,CAAST,EAASR,EAASr+L,GAAe,EAAXA,EAAEnL,UAE1Ci5B,KAAM,SAAU9tB,GACd,OAxJa,SAAUs+L,GACzB,IAAIx9L,EAAM,GAEV,IAAK,IAAInM,EAAI,EAAGA,EAAiB,GAAb2pM,EAAIzpM,OAAaF,GAAK,EACxCmM,GAAOkB,OAAO2nB,aAAa20K,EAAI3pM,GAAK,KAAOA,EAAI,GAAK,KAGtD,OAAOmM,EAiJEy+L,CAASV,EAASR,EAASr+L,GAAe,EAAXA,EAAEnL,WAuB5C,MAAM2qM,EAaJjzL,YAAY5M,EAAM8/L,EAAez6H,GAI/B7xE,KAAKusM,SAAW//L,EAKhBxM,KAAKssM,cAAgBA,EAarBtsM,KAAK6xE,SAAWA,EAsBlBtiE,OAEE,OAAO,EAUTi9L,QAAQ1pG,GACN9iG,KAAK2gL,YAAc79E,EAkBrB2pG,YAAY3pG,EAAY4pG,GAEtB,MAAM,IAAI1oM,MAAM,4CAclB2oM,gBAAgB7pG,GACd,IAAK9iG,KAAKssM,cACR,MAAM,IAAItoM,MAAM,mEAGlB,OAAOhE,KAAKysM,YAAY3pG,GAO1Bg2B,YACE94H,KAAK2gL,YAAc,KAOrBxsD,YACEn0H,KAAK2gL,YAAc,MAgDvB,MAAMisB,EACM,SAAUj/L,GAClB,IAAInM,EAAG2L,EACH0/L,EAAM,GACNprM,EAAMkM,EAAIjM,OAEd,IAAKF,EAAI,EAAGA,EAAIC,EAAKD,KACnB2L,EAAIQ,EAAI+O,WAAWlb,KAEV,GAAU2L,GAAK,IACtB0/L,GAAOl/L,EAAImnB,OAAOtzB,GACT2L,EAAI,MACb0/L,GAAOh+L,OAAO2nB,aAAa,IAAOrpB,GAAK,GAAK,IAC5C0/L,GAAOh+L,OAAO2nB,aAAa,IAAOrpB,GAAK,EAAI,IAC3C0/L,GAAOh+L,OAAO2nB,aAAa,IAAOrpB,GAAK,EAAI,MAE3C0/L,GAAOh+L,OAAO2nB,aAAa,IAAOrpB,GAAK,EAAI,IAC3C0/L,GAAOh+L,OAAO2nB,aAAa,IAAOrpB,GAAK,EAAI,KAI/C,OAAO0/L,GArBLD,EAuBQ,SAAUE,GAoBpBA,EAAUA,GAAW,GAErB,IAAK,MAAMC,KAAcD,EACvB,GAAI1sM,OAAOa,UAAUwX,eAAe7T,KAAKkoM,EAASC,GAAa,CAC7D,IAAIC,EAAU,GACVtrF,EAAS,GACTurF,EAAO,GACX,MAAMC,EAAYJ,EAAQC,GACpBI,EAA6B,iBAAdD,EACfE,EAAcr5J,OAAOs5J,SAASF,EAAQD,EAAU/lM,MAAQ+lM,IAE1DC,IACFH,EAAUE,EAAUF,QAAU,YAAcE,EAAUF,QAAU,GAChEtrF,EAASwrF,EAAUxrF,OAAS,WAAawrF,EAAUxrF,OAAS,GAC5DurF,EAAOC,EAAUD,KAAO,SAAWC,EAAUD,KAAO,IAGtDhzK,SAASqzK,OAASP,EAAa,IAAMK,EAAcJ,EAAUtrF,EAASurF,IA4F9E,SAASM,EAAU78L,EAAGjP,GAEpBiP,EAAEjP,GAAO,IAAM,KAAQ,GAAKA,EAAM,GAClCiP,EAAyB,IAAtBjP,EAAM,IAAM,GAAK,IAAWA,EAC/B,IAMID,EAAGwJ,EAAGhG,EAAG2mM,EAAMC,EAAMC,EAAMC,EAAM0B,EANjChiK,EAAI,IAAI9mC,MAAM,IACd2I,EAAI,WACJD,GAAK,UACLD,GAAK,WACL6sB,EAAI,UACJjtB,GAAK,WAGT,IAAKvL,EAAI,EAAGA,EAAIkP,EAAEhP,OAAQF,GAAK,GAAI,CAOjC,IANAmqM,EAAOt+L,EACPu+L,EAAOx+L,EACPy+L,EAAO1+L,EACP2+L,EAAO9xK,EACPwzK,EAAOzgM,EAEF/B,EAAI,EAAGA,EAAI,GAAIA,IAEhBwgC,EAAExgC,GADAA,EAAI,GACC0F,EAAElP,EAAIwJ,GAENyiM,EAAIjiK,EAAExgC,EAAI,GAAKwgC,EAAExgC,EAAI,GAAKwgC,EAAExgC,EAAI,IAAMwgC,EAAExgC,EAAI,IAAK,GAG1DhG,EAAI0oM,EAASA,EAASD,EAAIpgM,EAAG,GAAIsgM,EAAQ3iM,EAAGoC,EAAGD,EAAG6sB,IAAK0zK,EAASA,EAAS3gM,EAAGy+B,EAAExgC,IAAK4iM,EAAQ5iM,KAC3F+B,EAAIitB,EACJA,EAAI7sB,EACJA,EAAIsgM,EAAIrgM,EAAG,IACXA,EAAIC,EACJA,EAAIrI,EAGNqI,EAAIqgM,EAASrgM,EAAGs+L,GAChBv+L,EAAIsgM,EAAStgM,EAAGw+L,GAChBz+L,EAAIugM,EAASvgM,EAAG0+L,GAChB7xK,EAAI0zK,EAAS1zK,EAAG8xK,GAChB/+L,EAAI2gM,EAAS3gM,EAAGygM,GAGlB,MAAO,CAACngM,EAAGD,EAAGD,EAAG6sB,EAAGjtB,GAQtB,SAAS4gM,EAAQ3oM,EAAGoI,EAAGD,EAAG6sB,GACxB,OAAIh1B,EAAI,GACCoI,EAAID,GAAKC,EAAI4sB,EAGlBh1B,EAAI,GACCoI,EAAID,EAAI6sB,EAGbh1B,EAAI,GACCoI,EAAID,EAAIC,EAAI4sB,EAAI7sB,EAAI6sB,EAGtB5sB,EAAID,EAAI6sB,EAOjB,SAAS4zK,EAAQ5oM,GACf,OAAOA,EAAI,GAAK,WAAaA,EAAI,GAAK,WAAaA,EAAI,IAAM,YAAc,UAO7E,SAAS6oM,EAAe3/L,EAAKuI,GAC3B,IAAIq3L,EAAOC,EAAS7/L,GAEhB4/L,EAAKpsM,OAAS,KAChBosM,EAAOP,EAAUO,EAAmB,EAAb5/L,EAAIxM,SAM7B,IAHA,IAAIssM,EAAO,IAAItpM,MAAM,IACjBupM,EAAO,IAAIvpM,MAAM,IAEZlD,EAAI,EAAGA,EAAI,GAAIA,IACtBwsM,EAAKxsM,GAAe,UAAVssM,EAAKtsM,GACfysM,EAAKzsM,GAAe,WAAVssM,EAAKtsM,GAGjB,IAAIm5B,EAAO4yK,EAAUS,EAAKjpM,OAAOgpM,EAASt3L,IAAQ,IAAoB,EAAdA,EAAK/U,QAC7D,OAAO6rM,EAAUU,EAAKlpM,OAAO41B,GAAO,KAQtC,SAAS+yK,EAASh9L,EAAGs6L,GACnB,IAAIC,GAAW,MAAJv6L,IAAmB,MAAJs6L,GAE1B,OADWt6L,GAAK,KAAOs6L,GAAK,KAAOC,GAAO,KAC5B,GAAW,MAANA,EAOrB,SAASwC,EAAInvK,EAAK+sK,GAChB,OAAO/sK,GAAO+sK,EAAM/sK,IAAQ,GAAK+sK,EAQnC,SAAS0C,EAASpgM,GAIhB,IAHA,IAAIw9L,EAAM,GAGD3pM,EAAI,EAAGA,EAAiB,EAAbmM,EAAIjM,OAAYF,GAAK,EACvC2pM,EAAI3pM,GAAK,KAHA,IAGOmM,EAAI+O,WAAWlb,EAAI,KAAc,GAAKA,EAAI,GAG5D,OAAO2pM,EAOT,SAAS+C,EAASjC,GAKhB,IAJA,IAEIkC,EAASnjM,EADT2C,EAAM,GAGDnM,EAAI,EAAGA,EAAsB,EAAlByqM,EAASvqM,OAAYF,GAAK,EAG5C,IAFA2sM,GAAWlC,EAASzqM,GAAK,IAAM,GAAK,EAAIA,EAAI,GAAK,MAAS,IAAMyqM,EAASzqM,EAAI,GAAK,IAAM,GAAK,GAAKA,EAAI,GAAK,GAAK,MAAS,EAAIyqM,EAASzqM,EAAI,GAAK,IAAM,GAAK,GAAKA,EAAI,GAAK,GAAK,IAExKwJ,EAAI,EAAGA,EAAI,EAAGA,IACT,EAAJxJ,EAAY,EAAJwJ,EAA0B,GAAlBihM,EAASvqM,OAC3BiM,GAAO,IAEPA,GAXI,mEAWOmnB,OAAOq5K,GAAW,GAAK,EAAInjM,GAAK,IAKjD,OAAO2C,EAOT,SAASygM,EAASjD,GAIhB,IAHA,IAAIx9L,EAAM,GAGDnM,EAAI,EAAGA,EAAiB,GAAb2pM,EAAIzpM,OAAaF,GAAK,EACxCmM,GAAOkB,OAAO2nB,aAAa20K,EAAI3pM,GAAK,KAAO,GAAKA,EAAI,GAH3C,KAMX,OAAOmM,EAQT,MAAM0gM,EAAO,CACXC,cAAe,SAAUpgM,EAAKuI,GAC5B,OAAOy3L,EAASL,EAAe3/L,EAAKuI,KAEtC4kG,SAAU,SAAUxuG,GAClB,OAAOqhM,EAASX,EAAUQ,EAASlhM,GAAe,EAAXA,EAAEnL,UAE3C0sM,SAAUA,EACVP,eAAgBA,EAChBU,cAAe,SAAUrgM,EAAKuI,GAC5B,OAAO23L,EAASP,EAAe3/L,EAAKuI,KAEtC+3L,SAAU,SAAU3hM,GAClB,OAAOuhM,EAASb,EAAUQ,EAASlhM,GAAe,EAAXA,EAAEnL,WA4T7C,IAEI+sM,EAAO,CACTC,KAhMF,SAAgBj4L,GAsBd,IAjBAA,GAFAA,EAAO,GAAGA,KAEEhG,QAAQ,eAAgB,KAG3B/O,OAAS,GAAM,IACtB+U,EAAOA,EAAKhG,QAAQ,OAAQ,KAa1BgG,EAAK/U,OAAS,GAAM,GAAK,iBAAiB6N,KAAKkH,GACjD,OAAO,KAIT,IAAI8nB,EAAS,GAKTshC,EAAS,EACT8uI,EAAkB,EAKtB,IAAK,IAAIntM,EAAI,EAAGA,EAAIiV,EAAK/U,OAAQF,IAS/Bq+D,IAAW,EACXA,IAsCgB+uI,EAtCKn4L,EAAKjV,GAuCxB,QAAQ+N,KAAKq/L,GACRA,EAAIlyL,WAAW,GAAK,IAAIA,WAAW,GAGxC,QAAQnN,KAAKq/L,GACRA,EAAIlyL,WAAW,GAAK,IAAIA,WAAW,GAAK,GAG7C,QAAQnN,KAAKq/L,GACRA,EAAIlyL,WAAW,GAAK,IAAIA,WAAW,GAAK,GAGrC,MAARkyL,EACK,GAGG,MAARA,EACK,QADT,GAtDED,GAAmB,EAIK,KAApBA,IACFpwK,GAAU1vB,OAAO2nB,cAAuB,SAATqpC,IAAsB,IACrDthC,GAAU1vB,OAAO2nB,cAAuB,MAATqpC,IAAoB,GACnDthC,GAAU1vB,OAAO2nB,aAAsB,IAATqpC,GAC9BA,EAAS8uI,EAAkB,GA6BjC,IAAoBC,EARlB,OAVwB,KAApBD,GACF9uI,IAAW,EACXthC,GAAU1vB,OAAO2nB,aAAaqpC,IACD,KAApB8uI,IACT9uI,IAAW,EACXthC,GAAU1vB,OAAO2nB,cAAuB,MAATqpC,IAAoB,GACnDthC,GAAU1vB,OAAO2nB,aAAsB,IAATqpC,IAIzBthC,GAmHPswK,KA3EF,SAAgBhiM,GACd,IAAIrL,EAKJ,IAHAqL,EAAI,GAAGA,IAGFrL,EAAI,EAAGA,EAAIqL,EAAEnL,OAAQF,IACxB,GAAIqL,EAAE6P,WAAWlb,GAAK,IACpB,OAAO,KAIX,IAAIqrM,EAAM,GAEV,IAAKrrM,EAAI,EAAGA,EAAIqL,EAAEnL,OAAQF,GAAK,EAAG,CAChC,MAAMstM,EAAc,MAAC/iM,OAAWA,OAAWA,OAAWA,GACtD+iM,EAAY,GAAKjiM,EAAE6P,WAAWlb,IAAM,EACpCstM,EAAY,IAAwB,EAAlBjiM,EAAE6P,WAAWlb,KAAc,EAEzCqL,EAAEnL,OAASF,EAAI,IACjBstM,EAAY,IAAMjiM,EAAE6P,WAAWlb,EAAI,IAAM,EACzCstM,EAAY,IAA4B,GAAtBjiM,EAAE6P,WAAWlb,EAAI,KAAc,GAG/CqL,EAAEnL,OAASF,EAAI,IACjBstM,EAAY,IAAMjiM,EAAE6P,WAAWlb,EAAI,IAAM,EACzCstM,EAAY,GAA2B,GAAtBjiM,EAAE6P,WAAWlb,EAAI,IAGpC,IAAK,IAAIwJ,EAAI,EAAGA,EAAI8jM,EAAYptM,OAAQsJ,SACR,IAAnB8jM,EAAY9jM,GACrB6hM,GAAO,IAEPA,IAaY/yJ,EAbMg1J,EAAY9jM,IAc1B,GACD6D,OAAO2nB,aAAasjB,EAAM,IAAIp9B,WAAW,IAG9Co9B,EAAM,GACDjrC,OAAO2nB,aAAasjB,EAAM,GAAK,IAAIp9B,WAAW,IAGnDo9B,EAAM,GACDjrC,OAAO2nB,aAAasjB,EAAM,GAAK,IAAIp9B,WAAW,IAG3C,KAARo9B,EACK,IAGG,KAARA,EACK,SADT,EAjBF,IAAoBA,EARlB,OAAO+yJ,IA0DT,SAASz1E,EAAO5qH,EAAM8I,GACpB,OAAO,IAAIysF,EAAQgtG,QAAQviM,EAAM8I,GAYnC,SAASwvG,EAAKxvG,GACZ,OAAO,IAAIysF,EAAQgtG,QAAQ,UAAWz5L,GAYxC,SAAS0pG,EAAI1pG,GACX,OAAO,IAAIysF,EAAQgtG,QAAQ,KAAMz5L,GAYnC,SAASwuG,EAAMxuG,GACb,OAAO,IAAIysF,EAAQgtG,QAAQ,WAAYz5L,GAUzC,MAAMysF,EAAU,CAEditG,QAAS,QAqBTC,GAAI,CACFC,SAAU,sCACVC,KAAM,iBACNC,OAAQ,gBACRC,KAAM,iBACNC,OAAQ,mBACRC,QAAS,oBACTC,WAAY,wCACZC,YAAa,yCACbC,IAAK,iCACLC,KAAM,mCACNnI,OAAQ,mCACRoI,QAAS,sCACTC,KAAM,mCACNC,QAAS,sCACTd,QAAS,oBACTe,QAAS,sCACTC,SAAU,sCACVC,MAAO,gCASTA,MAAO,CACL1+E,KAAM,CAAC,IAAK,aAAc,KAAM,OAAQ,KAAM,MAAO,KAAM,KAAM,IAAK,OAAQ,SAAU,KAAM,QAC9F1xG,WAAY,CACV,EAAK,CAAC,QACN,WAAc,CAAC,SACf,GAAM,GACN,KAAQ,CAAC,SACT,GAAM,GACN,IAAO,CAAC,MAAO,MAAO,QAAS,SAAU,SACzC,GAAM,CAAC,SACP,GAAM,CAAC,SACP,EAAK,CAAC,SACN,KAAQ,CAAC,SACT,OAAU,GACV,GAAM,CAAC,SACP,KAAQ,IAEVknC,IAAK,CAAC,mBAAoB,QAAS,cAAe,YAAa,aAAc,cAAe,cAAe,eAAgB,aAAc,mBASzImpJ,SAASl5J,GACP,IAAK,IAAIx1C,EAAI,EAAGA,EAAIugG,EAAQkuG,MAAM1+E,KAAK7vH,OAAQF,IAC7C,GAAIw1C,IAAQ+qD,EAAQkuG,MAAM1+E,KAAK/vH,GAC7B,OAAO,EAIX,OAAO,GAUT2uM,eAAen5J,EAAK/vC,GAClB,QAA6C,IAAlC86F,EAAQkuG,MAAMpwL,WAAWm3B,IAAwB+qD,EAAQkuG,MAAMpwL,WAAWm3B,GAAKt1C,OAAS,EACjG,IAAK,IAAIF,EAAI,EAAGA,EAAIugG,EAAQkuG,MAAMpwL,WAAWm3B,GAAKt1C,OAAQF,IACxD,GAAIyF,IAAc86F,EAAQkuG,MAAMpwL,WAAWm3B,GAAKx1C,GAC9C,OAAO,EAKb,OAAO,GAGT4uM,SAASvpJ,GACP,IAAK,IAAIrlD,EAAI,EAAGA,EAAIugG,EAAQkuG,MAAMlpJ,IAAIrlD,OAAQF,IAC5C,GAAIqlD,IAAUk7C,EAAQkuG,MAAMlpJ,IAAIvlD,GAC9B,OAAO,EAIX,OAAO,IAqBXy+G,OAAQ,CACNr+G,MAAO,EACPyuM,WAAY,EACZC,SAAU,EACVC,eAAgB,EAChBC,SAAU,EACVlgF,UAAW,EACXmgF,aAAc,EACdC,cAAe,EACfC,SAAU,EACVC,SAAU,EACVC,YAAa,GACbC,aAAc,GACdC,WAAY,IAEdC,eAAgB,CACdC,WAAY,aACZC,SAAU,WACVC,iBAAkB,6BAClBC,aAAc,eACdC,eAAgB,WAYlBC,SAAU,CACR3rM,MAAO,EACPC,KAAM,EACNE,KAAM,EACNlE,MAAO,EACP2vM,MAAO,GAUTC,YAAa,CACXC,OAAQ,EACRC,KAAM,EACNC,MAAO,EACPC,SAAU,IAiBZ3xH,QAAS,IACT4xH,kBAAmB,GAcnBC,aAAatlM,EAAMrF,GACjB46F,EAAQktG,GAAGziM,GAAQrF,GAiBrB4qM,aAAa1iK,EAAM2iK,EAAUrwJ,GAC3B,IAAK,IAAIngD,EAAI,EAAGA,EAAI6tC,EAAKjyB,WAAW1b,OAAQF,IAAK,CAC/C,MAAMywM,EAAY5iK,EAAKjyB,WAAW5b,GAE9BywM,EAAUl0L,WAAagkF,EAAQyvG,YAAYC,QAAYO,IAAYhyM,KAAKkyM,WAAWD,EAAWD,IAChGrwJ,EAAKswJ,KAkBXC,WAAU,CAAC7gM,EAAI7E,IACN6E,EAAG6E,UAAY1J,EAOxB2lM,cAAe,KAQfC,aAAY,KACLrwG,EAAQowG,gBACXpwG,EAAQowG,cAAgBzH,KAGnB3oG,EAAQowG,eAqBjBzkF,WAAWlhH,GACT,IAAKA,EACH,OAAO,KAGT,MAAMyG,EAAO8uF,EAAQqwG,eAAenvL,cAAczW,GAGlD,IAAK,IAAIa,EAAI,EAAGA,EAAI1M,UAAUe,OAAQ2L,IAAK,CACzC,MAAM1L,EAAMhB,UAAU0M,GAEtB,GAAK1L,EAIL,GAAmB,iBAARA,GAAmC,iBAARA,EACpCsR,EAAKY,YAAYkuF,EAAQswG,YAAY1wM,SAChC,GAAmB,iBAARA,GAAwC,mBAAbA,EAAIkuC,KAC/C,IAAK,IAAIruC,EAAI,EAAGA,EAAIG,EAAID,OAAQF,IAAK,CACnC,MAAMkU,EAAO/T,EAAIH,GAEG,iBAATkU,GAA0C,mBAAdA,EAAKm6B,WAAmC9jC,IAAZ2J,EAAK,IAAgC,OAAZA,EAAK,IAC/FzC,EAAKwQ,aAAa/N,EAAK,GAAIA,EAAK,SAG/B,GAAmB,iBAAR/T,EAChB,IAAK,MAAM00B,KAAK10B,EACVvB,OAAOa,UAAUwX,eAAe7T,KAAKjD,EAAK00B,SAAiBtqB,IAAXpK,EAAI00B,IAA+B,OAAX10B,EAAI00B,IAC9EpjB,EAAKwQ,aAAa4S,EAAG10B,EAAI00B,IAMjC,OAAOpjB,GAYTq/L,UAAUtwM,IAIRA,GADAA,GADAA,GADAA,EAAOA,EAAKyO,QAAQ,MAAO,UACfA,QAAQ,KAAM,SACdA,QAAQ,KAAM,SACdA,QAAQ,KAAM,WACdA,QAAQ,KAAM,UAa5B8hM,YAAYvwM,IAIVA,GADAA,GADAA,GADAA,EAAOA,EAAKyO,QAAQ,UAAW,MACnBA,QAAQ,QAAS,MACjBA,QAAQ,QAAS,MACjBA,QAAQ,UAAW,MACnBA,QAAQ,UAAW,KAejC4hM,YAAYrwM,GACH+/F,EAAQqwG,eAAen7L,eAAejV,GAY/CwwM,YAAYpiJ,GACV,IAAIn9C,EAWJ,OATIL,EAEFK,GADe,IAAIL,GACLmB,gBAAgBq8C,EAAM,aAEpCn9C,EAAO,IAAI43L,cAAc,oBACzB53L,EAAK0mB,MAAQ,QACb1mB,EAAKw/L,QAAQriJ,IAGRn9C,GAYTk+B,QAAQ9B,GACN,IAAKA,EACH,OAAO,KAGT,IAAI1hC,EAAM,GAEqB,IAA3B0hC,EAAKjyB,WAAW1b,QAAgB2tC,EAAKtxB,WAAagkF,EAAQyvG,YAAYE,OACxE/jM,GAAO0hC,EAAKv5B,WAGd,IAAK,IAAItU,EAAI,EAAGA,EAAI6tC,EAAKjyB,WAAW1b,OAAQF,IACtC6tC,EAAKjyB,WAAW5b,GAAGuc,WAAagkF,EAAQyvG,YAAYE,OACtD/jM,GAAO0hC,EAAKjyB,WAAW5b,GAAGsU,WAI9B,OAAOisF,EAAQuwG,UAAU3kM,IAe3B+kM,YAAYrjK,GACV,IAAIh+B,EAEJ,GAAIg+B,EAAKtxB,WAAagkF,EAAQyvG,YAAYC,OAAQ,CAChDpgM,EAAK0wF,EAAQ2rB,WAAWr+E,EAAKn5B,SAE7B,IAAK,IAAI1U,EAAI,EAAGA,EAAI6tC,EAAKxvB,WAAWne,OAAQF,IAC1C6P,EAAGoS,aAAa4rB,EAAKxvB,WAAWre,GAAGse,SAAUuvB,EAAKxvB,WAAWre,GAAG2F,OAGlE,IAAK,IAAI3F,EAAI,EAAGA,EAAI6tC,EAAKjyB,WAAW1b,OAAQF,IAC1C6P,EAAGwC,YAAYkuF,EAAQ2wG,YAAYrjK,EAAKjyB,WAAW5b,UAE5C6tC,EAAKtxB,WAAagkF,EAAQyvG,YAAYE,OAC/CrgM,EAAK0wF,EAAQqwG,eAAen7L,eAAeo4B,EAAKv5B,YAGlD,OAAOzE,GAeTshM,WAAWtjK,GACT,IAAIh+B,EAEJ,GAAIg+B,EAAKtxB,WAAagkF,EAAQyvG,YAAYC,OAAQ,CAChD,MAAMz6J,EAAM3H,EAAKvvB,SAASqX,cAE1B,GAAI4qE,EAAQkuG,MAAMC,SAASl5J,GACzB,IACE3lC,EAAK0wF,EAAQ2rB,WAAW12E,GAExB,IAAK,IAAIx1C,EAAI,EAAGA,EAAIugG,EAAQkuG,MAAMpwL,WAAWm3B,GAAKt1C,OAAQF,IAAK,CAC7D,MAAMyF,EAAY86F,EAAQkuG,MAAMpwL,WAAWm3B,GAAKx1C,GAChD,IAAI2F,EAAQkoC,EAAK7sB,aAAavb,GAE9B,GAAI,MAAOE,GAAqD,KAAVA,IAA0B,IAAVA,GAA6B,IAAVA,EASzF,GALkB,UAAdF,GAA0C,iBAAVE,QAA+C,IAAlBA,EAAMsrD,UACrEtrD,EAAQA,EAAMsrD,SAIE,UAAdxrD,EAAuB,CACzB,MAAM8/C,EAAM,GACN6rJ,EAAWzrM,EAAMjD,MAAM,KAE7B,IAAK,IAAI8G,EAAI,EAAGA,EAAI4nM,EAASlxM,OAAQsJ,IAAK,CACxC,MAAM0K,EAAOk9L,EAAS5nM,GAAG9G,MAAM,KACzB2uM,EAAUn9L,EAAK,GAAGjF,QAAQ,OAAQ,IAAIA,QAAQ,OAAQ,IAAI0mB,cAEhE,GAAI4qE,EAAQkuG,MAAMG,SAASyC,GAAU,CACnC,MAAMC,EAAWp9L,EAAK,GAAGjF,QAAQ,OAAQ,IAAIA,QAAQ,OAAQ,IAC7Ds2C,EAAI7kD,KAAK2wM,EAAU,KAAOC,IAI1B/rJ,EAAIrlD,OAAS,IACfyF,EAAQ4/C,EAAIx9C,KAAK,MACjB8H,EAAGoS,aAAaxc,EAAWE,SAG7BkK,EAAGoS,aAAaxc,EAAWE,GAI/B,IAAK,IAAI3F,EAAI,EAAGA,EAAI6tC,EAAKjyB,WAAW1b,OAAQF,IAC1C6P,EAAGwC,YAAYkuF,EAAQ4wG,WAAWtjK,EAAKjyB,WAAW5b,KAEpD,MAAOuL,GAEPsE,EAAK0wF,EAAQswG,YAAY,QAEtB,CACLhhM,EAAK0wF,EAAQqwG,eAAelvL,yBAE5B,IAAK,IAAI1hB,EAAI,EAAGA,EAAI6tC,EAAKjyB,WAAW1b,OAAQF,IAC1C6P,EAAGwC,YAAYkuF,EAAQ4wG,WAAWtjK,EAAKjyB,WAAW5b,WAGjD,GAAI6tC,EAAKtxB,WAAagkF,EAAQyvG,YAAYI,SAAU,CACzDvgM,EAAK0wF,EAAQqwG,eAAelvL,yBAE5B,IAAK,IAAI1hB,EAAI,EAAGA,EAAI6tC,EAAKjyB,WAAW1b,OAAQF,IAC1C6P,EAAGwC,YAAYkuF,EAAQ4wG,WAAWtjK,EAAKjyB,WAAW5b,UAE3C6tC,EAAKtxB,WAAagkF,EAAQyvG,YAAYE,OAC/CrgM,EAAK0wF,EAAQswG,YAAYhjK,EAAKv5B,YAGhC,OAAOzE,GAYT0hM,WAAW9/L,GACW,iBAATA,EACFA,EAGFA,EAAKxC,QAAQ,aAAc,IAAIA,QAAQ,MAAO,QAAQA,QAAQ,KAAM,QAAQA,QAAQ,MAAO,QAAQA,QAAQ,MAAO,QAAQA,QAAQ,MAAO,QAAQA,QAAQ,MAAO,QAAQA,QAAQ,KAAM,QAAQA,QAAQ,KAAM,QAAQA,QAAQ,KAAM,QAAQA,QAAQ,KAAM,QAYjQuiM,aAAa//L,GACS,iBAATA,EACFA,EAGFA,EAAKxC,QAAQ,QAAS,KAAKA,QAAQ,QAAS,KAAKA,QAAQ,QAAS,KAAKA,QAAQ,QAAS,KAAKA,QAAQ,QAAS,KAAKA,QAAQ,QAAS,KAAKA,QAAQ,QAAS,KAAKA,QAAQ,QAAS,KAAKA,QAAQ,QAAS,KAAKA,QAAQ,QAAS,MAYrOwiM,eAAe9vG,GACTA,EAAI9/F,QAAQ,KAAO,EACd,KAGF8/F,EAAIj/F,MAAM,KAAK,GAYxBgvM,iBAAiB/vG,GACf,MAAMgwG,EAAOpxG,EAAQqxG,kBAAkBjwG,GAEvC,GAAIgwG,EAAK9vM,QAAQ,KAAO,EACtB,OAAO8vM,EACF,CACL,MAAMjoM,EAAQioM,EAAKjvM,MAAM,KAEzB,OADAgH,EAAM1H,OAAO,EAAG,GACT0H,EAAM3B,KAAK,OAatB8pM,mBAAmBlwG,GACjB,IAAKA,EACH,OAAO,KAGT,MAAMt2F,EAAIs2F,EAAIj/F,MAAM,KAEpB,OAAI2I,EAAEnL,OAAS,EACN,MAGTmL,EAAErJ,OAAO,EAAG,GACLqJ,EAAEtD,KAAK,OAYhB6pM,kBAAkBjwG,GACTA,EAAMA,EAAIj/F,MAAM,KAAK,GAAK,KAMnCovM,aAAavmM,QACY,IAAZA,EAAE9I,OACX89F,EAAQwxG,MAAMxmM,EAAE9I,OAGd8I,EAAEymM,UACJzxG,EAAQwxG,MAAM,UAAYvzM,KAAKq4B,QAAU,IAAMtrB,EAAEymM,UAAY,IAAMzmM,EAAEjJ,KAAO,MAAQiJ,EAAEP,KAAO,KAAOO,EAAEiO,SAC7FjO,EAAE0mM,SACX1xG,EAAQwxG,MAAM,UAAYvzM,KAAKq4B,QAAU,IAAMtrB,EAAE0mM,SAAW,IAAM1mM,EAAEmG,WAAa,MAAQnG,EAAEP,KAAO,KAAOO,EAAEiO,SAE3G+mF,EAAQwxG,MAAM,UAAYxmM,EAAEiO,UAiChC1W,IAAIE,EAAOjD,GAEP,IAAImyM,EADFlvM,IAAUxE,KAAKsxM,SAASC,QAGD,QAAxBmC,EAAWzwM,eAAkC,IAAbywM,GAA+BA,EAASryM,MAAME,KAUnFyqF,MAAMzqF,GACJvB,KAAKsE,IAAItE,KAAKsxM,SAAS3rM,MAAOpE,IAShCiK,KAAKjK,GACHvB,KAAKsE,IAAItE,KAAKsxM,SAAS1rM,KAAMrE,IAS/B2W,KAAK3W,GACHvB,KAAKsE,IAAItE,KAAKsxM,SAASxrM,KAAMvE,IAS/BF,MAAME,GACJvB,KAAKsE,IAAItE,KAAKsxM,SAAS1vM,MAAOL,IAShCgyM,MAAMhyM,GACJvB,KAAKsE,IAAItE,KAAKsxM,SAASC,MAAOhwM,IAYhCi6D,UAAUnsB,GACR,IAAKA,EACH,OAAO,KAGgB,mBAAdA,EAAK20E,OACd30E,EAAOA,EAAK20E,QAGd,MAAMr3G,EAAQ,IAAIjI,MAAM2qC,EAAKxvB,WAAWne,QAAQrB,QAAQ6G,KAAI1F,GAAK6tC,EAAKxvB,WAAWre,GAAGse,WACpFnT,EAAMkjC,OACN,IAAIvW,EAAS3sB,EAAMkD,QAAO,CAACxC,EAAGwD,IAAM,GAAGxD,KAAKwD,MAAMkxF,EAAQuwG,UAAUjjK,EAAKxvB,WAAWsB,aAAatQ,GAAG1J,WAAW,IAAIkoC,EAAKvvB,YAExH,GAAIuvB,EAAKjyB,WAAW1b,OAAS,EAAG,CAC9B43B,GAAU,IAEV,IAAK,IAAI93B,EAAI,EAAGA,EAAI6tC,EAAKjyB,WAAW1b,OAAQF,IAAK,CAC/C,MAAM6b,EAAQgyB,EAAKjyB,WAAW5b,GAE9B,OAAQ6b,EAAMU,UACZ,KAAKgkF,EAAQyvG,YAAYC,OAEvBn4K,GAAUyoE,EAAQvmC,UAAUn+C,GAC5B,MAEF,KAAK0kF,EAAQyvG,YAAYE,KAEvBp4K,GAAUyoE,EAAQuwG,UAAUj1L,EAAMvH,WAClC,MAEF,KAAKisF,EAAQyvG,YAAYG,MAEvBr4K,GAAU,YAAcjc,EAAMvH,UAAY,OAIhDwjB,GAAU,KAAO+V,EAAKvvB,SAAW,SAEjCwZ,GAAU,KAGZ,OAAOA,GAOTq6K,WAAY,EAMZC,mBAAoB,GASpB5yF,oBAAoBx0G,EAAMqnM,GACxB9xG,EAAQ6xG,mBAAmBpnM,GAAQqnM,GA+CvC9xG,QAAkB,MAChB3oF,YAAY5M,EAAM8I,GAEH,aAAT9I,GAAgC,YAATA,GAA+B,OAATA,IAC3C8I,IAAUA,EAAMlB,MAClBkB,EAAMlB,MAAQ2tF,EAAQktG,GAAGG,OACf95L,IACVA,EAAQ,CACNlB,MAAO2tF,EAAQktG,GAAGG,UAMxBpvM,KAAKywL,SAAW1uF,EAAQ2rB,WAAWlhH,EAAM8I,GAEzCtV,KAAKiT,KAAOjT,KAAKywL,SAanBzsE,OACE,OAAOhkH,KAAKywL,SAcdvvK,WACE,OAAO6gF,EAAQvmC,UAAUx7D,KAAKywL,UAchC1rE,KAEE,OADA/kH,KAAKiT,KAAOjT,KAAKiT,KAAKkD,WACfnW,KAcTX,OAEE,OADAW,KAAKiT,KAAOjT,KAAKywL,SACVzwL,KAgBTsV,MAAMw+L,GACJ,IAAK,MAAMz9K,KAAKy9K,EACV1zM,OAAOa,UAAUwX,eAAe7T,KAAKkvM,EAAWz9K,UAC7BtqB,IAAjB+nM,EAAUz9K,GACZr2B,KAAKiT,KAAKyQ,gBAAgB2S,GAE1Br2B,KAAKiT,KAAKwQ,aAAa4S,EAAGy9K,EAAUz9K,KAK1C,OAAOr2B,KAoBTmN,EAAEX,EAAM8I,EAAOtT,GACb,MAAMqb,EAAQ0kF,EAAQ2rB,WAAWlhH,EAAM8I,EAAOtT,GAO9C,OANAhC,KAAKiT,KAAKY,YAAYwJ,GAEF,iBAATrb,GAAqC,iBAATA,IACrChC,KAAKiT,KAAOoK,GAGPrd,KAkBT+jH,MAAM10E,GACJ,IAAI0kK,EACJ,MAAMC,EAASjyG,EAAQqwG,eAEvB,IACE2B,OAAgChoM,IAAtBioM,EAAOzzL,WACjB,MAAOxT,GACPgnM,GAAU,EAGZ,MAAME,EAAUF,EAAUC,EAAOzzL,WAAW8uB,GAAM,GAAQ0yD,EAAQ2wG,YAAYrjK,GAG9E,OAFArvC,KAAKiT,KAAKY,YAAYogM,GACtBj0M,KAAKiT,KAAOghM,EACLj0M,KAgBTgF,EAAEhD,GACA,MAAMqb,EAAQ0kF,EAAQswG,YAAYrwM,GAElC,OADAhC,KAAKiT,KAAKY,YAAYwJ,GACfrd,KAeTk0M,EAAE9jJ,GACA,MAAMlH,EAAW64C,EAAQqwG,eAAenvL,cAAc,QAEtDimC,EAASjS,UAAYmZ,EAErB,MAAM+jJ,EAAQpyG,EAAQ4wG,WAAWzpJ,GAEjC,KAAOirJ,EAAM/2L,WAAW1b,OAAS,GAC/B1B,KAAKiT,KAAKY,YAAYsgM,EAAM/2L,WAAW,IAGzC,OAAOpd,OAkCX+hG,QAAkB,SAAU1pE,EAAS3Y,EAAIlT,EAAM5E,EAAMvC,EAAIw5F,EAAM9+F,GAC7DC,KAAKq4B,QAAUA,EACfr4B,KAAK0f,GAAKA,EACV1f,KAAKwM,KAAOA,EACZxM,KAAK4H,KAAOA,EACZ5H,KAAKqF,GAAKA,EACVrF,KAAKD,QAAUA,GAAW,CACxB,kBAAoB,EACpB,yBAA2B,GAGzBC,KAAKD,QAAQq0M,YACfryG,EAAQ7pF,KAAK,yEACblY,KAAKD,QAAQs0M,iBAAmBr0M,KAAKD,QAAQq0M,iBACtCp0M,KAAKD,QAAQq0M,WAGlBp0M,KAAKD,QAAQs0M,iBACfr0M,KAAK6+F,KAAOA,EAAOkD,EAAQqxG,kBAAkBv0G,GAAQ,KAErD7+F,KAAK6+F,KAAOA,EAId7+F,KAAK8tG,MAAO,IAGd/L,EAAQuyG,QAAQrzM,UAAY,CAY1BszM,aAAallK,GACX,IAAImlK,EAAcnlK,EAAK7sB,aAAa,SAMpC,OAJIgyL,GAAex0M,KAAKD,QAAQ00M,0BAC9BD,EAAcA,EAAYtwM,MAAM,KAAK,IAGhCswM,GAYTE,eAAerlK,GACb,IAAIslK,GAAU,EAEd,OAAK30M,KAAK0f,KAGRqiF,EAAQgwG,aAAa1iK,EAAM,MAAMA,IAC3BrvC,KAAKu0M,aAAallK,KAAUrvC,KAAK0f,KACnCi1L,GAAU,MAGPA,GAAW30M,KAAKu0M,aAAallK,KAAUrvC,KAAK0f,KAavDk1L,QAAQvlK,GACN,IAAIwvD,EAAOxvD,EAAK7sB,aAAa,QAEzBxiB,KAAKD,QAAQs0M,mBACfx1G,EAAOkD,EAAQqxG,kBAAkBv0G,IAGnC,MAAMg2G,EAAYxlK,EAAK7sB,aAAa,QAEpC,SAAIxiB,KAAK00M,eAAerlK,IAAWrvC,KAAKwM,OAAQu1F,EAAQmwG,WAAW7iK,EAAMrvC,KAAKwM,OAAYxM,KAAK4H,OAASlD,MAAMgD,QAAQ1H,KAAK4H,OAA0C,IAAlC5H,KAAK4H,KAAKvE,QAAQwxM,GAAoBA,IAAc70M,KAAK4H,OAAY5H,KAAKqF,IAAMgqC,EAAK7sB,aAAa,QAAUxiB,KAAKqF,IAASrF,KAAK6+F,MAAQA,IAAS7+F,KAAK6+F,OAiB1Ri2G,IAAIzlK,GACF,IAAI/V,EAAS,KAEb,IACEA,EAASt5B,KAAKq4B,QAAQgX,GACtB,MAAOtiC,GAGP,MAFAg1F,EAAQuxG,aAAavmM,GAEfA,EAGR,OAAOusB,GASTpY,WACE,MAAO,aAAelhB,KAAKq4B,QAAU,IAAMr4B,KAAKwM,KAAO,IAAMxM,KAAKqF,GAAK,IAAMrF,KAAK0f,GAAK,OAiB3FqiF,EAAQgzG,aAAe,MAarB37L,YAAY47L,EAAQ38K,GAClBr4B,KAAKg1M,OAASA,EACdh1M,KAAKq4B,QAAUA,EACfr4B,KAAKi1M,YAAa,IAAI9vM,MAAOq6G,UAC7Bx/G,KAAK8tG,MAAO,EAWdgnG,MAEE,OADA90M,KAAKi1M,YAAa,IAAI9vM,MAAOq6G,UACtBx/G,KAAKq4B,UAOd2iB,QACEh7C,KAAKi1M,YAAa,IAAI9vM,MAAOq6G,UAU/Bt+F,WACE,MAAO,kBAAoBlhB,KAAKq4B,QAAU,IAAMr4B,KAAKg1M,OAAS,OAwKlEjzG,EAAQmzG,WAAa,MACnB97L,YAAY2jG,EAASh9G,GAEnBC,KAAK+8G,QAAUA,EAEf/8G,KAAKD,QAAUA,GAAW,GAC1BC,KAAKm1M,cAGLn1M,KAAKmjG,IAAM,GAGXnjG,KAAK0hH,OAAS,KAGd1hH,KAAK4hG,SAAW,KAEhB5hG,KAAKo1M,WAAa,GAClBp1M,KAAKq1M,SAAU,EACfr1M,KAAKs1M,YAAa,EAClBt1M,KAAKu1M,WAAa,GAElBv1M,KAAKw1M,cAAgB,GACrBx1M,KAAKg4B,SAAW,GAChBh4B,KAAKy1M,aAAe,GACpBz1M,KAAK01M,eAAiB,GACtB11M,KAAK21M,UAAY,GACjB31M,KAAK41M,YAAc,GACnB51M,KAAK61M,sBAAwB,CAC3B,KAAQ,GACR,UAAa,IAEf71M,KAAK81M,aAAe,KACpB91M,KAAK+1M,mBAAqB,KAC1B/1M,KAAKg2M,eAAgB,EACrBh2M,KAAK09G,WAAY,EACjB19G,KAAKyhH,eAAgB,EACrBzhH,KAAKi2M,mBAAoB,EACzBj2M,KAAKsQ,QAAS,EACdtQ,KAAKk2M,UAAW,EAChBl2M,KAAK6lD,MAAQ,GACb7lD,KAAKm2M,UAAY,EACjBn2M,KAAKo2M,sBAAwB,KAC7Bp2M,KAAKq2M,sBAAwB,KAC7Br2M,KAAKs2M,wBAA0B,KAE/Bt2M,KAAK2gH,WAAa,EAElB3gH,KAAK81M,aAAetzM,YAAW,IAAMxC,KAAKu2M,WAAW,KACrD3J,EAAiB5sM,KAAKD,QAAQ+sM,SAC9B9sM,KAAKw2M,uBAAuBx2M,KAAKD,QAAQw1M,YAEzC,IAAK,MAAMl/K,KAAK0rE,EAAQ6xG,mBACtB,GAAIxzM,OAAOa,UAAUwX,eAAe7T,KAAKm9F,EAAQ6xG,mBAAoBv9K,GAAI,CACvE,MAAMogL,EAAI,aAEVA,EAAEx1M,UAAY8gG,EAAQ6xG,mBAAmBv9K,GACzCr2B,KAAKq2B,GAAK,IAAIogL,EACdz2M,KAAKq2B,GAAGuT,KAAK5pC,OASnBm1M,cACE,MAAM/kK,EAAQpwC,KAAKD,QAAQ6xE,UAAY,GAEnC5xE,KAAKD,QAAQ8nI,OACf7nI,KAAKohH,OAAS,IAAIrf,EAAQ20G,gBAAgB12M,MACD,IAAhCA,KAAK+8G,QAAQ15G,QAAQ,QAAiD,IAAjCrD,KAAK+8G,QAAQ15G,QAAQ,SAAyC,IAAxB+sC,EAAM/sC,QAAQ,MAClGrD,KAAKohH,OAAS,IAAIrf,EAAQ40G,UAAU32M,MAEpCA,KAAKohH,OAAS,IAAIrf,EAAQ60G,KAAK52M,MAWnCg7C,QACEh7C,KAAKohH,OAAOy1F,SAGZ72M,KAAKs1M,YAAa,EAClBt1M,KAAKq1M,SAAU,EAEfr1M,KAAKw1M,cAAgB,GACrBx1M,KAAKg4B,SAAW,GAChBh4B,KAAKy1M,aAAe,GACpBz1M,KAAK01M,eAAiB,GACtB11M,KAAK21M,UAAY,GACjB31M,KAAK41M,YAAc,GACnB51M,KAAKg2M,eAAgB,EACrBh2M,KAAK09G,WAAY,EACjB19G,KAAKyhH,eAAgB,EACrBzhH,KAAKk2M,UAAW,EAChBl2M,KAAK6lD,MAAQ,GACb7lD,KAAK82M,UAAY,GACjB92M,KAAKm2M,UAAY,EAanB1sE,QACEzpI,KAAKsQ,QAAS,EAShB0hF,SACEhyF,KAAKsQ,QAAS,EA0BhBymM,YAAYx/I,GAEV,MAAMw7C,EAAO,uCAAuCtiG,QAAQ,SAAS,SAAUtD,GAC7E,MAAMD,EAAoB,GAAhBjD,KAAKE,SAAgB,EAE/B,OADgB,MAANgD,EAAYD,EAAQ,EAAJA,EAAU,GAC3BgU,SAAS,OAGpB,MAAsB,iBAAXq2C,GAAyC,iBAAXA,EAChCw7C,EAAO,IAAMx7C,EAEbw7C,EAAO,GA2BlBikG,wBAAwBplI,EAAUqlI,EAAar6L,GAC7C5c,KAAK61M,sBAAsBjkI,GAAUqlI,GAAer6L,EA8CtD01E,QAAQ6Q,EAAKgf,EAAMvlG,EAAUsnC,EAAM+Z,EAAMi5I,EAAOC,EAASC,EAAwB,KAC/Ep3M,KAAKmjG,IAAMA,EAKXnjG,KAAKq3M,QAAUt1G,EAAQqxG,kBAAkBpzM,KAAKmjG,KAK9CnjG,KAAKm3M,QAAUA,GAAWp1G,EAAQkxG,eAAejzM,KAAKmjG,KAKtDnjG,KAAKmiH,KAAOA,EACZniH,KAAKs3M,iBAAmB16L,EACxB5c,KAAKyhH,eAAgB,EACrBzhH,KAAK09G,WAAY,EACjB19G,KAAKg2M,eAAgB,EACrBh2M,KAAKk2M,UAAW,EAChBl2M,KAAKo3M,sBAAwBA,EAE7Bp3M,KAAK0hH,OAAS3f,EAAQmxG,iBAAiBlzM,KAAKmjG,KAE5CnjG,KAAK2jH,qBAAqB5hB,EAAQke,OAAOowF,WAAY,MAErDrwM,KAAKohH,OAAO8gC,SAASh+F,EAAM+Z,EAAMi5I,GA4BnCn1F,OAAO5e,EAAK6e,EAAKC,EAAKrlG,EAAUsnC,EAAM+Z,EAAMs5I,GAC1C,GAAIv3M,KAAKohH,OAAOo2F,QACd,OAAOx3M,KAAKohH,OAAOo2F,QAAQr0G,EAAK6e,EAAKC,EAAKrlG,EAAUsnC,EAAM+Z,EAAMs5I,GAC3D,CACL,MAAMl2M,EAAQ,IAAI2C,MAAM,qEAExB,MADA3C,EAAMmL,KAAO,sBACPnL,GAgCVo2M,QAAQt0G,EAAKvmF,EAAUsnC,EAAM+Z,EAAMs5I,GACjC,IAAIv3M,KAAK03M,2BAEF,CACL,MAAMr2M,EAAQ,IAAI2C,MAAM,iEAExB,MADA3C,EAAMmL,KAAO,sBACPnL,EAJNrB,KAAKohH,OAAOu2F,SAASx0G,EAAKvmF,EAAUsnC,EAAM+Z,EAAMs5I,GAapDG,2BACE,GAAI13M,KAAKohH,kBAAkBrf,EAAQ60G,KAAM,CACvC,IAAKx1M,KACH,OAAO,EAGT,IACEw2M,eAAe9yH,QAAQ,YAAa,aACpC8yH,eAAe5yH,WAAW,aAC1B,MAAOj4E,GACP,OAAO,EAGT,OAAO,EAGT,OAAO,EAsBT8qM,SAASxoK,IAwBTyoK,UAAUzoK,IAkBVkuE,SAAS9mG,IAkBTgoI,UAAUhoI,IAiBVshM,aAAa91F,IAkBbqB,KAAKj0E,GACH,GAAa,OAATA,EAAJ,CAIA,GAAyB,mBAAdA,EAAKQ,KACd,IAAK,IAAIruC,EAAI,EAAGA,EAAI6tC,EAAK3tC,OAAQF,IAC/BxB,KAAKg4M,WAAW3oK,EAAK7tC,QAEO,mBAAd6tC,EAAK20E,KACrBhkH,KAAKg4M,WAAW3oK,EAAK20E,QAErBhkH,KAAKg4M,WAAW3oK,GAGlBrvC,KAAKohH,OAAO6lC,SAYdxkJ,QAGEF,aAAavC,KAAK81M,cAElB91M,KAAKu2M,UAoBP97F,aAAaprE,EAAMzyB,EAAU4mG,EAAS1rD,GACpC,IAAImgJ,EAAiB,KAEI,mBAAd5oK,EAAK20E,OACd30E,EAAOA,EAAK20E,QAGd,IAAI3+G,EAAKgqC,EAAK7sB,aAAa,MAQ3B,GANKnd,IAEHA,EAAKrF,KAAK+2M,YAAY,gBACtB1nK,EAAK5rB,aAAa,KAAMpe,IAGF,mBAAbuX,GAA8C,mBAAZ4mG,EAAwB,CACnE,MAAMnrF,EAAUr4B,KAAKy4B,YAAW8qF,IAE1B00F,GACFj4M,KAAKk4M,mBAAmBD,GAGU,UAAhC10F,EAAO/gG,aAAa,QAClBghG,GACFA,EAAQD,GAED3mG,GACTA,EAAS2mG,KAEV,KAAM,WAAY,KAAMl+G,GAEvByyD,IACFmgJ,EAAiBj4M,KAAKm4M,gBAAgBrgJ,GAAS,KAE7C93D,KAAK+gJ,cAAc1oH,GAEfmrF,GACFA,EAAQ,OAGH,MAMb,OADAxjH,KAAKsjH,KAAKj0E,GACHhqC,EAkBTg+G,OAAOh0E,EAAMzyB,EAAU4mG,EAAS1rD,GAC9B,IAAImgJ,EAAiB,KAEI,mBAAd5oK,EAAK20E,OACd30E,EAAOA,EAAK20E,QAGd,IAAI3+G,EAAKgqC,EAAK7sB,aAAa,MAQ3B,GANKnd,IAEHA,EAAKrF,KAAK+2M,YAAY,UACtB1nK,EAAK5rB,aAAa,KAAMpe,IAGF,mBAAbuX,GAA8C,mBAAZ4mG,EAAwB,CACnE,MAAMnrF,EAAUr4B,KAAKy4B,YAAW8qF,IAE1B00F,GACFj4M,KAAKk4M,mBAAmBD,GAG1B,MAAMG,EAAS70F,EAAO/gG,aAAa,QAEnC,GAAe,WAAX41L,EACEx7L,GACFA,EAAS2mG,OAEN,IAAe,UAAX60F,EAIJ,CACL,MAAM/2M,EAAQ,IAAI2C,MAAM,sBAAsBo0M,KAE9C,MADA/2M,EAAMmL,KAAO,eACPnL,EANFmiH,GACFA,EAAQD,MAOX,KAAM,KAAM,CAAC,QAAS,UAAWl+G,GAEhCyyD,IACFmgJ,EAAiBj4M,KAAKm4M,gBAAgBrgJ,GAAS,KAE7C93D,KAAK+gJ,cAAc1oH,GAEfmrF,GACFA,EAAQ,OAGH,MAMb,OADAxjH,KAAKsjH,KAAKj0E,GACHhqC,EAQT2yM,WAAWx/L,GACT,GAAgB,OAAZA,IAAqBA,EAAQtC,UAAYsC,EAAQ4E,WAAY,CAC/D,MAAM/b,EAAQ,IAAI2C,MAAM,gCAExB,MADA3C,EAAMmL,KAAO,eACPnL,EAGRrB,KAAK6lD,MAAM3jD,KAAKsW,GAOlB6/L,eACEr4M,KAAK6lD,MAAM3jD,KAAK,WAEhBlC,KAAKohH,OAAOi3F,eAEZr4M,KAAK81M,aAAetzM,YAAW,IAAMxC,KAAKu2M,WAAW,KA0BvD4B,gBAAgBnD,EAAQ38K,GACtB,MAAMigL,EAAQ,IAAIv2G,EAAQgzG,aAAaC,EAAQ38K,GAE/C,OADAr4B,KAAK21M,UAAUzzM,KAAKo2M,GACbA,EAcTJ,mBAAmBK,GAGjBv4M,KAAKy1M,aAAavzM,KAAKq2M,GAoEzB9/K,WAAWJ,EAAS3Y,EAAIlT,EAAM5E,EAAMvC,EAAIw5F,EAAM9+F,GAC5C,MAAMy4M,EAAO,IAAIz2G,EAAQuyG,QAAQj8K,EAAS3Y,EAAIlT,EAAM5E,EAAMvC,EAAIw5F,EAAM9+F,GAEpE,OADAC,KAAK41M,YAAY1zM,KAAKs2M,GACfA,EAcTz3D,cAAcw3D,GAGZv4M,KAAK01M,eAAexzM,KAAKq2M,GAGzB,MAAM/2M,EAAIxB,KAAK41M,YAAYvyM,QAAQk1M,GAE/B/2M,GAAK,GACPxB,KAAK41M,YAAYpyM,OAAOhC,EAAG,GAc/Bg1M,uBAAuBjB,GACrBv1M,KAAKu1M,WAAa,IAClBA,EAAaA,GAAc,CAACxzG,EAAQ02G,cAAe12G,EAAQ22G,aAAc32G,EAAQ42G,gBAAiB52G,EAAQ62G,YAAa72G,EAAQ82G,UAAW92G,EAAQ+2G,WACvIv4M,SAAQ4D,GAAKnE,KAAK+4M,sBAAsB50M,KAYrD40M,sBAAsBC,GACpB,MAAM1hI,EAAY,IAAI0hI,EACtBh5M,KAAKu1M,WAAWj+H,EAAUi1H,UAAYj1H,EAoBxCud,WAAWt8D,GAST,GARAv4B,KAAK2jH,qBAAqB5hB,EAAQke,OAAOywF,cAAen4K,GAEpDA,EACFwpE,EAAQ7pF,KAAK,kCAAoCqgB,GAEjDwpE,EAAQv2F,KAAK,yBAGXxL,KAAK09G,UAAW,CAClB,IAAImG,GAAO,EACX7jH,KAAKyhH,eAAgB,EAEjBzhH,KAAKg2M,gBACPnyF,EAAOC,EAAM,CACX,MAAS/hB,EAAQktG,GAAGG,OACpB,KAAQ,iBAKZpvM,KAAK+1M,mBAAqB/1M,KAAKi5M,oBAAoBj5M,KAAKo3M,sBAAuBp3M,KAAKk5M,qBAAqBt4M,KAAKZ,OAE9GA,KAAKohH,OAAO+3F,YAAYt1F,QAExB9hB,EAAQ7pF,KAAK,gEAEblY,KAAKohH,OAAO6C,oBAEZjkH,KAAKkkH,gBAeTP,qBAAqB10B,EAAQmqH,EAAW/pK,GAEtC,IAAK,MAAMhZ,KAAK0rE,EAAQ6xG,mBACtB,GAAIxzM,OAAOa,UAAUwX,eAAe7T,KAAKm9F,EAAQ6xG,mBAAoBv9K,GAAI,CACvE,MAAMyrF,EAAS9hH,KAAKq2B,GAEpB,GAAIyrF,EAAOu3F,cACT,IACEv3F,EAAOu3F,cAAcpqH,EAAQmqH,GAC7B,MAAO3wK,GACPs5D,EAAQ1gG,MAAM,GAAGg1B,iDAAiDoS,MAO1E,GAAIzoC,KAAKs3M,iBACP,IACEt3M,KAAKs3M,iBAAiBroH,EAAQmqH,EAAW/pK,GACzC,MAAOtiC,GACPg1F,EAAQuxG,aAAavmM,GAErBg1F,EAAQ1gG,MAAM,iDAAiD0L,MAYrEm3G,cAAck1F,GACqB,iBAAtBp5M,KAAK81M,cACdvzM,aAAavC,KAAK81M,cAIY,OAA5B91M,KAAK+1M,qBACP/1M,KAAKk4M,mBAAmBl4M,KAAK+1M,oBAC7B/1M,KAAK+1M,mBAAqB,MAG5Bh0G,EAAQ/V,MAAM,4BAEdhsF,KAAKohH,OAAO8C,gBAEZlkH,KAAKg2M,eAAgB,EACrBh2M,KAAKyhH,eAAgB,EACrBzhH,KAAKk2M,UAAW,EAEhBl2M,KAAKg4B,SAAW,GAChBh4B,KAAKw1M,cAAgB,GACrBx1M,KAAKy1M,aAAe,GACpBz1M,KAAK01M,eAAiB,GACtB11M,KAAK21M,UAAY,GACjB31M,KAAK41M,YAAc,GAEnB51M,KAAK2jH,qBAAqB5hB,EAAQke,OAAOwwF,aAAc2I,GAEvDp5M,KAAK09G,WAAY,EAgBnB47F,UAAUv6D,EAAKx6F,GACb,MAAMlV,EAAOrvC,KAAKohH,OAAOm4F,WAAWx6D,GAEpC,GAAa,OAAT1vG,EACF,OAoBF,IAjBIrvC,KAAK63M,WAAa91G,EAAQmzG,WAAWj0M,UAAU42M,WAC7CxoK,EAAKvvB,WAAa9f,KAAKohH,OAAOo4F,OAASnqK,EAAKjyB,WAAW1b,OACzD1B,KAAK63M,SAASxoK,EAAKjyB,WAAW,IAE9Bpd,KAAK63M,SAASxoK,IAIdrvC,KAAKu9G,WAAaxb,EAAQmzG,WAAWj0M,UAAUs8G,WAC7Ch5D,EACFvkD,KAAKu9G,SAASh5D,GAEdvkD,KAAKu9G,SAASxb,EAAQvmC,UAAUnsB,KAK7BrvC,KAAK01M,eAAeh0M,OAAS,GAAG,CACrC,MAAM82M,EAAOx4M,KAAK01M,eAAez+K,MAC3Bz1B,EAAIxB,KAAKg4B,SAAS30B,QAAQm1M,GAE5Bh3M,GAAK,GACPxB,KAAKg4B,SAASx0B,OAAOhC,EAAG,GAK5B,KAAOxB,KAAK41M,YAAYl0M,OAAS,GAC/B1B,KAAKg4B,SAAS91B,KAAKlC,KAAK41M,YAAY3+K,OAItC,GAAIj3B,KAAKyhH,eAAiBzhH,KAAKohH,OAAOq4F,cAGpC,YAFAz5M,KAAKkkH,gBAKP,MAAMt8G,EAAOynC,EAAK7sB,aAAa,QAE/B,GAAa,OAAT5a,GAA0B,cAATA,EAAsB,CAEzC,GAAI5H,KAAKyhH,cACP,OAIF,IAAIi4F,EAAOrqK,EAAK7sB,aAAa,aAC7B,MAAMm3L,EAAWtqK,EAAKjrB,qBAAqB,YAc3C,OAZa,OAATs1L,GACW,wBAATA,GAAkCC,EAASj4M,OAAS,IACtDg4M,EAAO,YAGT15M,KAAK2jH,qBAAqB5hB,EAAQke,OAAOqwF,SAAUoJ,IAEnD15M,KAAK2jH,qBAAqB5hB,EAAQke,OAAOqwF,SAAUvuG,EAAQivG,eAAe4I,oBAG5E55M,KAAKkkH,cAAcw1F,GAMrB33G,EAAQgwG,aAAa1iK,EAAM,MAAMhyB,IAE/B,MAAMmoG,EAAUxlH,KAAKg4B,SACrBh4B,KAAKg4B,SAAW,GAEhB,IAAK,IAAIx2B,EAAI,EAAGA,EAAIgkH,EAAQ9jH,OAAQF,IAAK,CACvC,MAAMg3M,EAAOhzF,EAAQhkH,GAGrB,MACMg3M,EAAK5D,QAAQv3L,KAAWrd,KAAKg2M,eAAkBwC,EAAK1qG,MAClD0qG,EAAK1D,IAAIz3L,KAIbrd,KAAKg4B,SAAS91B,KAAKs2M,GAErB,MAAOzrM,GAEPg1F,EAAQ7pF,KAAK,wDAA0DnL,EAAEiO,cAuBjF6+L,YAAY96D,EAAK+6D,EAAWv1J,GAG1B,IAAIw1J,EAyCAC,EA3CJj4G,EAAQ/V,MAAM,0BACdhsF,KAAK09G,WAAY,EAGjB,IACEq8F,EAAW/5M,KAAKohH,OAAOm4F,WAAWx6D,GAClC,MAAOhyI,GACP,GAAIA,EAAEP,OAASu1F,EAAQivG,eAAeC,WACpC,MAAMlkM,EAGR/M,KAAK2jH,qBAAqB5hB,EAAQke,OAAOqwF,SAAUvuG,EAAQivG,eAAeC,YAE1EjxM,KAAKkkH,cAAcniB,EAAQivG,eAAeC,YAG5C,IAAK8I,EACH,OAqBF,GAlBI/5M,KAAK63M,WAAa91G,EAAQmzG,WAAWj0M,UAAU42M,WAC7CkC,EAASj6L,WAAa9f,KAAKohH,OAAOo4F,OAASO,EAAS38L,WAAW1b,OACjE1B,KAAK63M,SAASkC,EAAS38L,WAAW,IAElCpd,KAAK63M,SAASkC,IAId/5M,KAAKu9G,WAAaxb,EAAQmzG,WAAWj0M,UAAUs8G,WAC7Ch5D,EACFvkD,KAAKu9G,SAASh5D,GAEdvkD,KAAKu9G,SAASxb,EAAQvmC,UAAUu+I,KAIlB/5M,KAAKohH,OAAOy4F,YAAYE,KAExBh4G,EAAQke,OAAOqwF,SAC/B,OAYF,GALE0J,EADED,EAAS11L,uBACG01L,EAAS11L,uBAAuB09E,EAAQktG,GAAGzH,OAAQ,YAAY9lM,OAAS,EAExEq4M,EAAS31L,qBAAqB,mBAAmB1iB,OAAS,GAAKq4M,EAAS31L,qBAAqB,YAAY1iB,OAAS,GAG7Hs4M,EAGH,YAFAh6M,KAAKohH,OAAO64F,kBAAkBH,GAKhC,MAAM//J,EAAUr1C,MAAMm6F,KAAKk7G,EAAS31L,qBAAqB,cAAcld,KAAI/C,GAAKnE,KAAKu1M,WAAWpxM,EAAEm0C,eAAcvxC,QAAO5C,GAAKA,IAErG,IAAnB41C,EAAQr4C,QAC2C,IAAjDq4M,EAAS31L,qBAAqB,QAAQ1iB,QASb,IAA3B1B,KAAKi2M,mBACPj2M,KAAK4sH,aAAa7yE,GAPhB/5C,KAAKohH,OAAO64F,kBAAkBH,GAqBpCI,yBAAyB3E,GAGvB,IAAK,IAAI/zM,EAAI,EAAGA,EAAI+zM,EAAW7zM,OAAS,IAAKF,EAAG,CAC9C,IAAI24M,EAAS34M,EAEb,IAAK,IAAIwJ,EAAIxJ,EAAI,EAAGwJ,EAAIuqM,EAAW7zM,SAAUsJ,EACvCuqM,EAAWvqM,GAAG6mE,SAAW0jI,EAAW4E,GAAQtoI,WAC9CsoI,EAASnvM,GAIb,GAAImvM,IAAW34M,EAAG,CAChB,MAAMowD,EAAO2jJ,EAAW/zM,GACxB+zM,EAAW/zM,GAAK+zM,EAAW4E,GAC3B5E,EAAW4E,GAAUvoJ,GAIzB,OAAO2jJ,EAiBT3oF,aAAa7yE,GACN/5C,KAAKo6M,iBAAiBrgK,IACzB/5C,KAAKq6M,qBAkBTD,iBAAiB7E,GACfA,EAAav1M,KAAKk6M,yBAAyB3E,GAAc,IACzD,IAAI+E,GAAkB,EAEtB,IAAK,IAAI94M,EAAI,EAAGA,EAAI+zM,EAAW7zM,SAAUF,EAAG,CAC1C,IAAK+zM,EAAW/zM,GAAG+N,KAAKvP,MACtB,SAGFA,KAAKo2M,sBAAwBp2M,KAAKmiJ,eAAeniJ,KAAKu6M,iBAAiB35M,KAAKZ,MAAO,KAAM,UAAW,KAAM,MAC1GA,KAAKq2M,sBAAwBr2M,KAAKmiJ,eAAeniJ,KAAKw6M,iBAAiB55M,KAAKZ,MAAO,KAAM,UAAW,KAAM,MAC1GA,KAAKs2M,wBAA0Bt2M,KAAKmiJ,eAAeniJ,KAAKy6M,mBAAmB75M,KAAKZ,MAAO,KAAM,YAAa,KAAM,MAChHA,KAAK06M,gBAAkBnF,EAAW/zM,GAElCxB,KAAK06M,gBAAgBlO,QAAQxsM,MAE7B,MAAM26M,EAAwBvjF,EAAO,OAAQ,CAC3C,MAASr1B,EAAQktG,GAAGU,KACpB,UAAa3vM,KAAK06M,gBAAgBnO,WAGpC,GAAIvsM,KAAK06M,gBAAgBpO,cAAe,CACtC,MAAMxxF,EAAW96G,KAAK06M,gBAAgB/N,gBAAgB3sM,MAEtD26M,EAAsB31M,EAAEypM,EAAKI,KAAK/zF,IAGpC96G,KAAKsjH,KAAKq3F,EAAsB32F,QAChCs2F,GAAkB,EAClB,MAGF,OAAOA,EAQTG,mBAAmBprK,GACjB,MAAMq9J,EAAY+B,EAAKC,KAAK3sG,EAAQ5wD,QAAQ9B,IAEtCyrE,EAAW96G,KAAK06M,gBAAgBjO,YAAYzsM,KAAM0sM,GAElDnpF,EAAS6T,EAAO,WAAY,CAChC,MAASr1B,EAAQktG,GAAGU,OAQtB,MALiB,KAAb70F,GACFyI,EAAOv+G,EAAEypM,EAAKI,KAAK/zF,IAGrB96G,KAAKsjH,KAAKC,EAAOS,SACV,EAQTq2F,qBAC2C,OAArCt4G,EAAQkxG,eAAejzM,KAAKmjG,MAG9BnjG,KAAK2jH,qBAAqB5hB,EAAQke,OAAOqwF,SAAUvuG,EAAQivG,eAAeG,kBAE1EnxM,KAAK60F,WAAWkN,EAAQivG,eAAeG,oBAGvCnxM,KAAK2jH,qBAAqB5hB,EAAQke,OAAOswF,eAAgB,MAEzDvwM,KAAKmiJ,eAAeniJ,KAAK46M,sBAAsBh6M,KAAKZ,MAAO,KAAM,KAAM,KAAM,WAE7EA,KAAKsjH,KAAKtE,EAAI,CACZ,KAAQ,MACR,GAAMh/G,KAAK0hH,OACX,GAAM,YACLv0G,EAAE,QAAS,CACZiH,MAAO2tF,EAAQktG,GAAGI,OACjBliM,EAAE,WAAY,IAAInI,EAAE+8F,EAAQkxG,eAAejzM,KAAKmjG,MAAM6gB,SAmB7D42F,sBAAsBvrK,GAGpB,MAAM0vE,EAAKC,EAAI,CACbp3G,KAAM,MACNvC,GAAI,YACH8H,EAAE,QAAS,CACZiH,MAAO2tF,EAAQktG,GAAGI,OACjBliM,EAAE,WAAY,IAAInI,EAAE+8F,EAAQkxG,eAAejzM,KAAKmjG,MAAM4hB,KAAK53G,EAAE,YAAYnI,EAAEhF,KAAKmiH,MAcnF,OAZKpgB,EAAQsxG,mBAAmBrzM,KAAKmjG,OAInCnjG,KAAKmjG,IAAMpB,EAAQqxG,kBAAkBpzM,KAAKmjG,KAAO,YAGnD4b,EAAGgG,KAAK53G,EAAE,WAAY,IAAInI,EAAE+8F,EAAQsxG,mBAAmBrzM,KAAKmjG,MAE5DnjG,KAAKmiJ,eAAeniJ,KAAK66M,UAAUj6M,KAAKZ,MAAO,KAAM,KAAM,KAAM,WAEjEA,KAAKsjH,KAAKvE,EAAGiF,SACN,EAaTu2F,iBAAiBlrK,GACf,GAAIrvC,KAAKo1M,WAAW,oBAAqB,CACvC,IAAI0F,EACJ,MACMC,EAAc,wBACdj4L,EAFU2rL,EAAKC,KAAK3sG,EAAQ5wD,QAAQ9B,IAElBjrC,MAAM22M,GAM9B,GAJmB,MAAfj4L,EAAQ,KACVg4L,EAAkBh4L,EAAQ,IAGxBg4L,IAAoB96M,KAAKo1M,WAAW,oBAWtC,OATAp1M,KAAK+gJ,cAAc/gJ,KAAKq2M,uBACxBr2M,KAAKq2M,sBAAwB,KAEzBr2M,KAAKs2M,0BACPt2M,KAAK+gJ,cAAc/gJ,KAAKs2M,yBACxBt2M,KAAKs2M,wBAA0B,MAGjCt2M,KAAKo1M,WAAa,GACXp1M,KAAKw6M,iBAAiB,MAIjCz4G,EAAQv2F,KAAK,kCAETxL,KAAK06M,iBACP16M,KAAK06M,gBAAgBvmF,YAIvBn0H,KAAK+gJ,cAAc/gJ,KAAKq2M,uBACxBr2M,KAAKq2M,sBAAwB,KAEzBr2M,KAAKs2M,0BACPt2M,KAAK+gJ,cAAc/gJ,KAAKs2M,yBACxBt2M,KAAKs2M,wBAA0B,MAGjC,MAAM0E,EAAyB,GAEzB11E,EAAU,CAACttG,EAAUqX,KACzB,KAAOrX,EAASt2B,QACd1B,KAAK+gJ,cAAc/oH,EAASf,OAK9B,OAFAj3B,KAAKi7M,2BAA2B5rK,IAEzB,GAQT,OALA2rK,EAAuB94M,KAAKlC,KAAKmiJ,gBAAe9yG,GAAQi2F,EAAQ01E,EAAwB3rK,IAAO,KAAM,kBAAmB,KAAM,OAC9H2rK,EAAuB94M,KAAKlC,KAAKmiJ,gBAAe9yG,GAAQi2F,EAAQ01E,EAAwB3rK,IAAO0yD,EAAQktG,GAAGzH,OAAQ,WAAY,KAAM,OAEpIxnM,KAAKq4M,gBAEE,EAWT4C,2BAA2B5rK,GAEzBrvC,KAAK4hG,SAAWvyD,EAEhB,IAAK,IAAI7tC,EAAI,EAAGA,EAAI6tC,EAAKjyB,WAAW1b,OAAQF,IAAK,CAC/C,MAAM6b,EAAQgyB,EAAKjyB,WAAW5b,GAEP,SAAnB6b,EAAMyC,WACR9f,KAAKq1M,SAAU,GAGM,YAAnBh4L,EAAMyC,WACR9f,KAAKs1M,YAAa,GAItB,OAAKt1M,KAAKq1M,SAIEr1M,KAAKD,QAAQm7M,wBAGvBl7M,KAAK2jH,qBAAqB5hB,EAAQke,OAAO6wF,aAAc,MAFvD9wM,KAAKY,QAKA,IATLZ,KAAK2jH,qBAAqB5hB,EAAQke,OAAOuwF,SAAU,OAE5C,GAwBX5vM,OACE,IAAKZ,KAAKq1M,QAER,YADAtzG,EAAQz9F,IAAIy9F,EAAQuvG,SAAS1rM,KAAM,mEAIrC5F,KAAKmiJ,eAAeniJ,KAAKm7M,wBAAwBv6M,KAAKZ,MAAO,KAAM,KAAM,KAAM,gBAE/E,MAAMojG,EAAWrB,EAAQsxG,mBAAmBrzM,KAAKmjG,KAE7CC,EACFpjG,KAAKsjH,KAAKtE,EAAI,CACZp3G,KAAM,MACNvC,GAAI,iBACH8H,EAAE,OAAQ,CACXiH,MAAO2tF,EAAQktG,GAAGY,OACjB1iM,EAAE,WAAY,IAAInI,EAAEo+F,GAAU4gB,QAEjChkH,KAAKsjH,KAAKtE,EAAI,CACZp3G,KAAM,MACNvC,GAAI,iBACH8H,EAAE,OAAQ,CACXiH,MAAO2tF,EAAQktG,GAAGY,OACjB7rF,QAcPm3F,wBAAwB9rK,GACtB,GAAkC,UAA9BA,EAAK7sB,aAAa,QAAqB,CAGzC,IAAI42L,EAQJ,OAVAr3G,EAAQ7pF,KAAK,4BACIm3B,EAAKjrB,qBAAqB,YAG9B1iB,OAAS,IACpB03M,EAAYr3G,EAAQivG,eAAeE,UAGrClxM,KAAK2jH,qBAAqB5hB,EAAQke,OAAOuwF,SAAU4I,EAAW/pK,IAEvD,EAIT,MAAMzuC,EAAOyuC,EAAKjrB,qBAAqB,QAEvC,KAAIxjB,EAAKc,OAAS,GAkBhB,OAJAqgG,EAAQ7pF,KAAK,4BAEblY,KAAK2jH,qBAAqB5hB,EAAQke,OAAOuwF,SAAU,KAAMnhK,IAElD,EAlBY,CACnB,MAAM+rK,EAAUx6M,EAAK,GAAGwjB,qBAAqB,OAEzCg3L,EAAQ15M,OAAS,IACnB1B,KAAKg2M,eAAgB,EACrBh2M,KAAKmjG,IAAMpB,EAAQ5wD,QAAQiqK,EAAQ,IAE/Bp7M,KAAKs1M,WACPt1M,KAAKq7M,oBAELr7M,KAAK2jH,qBAAqB5hB,EAAQke,OAAOqQ,UAAW,QAqB5D+qF,oBACE,IAAKr7M,KAAKs1M,WACR,MAAM,IAAItxM,MAA0D,wEAAyB+9F,EAAQktG,GAAGa,2CAG1G9vM,KAAKmiJ,eAAeniJ,KAAKs7M,mBAAmB16M,KAAKZ,MAAO,KAAM,KAAM,KAAM,mBAE1EA,KAAKsjH,KAAKtE,EAAI,CACZp3G,KAAM,MACNvC,GAAI,oBACH8H,EAAE,UAAW,CACdiH,MAAO2tF,EAAQktG,GAAGa,UACjB9rF,QAsBLs3F,mBAAmBjsK,GACjB,GAAkC,WAA9BA,EAAK7sB,aAAa,QACpBxiB,KAAKg2M,eAAgB,EAErBh2M,KAAK2jH,qBAAqB5hB,EAAQke,OAAOqQ,UAAW,WAC/C,GAAkC,UAA9BjhF,EAAK7sB,aAAa,QAM3B,OALAxiB,KAAKg2M,eAAgB,EACrBj0G,EAAQ7pF,KAAK,4BAEblY,KAAK2jH,qBAAqB5hB,EAAQke,OAAOuwF,SAAU,KAAMnhK,IAElD,EAGT,OAAO,EAaTmrK,iBAAiBnrK,GAgBf,OAdIrvC,KAAKo2M,wBACPp2M,KAAK+gJ,cAAc/gJ,KAAKo2M,uBACxBp2M,KAAKo2M,sBAAwB,MAG3Bp2M,KAAKs2M,0BACPt2M,KAAK+gJ,cAAc/gJ,KAAKs2M,yBACxBt2M,KAAKs2M,wBAA0B,MAG7Bt2M,KAAK06M,iBAAiB16M,KAAK06M,gBAAgB5hF,YAE/C94H,KAAK2jH,qBAAqB5hB,EAAQke,OAAOuwF,SAAU,KAAMnhK,IAElD,EAgBTwrK,UAAUxrK,GAWR,MAVkC,WAA9BA,EAAK7sB,aAAa,SACpBxiB,KAAKg2M,eAAgB,EAErBh2M,KAAK2jH,qBAAqB5hB,EAAQke,OAAOqQ,UAAW,OACb,UAA9BjhF,EAAK7sB,aAAa,UAC3BxiB,KAAK2jH,qBAAqB5hB,EAAQke,OAAOuwF,SAAU,KAAMnhK,GAEzDrvC,KAAK60F,WAAW,2BAGX,EAeTokH,oBAAoBjE,EAAQ38K,GAC1B,MAAMigL,EAAQ,IAAIv2G,EAAQgzG,aAAaC,EAAQ38K,GAG/C,OAFAigL,EAAMxqG,MAAO,EACb9tG,KAAK21M,UAAUzzM,KAAKo2M,GACbA,EAkBTn2D,eAAe9pH,EAAS3Y,EAAIlT,EAAM5E,EAAMvC,GACtC,MAAMmzM,EAAO,IAAIz2G,EAAQuyG,QAAQj8K,EAAS3Y,EAAIlT,EAAM5E,EAAMvC,GAG1D,OAFAmzM,EAAK1qG,MAAO,EACZ9tG,KAAK41M,YAAY1zM,KAAKs2M,GACfA,EAaTU,uBAUE,OATAn3G,EAAQ/V,MAAM,mCAEdhsF,KAAK2jH,qBAAqB5hB,EAAQke,OAAO4wF,YAAa,MAEtD7wM,KAAKohH,OAAO83F,uBAGZl5M,KAAKkkH,iBAEE,EAUTqyF,UAIE,KAAOv2M,KAAK21M,UAAUj0M,OAAS,GAC7B1B,KAAKw1M,cAActzM,KAAKlC,KAAK21M,UAAU1+K,OAIzC,KAAOj3B,KAAKy1M,aAAa/zM,OAAS,GAAG,CACnC,MAAM42M,EAAQt4M,KAAKy1M,aAAax+K,MAC1Bz1B,EAAIxB,KAAKw1M,cAAcnyM,QAAQi1M,GAEjC92M,GAAK,GACPxB,KAAKw1M,cAAchyM,OAAOhC,EAAG,GAKjC,MAAMyrD,GAAM,IAAI9nD,MAAOq6G,UACjBgG,EAAU,GAEhB,IAAK,IAAIhkH,EAAI,EAAGA,EAAIxB,KAAKw1M,cAAc9zM,OAAQF,IAAK,CAClD,MAAM82M,EAAQt4M,KAAKw1M,cAAch0M,IAE7BxB,KAAKg2M,eAAkBsC,EAAMxqG,OACjBwqG,EAAMrD,WAAaqD,EAAMtD,OAE3B/nJ,GAAO,EACbqrJ,EAAMxD,OACRtvF,EAAQtjH,KAAKo2M,GAGf9yF,EAAQtjH,KAAKo2M,IAKnBt4M,KAAKw1M,cAAgBhwF,EACrBjjH,aAAavC,KAAK81M,cAElB91M,KAAKohH,OAAOm1F,UAGRv2M,KAAK09G,YACP19G,KAAK81M,aAAetzM,YAAW,IAAMxC,KAAKu2M,WAAW,QAK3Dx0G,EAAQsqG,cAAgBA,EAYxBtqG,EAAQ02G,cA3/HR,cAA4BpM,EAI1BjzL,YAAYmzL,EAAW,YAAaD,GAAgB,EAAOz6H,EAAW,IACpEqT,MAAMqnH,EAAUD,EAAez6H,GAGjCtiE,KAAKuzF,GAEH,OAA8B,OAAvBA,EAAWq0G,UAk/HtBp1G,EAAQ82G,UA/2HR,cAAwBxM,EAItBjzL,YAAYmzL,EAAW,QAASD,GAAgB,EAAMz6H,EAAW,IAC/DqT,MAAMqnH,EAAUD,EAAez6H,GAGjCtiE,KAAKuzF,GAEH,OAA8B,OAAvBA,EAAWq0G,QAGpB1K,YAAY3pG,GAEV,MAAM,QACJq0G,EAAO,QACPE,EAAO,OACP31F,EAAM,KACNS,GACErf,EAEJ,IAAK4e,EACH,MAAM,IAAI19G,MAAM,iDAKlB,IAAIu3M,EAAWlE,IAAY,GAAGF,KAAWz1F,IAAW21F,EAAU,GAK9D,OAJAkE,GAAsB,KACtBA,GAAsBpE,EACtBoE,GAAsB,KACtBA,GAAsBp5F,EACfyqF,EAAe2O,KA+0H1Bx5G,EAAQ+2G,SA1nHR,cAAuBzM,EAIrBjzL,YAAYmzL,EAAW,cAAeD,GAAgB,EAAMz6H,EAAW,IACrEqT,MAAMqnH,EAAUD,EAAez6H,GAGjCtiE,KAAKuzF,GAEH,OAA8B,OAAvBA,EAAWq0G,QAGpB1K,YAAY3pG,EAAY4pG,GAEtB,IAAIr+J,EAAOsqE,EAAM6iG,EAAMC,EAAIC,EAAGC,EAAOn6M,EAAG60B,EACpCs2J,EAAe,UACfivB,EAAc,GAAG94G,EAAWsyG,WAAW,gCAAgC1I,KAC3E,MAAMmP,EAAS/4G,EAAWsyG,WAAWyG,OAC/Bd,EAAc,wBAEpB,KAAOrO,EAAUtoM,MAAM22M,IAAc,CACnC,MAAMj4L,EAAU4pL,EAAUtoM,MAAM22M,GAGhC,OAFArO,EAAYA,EAAUj8L,QAAQqS,EAAQ,GAAI,IAElCA,EAAQ,IACd,IAAK,IACHurB,EAAQvrB,EAAQ,GAChB,MAEF,IAAK,IACH61F,EAAO71F,EAAQ,GACf,MAEF,IAAK,IACH04L,EAAO14L,EAAQ,IAKrB,GAAIurB,EAAMhqC,OAAO,EAAGw3M,EAAOn6M,UAAYm6M,EAErC,OADA/4G,EAAWsyG,WAAa,GACjBtyG,EAAW03G,mBAGpB7tB,GAAgB,KAAOt+I,EACvButK,GAAejvB,EACfh0E,EAAO+1F,KAAK/1F,GACZA,GAAQ,UACR,MAAMwJ,EAAOyqF,EAAe9pG,EAAWqf,MAGvC,IAFAs5F,EAAKE,EAAQtN,EAAKR,eAAe1rF,EAAMxJ,GAElCn3G,EAAI,EAAGA,EAAIg6M,EAAMh6M,IAAK,CAGzB,IAFAk6M,EAAIrN,EAAKR,eAAe1rF,EAAMksF,EAAKD,SAASuN,IAEvCtlL,EAAI,EAAGA,EAAI,EAAGA,IACjBolL,EAAGplL,IAAMqlL,EAAErlL,GAGbslL,EAAQD,EAGVD,EAAKpN,EAAKD,SAASqN,GACnB,MAAMK,EAAYzN,EAAKR,eAAe4N,EAAI,cACpCM,EAAY1N,EAAKE,cAAckN,EAAI,cACnCO,EAAkB3N,EAAKR,eAAeQ,EAAKG,SAASH,EAAKD,SAAS0N,IAAaF,GAGrF,IAFA94G,EAAWsyG,WAAW,oBAAsB/G,EAAKC,cAAcyN,EAAWH,GAErEvlL,EAAI,EAAGA,EAAI,EAAGA,IACjBylL,EAAUzlL,IAAM2lL,EAAgB3lL,GAIlC,OADAs2J,GAAgB,MAAQkiB,KAAKR,EAAKD,SAAS0N,IACpCnvB,EAGTggB,gBAAgB7pG,EAAYm5G,GAE1B,MAAMJ,EAASI,GAAelQ,EAAIC,UAAU,GAAqB,WAAhB/hM,KAAKE,UACtD,IAAIoxM,EAAW,KAAO3O,EAAe9pG,EAAWq0G,SAMhD,OALAoE,GAAY,MACZA,GAAYM,EACZ/4G,EAAWsyG,WAAWyG,OAASA,EAC/B/4G,EAAWsyG,WAAW,6BAA+BmG,EACrDA,EAAW,MAAQA,EACZA,IAsiHXx5G,EAAQ42G,gBAj5HR,cAA8BtM,EAI5BjzL,YAAYmzL,EAAW,cAAeD,GAAgB,EAAMz6H,EAAW,IACrEqT,MAAMqnH,EAAUD,EAAez6H,GAGjCtiE,KAAKuzF,GAEH,OAA2B,OAApBA,EAAWqf,KAGpBsqF,YAAY3pG,GAEV,IAAIy4G,EAAW,KAYf,OAV2B,OAAvBz4G,EAAWq0G,UACboE,EAAWA,EAAW,KAAOz4G,EAAWu0G,SAG1CkE,GAAsB,IACtBA,GAAsB,IACtBA,GAAsB,eACtBA,GAAsBz4G,EAAWqf,KACjCo5F,GAAsB,IACtBA,GAAsB,IACf3O,EAAe2O,KAu3H1Bx5G,EAAQ22G,aAh/HR,cAA2BrM,EASzBjzL,YAAYmzL,EAAW,WAAYD,GAAgB,EAAMz6H,EAAW,IAClEqT,MAAMqnH,EAAUD,EAAez6H,GAGjC46H,YAAY3pG,GAUV,OAAOA,EAAWq0G,UAAYr0G,EAAWu0G,QAAU,GAAKv0G,EAAWu0G,UA09HvEt1G,EAAQ62G,YAniHR,cAA0BvM,EAIxBjzL,YAAYmzL,EAAW,WAAYD,GAAgB,EAAMz6H,EAAW,IAClEqT,MAAMqnH,EAAUD,EAAez6H,GAGjCtiE,KAAKuzF,GAEH,OAA2B,OAApBA,EAAWqf,KAGpBsqF,YAAY3pG,GAEV,IAAIy4G,EAAW,KAQf,OAN2B,OAAvBz4G,EAAWq0G,UACboE,GAAsBz4G,EAAWu0G,SAGnCkE,GAAsB,KACtBA,GAAsBz4G,EAAWqf,KAC1ByqF,EAAe2O,KA6gH1B,IAAIW,EAAO,CACT,QAAWn6G,EACX,OAAUq1B,EACV,IAAOpY,EACP,KAAQ8F,EACR,MAAShB,EACT,KAAQuqF,EACR,IAAOtC,EACP,cAAiBsC,EAAKC,cACtB,SAAYD,EAAKhzF,SACjB,cAAiBgzF,EAAKE,cACtB,SAAYF,EAAKG,UAiBnBzsG,EAAQo6G,QAAU,MAWhB/iM,YAAYi2B,EAAMsS,EAAMsgE,EAAKm6F,GAC3Bp8M,KAAKqF,KAAO08F,EAAQ4xG,WACpB3zM,KAAKq8M,QAAUhtK,EACfrvC,KAAKyW,KAAOsrF,EAAQvmC,UAAUnsB,GAG9BrvC,KAAKs8M,SAAW36J,EAChB3hD,KAAK2hD,KAAOA,EACZ3hD,KAAKiiH,IAAMA,EACXjiH,KAAKu8M,KAAOC,IACZx8M,KAAKo8M,MAAQA,GAAS,EACtBp8M,KAAKy8M,OAAQ,EACbz8M,KAAK08M,KAAO,KAEZ18M,KAAK28M,IAAM,WACT,OAAK38M,KAAKu8M,MAIE,IAAIp3M,KACFnF,KAAKu8M,MAAQ,IAJlB,GAOXv8M,KAAK48M,SAAW,WACd,OAAK58M,KAAK08M,MAIE,IAAIv3M,KACFnF,KAAK08M,MAAQ,IAJlB,GAOX18M,KAAK68M,IAAM78M,KAAK88M,UAiBlBC,cACE,IAAI9pM,EAAO,KAEX,GAAIjT,KAAK68M,IAAIG,aAAeh9M,KAAK68M,IAAIG,YAAY59L,iBAG/C,GAFAnM,EAAOjT,KAAK68M,IAAIG,YAAY59L,gBAEP,gBAAjBnM,EAAKiD,QAIP,MAHA6rF,EAAQ1gG,MAAM,6BACd0gG,EAAQ1gG,MAAM,iBAAmBrB,KAAK68M,IAAIlwB,cAC1C5qF,EAAQ1gG,MAAM,gBAAkB0gG,EAAQvmC,UAAUx7D,KAAK68M,IAAIG,cACrD,IAAIh5M,MAAM,oBAEb,GAAIhE,KAAK68M,IAAIlwB,aAAc,CAKhC,GAHA5qF,EAAQ/V,MAAM,iFACd/4E,GAAO,IAAIL,GAAYmB,gBAAgB/T,KAAK68M,IAAIlwB,aAAc,mBAAmBvtK,iBAE5EnM,EACH,MAAM,IAAIjP,MAAM,8BACX,GAAIiP,EAAKg9F,cAAc,eAAgB,CAC5ClO,EAAQ1gG,MAAM,8BAAgC4R,EAAKg9F,cAAc,eAAe33D,aAChFypD,EAAQ1gG,MAAM,iBAAmBrB,KAAK68M,IAAIlwB,cAC1C,MAAMtrL,EAAQ,IAAI2C,MAElB,MADA3C,EAAMmL,KAAOu1F,EAAQivG,eAAeC,WAC9B5vM,GAIV,OAAO4R,EAYT6pM,UACE,IAAID,EAAM,KAcV,OAZIv6M,OAAOkqL,gBACTqwB,EAAM,IAAIrwB,eAENqwB,EAAII,kBACNJ,EAAII,iBAAiB,4BAEd36M,OAAOuoM,gBAChBgS,EAAM,IAAIhS,cAAc,sBAI1BgS,EAAIpwB,mBAAqBzsL,KAAK2hD,KAAK/gD,KAAK,KAAMZ,MACvC68M,IA6BX96G,EAAQ60G,KAAO,MAAMA,EACnBx9L,YAAY0pF,GACV9iG,KAAKk9M,MAAQp6G,EAGb9iG,KAAKiiH,IAAMh4G,KAAKC,MAAsB,WAAhBD,KAAKE,UAG3BnK,KAAKgiH,IAAM,KAEXhiH,KAAKi+D,KAAO,EACZj+D,KAAKkkD,KAAO,GACZlkD,KAAKsC,OAAS,EACdtC,KAAK2nM,OAAS,EACd3nM,KAAKm9M,WAAa,KAClBn9M,KAAK2hH,oBAAsB,KAC3B3hH,KAAK82M,UAAY,GAUnBlzF,aACE,MAAMm2F,EAAW3iF,EAAO,OAAQ,CAC9B,IAAOp3H,KAAKiiH,MACZ,MAASlgB,EAAQktG,GAAGC,WAatB,OAViB,OAAblvM,KAAKgiH,KACP+3F,EAASzkM,MAAM,CACb,IAAOtV,KAAKgiH,MAIZhiH,KAAKk9M,MAAMn9M,QAAQq9M,WAAap9M,KAAKk9M,MAAMxF,4BAC7C13M,KAAKq9M,gBAGAtD,EASTlD,SACE72M,KAAKiiH,IAAMh4G,KAAKC,MAAsB,WAAhBD,KAAKE,UAC3BnK,KAAKgiH,IAAM,KACXhiH,KAAK2nM,OAAS,EAEV3nM,KAAKk9M,MAAMxF,4BACbp1M,OAAOs1M,eAAe5yH,WAAW,wBAGnChlF,KAAKk9M,MAAMnF,aAAa/3M,KAAKiiH,KAS/BigC,SAASh+F,EAAM+Z,EAAMi5I,GACnBl3M,KAAKkkD,KAAOA,GAAQlkD,KAAKkkD,KACzBlkD,KAAKi+D,KAAOA,GAAQj+D,KAAKi+D,KACzBj+D,KAAK2nM,OAAS,EAEd,MAAMzgJ,EAAOlnD,KAAK4jH,aAAatuG,MAAM,CACnC,GAAMtV,KAAKk9M,MAAMx7F,OACjB,WAAY,KACZ,KAAQ1hH,KAAKkkD,KACb,KAAQlkD,KAAKi+D,KACb,QAAW,0BACX,IAAO,MACP,eAAgB,MAChB,aAAc8jC,EAAQktG,GAAGE,OAGvB+H,GACFhwJ,EAAK5xC,MAAM,CACT,MAAS4hM,IAIb,MAAM2C,EAAc75M,KAAKk9M,MAAMrD,YAE/B75M,KAAK82M,UAAU50M,KAAK,IAAI6/F,EAAQo6G,QAAQj1J,EAAK88D,OAAQhkH,KAAKs9M,sBAAsB18M,KAAKZ,KAAM65M,EAAYj5M,KAAKZ,KAAKk9M,QAASh2J,EAAK88D,OAAOxhG,aAAa,SAEnJxiB,KAAKu9M,2BA4BP/F,QAAQr0G,EAAK6e,EAAKC,EAAKrlG,EAAUsnC,EAAM+Z,EAAMs5I,GAC3Cv3M,KAAKk9M,MAAM/5G,IAAMA,EACjBnjG,KAAKgiH,IAAMA,EACXhiH,KAAKiiH,IAAMA,EACXjiH,KAAKk9M,MAAM5F,iBAAmB16L,EAC9B5c,KAAKk9M,MAAMx7F,OAAS3f,EAAQmxG,iBAAiBlzM,KAAKk9M,MAAM/5G,KACxDnjG,KAAKk9M,MAAMlH,eAAgB,EAC3Bh2M,KAAKk9M,MAAMx/F,WAAY,EACvB19G,KAAKkkD,KAAOA,GAAQlkD,KAAKkkD,KACzBlkD,KAAKi+D,KAAOA,GAAQj+D,KAAKi+D,KACzBj+D,KAAKsC,OAASi1M,GAAQv3M,KAAKsC,OAE3BtC,KAAKk9M,MAAMv5F,qBAAqB5hB,EAAQke,OAAO0wF,SAAU,MAuB3DgH,SAASx0G,EAAKvmF,EAAUsnC,EAAM+Z,EAAMs5I,GAClC,MAAM/vM,EAAUpG,KAAKwJ,MAAMtI,OAAOs1M,eAAehzH,QAAQ,yBAEzD,KAAI,MAAOp9E,GAA+CA,EAAQy6G,KAAOz6G,EAAQw6G,KAAOx6G,EAAQ27F,MAAQ,MAAOA,GAAuCpB,EAAQqxG,kBAAkB5rM,EAAQ27F,OAASpB,EAAQqxG,kBAAkBjwG,IAE3L,OAAhCpB,EAAQkxG,eAAe9vG,IAAiBpB,EAAQmxG,iBAAiB1rM,EAAQ27F,OAASA,IAI3E,CACL,MAAM9hG,EAAQ,IAAI2C,MAAM,qCAExB,MADA3C,EAAMmL,KAAO,sBACPnL,EANNrB,KAAKk9M,MAAMhH,UAAW,EAEtBl2M,KAAKw3M,QAAQhwM,EAAQ27F,IAAK37F,EAAQw6G,IAAKx6G,EAAQy6G,IAAKrlG,EAAUsnC,EAAM+Z,EAAMs5I,GAgB9E8F,gBACMr9M,KAAKk9M,MAAMlH,cACTh2M,KAAKk9M,MAAM/5G,KAAOnjG,KAAKiiH,KAAOjiH,KAAKgiH,KACrC1/G,OAAOs1M,eAAe9yH,QAAQ,uBAAwB1jF,KAAKF,UAAU,CACnE,IAAOlB,KAAKk9M,MAAM/5G,IAClB,IAAOnjG,KAAKiiH,IACZ,IAAOjiH,KAAKgiH,OAIhB1/G,OAAOs1M,eAAe5yH,WAAW,wBAYrC60H,YAAYE,GACV,MAAMyD,EAAMzD,EAASv3L,aAAa,QAElC,GAAY,OAARg7L,GAAwB,cAARA,EAAqB,CAEvC,IAAI9D,EAAOK,EAASv3L,aAAa,aACjCu/E,EAAQ1gG,MAAM,2BAA6Bq4M,GAC3C,MAAMC,EAAWI,EAAS31L,qBAAqB,YAc/C,OAZa,OAATs1L,GACW,wBAATA,GAAkCC,EAASj4M,OAAS,IACtDg4M,EAAO,YAGT15M,KAAKk9M,MAAMv5F,qBAAqB5hB,EAAQke,OAAOqwF,SAAUoJ,IAEzD15M,KAAKk9M,MAAMv5F,qBAAqB5hB,EAAQke,OAAOqwF,SAAU,WAG3DtwM,KAAKk9M,MAAMh5F,cAAcw1F,GAElB33G,EAAQke,OAAOqwF,SAKnBtwM,KAAKgiH,MACRhiH,KAAKgiH,IAAM+3F,EAASv3L,aAAa,QAGnC,MAAM+0L,EAAOwC,EAASv3L,aAAa,YAE/B+0L,IACFv3M,KAAKsC,OAASmG,SAAS8uM,EAAM,KAG/B,MAAMt5I,EAAO87I,EAASv3L,aAAa,QAE/By7C,IACFj+D,KAAKi+D,KAAOx1D,SAASw1D,EAAM,KAG7B,MAAM/Z,EAAO61J,EAASv3L,aAAa,QAE/B0hC,IACFlkD,KAAKkkD,KAAOz7C,SAASy7C,EAAM,KAG7B,MAAMi5J,EAAapD,EAASv3L,aAAa,cAErC26L,IACFn9M,KAAKm9M,WAAa10M,SAAS00M,EAAY,KAW3ChE,YAAYt1F,GACV7jH,KAAKy9M,eAAe55F,GAStBK,gBACElkH,KAAKgiH,IAAM,KACXhiH,KAAKiiH,IAAMh4G,KAAKC,MAAsB,WAAhBD,KAAKE,UAEvBnK,KAAKk9M,MAAMxF,4BACbp1M,OAAOs1M,eAAe5yH,WAAW,wBAGnChlF,KAAKk9M,MAAMnF,aAAa/3M,KAAKiiH,KAU/Bw3F,cACE,OAAiC,IAA1Bz5M,KAAK82M,UAAUp1M,OAUxBg8M,2BAA2B3+D,GACzB,MAAM4+D,EAAY/G,EAAKgH,kBAAkB7+D,GAEnC8+D,EAAe79M,KAAKk9M,MAAMrH,sBAAsBiI,KAAKH,GAEvDE,GACFA,EAAaj5M,KAAK5E,KAAM29M,GAe5BI,UAAUJ,GACR39M,KAAK2nM,SACL5lG,EAAQ7pF,KAAK,4BAA8BylM,EAAY,uBAAyB39M,KAAK2nM,QAEjF3nM,KAAK2nM,OAAS,GAChB3nM,KAAKk9M,MAAMhE,uBAUfe,kBAAkBr9L,GAChBmlF,EAAQ7pF,KAAK,gGAGX0E,EADEA,EACSA,EAAShc,KAAKZ,KAAKk9M,OAEnBl9M,KAAKk9M,MAAMrD,YAAYj5M,KAAKZ,KAAKk9M,OAG9C,MAAMh2J,EAAOlnD,KAAK4jH,aAElB5jH,KAAK82M,UAAU50M,KAAK,IAAI6/F,EAAQo6G,QAAQj1J,EAAK88D,OAAQhkH,KAAKs9M,sBAAsB18M,KAAKZ,KAAM4c,GAAWsqC,EAAK88D,OAAOxhG,aAAa,SAE/HxiB,KAAKu9M,2BASPrE,uBACEl5M,KAAKikH,oBAOPA,oBACE,KAAOjkH,KAAK82M,UAAUp1M,OAAS,GAAG,CAChC,MAAMq9I,EAAM/+I,KAAK82M,UAAU7/K,MAE3B8nH,EAAI09D,OAAQ,EACZ19D,EAAI89D,IAAIJ,QAER19D,EAAI89D,IAAIpwB,mBAAqB,cAUjC8pB,UACE,MAAM9/L,EAAOzW,KAAKk9M,MAAMr3J,MAOxB,GALI7lD,KAAKk9M,MAAMlH,eAA2C,IAA1Bh2M,KAAK82M,UAAUp1M,QAAgC,IAAhB+U,EAAK/U,SAAiB1B,KAAKk9M,MAAMz7F,gBAC9F1f,EAAQ/V,MAAM,wDACdv1E,EAAKvU,KAAK,QAGRlC,KAAKk9M,MAAM5sM,OAAf,CAIA,GAAItQ,KAAK82M,UAAUp1M,OAAS,GAAK+U,EAAK/U,OAAS,EAAG,CAChD,MAAMwlD,EAAOlnD,KAAK4jH,aAElB,IAAK,IAAIpiH,EAAI,EAAGA,EAAIiV,EAAK/U,OAAQF,IACf,OAAZiV,EAAKjV,KACS,YAAZiV,EAAKjV,GACP0lD,EAAK5xC,MAAM,CACT,GAAMtV,KAAKk9M,MAAMx7F,OACjB,WAAY,KACZ,eAAgB,OAChB,aAAc3f,EAAQktG,GAAGE,OAG3BjoJ,EAAK68D,MAAMttG,EAAKjV,IAAIujH,aAKnB/kH,KAAKk9M,MAAMr3J,MAClB7lD,KAAKk9M,MAAMr3J,MAAQ,GAEnB7lD,KAAK82M,UAAU50M,KAAK,IAAI6/F,EAAQo6G,QAAQj1J,EAAK88D,OAAQhkH,KAAKs9M,sBAAsB18M,KAAKZ,KAAMA,KAAKk9M,MAAM5D,UAAU14M,KAAKZ,KAAKk9M,QAASh2J,EAAK88D,OAAOxhG,aAAa,SAE5JxiB,KAAKu9M,2BAGP,GAAIv9M,KAAK82M,UAAUp1M,OAAS,EAAG,CAC7B,MAAMs8M,EAAeh+M,KAAK82M,UAAU,GAAG6F,MAER,OAA3B38M,KAAK82M,UAAU,GAAG4F,MAChB18M,KAAK82M,UAAU,GAAG8F,WAAa3yM,KAAKC,MAAM63F,EAAQ8vG,kBAAoB7xM,KAAKkkD,OAC7ElkD,KAAKu9M,2BAILS,EAAe/zM,KAAKC,MAAM63F,EAAQ9hB,QAAUjgF,KAAKkkD,QACnD69C,EAAQ7pF,KAAK,WAAalY,KAAK82M,UAAU,GAAGzxM,GAAK,oBAAsB4E,KAAKC,MAAM63F,EAAQ9hB,QAAUjgF,KAAKkkD,MAAQ,gCAEjHlkD,KAAKu9M,8BAeXU,yBAAyBl/D,EAAKm/D,GAC5B,IAAIP,EAEJ,GAA2B,IAAvB5+D,EAAI89D,IAAIr0K,WACV,IACEm1K,EAAY5+D,EAAI89D,IAAI5tH,OACpB,MAAOliF,GAGPg1F,EAAQ1gG,MAAM,mEAA0Es8M,GAQ5F,YAJyB,IAAdA,IACTA,EAA2B,iBAARO,EAAmBA,EAAM,GAGvCP,EAgBTL,sBAAsB37J,EAAMo9F,GAG1B,GAFAh9C,EAAQ/V,MAAM,cAAgB+yD,EAAI15I,GAAK,IAAM05I,EAAIq9D,MAAQ,qBAAuBr9D,EAAI89D,IAAIr0K,YAEpFu2G,EAAI09D,MAEN,YADA19D,EAAI09D,OAAQ,GAId,GAA2B,IAAvB19D,EAAI89D,IAAIr0K,WAEV,OAGF,MAAMm1K,EAAY/G,EAAKgH,kBAAkB7+D,GAIzC,GAFA/+I,KAAK2hH,oBAAsBo9B,EAAI89D,IAAIsB,wBAE/Bn+M,KAAKk9M,MAAMz7F,eAAiBk8F,GAAa,IAK3C,OAJA39M,KAAK+9M,UAAUJ,QAEf39M,KAAK09M,2BAA2B3+D,GAKlC,MAAMq/D,EAAgBT,EAAY,GAAKA,EAAY,IAC7CU,EAAmBt/D,EAAIq9D,MAAQp8M,KAAKk9M,MAAMv8F,WAShD,IAPIy9F,GAAiBC,KAEnBr+M,KAAKs+M,eAAev/D,GAEpBh9C,EAAQ/V,MAAM,cAAgB+yD,EAAI15I,GAAK,2BAGvB,MAAds4M,EAAmB,CAErB,MAAMY,EAASv+M,KAAK82M,UAAU,KAAO/3D,GACtB/+I,KAAK82M,UAAU,KAAO/3D,GAKvBw/D,GAAUv+M,KAAK82M,UAAUp1M,OAAS,GAAK1B,KAAK82M,UAAU,GAAG6F,MAAQ1yM,KAAKC,MAAM63F,EAAQ8vG,kBAAoB7xM,KAAKkkD,QACzHlkD,KAAKw+M,gBAAgB,GAGvBx+M,KAAKk9M,MAAMnF,aAAajpM,OAAOiwI,EAAI98B,KAAO,GAE1ClgB,EAAQ/V,MAAM,cAAgB+yD,EAAI15I,GAAK,IAAM05I,EAAIq9D,MAAQ,YACzDz6J,EAAKo9F,GAEL/+I,KAAK2nM,OAAS,OACS,IAAdgW,GAAmBA,GAAa,KAAOA,EAAY,KAAOA,GAAa,MAEhF57G,EAAQ1gG,MAAM,cAAgB09I,EAAI15I,GAAK,IAAM05I,EAAIq9D,MAAQ,UAAYuB,EAAY,aAEjF39M,KAAK+9M,UAAUJ,GAEf39M,KAAK09M,2BAA2B3+D,GAE5B4+D,GAAa,KAAOA,EAAY,MAClC39M,KAAKk9M,MAAMv5F,qBAAqB5hB,EAAQke,OAAOywF,cAAe,MAE9D1wM,KAAKk9M,MAAMh5F,kBAGbniB,EAAQ1gG,MAAM,cAAgB09I,EAAI15I,GAAK,IAAM05I,EAAIq9D,MAAQ,UAAYuB,EAAY,aAG9ES,GAAkBC,EAEZA,IAAqBr+M,KAAKk9M,MAAMx/F,WACzC19G,KAAKk9M,MAAMv5F,qBAAqB5hB,EAAQke,OAAOqwF,SAAU,aAFzDtwM,KAAKu9M,2BAgBTkB,gBAAgBj9M,GACd,IAAIu9I,EAAM/+I,KAAK82M,UAAUt1M,GAEzB,MAAMm8M,EAAY/G,EAAKgH,kBAAkB7+D,GAAM,GAG/C,GAAIA,EAAIq9D,MAAQp8M,KAAKk9M,MAAMv8F,WAGzB,YAFA3gH,KAAKk9M,MAAMhE,uBAKb,MAAM8E,EAAej/D,EAAI49D,MACnB+B,GAAmBh1K,MAAMs0K,IAAiBA,EAAe/zM,KAAKC,MAAM63F,EAAQ9hB,QAAUjgF,KAAKkkD,MAC3Fy6J,EAAiC,OAAb5/D,EAAI29D,MAAiB39D,EAAI69D,WAAa3yM,KAAKC,MAAM63F,EAAQ8vG,kBAAoB7xM,KAAKkkD,MACtG06J,EAAsC,IAAvB7/D,EAAI89D,IAAIr0K,aAAqBm1K,EAAY,GAAKA,GAAa,KAgBhF,IAdIe,GAAmBC,GAAqBC,KACtCD,GACF58G,EAAQ1gG,MAAM,WAAWrB,KAAK82M,UAAUt1M,GAAG6D,wCAG7C05I,EAAI09D,OAAQ,EACZ19D,EAAI89D,IAAIJ,QAER19D,EAAI89D,IAAIpwB,mBAAqB,aAE7BzsL,KAAK82M,UAAUt1M,GAAK,IAAIugG,EAAQo6G,QAAQp9D,EAAIs9D,QAASt9D,EAAIu9D,SAAUv9D,EAAI98B,IAAK88B,EAAIq9D,OAChFr9D,EAAM/+I,KAAK82M,UAAUt1M,IAGI,IAAvBu9I,EAAI89D,IAAIr0K,WAAkB,CAC5Bu5D,EAAQ/V,MAAM,cAAgB+yD,EAAI15I,GAAK,IAAM05I,EAAIq9D,MAAQ,YAEzD,IACE,MAAMyC,EAAe7+M,KAAKk9M,MAAMn9M,QAAQ++M,aAAe,0BACvD//D,EAAI89D,IAAIjwB,KAAK,OAAQ5sL,KAAKk9M,MAAMngG,SAAS/8G,KAAKk9M,MAAMn9M,QAAQ+qI,WAEpB,IAA7BiU,EAAI89D,IAAIhwB,kBAEjB9tC,EAAI89D,IAAIhwB,iBAAiB,eAAgBgyB,GAGvC7+M,KAAKk9M,MAAMn9M,QAAQg/M,kBACrBhgE,EAAI89D,IAAIkC,iBAAkB,GAE5B,MAAOC,GASP,OARAj9G,EAAQ1gG,MAAM,oBAAsB29M,EAAG99L,YAElClhB,KAAKk9M,MAAMx/F,WACd19G,KAAKk9M,MAAMv5F,qBAAqB5hB,EAAQke,OAAOqwF,SAAU,oBAG3DtwM,KAAKk9M,MAAMroH,aAOb,MAAMoqH,EAAW,KAGf,GAFAlgE,EAAIw9D,KAAO,IAAIp3M,KAEXnF,KAAKk9M,MAAMn9M,QAAQm/M,cAAe,CACpC,MAAM/7F,EAAUnjH,KAAKk9M,MAAMn9M,QAAQm/M,cAEnC,IAAK,MAAM37D,KAAUpgC,EACf/iH,OAAOa,UAAUwX,eAAe7T,KAAKu+G,EAASogC,IAChDxE,EAAI89D,IAAIhwB,iBAAiBtpC,EAAQpgC,EAAQogC,IAK/CxE,EAAI89D,IAAIv5F,KAAKy7B,EAAItoI,OAKnB,GAAIsoI,EAAIq9D,MAAQ,EAAG,CAGjB,MAAM+C,EAAsF,IAA5El1M,KAAK6uB,IAAI7uB,KAAKC,MAAM63F,EAAQ9hB,QAAUjgF,KAAKkkD,MAAOj6C,KAAK2wB,IAAImkH,EAAIq9D,MAAO,IACtF55M,YAAW,WAETy8M,MACCE,QAEHF,IAGFlgE,EAAIq9D,QAEAp8M,KAAKk9M,MAAMpF,YAAc/1G,EAAQmzG,WAAWj0M,UAAU62M,YACpD/4D,EAAIs9D,QAAQv8L,WAAa9f,KAAKw5M,OAASz6D,EAAIs9D,QAAQj/L,WAAW1b,OAChE1B,KAAKk9M,MAAMpF,UAAU/4D,EAAIs9D,QAAQj/L,WAAW,IAE5Cpd,KAAKk9M,MAAMpF,UAAU/4D,EAAIs9D,UAIzBr8M,KAAKk9M,MAAMz+D,YAAc18C,EAAQmzG,WAAWj0M,UAAUw9I,WACxDz+I,KAAKk9M,MAAMz+D,UAAUM,EAAItoI,WAG3BsrF,EAAQ/V,MAAM,qBAA6B,IAANxqF,EAAU,QAAU,UAAY,8BAAgCu9I,EAAI89D,IAAIr0K,YAWjH81K,eAAev/D,GACbh9C,EAAQ/V,MAAM,oBAEd,IAAK,IAAIxqF,EAAIxB,KAAK82M,UAAUp1M,OAAS,EAAGF,GAAK,EAAGA,IAC1Cu9I,IAAQ/+I,KAAK82M,UAAUt1M,IACzBxB,KAAK82M,UAAUtzM,OAAOhC,EAAG,GAK7Bu9I,EAAI89D,IAAIpwB,mBAAqB,aAE7BzsL,KAAKu9M,2BAUPiB,gBAAgBh9M,GACd,MAAMu9I,EAAM/+I,KAAK82M,UAAUt1M,GAEV,OAAbu9I,EAAI29D,OACN39D,EAAI29D,KAAO,IAAIv3M,MAGjBnF,KAAKy+M,gBAAgBj9M,GAgBvB+3M,WAAWx6D,GACT,IACE,OAAOA,EAAIg+D,cACX,MAAOhwM,GACP,GAAkB,gBAAdA,EAAEiO,QACJ,MAAMjO,EAGR/M,KAAKk9M,MAAMroH,WAAW,wBAY1B4oH,eAAe55F,GACb9hB,EAAQ/V,MAAM,6BAEd,MAAM9kC,EAAOlnD,KAAK4jH,aAAatuG,MAAM,CACnC1N,KAAM,cAGJi8G,GACF38D,EAAK68D,MAAMF,EAAKG,QAGlB,MAAM+6B,EAAM,IAAIh9C,EAAQo6G,QAAQj1J,EAAK88D,OAAQhkH,KAAKs9M,sBAAsB18M,KAAKZ,KAAMA,KAAKk9M,MAAM5D,UAAU14M,KAAKZ,KAAKk9M,QAASh2J,EAAK88D,OAAOxhG,aAAa,QAEpJxiB,KAAK82M,UAAU50M,KAAK68I,GAEpB/+I,KAAKu9M,2BASPt2D,QACE1kJ,aAAavC,KAAKk9M,MAAMpH,cAExB91M,KAAKu9M,2BAELv9M,KAAKk9M,MAAMpH,aAAetzM,YAAW,IAAMxC,KAAKk9M,MAAM3G,WAAW,KAQnE8B,eACEr4M,KAAKu9M,2BAELh7M,aAAavC,KAAKk9M,MAAMpH,cAW1ByH,2BACOv9M,KAAK82M,UAGR/0G,EAAQ/V,MAAM,wCAA0ChsF,KAAK82M,UAAUp1M,OAAS,aAFhFqgG,EAAQ/V,MAAM,2DAKXhsF,KAAK82M,WAAuC,IAA1B92M,KAAK82M,UAAUp1M,SAIlC1B,KAAK82M,UAAUp1M,OAAS,GAC1B1B,KAAKy+M,gBAAgB,GAGnBz+M,KAAK82M,UAAUp1M,OAAS,GAAKuI,KAAK4wB,IAAI76B,KAAK82M,UAAU,GAAG70F,IAAMjiH,KAAK82M,UAAU,GAAG70F,KAAOjiH,KAAKsC,QAC9FtC,KAAKy+M,gBAAgB,MAiB3B18G,EAAQ60G,KAAK31M,UAAUu4M,MAAQ,KA2B/Bz3G,EAAQ40G,UAAY,MAWlBv9L,YAAY0pF,GACV9iG,KAAKk9M,MAAQp6G,EACb9iG,KAAKw5M,MAAQ,UACb,MAAMz8F,EAAUja,EAAWia,QAE3B,GAA+B,IAA3BA,EAAQ15G,QAAQ,QAA4C,IAA5B05G,EAAQ15G,QAAQ,QAAe,CAGjE,IAAI+7M,EAAc,GAEkB,OAAhCt8G,EAAW/iG,QAAQ6xE,UAAkD,WAA7BtvE,OAAO0M,SAAS4iE,SAC1DwtI,GAAe,KAEfA,GAAe,MAGjBA,GAAe,MAAQ98M,OAAO0M,SAASqwM,KAEV,IAAzBtiG,EAAQ15G,QAAQ,KAClB+7M,GAAe98M,OAAO0M,SAASswM,SAAWviG,EAE1CqiG,GAAeriG,EAGjBja,EAAWia,QAAUqiG,GAWzBG,eACE,OAAOnoF,EAAO,OAAQ,CACpB,MAASr1B,EAAQktG,GAAGW,QACpB,GAAM5vM,KAAKk9M,MAAMx7F,OACjB,QAAW,QAcf89F,kBAAkBzF,EAAU0F,GAC1B,IAAI9X,EAQJ,GALEA,EADEoS,EAAS11L,uBACF01L,EAAS11L,uBAAuB09E,EAAQktG,GAAGzH,OAAQ,SAEnDuS,EAAS31L,qBAAqB,gBAGnB,IAAlBujL,EAAOjmM,OACT,OAAO,EAGT,MAAML,EAAQsmM,EAAO,GACrB,IAAIyR,EAAY,GACZp3M,EAAO,GAGX,IAAK,IAAIR,EAAI,EAAGA,EAAIH,EAAM+b,WAAW1b,OAAQF,IAAK,CAChD,MAAMuL,EAAI1L,EAAM+b,WAAW5b,GAE3B,GALS,wCAKLuL,EAAEyV,aAAa,SACjB,MAGiB,SAAfzV,EAAE+S,SACJ9d,EAAO+K,EAAEurC,YAET8gK,EAAYrsM,EAAE+S,SAIlB,IAAI4/L,EAAc,2BAkBlB,OAfEA,GADEtG,GAGa,UAGbp3M,IACF09M,GAAe,MAAQ19M,GAGzB+/F,EAAQ1gG,MAAMq+M,GAEd1/M,KAAKk9M,MAAMv5F,qBAAqB87F,EAAerG,GAE/Cp5M,KAAKk9M,MAAMh5F,iBAEJ,EAUT2yF,UAYA30D,WAEEliJ,KAAK6iH,eAEL7iH,KAAKqhH,OAAS,IAAIE,EAAUvhH,KAAKk9M,MAAMngG,QAAS,QAEhD/8G,KAAKqhH,OAAO0mC,OAAS,IAAM/nJ,KAAK2/M,UAEhC3/M,KAAKqhH,OAAOnpF,QAAUnrB,GAAK/M,KAAK0jM,SAAS32L,GAEzC/M,KAAKqhH,OAAOknC,QAAUx7I,GAAK/M,KAAK8iH,SAAS/1G,GAGzC/M,KAAKqhH,OAAO2mC,UAAYhtI,GAAWhb,KAAK4/M,kBAAkB5kM,GAY5D6+L,YAAYE,GAGV,GAFc/5M,KAAKw/M,kBAAkBzF,EAAUh4G,EAAQke,OAAOqwF,UAG5D,OAAOvuG,EAAQke,OAAOqwF,SAa1BuP,mBAAmB7kM,GACjB,IAAI3Z,GAAQ,EAEZ,MAAMqe,EAAK1E,EAAQwH,aAAa,SAEd,iBAAP9C,EACTre,EAAQ,4BACCqe,IAAOqiF,EAAQktG,GAAGW,UAC3BvuM,EAAQ,4BAA8Bqe,GAGxC,MAAMs7F,EAAMhgG,EAAQwH,aAAa,WAQjC,MANmB,iBAARw4F,EACT35G,EAAQ,8BACS,QAAR25G,IACT35G,EAAQ,8BAAgC25G,IAGtC35G,IACFrB,KAAKk9M,MAAMv5F,qBAAqB5hB,EAAQke,OAAOqwF,SAAUjvM,GAEzDrB,KAAKk9M,MAAMh5F,iBAEJ,GAaX07F,kBAAkB5kM,GAChB,GAAuC,IAAnCA,EAAQvE,KAAKpT,QAAQ,WAAqD,IAAlC2X,EAAQvE,KAAKpT,QAAQ,SAAgB,CAE/E,MAAMoT,EAAOuE,EAAQvE,KAAKhG,QAAQ,mBAAoB,IACtD,GAAa,KAATgG,EAAa,OACjB,MAAMqpM,GAAc,IAAIltM,GAAYmB,gBAAgB0C,EAAM,YAAY2I,gBAEtEpf,KAAKk9M,MAAMrF,SAASiI,GAEpB9/M,KAAKk9M,MAAM3/F,SAASviG,EAAQvE,MAGxBzW,KAAK6/M,mBAAmBC,IAE1B9/M,KAAK65M,YAAYiG,QAEd,GAAwC,IAApC9kM,EAAQvE,KAAKpT,QAAQ,WAAkB,CAGhD,MAAM08M,GAAgB,IAAIntM,GAAYmB,gBAAgBiH,EAAQvE,KAAM,YAAY2I,gBAEhFpf,KAAKk9M,MAAMrF,SAASkI,GAEpB//M,KAAKk9M,MAAM3/F,SAASviG,EAAQvE,MAE5B,MAAMupM,EAAUD,EAAcv9L,aAAa,iBAE3C,GAAIw9L,EAAS,CACX,MAAMjjG,EAAU/8G,KAAKk9M,MAAMngG,SAEFA,EAAQ15G,QAAQ,SAAW,GAAK28M,EAAQ38M,QAAQ,SAAW,GAAK05G,EAAQ15G,QAAQ,QAAU,KAGjHrD,KAAKk9M,MAAMv5F,qBAAqB5hB,EAAQke,OAAO2wF,SAAU,gDAEzD5wM,KAAKk9M,MAAMliK,QAEXh7C,KAAKk9M,MAAMngG,QAAUijG,EAErBhgN,KAAKkiJ,iBAGPliJ,KAAKk9M,MAAMv5F,qBAAqB5hB,EAAQke,OAAOqwF,SAAU,2BAEzDtwM,KAAKk9M,MAAMh5F,oBAER,CACLlkH,KAAKigN,yBAEL,MAAMxlL,EAASz6B,KAAKkgN,YAAYllM,EAAQvE,MAElC44B,GAAO,IAAIz8B,GAAYmB,gBAAgB0mB,EAAQ,YAAYrb,gBAEjEpf,KAAKk9M,MAAMrD,YAAYxqK,EAAM,KAAMr0B,EAAQvE,OAY/CwpM,yBACEjgN,KAAKqhH,OAAO2mC,UAAY7jJ,GAAKnE,KAAK4kH,WAAWzgH,GAY/Cg1M,YAAYt1F,GACV,GAAI7jH,KAAKqhH,QAAUrhH,KAAKqhH,OAAO74E,aAAe+4E,EAAU4+F,OAAQ,CAC1Dt8F,GACF7jH,KAAKk9M,MAAM55F,KAAKO,GAGlB,MAAM+yB,EAAQxf,EAAO,QAAS,CAC5B,MAASr1B,EAAQktG,GAAGW,UAGtB5vM,KAAKk9M,MAAMpF,UAAUlhE,EAAM5yB,QAE3B,MAAMo8F,EAAcr+G,EAAQvmC,UAAUo7E,GAEtC52I,KAAKk9M,MAAMz+D,UAAU2hE,GAErB,IACEpgN,KAAKqhH,OAAOiC,KAAK88F,GACjB,MAAOrzM,GACPg1F,EAAQ7pF,KAAK,iCAIjB1V,YAAW,IAAMxC,KAAKk9M,MAAMh5F,eAAe,GAS7CA,gBACEniB,EAAQ/V,MAAM,uCAEdhsF,KAAK6iH,eAQPq9F,YAAY38F,GAEV,MAAO,YAAcA,EAAS,aAShCV,eACE,GAAI7iH,KAAKqhH,OACP,IACErhH,KAAKqhH,OAAOknC,QAAU,KACtBvoJ,KAAKqhH,OAAOnpF,QAAU,KACtBl4B,KAAKqhH,OAAO2mC,UAAY,KACxBhoJ,KAAKqhH,OAAOu1B,QACZ,MAAO7pI,GACPg1F,EAAQ/V,MAAMj/E,EAAEiO,SAIpBhb,KAAKqhH,OAAS,KAUhBo4F,cAEE,OAAO,EAOT32F,SAAS/1G,GACH/M,KAAKk9M,MAAMx/F,YAAc19G,KAAKk9M,MAAMz7F,eACtC1f,EAAQ1gG,MAAM,iCAEdrB,KAAKk9M,MAAMh5F,iBACFn3G,GAAgB,OAAXA,EAAEgO,OAAkB/a,KAAKk9M,MAAMx/F,WAAa19G,KAAKqhH,QAK/Dtf,EAAQ1gG,MAAM,iCAEdrB,KAAKk9M,MAAMv5F,qBAAqB5hB,EAAQke,OAAOqwF,SAAU,0EAEzDtwM,KAAKk9M,MAAMh5F,iBAEXniB,EAAQ/V,MAAM,oBAUlBiuH,kBAAkBr9L,GAChBmlF,EAAQ1gG,MAAM,6DAEdrB,KAAKk9M,MAAMv5F,qBAAqB5hB,EAAQke,OAAOqwF,SAAUvuG,EAAQivG,eAAeI,cAE5Ex0L,GACFA,EAAShY,KAAK5E,KAAKk9M,OAGrBl9M,KAAKk9M,MAAMh5F,gBASbg1F,wBAOAj1F,qBAUAy/E,SAASriM,GACP0gG,EAAQ1gG,MAAM,mBAAqBD,KAAKF,UAAUG,IAElDrB,KAAKk9M,MAAMv5F,qBAAqB5hB,EAAQke,OAAOqwF,SAAU,0EAEzDtwM,KAAKm5M,cASP5C,UACE,MAAM9/L,EAAOzW,KAAKk9M,MAAMr3J,MAExB,GAAIpvC,EAAK/U,OAAS,IAAM1B,KAAKk9M,MAAM5sM,OAAQ,CACzC,IAAK,IAAI9O,EAAI,EAAGA,EAAIiV,EAAK/U,OAAQF,IAC/B,GAAgB,OAAZiV,EAAKjV,GAAa,CACpB,IAAI+hH,EAGFA,EADc,YAAZ9sG,EAAKjV,GACExB,KAAKu/M,eAAev7F,OAEpBvtG,EAAKjV,GAGhB,MAAM6+M,EAAYt+G,EAAQvmC,UAAU+nD,GAEpCvjH,KAAKk9M,MAAMpF,UAAUv0F,GAErBvjH,KAAKk9M,MAAMz+D,UAAU4hE,GAErBrgN,KAAKqhH,OAAOiC,KAAK+8F,GAIrBrgN,KAAKk9M,MAAMr3J,MAAQ,IA4BvB++D,WAAW5pG,GACT,IAAIq0B,EAEJ,MAAMunG,EAAQ,wDAEd,GAAI57H,EAAQvE,OAASmgI,EASnB,OARA52I,KAAKk9M,MAAM3/F,SAASq5B,GAEpB52I,KAAKk9M,MAAMrF,SAAS78L,QAEfhb,KAAKk9M,MAAMz7F,eACdzhH,KAAKk9M,MAAMh5F,iBAIR,GAAsC,IAAlClpG,EAAQvE,KAAKwwB,OAAO,WAI7B,GAFAoI,GAAO,IAAIz8B,GAAYmB,gBAAgBiH,EAAQvE,KAAM,YAAY2I,iBAE5Dpf,KAAK6/M,mBAAmBxwK,GAC3B,WAEG,CACL,MAAM54B,EAAOzW,KAAKkgN,YAAYllM,EAAQvE,MAEtC44B,GAAO,IAAIz8B,GAAYmB,gBAAgB0C,EAAM,YAAY2I,gBAG3D,OAAIpf,KAAKw/M,kBAAkBnwK,EAAM0yD,EAAQke,OAAOr+G,YAAhD,EAKI5B,KAAKk9M,MAAMz7F,eAA8C,aAA7BpyE,EAAKxyB,WAAWiD,UAAoE,gBAAzCuvB,EAAKxyB,WAAW2F,aAAa,SACtGxiB,KAAKk9M,MAAMrF,SAASxoK,QAEpBrvC,KAAKk9M,MAAM3/F,SAASxb,EAAQvmC,UAAUnsB,UAOxCrvC,KAAKk9M,MAAM5D,UAAUjqK,EAAMr0B,EAAQvE,MASrCkpM,UACE59G,EAAQ/V,MAAM,kBAEd,MAAM5pF,EAAQpC,KAAKu/M,eAEnBv/M,KAAKk9M,MAAMpF,UAAU11M,EAAM4hH,QAE3B,MAAMs8F,EAAcv+G,EAAQvmC,UAAUp5D,GAEtCpC,KAAKk9M,MAAMz+D,UAAU6hE,GAErBtgN,KAAKqhH,OAAOiC,KAAKg9F,GAenB/G,WAAWh2F,GAET,OAAOA,EAST0jC,QACEjnJ,KAAKk9M,MAAMz6M,QAQb41M,eACE91M,aAAavC,KAAKk9M,MAAMpH,cAExB91M,KAAKk9M,MAAM3G,QAAQ31M,KAAKZ,KAAKk9M,MAA7Bl9M,KAWJ,MAAMugN,EAAO,GACbA,EAAY,MAAIx+G,EAAQuvG,SAAS3rM,MACjC46M,EAAW,KAAIx+G,EAAQuvG,SAAS1rM,KAChC26M,EAAW,KAAIx+G,EAAQuvG,SAASxrM,KAChCy6M,EAAY,MAAIx+G,EAAQuvG,SAAS1vM,MACjC2+M,EAAY,MAAIx+G,EAAQuvG,SAASC,MAKjCxvG,EAAQ20G,gBAAkB,cAA8B30G,EAAQ40G,UAU9Dv9L,YAAY0pF,GACV5d,MAAM4d,GACN9iG,KAAKk9M,MAAQp6G,EACb9iG,KAAK6nI,OAAS,IAAI24E,aAAaxgN,KAAKk9M,MAAMn9M,QAAQ8nI,OAAQ,2BAE1D7nI,KAAK6nI,OAAO3vG,QAAUnrB,IACpB,IAAI2mM,EAEqB,QAAxBA,EAAWzwM,eAAkC,IAAbywM,GAA+BA,EAASryM,MAAM0L,GAC/Eg1F,EAAQz9F,IAAIy9F,EAAQuvG,SAAS1vM,MAAO,wBAAwBmL,MAI5Ds0G,aACF,MAAO,CACL,KAAQ1zG,GAAO3N,KAAK6nI,OAAO53H,KAAK05E,YAAY,CAAC,OAAQh8E,KAIzDu0I,WACEliJ,KAAKygN,gBAAkBt8M,GAAKnE,KAAK4/M,kBAAkBz7M,GAEnDnE,KAAK6nI,OAAO53H,KAAK7N,QAEjBpC,KAAK6nI,OAAO53H,KAAK+3I,UAAY5f,GAAMpoI,KAAK0gN,iBAAiBt4E,GAEzDpoI,KAAK6nI,OAAO53H,KAAK05E,YAAY,CAAC,WAAY3pF,KAAKk9M,MAAMngG,QAAS/8G,KAAKk9M,MAAM/5G,MAG3Eq0G,QAAQ56L,GACN5c,KAAKygN,gBAAkBt8M,GAAKnE,KAAK4kH,WAAWzgH,GAE5CnE,KAAKk9M,MAAM5F,iBAAmB16L,EAC9B5c,KAAK6nI,OAAO53H,KAAK7N,QAEjBpC,KAAK6nI,OAAO53H,KAAK+3I,UAAY5f,GAAMpoI,KAAK0gN,iBAAiBt4E,GAEzDpoI,KAAK6nI,OAAO53H,KAAK05E,YAAY,CAAC,UAAW3pF,KAAKk9M,MAAMngG,UAGtD4jG,gBAAgB1xH,EAAQkU,GAClBlU,IAAW8S,EAAQke,OAAO0wF,UAC5B3wM,KAAKk9M,MAAM/5G,IAAMA,EACjBnjG,KAAKk9M,MAAMlH,eAAgB,EAC3Bh2M,KAAKk9M,MAAMx/F,WAAY,EACvB19G,KAAKk9M,MAAMhH,UAAW,EAEtBl2M,KAAKk9M,MAAMv5F,qBAAqB5hB,EAAQke,OAAO0wF,WACtC1hH,IAAW8S,EAAQke,OAAO8wF,aACnC/wM,KAAKk9M,MAAMlH,eAAgB,EAC3Bh2M,KAAKk9M,MAAMx/F,WAAY,EACvB19G,KAAKk9M,MAAMhH,UAAW,EAEtBl2M,KAAKk9M,MAAMv5F,qBAAqB5hB,EAAQke,OAAO8wF,aAInDoI,YAAY3wK,EAAYq7E,GACtBA,GAAQ7jH,KAAKk9M,MAAM55F,KAAKO,GACxB,MAAM+yB,EAAQxf,EAAO,QAAS,CAC5B,MAASr1B,EAAQktG,GAAGW,UAGtB5vM,KAAKk9M,MAAMpF,UAAUlhE,EAAM5yB,QAE3B,MAAMo8F,EAAcr+G,EAAQvmC,UAAUo7E,GAEtC52I,KAAKk9M,MAAMz+D,UAAU2hE,GAErBpgN,KAAK6nI,OAAO53H,KAAK05E,YAAY,CAAC,OAAQy2H,IAEtCpgN,KAAKk9M,MAAMh5F,gBAGbpB,SAAS/1G,GACH/M,KAAKk9M,MAAMx/F,YAAc19G,KAAKk9M,MAAMz7F,eACtC1f,EAAQ1gG,MAAM,iCAEdrB,KAAKk9M,MAAMh5F,iBACFn3G,GAAgB,OAAXA,EAAEgO,OAAkB/a,KAAKk9M,MAAMx/F,WAK7C3b,EAAQ1gG,MAAM,iCAEdrB,KAAKk9M,MAAMv5F,qBAAqB5hB,EAAQke,OAAOqwF,SAAU,0EAEzDtwM,KAAKk9M,MAAMh5F,iBAEXniB,EAAQ/V,MAAM,oBAIlB62B,eACE7iH,KAAK6nI,OAAO53H,KAAK05E,YAAY,CAAC,iBAWhCs2H,yBACEjgN,KAAKygN,gBAAkBt8M,GAAKnE,KAAK4kH,WAAWzgH,GAO9Cu8M,iBAAiBt4E,GACf,MAAM,KACJ3xH,GACE2xH,EACEw4E,EAAcnqM,EAAK,GAEzB,GAAoB,eAAhBmqM,EACF5gN,KAAKygN,gBAAgBhqM,EAAK,SACrB,GAAImqM,KAAe5gN,KACxB,IACEA,KAAK4gN,GAAalgN,MAAMV,KAAMooI,EAAG3xH,KAAK9R,MAAM,IAC5C,MAAOoI,GACPg1F,EAAQz9F,IAAIy9F,EAAQuvG,SAAS1vM,MAAOmL,QAEjC,GAAoB,QAAhB6zM,EAAuB,CAChC,MAAMp8M,EAAQiS,EAAK,GACblV,EAAMkV,EAAK,GACjBsrF,EAAQz9F,IAAIi8M,EAAK/7M,GAAQjD,QAEzBwgG,EAAQz9F,IAAIy9F,EAAQuvG,SAAS1vM,MAAO,2CAA2C6U,OAMrF4zL,EAASjzE,OAAS8kF,EAAK9kF,OACvBizE,EAASrrF,IAAMk9F,EAAKl9F,IACpBqrF,EAASvlF,KAAOo3F,EAAKp3F,KACrBulF,EAASvmF,MAAQo4F,EAAKp4F,MACtBumF,EAAStoG,QAAUm6G,EAAKn6G,QACxB,MAAM,SACJsZ,GACEgzF,EAEJ9uM,EAAQ63H,OAASA,EACjB73H,EAAQy/G,IAAMA,EACdz/G,EAAQulH,KAAOA,EACfvlH,EAAQukH,MAAQA,EAChBvkH,EAAQwiG,QAAUA,EAClBxiG,EAAQ87G,SAAWA,EAEnBj7G,OAAO0kB,eAAevlB,EAAS,aAAc,CAAE4H,OAAO,IA7wMS7H,CAAQC,yBCG3E,SAAWshN,GAAc,aAEjCA,EAAW9+G,QAAQif,oBAAoB,QACvC,CACI2/D,YAAa,KACbplE,YAAc,GACdpO,UAAY,GACZ2zG,OAAS,GAOTl3K,KAAM,SAASm3K,GAEf/gN,KAAK2gL,YAAcogC,EACf/gN,KAAKu7G,YAAc,GACnBv7G,KAAKmtG,UAAc,GACnBntG,KAAK8gN,OAAc,GAEnBC,EAAKtoL,WAAWz4B,KAAKghN,aAAapgN,KAAKZ,MAAO6gN,EAAW9+G,QAAQktG,GAAGO,WAAY,KAAM,MAAO,KAAM,MAEnGuR,EAAKtoL,WAAWz4B,KAAKihN,cAAcrgN,KAAKZ,MAAO6gN,EAAW9+G,QAAQktG,GAAGQ,YAAa,KAAM,MAAO,KAAM,OAazGyR,YAAa,SAASrnG,EAAUjyG,EAAM4E,EAAMiH,GAExC,IAAK,IAAIjS,EAAE,EAAGA,EAAExB,KAAKu7G,YAAY75G,OAAQF,IAErC,GAAIxB,KAAKu7G,YAAY/5G,GAAGq4G,UAAYA,GAChC75G,KAAKu7G,YAAY/5G,GAAGoG,MAAQA,GAC5B5H,KAAKu7G,YAAY/5G,GAAGgL,MAAQA,GAC5BxM,KAAKu7G,YAAY/5G,GAAGiS,MAAQA,EAE5B,OAAO,EAIf,OADAzT,KAAKu7G,YAAYr5G,KAAK,CAAC23G,SAAUA,EAAUjyG,KAAMA,EAAM4E,KAAMA,EAAMiH,KAAMA,KAClE,GAUX2mG,WAAY,SAAS+mG,GAEjB,IAAK,IAAI3/M,EAAE,EAAGA,EAAExB,KAAKmtG,UAAUzrG,OAAQF,IAElC,GAAIxB,KAAKmtG,UAAU3rG,IAAM2/M,EACrB,OAAO,EAGhB,OADAnhN,KAAKmtG,UAAUjrG,KAAKi/M,IACb,GAUX3mG,cAAe,SAAS2mG,GAEpB,IAAK,IAAI3/M,EAAE,EAAGA,EAAExB,KAAKmtG,UAAUzrG,OAAQF,IAElC,GAAIxB,KAAKmtG,UAAU3rG,KAAO2/M,EAEtB,OADAnhN,KAAKmtG,UAAU3pG,OAAOhC,EAAE,IACjB,EAGhB,OAAO,GAaX4/M,QAAS,SAASj+G,EAAK32F,EAAMyG,EAAMouM,GAE/B,QAAIpuM,IAASouM,IAEbrhN,KAAK8gN,OAAO5+M,KAAK,CAACihG,IAAKA,EAAK32F,KAAMA,EAAMyG,KAAMA,EAAMouM,UAAWA,IACxD,KAUX71M,KAAM,SAAS23F,EAAKlwF,EAAM88E,EAAS1uF,EAAOy2D,GAEtC,IAAIxiD,EAAQ,CAAClB,MAAOysM,EAAW9+G,QAAQktG,GAAGO,YACtCv8L,IACAqC,EAAMrC,KAAOA,GAEjB,IAAIzH,EAAOq1M,EAAW7hG,IAAI,CAACngB,KAAK7+F,KAAK2gL,YAAYx9E,IAChC8b,GAAG9b,EAAKv7F,KAAK,QAAQuF,EAAE,QAASmI,GACjDtV,KAAK2gL,YAAYt9D,OAAO73G,EAAMukF,EAAS1uF,EAAOy2D,IAUlD6zE,MAAO,SAASxoC,EAAKlwF,EAAM88E,EAAS1uF,EAAOy2D,GAEvC,IAAIxiD,EAAQ,CAAClB,MAAOysM,EAAW9+G,QAAQktG,GAAGQ,aACtCx8L,IACAqC,EAAMrC,KAAOA,GAEjB,IAAI04H,EAAQk1E,EAAW7hG,IAAI,CAACngB,KAAK7+F,KAAK2gL,YAAYx9E,IACjC8b,GAAG9b,EAAKv7F,KAAK,QAAQuF,EAAE,QAASmI,GACjDtV,KAAK2gL,YAAYt9D,OAAOsoB,EAAO57C,EAAS1uF,EAAOy2D,IAKnDwpJ,eAAgB,SAAS/9F,EAAQg+F,GAE7B,IAAIl8M,EAAQk+G,EAAO/gG,aAAa,MAC5Bq8E,EAAO0kB,EAAO/gG,aAAa,QAC3Bg/L,EAAWX,EAAW7hG,IAAI,CAACp3G,KAAM,SAAUvC,GAAIA,IAMnD,OAJa,OAATw5F,GACA2iH,EAASlsM,MAAM,CAAC2pG,GAAIpgB,IAGjB2iH,EAASr0M,EAAE,QAASo0M,IAM/BP,aAAc,SAASz9F,GAEnB,IAEI/hH,EAFAyR,EAAOswG,EAAOn/F,qBAAqB,SAAS,GAAG5B,aAAa,QAC5DlN,EAAQ,CAAClB,MAAOysM,EAAW9+G,QAAQktG,GAAGO,YAEtCv8L,IAEAqC,EAAMrC,KAAOA,GAEjB,IAAIuuM,EAAWxhN,KAAKshN,eAAe/9F,EAAQjuG,GAC3C,IAAK9T,EAAE,EAAGA,EAAExB,KAAKu7G,YAAY75G,OAAQF,IAEjC8T,EAAQ,CAACukG,SAAU75G,KAAKu7G,YAAY/5G,GAAGq4G,SAC1BjyG,KAAU5H,KAAKu7G,YAAY/5G,GAAGoG,MACvC5H,KAAKu7G,YAAY/5G,GAAGgL,OACpB8I,EAAM9I,KAAOxM,KAAKu7G,YAAY/5G,GAAGgL,MACjCxM,KAAKu7G,YAAY/5G,GAAGiS,OACpB6B,EAAM,YAActV,KAAKu7G,YAAY/5G,GAAGiS,MAC5C+tM,EAASr0M,EAAE,WAAYmI,GAAOyvG,KAElC,IAAKvjH,EAAE,EAAGA,EAAExB,KAAKmtG,UAAUzrG,OAAQF,IAE/BggN,EAASr0M,EAAE,UAAW,CAAC,IAAMnN,KAAKmtG,UAAU3rG,KAAKujH,KAGrD,OADA/kH,KAAK2gL,YAAYr9D,KAAKk+F,EAASx9F,SACxB,GAKXi9F,cAAe,SAAS19F,GAEpB,IAEIooB,EAAOnqI,EAFP+/M,EAAc,CAACntM,MAAOysM,EAAW9+G,QAAQktG,GAAGQ,aAC5Cx8L,EAAOswG,EAAOn/F,qBAAqB,SAAS,GAAG5B,aAAa,QAEhE,GAAIvP,GAIA,IAFAsuM,EAAYtuM,KAAOA,EACnB04H,EAAQ,GACHnqI,EAAI,EAAGA,EAAIxB,KAAK8gN,OAAOp/M,OAAQF,IAEhC,GAAIxB,KAAK8gN,OAAOt/M,GAAGyR,MAAQA,EAC3B,CACI04H,EAAQ3rI,KAAK8gN,OAAOt/M,GAAG6/M,UAAU99F,GACjC,YAMRooB,EAAQ3rI,KAAK8gN,OAEjB,IAAIU,EAAWxhN,KAAKshN,eAAe/9F,EAAQg+F,GAC3C,IAAK//M,EAAI,EAAGA,EAAImqI,EAAMjqI,OAAQF,IAC9B,CACI,IAAI8T,EAAQ,CAAC6tF,IAAMwoC,EAAMnqI,GAAG2hG,KACxBwoC,EAAMnqI,GAAGgL,OACT8I,EAAM9I,KAAOm/H,EAAMnqI,GAAGgL,MACtBm/H,EAAMnqI,GAAGyR,OACTqC,EAAMrC,KAAO04H,EAAMnqI,GAAGyR,MAC1BuuM,EAASr0M,EAAE,OAAQmI,GAAOyvG,KAG9B,OADA/kH,KAAK2gL,YAAYr9D,KAAKk+F,EAASx9F,SACxB,KAnOiD1kH,CAAQ,EAAQ,4BCGxE,SAAWuhN,GAAc,aAYhCA,EAAW9+G,QAAQif,oBAAoB,mBAAoB,CAK1DygG,SAAS,EAOTC,oCAAoC,EAQpCC,wBAAyB,EAMzBC,GAAI,KAMJC,IAAK,gBAMLC,4BAA4B,EAQ5BC,gCAAiC,KAQjCC,+BAAgC,KAMhCC,0BAA2B,KAQ3BC,mBAAoB,KAMpBC,gBAAiB,KAMjBC,iBAAkB,KAKlBC,8BAA+B,EAM/BC,cAAc,EAKdC,uBAAwB,GAOxBC,6BAA8B,GAE9BC,8BAA+B,SAAS33K,GACvC9qC,KAAKwiN,6BAA6BtgN,KAAK4oC,IAGxCi4E,OAAQ,SAAS/wB,GAChB,IAAKhyF,KAAKsiN,aACT,MAAM,IAAIt+M,MAAM,sDACV,GAAIhE,KAAK8sG,oBAAsB+zG,EAAW9+G,QAAQke,OAAOqQ,UAC/D,MAAM,IAAItsH,MAAM,sDAEjBhE,KAAK4hN,GAAGt+F,KAAKu9F,EAAWzpF,OAAO,SAAU,CAAEhjH,MAAOpU,KAAK6hN,IAAK7vH,OAAAA,KAC5DhyF,KAAK4hN,GAAGn/M,QACRzC,KAAK4hN,GAAGn4E,SAGT3sB,eAAgB,WACf,OAAO98G,KAAK0iN,cAGbzgM,cACC,OAAOjiB,KAAKsiN,cAGbtwH,OAAQ,WACP,IAAKhyF,KAAK88G,iBACT,MAAM,IAAI94G,MAAM,mBAEjB,GAAIhE,KAAK8sG,oBAAsB+zG,EAAW9+G,QAAQke,OAAOwwF,aACxD,MAAM,IAAIzsM,MAAM,yDAGjBhE,KAAK4hN,GAAG7hN,QAAQm7M,yBAA0B,EAC1Cl7M,KAAK2iN,WAAY,EAEjB3iN,KAAK4iN,iBAAiBliN,MAAMV,KAAK4hN,GAAI5hN,KAAK6iN,eAG3CC,uBAAwB,WACvB,GAAI9iN,KAAK8sG,oBAAsB+zG,EAAW9+G,QAAQke,OAAOqQ,UACxD,MAAM,IAAItsH,MAAM,sEAEjBhE,KAAKqiN,8BAAgC,EACrCriN,KAAK4hN,GAAGt+F,KAAKu9F,EAAWzpF,OAAO,IAAK,CAAEhjH,MAAOpU,KAAK6hN,QAGnDkB,mBAAoB,WACnB,OAAO/iN,KAAKiiN,2BAGbe,mBAAoB,WACnB,OAAOhjN,KAAKgiN,gCAGbp4K,KAAM,SAASm3K,GACd/gN,KAAK4hN,GAAKb,EACVF,EAAW9+G,QAAQ+vG,aAAa,KAAM9xM,KAAK6hN,KAG3C7hN,KAAKkiN,mBAAqBliN,KAAK4hN,GAAG9J,UAClC93M,KAAK4hN,GAAG9J,UAAY93M,KAAK83M,UAAUl3M,KAAKZ,MAExCA,KAAK4iN,iBAAmB5iN,KAAK4hN,GAAGtvH,QAChCtyF,KAAK4hN,GAAGtvH,QAAUtyF,KAAKijN,sBAAsBriN,KAAKZ,MAElDA,KAAKkjN,mCAAqCljN,KAAK4hN,GAAG3G,2BAClDj7M,KAAK4hN,GAAG3G,2BAA6Bj7M,KAAKi7M,2BAA2Br6M,KAAKZ,MAE1EA,KAAKmjN,sBAAwBnjN,KAAK4hN,GAAG19F,cACrClkH,KAAK4hN,GAAG19F,cAAgBlkH,KAAKojN,uBAAuBxiN,KAAKZ,MAEzDA,KAAKqjN,oBAAsBrjN,KAAK4hN,GAAG/sH,WACnC70F,KAAK4hN,GAAG/sH,WAAa70F,KAAKsjN,qBAAqB1iN,KAAKZ,OAGrDsjN,qBAAsB,WACrBtjN,KAAK0iN,kBAAe32M,EACpB/L,KAAKqjN,oBAAoB3iN,MAAMV,KAAK4hN,GAAIjhN,YAGzCyiN,uBAAwB,WACnBpjN,KAAK88G,mBACH98G,KAAK2iN,WACN3iN,KAAK4hN,GAAGlkG,YAAc19G,KAAK4hN,GAAGngG,gBAClCzhH,KAAKujN,aAAe,CACnBvrL,SAAUh4B,KAAK4hN,GAAG5pL,SAClBw9K,cAAex1M,KAAK4hN,GAAGpM,cACvBC,aAAcz1M,KAAK4hN,GAAGnM,aACtBC,eAAgB11M,KAAK4hN,GAAGlM,eACxBC,UAAW31M,KAAK4hN,GAAGjM,UACnBC,YAAa51M,KAAK4hN,GAAGhM,aAEtB51M,KAAKwjN,WAAaxjN,KAAK4hN,GAAGz+G,IAE1BnjG,KAAKyhN,SAAWZ,EAAW9+G,QAAQ/V,MAAM,0CAA4ChsF,KAAKujN,aAAavrL,SAASt2B,SAKjH1B,KAAK4hN,GAAG/7J,MAAQ,GAEhB7lD,KAAKmjN,sBAAsBziN,MAAMV,KAAK4hN,GAAIjhN,YAG3CsiN,sBAAuB,WACtBjjN,KAAK6iN,aAAeliN,UAEpBX,KAAK4iN,iBAAiBliN,MAAMV,KAAK4hN,GAAIjhN,YAGtCs6M,2BAA4B,SAAS5rK,GAGpC,OAFArvC,KAAKsiN,aAAejzK,EAAKhrB,uBAAuBrkB,KAAK6hN,IAAK,MAAMngN,OAAS,EAElE1B,KAAKkjN,mCAAmCxiN,MAAMV,KAAK4hN,GAAIjhN,YAG/D04M,cAAe,SAAUpqH,GAExB,GADAjvF,KAAK8sG,kBAAoB7d,EACpBjvF,KAAK88G,kBACL7tB,IAAW4xH,EAAW9+G,QAAQke,OAAOqQ,WAAarhC,IAAW4xH,EAAW9+G,QAAQke,OAAOwwF,aAqCrF,GAAIxhH,IAAW4xH,EAAW9+G,QAAQke,OAAO6wF,aAAe,CAC9D9wM,KAAK4hN,GAAGz+G,IAAMnjG,KAAKwjN,WAGnB,IAAK,MAAMrlB,KAAYn+L,KAAKujN,aAC3BvjN,KAAK4hN,GAAGzjB,GAAYn+L,KAAKujN,aAAaplB,GAIvCn+L,KAAK4hN,GAAGt+F,KAAKu9F,EAAWzpF,OAAO,SAAU,CACxChjH,MAAOpU,KAAK6hN,IACZ3N,EAAGl0M,KAAKgiN,+BACRyB,OAAQzjN,KAAK0iN,gBAEd1iN,KAAK4hN,GAAGn/M,aACEwsF,IAAW4xH,EAAW9+G,QAAQke,OAAOr+G,QAC/C5B,KAAKyhN,SAAWZ,EAAW9+G,QAAQ/V,MAAM,oCACzChsF,KAAK0iN,kBAAe32M,QArDpB/L,KAAKyhN,SAAWZ,EAAW9+G,QAAQ/V,MAAM,kBAEzChsF,KAAK+hN,gCAAkC,EACvC/hN,KAAKgiN,+BAAiC,EAEtChiN,KAAKiiN,0BAA4B,EAEjCjiN,KAAK8hN,4BAA6B,EAClC9hN,KAAKqiN,8BAAgC,EAGrCriN,KAAK2iN,WAAY,EAEb1zH,IAAW4xH,EAAW9+G,QAAQke,OAAOwwF,eACxCzwM,KAAKsiN,cAAe,GAGrBtiN,KAAKuiN,uBAAyB,GAE1BviN,KAAKmiN,iBACRniN,KAAK4hN,GAAG7gE,cAAc/gJ,KAAKmiN,iBAGxBniN,KAAKoiN,kBACRpiN,KAAK4hN,GAAG7gE,cAAc/gJ,KAAKoiN,kBAG5BpiN,KAAKmiN,gBAAkBniN,KAAK4hN,GAAGnpL,WAAWz4B,KAAK0jN,4BAA4B9iN,KAAKZ,MAAOA,KAAK6hN,IAAK,KACjG7hN,KAAK2jN,YAAc3jN,KAAK4hN,GAAGnpL,WAAWz4B,KAAK4jN,iBAAiBhjN,KAAKZ,MAAOA,KAAK6hN,IAAK,KAClF7hN,KAAKoiN,iBAAmBpiN,KAAK4hN,GAAGnpL,WAAWz4B,KAAK6jN,uBAAuBjjN,KAAKZ,OAG5EA,KAAK8jN,gBAAkB9jN,KAAK4hN,GAAGz/D,eAAeniJ,KAAK+jN,eAAenjN,KAAKZ,MAAOA,KAAK6hN,IAAK,WACxF7hN,KAAKgkN,qBAAuBhkN,KAAK4hN,GAAGz/D,eAAeniJ,KAAKikN,oBAAoBrjN,KAAKZ,MAAOA,KAAK6hN,IAAK,UAClG7hN,KAAKkkN,gBAAmBlkN,KAAK4hN,GAAGz/D,eAAeniJ,KAAKmkN,eAAevjN,KAAKZ,MAAOA,KAAK6hN,IAAI,YA8B1F/J,UAAW,SAASzoK,GAOnB,OANIwxK,EAAW9+G,QAAQmwG,WAAW7iK,EAAM,OACvCwxK,EAAW9+G,QAAQmwG,WAAW7iK,EAAM,aACpCwxK,EAAW9+G,QAAQmwG,WAAW7iK,EAAM,aACpCrvC,KAAKokN,4BAA4B/0K,GAG3BrvC,KAAKkiN,mBAAmBt9M,KAAK5E,KAAK4hN,GAAIvyK,IAG9C00K,eAAgB,SAAS10K,GAOxB,OANArvC,KAAK8hN,4BAA6B,EAElC9hN,KAAK0iN,aAA+C,SAAhCrzK,EAAK7sB,aAAa,WAAwB6sB,EAAK7sB,aAAa,MAEhFxiB,KAAK4hN,GAAG5vH,UAED,GAGRiyH,oBAAqB,SAAS50K,GAC7B,MAAMhuC,EAAQguC,GAAQA,EAAKssB,mBAAqBtsB,EAAKssB,kBAAkBzlD,QAKvE,OAHAlW,KAAK4hN,GAAGj+F,qBAAqBk9F,EAAW9+G,QAAQke,OAAOr+G,MAAOP,EAAOguC,GACrErvC,KAAK4hN,GAAG19F,iBAED,GAGRigG,eAAgB,SAAS90K,GAExB,IAAIg1K,EAAe57M,SAAS4mC,EAAK7sB,aAAa,MAQ9C,GAPAxiB,KAAKskN,2BAA2BD,EAAcrkN,KAAK+hN,iCAEnD/hN,KAAK2iN,WAAY,EACjB3iN,KAAK4hN,GAAGvM,SAAU,EAClBr1M,KAAK4hN,GAAG5L,eAAgB,EACxBh2M,KAAK4hN,GAAG1L,UAAW,EAEfl2M,KAAKuiN,uBAAuB7gN,OAAS,EAAG,CAC3C1B,KAAKyhN,SAAWZ,EAAW9+G,QAAQ/V,MAAM,oCAAqChsF,KAAKuiN,wBACnF,IAAI,MAAMh/F,KAAUvjH,KAAKuiN,uBACxBviN,KAAK4hN,GAAGt+F,KAAKC,QAGdvjH,KAAKyhN,SAAWZ,EAAW9+G,QAAQ/V,MAAM,+BAAgChsF,KAAKuiN,wBAK/E,OAFAviN,KAAK4hN,GAAGj+F,qBAAqBk9F,EAAW9+G,QAAQke,OAAOqQ,UAAW,OAE3D,GAGRuzF,uBAAwB,SAASx0K,GAShC,OARIwxK,EAAW9+G,QAAQmwG,WAAW7iK,EAAM,OAASwxK,EAAW9+G,QAAQmwG,WAAW7iK,EAAM,aAAewxK,EAAW9+G,QAAQmwG,WAAW7iK,EAAM,cACvIrvC,KAAKukN,kCAEDvkN,KAAK0hN,oCACR1hN,KAAKwkN,4BAIA,GAGRF,2BAA4B,SAASG,EAAsBC,GAC1D,IAAIr1L,EAAQo1L,EAAuBC,EAE/Br1L,EAAQ,GACXrvB,KAAK2kN,YAAY,uDAAyDF,EAAuB,gBAAkBC,GAGhHr1L,EAAQrvB,KAAKuiN,uBAAuB7gN,QACvC1B,KAAK2kN,YAAY,8FAAgGt1L,EAAQ,kCAAoCrvB,KAAKuiN,uBAAuB7gN,OAAS,WAAa+iN,EAAuB,gBAAkBC,GAGzP,IAAI,IAAIljN,EAAI,EAAGA,EAAI6tB,EAAO7tB,IAEzB,IADA,IAAI+hH,EAASvjH,KAAKuiN,uBAAuBp1K,QAChCniC,EAAI,EAAGA,EAAIhL,KAAKwiN,6BAA6B9gN,OAAQsJ,IAC7DhL,KAAKwiN,6BAA6Bx3M,GAAGu4G,GAInCvjH,KAAKyhN,SAAWzhN,KAAKuiN,uBAAuB7gN,OAAS,GACxDm/M,EAAW9+G,QAAQ7pF,KAAK,4BAA6BlY,KAAKuiN,wBAG3DviN,KAAK+hN,gCAAkC0C,EAEnCzkN,KAAK2hN,wBAA0B,IAClC3hN,KAAKqiN,8BAAgC,IAIvCqB,4BAA6B,WAG5B,OAFA1jN,KAAKwkN,2BAEE,GAGRZ,iBAAkB,SAASv0K,GAC1B,IAAIg1K,EAAe57M,SAAS4mC,EAAK7sB,aAAa,MAG9C,OAFAxiB,KAAKskN,2BAA2BD,EAAcrkN,KAAK+hN,kCAE5C,GAGRyC,wBAAyB,WACpBxkN,KAAK8hN,4BACR9hN,KAAK4hN,GAAGt+F,KAAKu9F,EAAWzpF,OAAO,IAAK,CAAEhjH,MAAOpU,KAAK6hN,IAAK3N,EAAGl0M,KAAKgiN,mCAIjEoC,4BAA6B,SAAS/0K,GACrC,GAAIrvC,KAAK8hN,2BAA4B,CACpC,IAAmD,IAA/C9hN,KAAKuiN,uBAAuBl/M,QAAQgsC,GAEvC,OAGDrvC,KAAKuiN,uBAAuBrgN,KAAKmtC,GACjCrvC,KAAKiiN,4BAEDjiN,KAAK2hN,wBAA0B,IAClC3hN,KAAKqiN,gCAEDriN,KAAKqiN,gCAAkCriN,KAAK2hN,yBAE/Cn/M,YAAW,KACNxC,KAAK8sG,oBAAsB+zG,EAAW9+G,QAAQke,OAAOqQ,WACxDtwH,KAAK8iN,2BAEJ,MAMPyB,gCAAiC,WAC5BvkN,KAAK8hN,4BACR9hN,KAAKgiN,kCAIP2C,YAAa,SAASpjN,GAErB,MADAs/M,EAAW9+G,QAAQ1gG,MAAME,GACnB,IAAIyC,MAAMzC,MAjc6CjC,CAAQ,EAAQ,4qCCShF,IAAIslN,GAAe,EACfC,GAAuB,EAUpB,SAASC,EAAeC,EAAUn1M,EAAM8lB,GAC7C,MAAMtxB,EAAQ2gN,EAAS3gN,MAAMwL,GAC7B,OAAOxL,GAASA,EAAM1C,QAAUg0B,GAAOjtB,SAASrE,EAAMsxB,GAAM,IAMvD,SAASsvL,EAAwB1iN,EAAQ2iN,EAAiB3/E,GAC/D,IAAKhjI,EAAO2oJ,kBACV,OAEF,MAAM76G,EAAQ9tC,EAAO2oJ,kBAAkBhqJ,UACjCikN,EAAyB90K,EAAM/D,iBACrC+D,EAAM/D,iBAAmB,SAAS84K,EAAiBngF,GACjD,GAAImgF,IAAoBF,EACtB,OAAOC,EAAuBxkN,MAAMV,KAAMW,WAE5C,MAAMykN,EAAmBr4M,IACvB,MAAMs4M,EAAgB//E,EAAQv4H,GAC1Bs4M,IACErgF,EAAGsgF,YACLtgF,EAAGsgF,YAAYD,GAEfrgF,EAAGqgF,KAST,OALArlN,KAAKulN,UAAYvlN,KAAKulN,WAAa,GAC9BvlN,KAAKulN,UAAUN,KAClBjlN,KAAKulN,UAAUN,GAAmB,IAAI5+I,KAExCrmE,KAAKulN,UAAUN,GAAiB//L,IAAI8/G,EAAIogF,GACjCF,EAAuBxkN,MAAMV,KAAM,CAACmlN,EACzCC,KAGJ,MAAMI,EAA4Bp1K,EAAM7D,oBACxC6D,EAAM7D,oBAAsB,SAAS44K,EAAiBngF,GACpD,GAAImgF,IAAoBF,IAAoBjlN,KAAKulN,YACzCvlN,KAAKulN,UAAUN,GACrB,OAAOO,EAA0B9kN,MAAMV,KAAMW,WAE/C,IAAKX,KAAKulN,UAAUN,GAAiB1lK,IAAIylF,GACvC,OAAOwgF,EAA0B9kN,MAAMV,KAAMW,WAE/C,MAAM8kN,EAAczlN,KAAKulN,UAAUN,GAAiBjgM,IAAIggH,GAQxD,OAPAhlI,KAAKulN,UAAUN,GAAiB10H,OAAOy0C,GACM,IAAzChlI,KAAKulN,UAAUN,GAAiBjgJ,aAC3BhlE,KAAKulN,UAAUN,GAEmB,IAAvC7kN,OAAOC,KAAKL,KAAKulN,WAAW7jN,eACvB1B,KAAKulN,UAEPC,EAA0B9kN,MAAMV,KAAM,CAACmlN,EAC5CM,KAGJrlN,OAAO0kB,eAAesrB,EAAO,KAAO60K,EAAiB,CACnDjgM,MACE,OAAOhlB,KAAK,MAAQilN,IAEtB//L,IAAI8/G,GACEhlI,KAAK,MAAQilN,KACfjlN,KAAKusC,oBAAoB04K,EACrBjlN,KAAK,MAAQilN,WACVjlN,KAAK,MAAQilN,IAElBjgF,GACFhlI,KAAKqsC,iBAAiB44K,EAClBjlN,KAAK,MAAQilN,GAAmBjgF,IAGxCxmG,YAAY,EACZuG,cAAc,IAIX,SAAS2gL,EAAWntJ,GACzB,MAAoB,kBAATA,EACF,IAAIv0D,MAAM,yBAA2Bu0D,EACxC,4BAENqsJ,EAAersJ,EACR,EAAS,8BACZ,8BAOC,SAASotJ,EAAgBptJ,GAC9B,MAAoB,kBAATA,EACF,IAAIv0D,MAAM,yBAA2Bu0D,EACxC,4BAENssJ,GAAwBtsJ,EACjB,oCAAsCA,EAAO,WAAa,YAG5D,SAASj0D,IACd,GAAsB,iBAAXhC,OAAqB,CAC9B,GAAIsiN,EACF,OAEqB,oBAAZ3hN,SAAkD,mBAAhBA,QAAQqB,KACnDrB,QAAQqB,IAAI5D,MAAMuC,QAAStC,YAQ1B,SAASilN,EAAWC,EAAWC,GAC/BjB,GAGL5hN,QAAQiV,KAAK2tM,EAAY,8BAAgCC,EACrD,aAwDN,SAAS79I,EAASz5B,GAChB,MAA+C,oBAAxCpuC,OAAOa,UAAUigB,SAAStc,KAAK4pC,GAQjC,SAASu3K,EAActvM,GAC5B,OAAKwxD,EAASxxD,GAIPrW,OAAOC,KAAKoW,GAAM5G,QAAO,SAAS+0D,EAAa12D,GACpD,MAAMi/L,EAAQllI,EAASxxD,EAAKvI,IACtB/G,EAAQgmM,EAAQ4Y,EAActvM,EAAKvI,IAAQuI,EAAKvI,GAChDoiC,EAAgB68J,IAAU/sM,OAAOC,KAAK8G,GAAOzF,OACnD,YAAcqK,IAAV5E,GAAuBmpC,EAClBs0B,EAEFxkE,OAAOqmC,OAAOm+B,EAAa,CAAC,CAAC12D,GAAM/G,MACzC,IAXMsP,EAeJ,SAASuvM,EAAUpyH,EAAOhxE,EAAMqjM,GAChCrjM,IAAQqjM,EAAU1mK,IAAI38B,EAAKvd,MAGhC4gN,EAAU/gM,IAAItC,EAAKvd,GAAIud,GACvBxiB,OAAOC,KAAKuiB,GAAMriB,SAAQiM,IACpBA,EAAKu1I,SAAS,MAChBikE,EAAUpyH,EAAOA,EAAM5uE,IAAIpC,EAAKpW,IAAQy5M,GAC/Bz5M,EAAKu1I,SAAS,QACvBn/H,EAAKpW,GAAMjM,SAAQ8E,IACjB2gN,EAAUpyH,EAAOA,EAAM5uE,IAAI3f,GAAK4gN,UAOjC,SAASC,EAAY5sL,EAAQ6+C,EAAOguI,GACzC,MAAMC,EAAkBD,EAAW,eAAiB,cAC9CE,EAAiB,IAAIhgJ,IAC3B,GAAc,OAAV8R,EACF,OAAOkuI,EAET,MAAMC,EAAa,GAcnB,OAbAhtL,EAAO/4B,SAAQ4G,IACM,UAAfA,EAAMS,MACNT,EAAM80F,kBAAoB9jB,EAAM9yE,IAClCihN,EAAWpkN,KAAKiF,MAGpBm/M,EAAW/lN,SAAQgmN,IACjBjtL,EAAO/4B,SAAQqzF,IACTA,EAAMhsF,OAASw+M,GAAmBxyH,EAAM88D,UAAY61D,EAAUlhN,IAChE2gN,EAAU1sL,EAAQs6D,EAAOyyH,SAIxBA,EC1PT,MAAM5E,EAAU,EAET,SAAS+E,EAAiBlkN,EAAQmkN,GACvC,MAAMpiI,EAAY/hF,GAAUA,EAAO+hF,UAEnC,IAAKA,EAAUkD,aACb,OAGF,MAAMm/H,EAAuB,SAASv5M,GACpC,GAAiB,iBAANA,GAAkBA,EAAE2zE,WAAa3zE,EAAEktH,SAC5C,OAAOltH,EAET,MAAMw5M,EAAK,GA4CX,OA3CAvmN,OAAOC,KAAK8M,GAAG5M,SAAQ2N,IACrB,GAAY,YAARA,GAA6B,aAARA,GAA8B,gBAARA,EAC7C,OAEF,MAAMhB,EAAuB,iBAAXC,EAAEe,GAAqBf,EAAEe,GAAO,CAACw6I,MAAOv7I,EAAEe,SAC5CnC,IAAZmB,EAAE05M,OAA0C,iBAAZ15M,EAAE05M,QACpC15M,EAAE4rB,IAAM5rB,EAAEmqB,IAAMnqB,EAAE05M,OAEpB,MAAMC,EAAW,SAASxwM,EAAQ7J,GAChC,OAAI6J,EACKA,EAAS7J,EAAKsoB,OAAO,GAAGiwB,cAAgBv4C,EAAK7H,MAAM,GAE3C,aAAT6H,EAAuB,WAAaA,GAE9C,QAAgBT,IAAZmB,EAAEw7I,MAAqB,CACzBi+D,EAAGtsF,SAAWssF,EAAGtsF,UAAY,GAC7B,IAAI7oH,EAAK,GACc,iBAAZtE,EAAEw7I,OACXl3I,EAAGq1M,EAAS,MAAO34M,IAAQhB,EAAEw7I,MAC7Bi+D,EAAGtsF,SAASn4H,KAAKsP,GACjBA,EAAK,GACLA,EAAGq1M,EAAS,MAAO34M,IAAQhB,EAAEw7I,MAC7Bi+D,EAAGtsF,SAASn4H,KAAKsP,KAEjBA,EAAGq1M,EAAS,GAAI34M,IAAQhB,EAAEw7I,MAC1Bi+D,EAAGtsF,SAASn4H,KAAKsP,SAGLzF,IAAZmB,EAAE05M,OAA0C,iBAAZ15M,EAAE05M,OACpCD,EAAG7lI,UAAY6lI,EAAG7lI,WAAa,GAC/B6lI,EAAG7lI,UAAU+lI,EAAS,GAAI34M,IAAQhB,EAAE05M,OAEpC,CAAC,MAAO,OAAOrmN,SAAQumN,SACN/6M,IAAXmB,EAAE45M,KACJH,EAAG7lI,UAAY6lI,EAAG7lI,WAAa,GAC/B6lI,EAAG7lI,UAAU+lI,EAASC,EAAK54M,IAAQhB,EAAE45M,UAKzC35M,EAAE45M,WACJJ,EAAGtsF,UAAYssF,EAAGtsF,UAAY,IAAIt1H,OAAOoI,EAAE45M,WAEtCJ,GAGHK,EAAmB,SAASvmI,EAAa9+B,GAC7C,GAAI8kK,EAAex1M,SAAW,GAC5B,OAAO0wC,EAAK8+B,GAGd,IADAA,EAAcr/E,KAAKwJ,MAAMxJ,KAAKF,UAAUu/E,MACQ,iBAAtBA,EAAYqY,MAAoB,CACxD,MAAMmuH,EAAQ,SAAS94M,EAAKd,EAAGD,GACzBC,KAAKc,KAASf,KAAKe,KACrBA,EAAIf,GAAKe,EAAId,UACNc,EAAId,KAIf45M,GADAxmI,EAAcr/E,KAAKwJ,MAAMxJ,KAAKF,UAAUu/E,KACtBqY,MAAO,kBAAmB,uBAC5CmuH,EAAMxmI,EAAYqY,MAAO,mBAAoB,wBAC7CrY,EAAYqY,MAAQ4tH,EAAqBjmI,EAAYqY,OAEvD,GAAIrY,GAA4C,iBAAtBA,EAAYG,MAAoB,CAExD,IAAIsmI,EAAOzmI,EAAYG,MAAMssE,WAC7Bg6D,EAAOA,IAA0B,iBAATA,EAAqBA,EAAO,CAACx+D,MAAOw+D,IAC5D,MAAMC,EAA6BV,EAAex1M,QAAU,GAE5D,GAAKi2M,IAAwB,SAAfA,EAAKN,OAAmC,gBAAfM,EAAKN,OACf,SAAfM,EAAKx+D,OAAmC,gBAAfw+D,EAAKx+D,UACtCrkE,EAAUkD,aAAa6/H,0BACvB/iI,EAAUkD,aAAa6/H,0BAA0Bl6D,YAChDi6D,GAA6B,CAElC,IAAIrkM,EAMJ,UAPO29D,EAAYG,MAAMssE,WAEN,gBAAfg6D,EAAKN,OAA0C,gBAAfM,EAAKx+D,MACvC5lI,EAAU,CAAC,OAAQ,QACK,SAAfokM,EAAKN,OAAmC,SAAfM,EAAKx+D,QACvC5lI,EAAU,CAAC,UAETA,EAEF,OAAOuhE,EAAUkD,aAAaskE,mBAC7BjrG,MAAK2/B,IAEJ,IAAI8mI,GADJ9mI,EAAUA,EAAQx5E,QAAOizB,GAAgB,eAAXA,EAAEu8C,QACdluE,MAAK2xB,GAAKlX,EAAQlX,MAAKxH,GACvC41B,EAAEuwH,MAAMpzH,cAAcsmF,SAASr5G,OAUjC,OATKijN,GAAO9mI,EAAQ7+E,QAAUohB,EAAQ26F,SAAS,UAC7C4pG,EAAM9mI,EAAQA,EAAQ7+E,OAAS,IAE7B2lN,IACF5mI,EAAYG,MAAMypE,SAAW68D,EAAKN,MAAQ,CAACA,MAAOS,EAAIh9D,UACZ,CAAC3B,MAAO2+D,EAAIh9D,WAExD5pE,EAAYG,MAAQ8lI,EAAqBjmI,EAAYG,OACrD6gI,EAAQ,WAAargN,KAAKF,UAAUu/E,IAC7B9+B,EAAK8+B,MAIlBA,EAAYG,MAAQ8lI,EAAqBjmI,EAAYG,OAGvD,OADA6gI,EAAQ,WAAargN,KAAKF,UAAUu/E,IAC7B9+B,EAAK8+B,IAGR6mI,EAAa,SAASv6M,GAC1B,OAAI05M,EAAex1M,SAAW,GACrBlE,EAEF,CACLP,KAAM,CACJ+6M,sBAAuB,kBACvBC,yBAA0B,kBAC1BC,kBAAmB,kBACnBC,qBAAsB,gBACtBC,4BAA6B,uBAC7BC,gBAAiB,mBACjBC,+BAAgC,kBAChCC,wBAAyB,kBACzBC,gBAAiB,aACjBC,mBAAoB,aACpBC,mBAAoB,cACpBl7M,EAAEP,OAASO,EAAEP,KACfwO,QAASjO,EAAEiO,QACX2lE,WAAY5zE,EAAE4zE,YAAc5zE,EAAE2zE,eAC9Bx/D,WACE,OAAOlhB,KAAKwM,MAAQxM,KAAKgb,SAAW,MAAQhb,KAAKgb,WAmBvD,GALAqpE,EAAUmD,aATY,SAAS/G,EAAa0zC,EAAWC,GACrD4yF,EAAiBvmI,GAAatzE,IAC5Bk3E,EAAU6jI,mBAAmB/6M,EAAGgnH,GAAWpnH,IACrCqnH,GACFA,EAAQkzF,EAAWv6M,WAKYnM,KAAKyjF,GAKxCA,EAAUkD,aAAaC,aAAc,CACvC,MAAM2gI,EAAmB9jI,EAAUkD,aAAaC,aAC5C5mF,KAAKyjF,EAAUkD,cACnBlD,EAAUkD,aAAaC,aAAe,SAASrqE,GAC7C,OAAO6pM,EAAiB7pM,GAAIhQ,GAAKg7M,EAAiBh7M,GAAGyzC,MAAKxwC,IACxD,GAAIjD,EAAE2rF,QAAU1oF,EAAOs5I,iBAAiBhoJ,QACpCyL,EAAEyzE,QAAUxwE,EAAOw5I,iBAAiBloJ,OAItC,MAHA0O,EAAOk9F,YAAY/sG,SAAQ43E,IACzBA,EAAMp1E,UAEF,IAAI+X,aAAa,GAAI,iBAE7B,OAAO1K,KACNrD,GAAKg9B,QAAQE,OAAOq9K,EAAWv6M,UC/KjC,SAASq7M,EAAoB9lN,EAAQ+lN,GACtC/lN,EAAO+hF,UAAUkD,cACnB,oBAAqBjlF,EAAO+hF,UAAUkD,cAGlCjlF,EAAO+hF,UAAsB,eAKR,mBAAhBgkI,EAKX/lN,EAAO+hF,UAAUkD,aAAa6B,gBAC5B,SAAyB3I,GACvB,OAAO4nI,EAAY5nI,GAChB7/B,MAAKg6E,IACJ,MAAM0tF,EAAiB7nI,EAAYG,OAASH,EAAYG,MAAMhkD,MACxD2rL,EAAkB9nI,EAAYG,OAClCH,EAAYG,MAAM/jD,OACd2rL,EAAqB/nI,EAAYG,OACrCH,EAAYG,MAAMwa,UAcpB,OAbA3a,EAAYG,MAAQ,CAClBE,UAAW,CACTw5C,kBAAmB,UACnBC,oBAAqBK,EACrBH,aAAc+tF,GAAsB,IAGpCF,IACF7nI,EAAYG,MAAME,UAAU7uB,SAAWq2J,GAErCC,IACF9nI,EAAYG,MAAME,UAAU65C,UAAY4tF,GAEnCjmN,EAAO+hF,UAAUkD,aAAaC,aAAa/G,OA1BxDx9E,QAAQ5B,MAAM,gECNX,SAASonN,EAAgBnmN,GAC9BA,EAAOmrJ,YAAcnrJ,EAAOmrJ,aAAenrJ,EAAOomN,kBAG7C,SAASC,EAAYrmN,GAC1B,GAAsB,iBAAXA,GAAuBA,EAAO2oJ,qBAAuB,YAC5D3oJ,EAAO2oJ,kBAAkBhqJ,WAAY,CACvCb,OAAO0kB,eAAexiB,EAAO2oJ,kBAAkBhqJ,UAAW,UAAW,CACnE+jB,MACE,OAAOhlB,KAAK4oN,UAEd1jM,IAAIkP,GACEp0B,KAAK4oN,UACP5oN,KAAKusC,oBAAoB,QAASvsC,KAAK4oN,UAEzC5oN,KAAKqsC,iBAAiB,QAASrsC,KAAK4oN,SAAWx0L,IAEjDoK,YAAY,EACZuG,cAAc,IAEhB,MAAM8jL,EACFvmN,EAAO2oJ,kBAAkBhqJ,UAAUs3I,qBACvCj2I,EAAO2oJ,kBAAkBhqJ,UAAUs3I,qBACjC,WAuCE,OAtCKv4I,KAAK8oN,eACR9oN,KAAK8oN,aAAgB/7M,IAGnBA,EAAEqD,OAAOi8B,iBAAiB,YAAY08K,IACpC,IAAI1/K,EAEFA,EADE/mC,EAAO2oJ,kBAAkBhqJ,UAAUqmK,aAC1BtnK,KAAKsnK,eACbj/J,MAAK6E,GAAKA,EAAEirE,OAASjrE,EAAEirE,MAAM9yE,KAAO0jN,EAAG5wI,MAAM9yE,KAErC,CAAC8yE,MAAO4wI,EAAG5wI,OAGxB,MAAM7/C,EAAQ,IAAIgyB,MAAM,SACxBhyB,EAAM6/C,MAAQ4wI,EAAG5wI,MACjB7/C,EAAM+Q,SAAWA,EACjB/Q,EAAMurI,YAAc,CAACx6H,SAAAA,GACrB/Q,EAAM0pG,QAAU,CAACj1H,EAAEqD,QACnBpQ,KAAKgpN,cAAc1wL,MAErBvrB,EAAEqD,OAAOk9F,YAAY/sG,SAAQ43E,IAC3B,IAAI9uC,EAEFA,EADE/mC,EAAO2oJ,kBAAkBhqJ,UAAUqmK,aAC1BtnK,KAAKsnK,eACbj/J,MAAK6E,GAAKA,EAAEirE,OAASjrE,EAAEirE,MAAM9yE,KAAO8yE,EAAM9yE,KAElC,CAAC8yE,MAAAA,GAEd,MAAM7/C,EAAQ,IAAIgyB,MAAM,SACxBhyB,EAAM6/C,MAAQA,EACd7/C,EAAM+Q,SAAWA,EACjB/Q,EAAMurI,YAAc,CAACx6H,SAAAA,GACrB/Q,EAAM0pG,QAAU,CAACj1H,EAAEqD,QACnBpQ,KAAKgpN,cAAc1wL,OAGvBt4B,KAAKqsC,iBAAiB,YAAarsC,KAAK8oN,eAEnCD,EAAyBnoN,MAAMV,KAAMW,iBAMhD,EAA8B2B,EAAQ,SAASyK,IACxCA,EAAE82J,aACLzjK,OAAO0kB,eAAe/X,EAAG,cACvB,CAAC5F,MAAO,CAACkiC,SAAUt8B,EAAEs8B,YAElBt8B,KAKN,SAASk8M,EAAuB3mN,GAErC,GAAsB,iBAAXA,GAAuBA,EAAO2oJ,qBACnC,eAAgB3oJ,EAAO2oJ,kBAAkBhqJ,YAC3C,qBAAsBqB,EAAO2oJ,kBAAkBhqJ,UAAW,CAC5D,MAAMioN,EAAqB,SAASt8H,EAAIzU,GACtC,MAAO,CACLA,MAAAA,EACI+1F,WAQF,YAPmBniK,IAAf/L,KAAKmpN,QACY,UAAfhxI,EAAM5B,KACRv2E,KAAKmpN,MAAQv8H,EAAGwhF,iBAAiBj2F,GAEjCn4E,KAAKmpN,MAAQ,MAGVnpN,KAAKmpN,OAEdC,IAAKx8H,IAKT,IAAKtqF,EAAO2oJ,kBAAkBhqJ,UAAUiqK,WAAY,CAClD5oK,EAAO2oJ,kBAAkBhqJ,UAAUiqK,WAAa,WAE9C,OADAlrK,KAAKqpN,SAAWrpN,KAAKqpN,UAAY,GAC1BrpN,KAAKqpN,SAAS1kN,SAEvB,MAAM2kN,EAAehnN,EAAO2oJ,kBAAkBhqJ,UAAU2yI,SACxDtxI,EAAO2oJ,kBAAkBhqJ,UAAU2yI,SACjC,SAAkBz7D,EAAO/nE,GACvB,IAAI8gG,EAASo4G,EAAa5oN,MAAMV,KAAMW,WAKtC,OAJKuwG,IACHA,EAASg4G,EAAmBlpN,KAAMm4E,GAClCn4E,KAAKqpN,SAASnnN,KAAKgvG,IAEdA,GAGX,MAAMq4G,EAAkBjnN,EAAO2oJ,kBAAkBhqJ,UAAUmzJ,YAC3D9xJ,EAAO2oJ,kBAAkBhqJ,UAAUmzJ,YACjC,SAAqBljD,GACnBq4G,EAAgB7oN,MAAMV,KAAMW,WAC5B,MAAMm5C,EAAM95C,KAAKqpN,SAAShmN,QAAQ6tG,IACrB,IAATp3D,GACF95C,KAAKqpN,SAAS7lN,OAAOs2C,EAAK,IAIlC,MAAM0vK,EAAgBlnN,EAAO2oJ,kBAAkBhqJ,UAAU0pK,UACzDroK,EAAO2oJ,kBAAkBhqJ,UAAU0pK,UAAY,SAAmBv6J,GAChEpQ,KAAKqpN,SAAWrpN,KAAKqpN,UAAY,GACjCG,EAAc9oN,MAAMV,KAAM,CAACoQ,IAC3BA,EAAOk9F,YAAY/sG,SAAQ43E,IACzBn4E,KAAKqpN,SAASnnN,KAAKgnN,EAAmBlpN,KAAMm4E,QAIhD,MAAMsxI,EAAmBnnN,EAAO2oJ,kBAAkBhqJ,UAAU4pK,aAC5DvoK,EAAO2oJ,kBAAkBhqJ,UAAU4pK,aACjC,SAAsBz6J,GACpBpQ,KAAKqpN,SAAWrpN,KAAKqpN,UAAY,GACjCI,EAAiB/oN,MAAMV,KAAM,CAACoQ,IAE9BA,EAAOk9F,YAAY/sG,SAAQ43E,IACzB,MAAM+4B,EAASlxG,KAAKqpN,SAAShhN,MAAKwE,GAAKA,EAAEsrE,QAAUA,IAC/C+4B,GACFlxG,KAAKqpN,SAAS7lN,OAAOxD,KAAKqpN,SAAShmN,QAAQ6tG,GAAS,YAIvD,GAAsB,iBAAX5uG,GAAuBA,EAAO2oJ,mBACrC,eAAgB3oJ,EAAO2oJ,kBAAkBhqJ,WACzC,qBAAsBqB,EAAO2oJ,kBAAkBhqJ,WAC/CqB,EAAOknF,gBACL,SAAUlnF,EAAOknF,aAAavoF,WAAY,CACrD,MAAMyoN,EAAiBpnN,EAAO2oJ,kBAAkBhqJ,UAAUiqK,WAC1D5oK,EAAO2oJ,kBAAkBhqJ,UAAUiqK,WAAa,WAC9C,MAAMvpC,EAAU+nF,EAAehpN,MAAMV,KAAM,IAE3C,OADA2hI,EAAQphI,SAAQ2wG,GAAUA,EAAOk4G,IAAMppN,OAChC2hI,GAGTvhI,OAAO0kB,eAAexiB,EAAOknF,aAAavoF,UAAW,OAAQ,CAC3D+jB,MAQE,YAPmBjZ,IAAf/L,KAAKmpN,QACiB,UAApBnpN,KAAKm4E,MAAM5B,KACbv2E,KAAKmpN,MAAQnpN,KAAKopN,IAAIh7C,iBAAiBpuK,KAAKm4E,OAE5Cn4E,KAAKmpN,MAAQ,MAGVnpN,KAAKmpN,UAMb,SAASQ,EAAarnN,GAC3B,IAAKA,EAAO2oJ,kBACV,OAGF,MAAM2+D,EAAetnN,EAAO2oJ,kBAAkBhqJ,UAAUk2F,SACxD70F,EAAO2oJ,kBAAkBhqJ,UAAUk2F,SAAW,WAC5C,MAAOvoD,EAAUi7K,EAAQC,GAASnpN,UAIlC,GAAIA,UAAUe,OAAS,GAAyB,mBAAbktC,EACjC,OAAOg7K,EAAalpN,MAAMV,KAAMW,WAKlC,GAA4B,IAAxBipN,EAAaloN,SAAsC,IAArBf,UAAUe,QACpB,mBAAbktC,GACT,OAAOg7K,EAAalpN,MAAMV,KAAM,IAGlC,MAAM+pN,EAAkB,SAASjvG,GAC/B,MAAMkvG,EAAiB,GAiBvB,OAhBgBlvG,EAASxhF,SACjB/4B,SAAQisF,IACd,MAAMy9H,EAAgB,CACpB5kN,GAAImnF,EAAOnnF,GACXxD,UAAW2qF,EAAO3qF,UAClB+F,KAAM,CACJsiN,eAAgB,kBAChBC,gBAAiB,oBACjB39H,EAAO5kF,OAAS4kF,EAAO5kF,MAE3B4kF,EAAO7/E,QAAQpM,SAAQiM,IACrBy9M,EAAcz9M,GAAQggF,EAAOi6E,KAAKj6J,MAEpCw9M,EAAeC,EAAc5kN,IAAM4kN,KAG9BD,GAIHI,EAAe,SAASx2H,GAC5B,OAAO,IAAIvtB,IAAIjmE,OAAOC,KAAKuzF,GAAO1sF,KAAIgH,GAAO,CAACA,EAAK0lF,EAAM1lF,QAG3D,GAAIvN,UAAUe,QAAU,EAAG,CACzB,MAAM2oN,EAA0B,SAASvvG,GACvC+uG,EAAOO,EAAaL,EAAgBjvG,MAGtC,OAAO8uG,EAAalpN,MAAMV,KAAM,CAACqqN,EAC/Bz7K,IAIJ,OAAO,IAAI7E,SAAQ,CAACC,EAASC,KAC3B2/K,EAAalpN,MAAMV,KAAM,CACvB,SAAS86G,GACP9wE,EAAQogL,EAAaL,EAAgBjvG,MACpC7wE,OACJ2W,KAAKipK,EAAQC,IAIb,SAASQ,EAA2BhoN,GACzC,KAAwB,iBAAXA,GAAuBA,EAAO2oJ,mBACvC3oJ,EAAOknF,cAAgBlnF,EAAO+lF,gBAChC,OAIF,KAAM,aAAc/lF,EAAOknF,aAAavoF,WAAY,CAClD,MAAMyoN,EAAiBpnN,EAAO2oJ,kBAAkBhqJ,UAAUiqK,WACtDw+C,IACFpnN,EAAO2oJ,kBAAkBhqJ,UAAUiqK,WAAa,WAC9C,MAAMvpC,EAAU+nF,EAAehpN,MAAMV,KAAM,IAE3C,OADA2hI,EAAQphI,SAAQ2wG,GAAUA,EAAOk4G,IAAMppN,OAChC2hI,IAIX,MAAM2nF,EAAehnN,EAAO2oJ,kBAAkBhqJ,UAAU2yI,SACpD01E,IACFhnN,EAAO2oJ,kBAAkBhqJ,UAAU2yI,SAAW,WAC5C,MAAM1iC,EAASo4G,EAAa5oN,MAAMV,KAAMW,WAExC,OADAuwG,EAAOk4G,IAAMppN,KACNkxG,IAGX5uG,EAAOknF,aAAavoF,UAAUk2F,SAAW,WACvC,MAAM+Z,EAASlxG,KACf,OAAOA,KAAKopN,IAAIjyH,WAAWv2C,MAAKtnB,GAK9B,EAAkBA,EAAQ43E,EAAO/4B,OAAO,MAK9C,KAAM,aAAc71E,EAAO+lF,eAAepnF,WAAY,CACpD,MAAMspN,EAAmBjoN,EAAO2oJ,kBAAkBhqJ,UAAUqmK,aACxDijD,IACFjoN,EAAO2oJ,kBAAkBhqJ,UAAUqmK,aACjC,WACE,MAAMH,EAAYojD,EAAiB7pN,MAAMV,KAAM,IAE/C,OADAmnK,EAAU5mK,SAAQ8oC,GAAYA,EAAS+/K,IAAMppN,OACtCmnK,IAGb,EAA8B7kK,EAAQ,SAASyK,IAC7CA,EAAEs8B,SAAS+/K,IAAMr8M,EAAEy9M,WACZz9M,KAETzK,EAAO+lF,eAAepnF,UAAUk2F,SAAW,WACzC,MAAM9tD,EAAWrpC,KACjB,OAAOA,KAAKopN,IAAIjyH,WAAWv2C,MAAKtnB,GAC9B,EAAkBA,EAAQ+P,EAAS8uC,OAAO,MAIhD,KAAM,aAAc71E,EAAOknF,aAAavoF,cACpC,aAAcqB,EAAO+lF,eAAepnF,WACtC,OAIF,MAAM2oN,EAAetnN,EAAO2oJ,kBAAkBhqJ,UAAUk2F,SACxD70F,EAAO2oJ,kBAAkBhqJ,UAAUk2F,SAAW,WAC5C,GAAIx2F,UAAUe,OAAS,GACnBf,UAAU,aAAc2B,EAAOmoN,iBAAkB,CACnD,MAAMtyI,EAAQx3E,UAAU,GACxB,IAAIuwG,EACA7nE,EACAZ,EAoBJ,OAnBAzoC,KAAKkrK,aAAa3qK,SAAQsM,IACpBA,EAAEsrE,QAAUA,IACV+4B,EACFzoE,GAAM,EAENyoE,EAASrkG,MAIf7M,KAAKsnK,eAAe/mK,SAAQ2M,IACtBA,EAAEirE,QAAUA,IACV9uC,EACFZ,GAAM,EAENY,EAAWn8B,GAGRA,EAAEirE,QAAUA,KAEjB1vC,GAAQyoE,GAAU7nE,EACbU,QAAQE,OAAO,IAAInvB,aACxB,4DACA,uBACOo2F,EACFA,EAAO/Z,WACL9tD,EACFA,EAAS8tD,WAEXptD,QAAQE,OAAO,IAAInvB,aACxB,gDACA,uBAEJ,OAAO8uM,EAAalpN,MAAMV,KAAMW,YAI7B,SAAS+pN,EAAkCpoN,GAIhDA,EAAO2oJ,kBAAkBhqJ,UAAU0pN,gBACjC,WAEE,OADA3qN,KAAK4qN,qBAAuB5qN,KAAK4qN,sBAAwB,GAClDxqN,OAAOC,KAAKL,KAAK4qN,sBACrB1jN,KAAI8yH,GAAYh6H,KAAK4qN,qBAAqB5wF,GAAU,MAG3D,MAAMsvF,EAAehnN,EAAO2oJ,kBAAkBhqJ,UAAU2yI,SACxDtxI,EAAO2oJ,kBAAkBhqJ,UAAU2yI,SACjC,SAAkBz7D,EAAO/nE,GACvB,IAAKA,EACH,OAAOk5M,EAAa5oN,MAAMV,KAAMW,WAElCX,KAAK4qN,qBAAuB5qN,KAAK4qN,sBAAwB,GAEzD,MAAM15G,EAASo4G,EAAa5oN,MAAMV,KAAMW,WAMxC,OALKX,KAAK4qN,qBAAqBx6M,EAAO/K,KAE+B,IAA1DrF,KAAK4qN,qBAAqBx6M,EAAO/K,IAAIhC,QAAQ6tG,IACtDlxG,KAAK4qN,qBAAqBx6M,EAAO/K,IAAInD,KAAKgvG,GAF1ClxG,KAAK4qN,qBAAqBx6M,EAAO/K,IAAM,CAAC+K,EAAQ8gG,GAI3CA,GAGX,MAAMs4G,EAAgBlnN,EAAO2oJ,kBAAkBhqJ,UAAU0pK,UACzDroK,EAAO2oJ,kBAAkBhqJ,UAAU0pK,UAAY,SAAmBv6J,GAChEpQ,KAAK4qN,qBAAuB5qN,KAAK4qN,sBAAwB,GAEzDx6M,EAAOk9F,YAAY/sG,SAAQ43E,IAEzB,GADsBn4E,KAAKkrK,aAAa7iK,MAAKwE,GAAKA,EAAEsrE,QAAUA,IAE5D,MAAM,IAAIr9D,aAAa,wBACnB,yBAGR,MAAM+vM,EAAkB7qN,KAAKkrK,aAC7Bs+C,EAAc9oN,MAAMV,KAAMW,WAC1B,MAAMmqN,EAAa9qN,KAAKkrK,aACrBnkK,QAAOgkN,IAAqD,IAAxCF,EAAgBxnN,QAAQ0nN,KAC/C/qN,KAAK4qN,qBAAqBx6M,EAAO/K,IAAM,CAAC+K,GAAQrL,OAAO+lN,IAGzD,MAAMrB,EAAmBnnN,EAAO2oJ,kBAAkBhqJ,UAAU4pK,aAC5DvoK,EAAO2oJ,kBAAkBhqJ,UAAU4pK,aACjC,SAAsBz6J,GAGpB,OAFApQ,KAAK4qN,qBAAuB5qN,KAAK4qN,sBAAwB,UAClD5qN,KAAK4qN,qBAAqBx6M,EAAO/K,IACjCokN,EAAiB/oN,MAAMV,KAAMW,YAGxC,MAAM4oN,EAAkBjnN,EAAO2oJ,kBAAkBhqJ,UAAUmzJ,YAC3D9xJ,EAAO2oJ,kBAAkBhqJ,UAAUmzJ,YACjC,SAAqBljD,GAanB,OAZAlxG,KAAK4qN,qBAAuB5qN,KAAK4qN,sBAAwB,GACrD15G,GACF9wG,OAAOC,KAAKL,KAAK4qN,sBAAsBrqN,SAAQy5H,IAC7C,MAAMlgF,EAAM95C,KAAK4qN,qBAAqB5wF,GAAU32H,QAAQ6tG,IAC3C,IAATp3D,GACF95C,KAAK4qN,qBAAqB5wF,GAAUx2H,OAAOs2C,EAAK,GAEC,IAA/C95C,KAAK4qN,qBAAqB5wF,GAAUt4H,eAC/B1B,KAAK4qN,qBAAqB5wF,MAIhCuvF,EAAgB7oN,MAAMV,KAAMW,YAIlC,SAASqqN,EAAwB1oN,EAAQmkN,GAC9C,IAAKnkN,EAAO2oJ,kBACV,OAGF,GAAI3oJ,EAAO2oJ,kBAAkBhqJ,UAAU2yI,UACnC6yE,EAAex1M,SAAW,GAC5B,OAAOy5M,EAAkCpoN,GAK3C,MAAM2oN,EAAsB3oN,EAAO2oJ,kBAAkBhqJ,UAChD0pN,gBACLroN,EAAO2oJ,kBAAkBhqJ,UAAU0pN,gBACjC,WACE,MAAMO,EAAgBD,EAAoBvqN,MAAMV,MAEhD,OADAA,KAAKmrN,gBAAkBnrN,KAAKmrN,iBAAmB,GACxCD,EAAchkN,KAAIkJ,GAAUpQ,KAAKmrN,gBAAgB/6M,EAAO/K,OAGnE,MAAMmkN,EAAgBlnN,EAAO2oJ,kBAAkBhqJ,UAAU0pK,UACzDroK,EAAO2oJ,kBAAkBhqJ,UAAU0pK,UAAY,SAAmBv6J,GAahE,GAZApQ,KAAKorN,SAAWprN,KAAKorN,UAAY,GACjCprN,KAAKmrN,gBAAkBnrN,KAAKmrN,iBAAmB,GAE/C/6M,EAAOk9F,YAAY/sG,SAAQ43E,IAEzB,GADsBn4E,KAAKkrK,aAAa7iK,MAAKwE,GAAKA,EAAEsrE,QAAUA,IAE5D,MAAM,IAAIr9D,aAAa,wBACnB,0BAKH9a,KAAKmrN,gBAAgB/6M,EAAO/K,IAAK,CACpC,MAAMgmN,EAAY,IAAI/oN,EAAOmrJ,YAAYr9I,EAAOk9F,aAChDttG,KAAKorN,SAASh7M,EAAO/K,IAAMgmN,EAC3BrrN,KAAKmrN,gBAAgBE,EAAUhmN,IAAM+K,EACrCA,EAASi7M,EAEX7B,EAAc9oN,MAAMV,KAAM,CAACoQ,KAG7B,MAAMq5M,EAAmBnnN,EAAO2oJ,kBAAkBhqJ,UAAU4pK,aA6D5D,SAASygD,EAAwB1+H,EAAI9W,GACnC,IAAI/tE,EAAM+tE,EAAY/tE,IAOtB,OANA3H,OAAOC,KAAKusF,EAAGu+H,iBAAmB,IAAI5qN,SAAQgrN,IAC5C,MAAMC,EAAiB5+H,EAAGu+H,gBAAgBI,GACpCE,EAAiB7+H,EAAGw+H,SAASI,EAAenmN,IAClD0C,EAAMA,EAAI0I,QAAQ,IAAIzC,OAAOy9M,EAAepmN,GAAI,KAC5CmmN,EAAenmN,OAEd,IAAI4G,sBAAsB,CAC/BrE,KAAMkuE,EAAYluE,KAClBG,IAAAA,IAGJ,SAAS2jN,EAAwB9+H,EAAI9W,GACnC,IAAI/tE,EAAM+tE,EAAY/tE,IAOtB,OANA3H,OAAOC,KAAKusF,EAAGu+H,iBAAmB,IAAI5qN,SAAQgrN,IAC5C,MAAMC,EAAiB5+H,EAAGu+H,gBAAgBI,GACpCE,EAAiB7+H,EAAGw+H,SAASI,EAAenmN,IAClD0C,EAAMA,EAAI0I,QAAQ,IAAIzC,OAAOw9M,EAAenmN,GAAI,KAC5ComN,EAAepmN,OAEd,IAAI4G,sBAAsB,CAC/BrE,KAAMkuE,EAAYluE,KAClBG,IAAAA,IAnFJzF,EAAO2oJ,kBAAkBhqJ,UAAU4pK,aACjC,SAAsBz6J,GACpBpQ,KAAKorN,SAAWprN,KAAKorN,UAAY,GACjCprN,KAAKmrN,gBAAkBnrN,KAAKmrN,iBAAmB,GAE/C1B,EAAiB/oN,MAAMV,KAAM,CAAEA,KAAKorN,SAASh7M,EAAO/K,KAAO+K,WACpDpQ,KAAKmrN,gBAAiBnrN,KAAKorN,SAASh7M,EAAO/K,IAC9CrF,KAAKorN,SAASh7M,EAAO/K,IAAIA,GAAK+K,EAAO/K,WAClCrF,KAAKorN,SAASh7M,EAAO/K,KAGhC/C,EAAO2oJ,kBAAkBhqJ,UAAU2yI,SACjC,SAAkBz7D,EAAO/nE,GACvB,GAA4B,WAAxBpQ,KAAKswI,eACP,MAAM,IAAIx1H,aACR,sDACA,qBAEJ,MAAMknH,EAAU,GAAGr9H,MAAMC,KAAKjE,UAAW,GACzC,GAAuB,IAAnBqhI,EAAQtgI,SACPsgI,EAAQ,GAAG10B,YAAYjlG,MAAKrD,GAAKA,IAAMmzE,IAG1C,MAAM,IAAIr9D,aACR,gHAEA,qBAGJ,MAAM6wM,EAAgB3rN,KAAKkrK,aAAa7iK,MAAKwE,GAAKA,EAAEsrE,QAAUA,IAC9D,GAAIwzI,EACF,MAAM,IAAI7wM,aAAa,wBACnB,sBAGN9a,KAAKorN,SAAWprN,KAAKorN,UAAY,GACjCprN,KAAKmrN,gBAAkBnrN,KAAKmrN,iBAAmB,GAC/C,MAAMS,EAAY5rN,KAAKorN,SAASh7M,EAAO/K,IACvC,GAAIumN,EAKFA,EAAUh4E,SAASz7D,GAGnBpuC,QAAQC,UAAU4W,MAAK,KACrB5gD,KAAKgpN,cAAc,IAAI1+J,MAAM,6BAE1B,CACL,MAAM+gK,EAAY,IAAI/oN,EAAOmrJ,YAAY,CAACt1E,IAC1Cn4E,KAAKorN,SAASh7M,EAAO/K,IAAMgmN,EAC3BrrN,KAAKmrN,gBAAgBE,EAAUhmN,IAAM+K,EACrCpQ,KAAK2qK,UAAU0gD,GAEjB,OAAOrrN,KAAKkrK,aAAa7iK,MAAKwE,GAAKA,EAAEsrE,QAAUA,KA+BnD,CAAC,cAAe,gBAAgB53E,SAAQ,SAASkgD,GAC/C,MAAMorK,EAAevpN,EAAO2oJ,kBAAkBhqJ,UAAUw/C,GAClDqrK,EAAY,CAAC,CAACrrK,KAClB,MAAMh8C,EAAO9D,UAGb,OAFqBA,UAAUe,QACH,mBAAjBf,UAAU,GAEZkrN,EAAanrN,MAAMV,KAAM,CAC7B81E,IACC,MAAMhuE,EAAOwjN,EAAwBtrN,KAAM81E,GAC3CrxE,EAAK,GAAG/D,MAAM,KAAM,CAACoH,KAEtB2gC,IACKhkC,EAAK,IACPA,EAAK,GAAG/D,MAAM,KAAM+nC,IAErB9nC,UAAU,KAGVkrN,EAAanrN,MAAMV,KAAMW,WAC/BigD,MAAKk1B,GAAew1I,EAAwBtrN,KAAM81E,OAErDxzE,EAAO2oJ,kBAAkBhqJ,UAAUw/C,GAAUqrK,EAAUrrK,MAGzD,MAAMsrK,EACFzpN,EAAO2oJ,kBAAkBhqJ,UAAU+yI,oBACvC1xI,EAAO2oJ,kBAAkBhqJ,UAAU+yI,oBACjC,WACE,OAAKrzI,UAAUe,QAAWf,UAAU,GAAGiH,MAGvCjH,UAAU,GAAK+qN,EAAwB1rN,KAAMW,UAAU,IAChDorN,EAAwBrrN,MAAMV,KAAMW,YAHlCorN,EAAwBrrN,MAAMV,KAAMW,YAQjD,MAAMqrN,EAAuB5rN,OAAO6rN,yBAChC3pN,EAAO2oJ,kBAAkBhqJ,UAAW,oBACxCb,OAAO0kB,eAAexiB,EAAO2oJ,kBAAkBhqJ,UAC3C,mBAAoB,CAClB+jB,MACE,MAAM8wD,EAAck2I,EAAqBhnM,IAAItkB,MAAMV,MACnD,MAAyB,KAArB81E,EAAYluE,KACPkuE,EAEFw1I,EAAwBtrN,KAAM81E,MAI7CxzE,EAAO2oJ,kBAAkBhqJ,UAAUmzJ,YACjC,SAAqBljD,GACnB,GAA4B,WAAxBlxG,KAAKswI,eACP,MAAM,IAAIx1H,aACR,sDACA,qBAIJ,IAAKo2F,EAAOk4G,IACV,MAAM,IAAItuM,aAAa,yFAC2B,aAGpD,GADgBo2F,EAAOk4G,MAAQppN,KAE7B,MAAM,IAAI8a,aAAa,6CACnB,sBAKN,IAAI1K,EADJpQ,KAAKorN,SAAWprN,KAAKorN,UAAY,GAEjChrN,OAAOC,KAAKL,KAAKorN,UAAU7qN,SAAQ2rN,IAChBlsN,KAAKorN,SAASc,GAAU5+G,YACtCjlG,MAAK8vE,GAAS+4B,EAAO/4B,QAAUA,MAEhC/nE,EAASpQ,KAAKorN,SAASc,OAIvB97M,IACgC,IAA9BA,EAAOk9F,YAAY5rG,OAGrB1B,KAAK6qK,aAAa7qK,KAAKmrN,gBAAgB/6M,EAAO/K,KAG9C+K,EAAOgkJ,YAAYljD,EAAO/4B,OAE5Bn4E,KAAKgpN,cAAc,IAAI1+J,MAAM,wBAK9B,SAAS6hK,EAAmB7pN,EAAQmkN,IACpCnkN,EAAO2oJ,mBAAqB3oJ,EAAO8pN,0BAEtC9pN,EAAO2oJ,kBAAoB3oJ,EAAO8pN,yBAE/B9pN,EAAO2oJ,mBAKRw7D,EAAex1M,QAAU,IAC3B,CAAC,sBAAuB,uBAAwB,mBAC3C1Q,SAAQ,SAASkgD,GAChB,MAAMorK,EAAevpN,EAAO2oJ,kBAAkBhqJ,UAAUw/C,GAClDqrK,EAAY,CAAC,CAACrrK,KAIlB,OAHA9/C,UAAU,GAAK,IAAiB,oBAAX8/C,EACjBn+C,EAAOowI,gBACPpwI,EAAO2J,uBAAuBtL,UAAU,IACrCkrN,EAAanrN,MAAMV,KAAMW,aAElC2B,EAAO2oJ,kBAAkBhqJ,UAAUw/C,GAAUqrK,EAAUrrK,MAM1D,SAAS4rK,EAAqB/pN,EAAQmkN,GAC3C,EAA8BnkN,EAAQ,qBAAqByK,IACzD,MAAM6/E,EAAK7/E,EAAEyJ,OACb,KAAIiwM,EAAex1M,QAAU,IAAO27E,EAAG0/H,kBACI,WAAvC1/H,EAAG0/H,mBAAmBp6C,eACE,WAAtBtlF,EAAG0jD,eAIT,OAAOvjI,KC/qBJ,SAAS,EAAiBzK,EAAQmkN,GACvC,MAAMpiI,EAAY/hF,GAAUA,EAAO+hF,UAC7BomI,EAAmBnoN,GAAUA,EAAOmoN,iBAS1C,GAPApmI,EAAUmD,aAAe,SAAS/G,EAAa0zC,EAAWC,GAExD,EAAiB,yBACb,uCACJ/vC,EAAUkD,aAAaC,aAAa/G,GAAa7/B,KAAKuzE,EAAWC,MAG7DqyF,EAAex1M,QAAU,IAC3B,oBAAqBozE,EAAUkD,aAAa6/H,2BAA4B,CAC1E,MAAMH,EAAQ,SAAS94M,EAAKd,EAAGD,GACzBC,KAAKc,KAASf,KAAKe,KACrBA,EAAIf,GAAKe,EAAId,UACNc,EAAId,KAITk/M,EAAqBloI,EAAUkD,aAAaC,aAC9C5mF,KAAKyjF,EAAUkD,cAUnB,GATAlD,EAAUkD,aAAaC,aAAe,SAASr6E,GAM7C,MALiB,iBAANA,GAAqC,iBAAZA,EAAE2rF,QACpC3rF,EAAI/L,KAAKwJ,MAAMxJ,KAAKF,UAAUiM,IAC9B85M,EAAM95M,EAAE2rF,MAAO,kBAAmB,sBAClCmuH,EAAM95M,EAAE2rF,MAAO,mBAAoB,wBAE9ByzH,EAAmBp/M,IAGxBs9M,GAAoBA,EAAiBxpN,UAAUiwJ,YAAa,CAC9D,MAAMs7D,EAAoB/B,EAAiBxpN,UAAUiwJ,YACrDu5D,EAAiBxpN,UAAUiwJ,YAAc,WACvC,MAAM/iJ,EAAMq+M,EAAkB9rN,MAAMV,KAAMW,WAG1C,OAFAsmN,EAAM94M,EAAK,qBAAsB,mBACjC84M,EAAM94M,EAAK,sBAAuB,oBAC3BA,GAIX,GAAIs8M,GAAoBA,EAAiBxpN,UAAUwrN,iBAAkB,CACnE,MAAMC,EACJjC,EAAiBxpN,UAAUwrN,iBAC7BhC,EAAiBxpN,UAAUwrN,iBAAmB,SAASt/M,GAMrD,MALkB,UAAdnN,KAAKu2E,MAAiC,iBAANppE,IAClCA,EAAI/L,KAAKwJ,MAAMxJ,KAAKF,UAAUiM,IAC9B85M,EAAM95M,EAAG,kBAAmB,sBAC5B85M,EAAM95M,EAAG,mBAAoB,wBAExBu/M,EAAuBhsN,MAAMV,KAAM,CAACmN,OCpD5C,SAAS,EAAoB7K,EAAQqqN,GACtCrqN,EAAO+hF,UAAUkD,cACnB,oBAAqBjlF,EAAO+hF,UAAUkD,cAGlCjlF,EAAO+hF,UAAsB,eAGnC/hF,EAAO+hF,UAAUkD,aAAa6B,gBAC5B,SAAyB3I,GACvB,IAAMA,IAAeA,EAAYG,MAAQ,CACvC,MAAMn4C,EAAM,IAAI3tB,aAAa,0DAK7B,OAHA2tB,EAAIj8B,KAAO,gBAEXi8B,EAAI1tB,KAAO,EACJgvB,QAAQE,OAAOxB,GAOxB,OAL0B,IAAtBg4C,EAAYG,MACdH,EAAYG,MAAQ,CAACgsI,YAAaD,GAElClsI,EAAYG,MAAMgsI,YAAcD,EAE3BrqN,EAAO+hF,UAAUkD,aAAaC,aAAa/G,KCnBjD,SAAS,EAAYn+E,GACJ,iBAAXA,GAAuBA,EAAOuqN,eACpC,aAAcvqN,EAAOuqN,cAAc5rN,aAClC,gBAAiBqB,EAAOuqN,cAAc5rN,YAC1Cb,OAAO0kB,eAAexiB,EAAOuqN,cAAc5rN,UAAW,cAAe,CACnE+jB,MACE,MAAO,CAACqkB,SAAUrpC,KAAKqpC,aAMxB,SAAS,EAAmB/mC,EAAQmkN,GACzC,GAAsB,iBAAXnkN,IACLA,EAAO2oJ,oBAAqB3oJ,EAAOwqN,qBACvC,QAEGxqN,EAAO2oJ,mBAAqB3oJ,EAAOwqN,uBAEtCxqN,EAAO2oJ,kBAAoB3oJ,EAAOwqN,sBAGhCrG,EAAex1M,QAAU,IAE3B,CAAC,sBAAuB,uBAAwB,mBAC3C1Q,SAAQ,SAASkgD,GAChB,MAAMorK,EAAevpN,EAAO2oJ,kBAAkBhqJ,UAAUw/C,GAClDqrK,EAAY,CAAC,CAACrrK,KAIlB,OAHA9/C,UAAU,GAAK,IAAiB,oBAAX8/C,EACjBn+C,EAAOowI,gBACPpwI,EAAO2J,uBAAuBtL,UAAU,IACrCkrN,EAAanrN,MAAMV,KAAMW,aAElC2B,EAAO2oJ,kBAAkBhqJ,UAAUw/C,GAAUqrK,EAAUrrK,MAI/D,MAAMssK,EAAmB,CACvBC,WAAY,cACZC,YAAa,eACbC,cAAe,iBACfhD,eAAgB,kBAChBC,gBAAiB,oBAGbgD,EAAiB7qN,EAAO2oJ,kBAAkBhqJ,UAAUk2F,SAC1D70F,EAAO2oJ,kBAAkBhqJ,UAAUk2F,SAAW,WAC5C,MAAOvoD,EAAUi7K,EAAQC,GAASnpN,UAClC,OAAOwsN,EAAezsN,MAAMV,KAAM,CAAC4uC,GAAY,OAC5CgS,MAAKgzC,IACJ,GAAI6yH,EAAex1M,QAAU,KAAO44M,EAGlC,IACEj2H,EAAMrzF,SAAQkmK,IACZA,EAAK7+J,KAAOmlN,EAAiBtmD,EAAK7+J,OAAS6+J,EAAK7+J,QAElD,MAAOmF,GACP,GAAe,cAAXA,EAAEP,KACJ,MAAMO,EAGR6mF,EAAMrzF,SAAQ,CAACkmK,EAAMjlK,KACnBoyF,EAAM1uE,IAAI1jB,EAAGpB,OAAOqmC,OAAO,GAAIggI,EAAM,CACnC7+J,KAAMmlN,EAAiBtmD,EAAK7+J,OAAS6+J,EAAK7+J,WAKlD,OAAOgsF,KAERhzC,KAAKipK,EAAQC,IAIb,SAASsD,EAAmB9qN,GACjC,GAAwB,iBAAXA,IAAuBA,EAAO2oJ,oBACvC3oJ,EAAOknF,aACT,OAEF,GAAIlnF,EAAOknF,cAAgB,aAAclnF,EAAOknF,aAAavoF,UAC3D,OAEF,MAAMyoN,EAAiBpnN,EAAO2oJ,kBAAkBhqJ,UAAUiqK,WACtDw+C,IACFpnN,EAAO2oJ,kBAAkBhqJ,UAAUiqK,WAAa,WAC9C,MAAMvpC,EAAU+nF,EAAehpN,MAAMV,KAAM,IAE3C,OADA2hI,EAAQphI,SAAQ2wG,GAAUA,EAAOk4G,IAAMppN,OAChC2hI,IAIX,MAAM2nF,EAAehnN,EAAO2oJ,kBAAkBhqJ,UAAU2yI,SACpD01E,IACFhnN,EAAO2oJ,kBAAkBhqJ,UAAU2yI,SAAW,WAC5C,MAAM1iC,EAASo4G,EAAa5oN,MAAMV,KAAMW,WAExC,OADAuwG,EAAOk4G,IAAMppN,KACNkxG,IAGX5uG,EAAOknF,aAAavoF,UAAUk2F,SAAW,WACvC,OAAOn3F,KAAKm4E,MAAQn4E,KAAKopN,IAAIjyH,SAASn3F,KAAKm4E,OACvCpuC,QAAQC,QAAQ,IAAIq8B,MAIrB,SAASgnJ,EAAqB/qN,GACnC,GAAwB,iBAAXA,IAAuBA,EAAO2oJ,oBACvC3oJ,EAAOknF,aACT,OAEF,GAAIlnF,EAAOknF,cAAgB,aAAclnF,EAAO+lF,eAAepnF,UAC7D,OAEF,MAAMspN,EAAmBjoN,EAAO2oJ,kBAAkBhqJ,UAAUqmK,aACxDijD,IACFjoN,EAAO2oJ,kBAAkBhqJ,UAAUqmK,aAAe,WAChD,MAAMH,EAAYojD,EAAiB7pN,MAAMV,KAAM,IAE/C,OADAmnK,EAAU5mK,SAAQ8oC,GAAYA,EAAS+/K,IAAMppN,OACtCmnK,IAGX,EAA8B7kK,EAAQ,SAASyK,IAC7CA,EAAEs8B,SAAS+/K,IAAMr8M,EAAEy9M,WACZz9M,KAETzK,EAAO+lF,eAAepnF,UAAUk2F,SAAW,WACzC,OAAOn3F,KAAKopN,IAAIjyH,SAASn3F,KAAKm4E,QAI3B,SAASm1I,EAAiBhrN,GAC1BA,EAAO2oJ,qBACR,iBAAkB3oJ,EAAO2oJ,kBAAkBhqJ,aAG/CqB,EAAO2oJ,kBAAkBhqJ,UAAU4pK,aACjC,SAAsBz6J,GACpB,EAAiB,eAAgB,eACjCpQ,KAAKkrK,aAAa3qK,SAAQ2wG,IACpBA,EAAO/4B,OAAS/nE,EAAOk9F,YAAYmQ,SAASvM,EAAO/4B,QACrDn4E,KAAKo0J,YAAYljD,QAMpB,SAASq8G,EAAmBjrN,GAG7BA,EAAOkrN,cAAgBlrN,EAAOmrN,iBAChCnrN,EAAOmrN,eAAiBnrN,EAAOkrN,aAI5B,SAASE,EAAmBprN,GAIjC,GAAwB,iBAAXA,IAAuBA,EAAO2oJ,kBACzC,OAEF,MAAM0iE,EAAqBrrN,EAAO2oJ,kBAAkBhqJ,UAAUkiK,eAC1DwqD,IACFrrN,EAAO2oJ,kBAAkBhqJ,UAAUkiK,eACjC,WACEnjK,KAAK4tN,sBAAwB,GAC7B,MAAMC,EAAiBltN,UAAU,GAC3BmtN,EAAqBD,GACD,kBAAmBA,EACzCC,GAEFD,EAAe3qD,cAAc3iK,SAASwtN,IACpC,GAAI,QAASA,IACM,oBACHx+M,KAAKw+M,EAAc9rG,KAC/B,MAAM,IAAIl3E,UAAU,+BAGxB,GAAI,0BAA2BgjL,KACvB16J,WAAW06J,EAAcxrD,wBAA0B,GACvD,MAAM,IAAI/1H,WAAW,2CAGzB,GAAI,iBAAkBuhL,KACd16J,WAAW06J,EAAcC,eAAiB,GAC9C,MAAM,IAAIxhL,WAAW,mCAK7B,MAAMq3H,EAAc8pD,EAAmBjtN,MAAMV,KAAMW,WACnD,GAAImtN,EAAoB,CAQtB,MAAM,OAAC58G,GAAU2yD,EACXxwF,EAAS69B,EAAO+yD,mBAChB,cAAe5wF,IAEY,IAA5BA,EAAO6wF,UAAUxiK,QAC2B,IAA5CtB,OAAOC,KAAKgzE,EAAO6wF,UAAU,IAAIxiK,UACpC2xE,EAAO6wF,UAAY2pD,EAAe3qD,cAClChyD,EAAOgyD,cAAgB2qD,EAAe3qD,cACtCljK,KAAK4tN,sBAAsB1rN,KAAKgvG,EAAOizD,cAAc9wF,GAClDzyB,MAAK,YACGswD,EAAOgyD,iBACbl/G,OAAM,YACAktD,EAAOgyD,mBAKtB,OAAOW,IAKR,SAASoqD,EAAkB3rN,GAChC,GAAwB,iBAAXA,IAAuBA,EAAOknF,aACzC,OAEF,MAAM0kI,EAAoB5rN,EAAOknF,aAAavoF,UAAUgjK,cACpDiqD,IACF5rN,EAAOknF,aAAavoF,UAAUgjK,cAC5B,WACE,MAAM5wF,EAAS66I,EAAkBxtN,MAAMV,KAAMW,WAI7C,MAHM,cAAe0yE,IACnBA,EAAO6wF,UAAY,GAAGn/J,OAAO/E,KAAKkjK,eAAiB,CAAC,MAE/C7vF,IAKR,SAAS86I,EAAgB7rN,GAI9B,GAAwB,iBAAXA,IAAuBA,EAAO2oJ,kBACzC,OAEF,MAAMmjE,EAAkB9rN,EAAO2oJ,kBAAkBhqJ,UAAU6yI,YAC3DxxI,EAAO2oJ,kBAAkBhqJ,UAAU6yI,YAAc,WAC/C,OAAI9zI,KAAK4tN,uBAAyB5tN,KAAK4tN,sBAAsBlsN,OACpDqoC,QAAQ8pG,IAAI7zI,KAAK4tN,uBACvBhtK,MAAK,IACGwtK,EAAgB1tN,MAAMV,KAAMW,aAEpC0tN,SAAQ,KACPruN,KAAK4tN,sBAAwB,MAG1BQ,EAAgB1tN,MAAMV,KAAMW,YAIhC,SAAS2tN,EAAiBhsN,GAI/B,GAAwB,iBAAXA,IAAuBA,EAAO2oJ,kBACzC,OAEF,MAAMsjE,EAAmBjsN,EAAO2oJ,kBAAkBhqJ,UAAUu3I,aAC5Dl2I,EAAO2oJ,kBAAkBhqJ,UAAUu3I,aAAe,WAChD,OAAIx4I,KAAK4tN,uBAAyB5tN,KAAK4tN,sBAAsBlsN,OACpDqoC,QAAQ8pG,IAAI7zI,KAAK4tN,uBACvBhtK,MAAK,IACG2tK,EAAiB7tN,MAAMV,KAAMW,aAErC0tN,SAAQ,KACPruN,KAAK4tN,sBAAwB,MAG1BW,EAAiB7tN,MAAMV,KAAMW,YC3RjC,SAAS6tN,EAAoBlsN,GAClC,GAAsB,iBAAXA,GAAwBA,EAAO2oJ,kBAA1C,CAYA,GATM,oBAAqB3oJ,EAAO2oJ,kBAAkBhqJ,YAClDqB,EAAO2oJ,kBAAkBhqJ,UAAU0pN,gBACjC,WAIE,OAHK3qN,KAAKyuN,gBACRzuN,KAAKyuN,cAAgB,IAEhBzuN,KAAKyuN,kBAGZ,cAAensN,EAAO2oJ,kBAAkBhqJ,WAAY,CACxD,MAAMytN,EAAYpsN,EAAO2oJ,kBAAkBhqJ,UAAU2yI,SACrDtxI,EAAO2oJ,kBAAkBhqJ,UAAU0pK,UAAY,SAAmBv6J,GAC3DpQ,KAAKyuN,gBACRzuN,KAAKyuN,cAAgB,IAElBzuN,KAAKyuN,cAAchxG,SAASrtG,IAC/BpQ,KAAKyuN,cAAcvsN,KAAKkO,GAI1BA,EAAOs5I,iBAAiBnpJ,SAAQ43E,GAASu2I,EAAU9pN,KAAK5E,KAAMm4E,EAC5D/nE,KACFA,EAAOw5I,iBAAiBrpJ,SAAQ43E,GAASu2I,EAAU9pN,KAAK5E,KAAMm4E,EAC5D/nE,MAGJ9N,EAAO2oJ,kBAAkBhqJ,UAAU2yI,SACjC,SAAkBz7D,KAAU6pD,GAU1B,OATIA,GACFA,EAAQzhI,SAAS6P,IACVpQ,KAAKyuN,cAEEzuN,KAAKyuN,cAAchxG,SAASrtG,IACtCpQ,KAAKyuN,cAAcvsN,KAAKkO,GAFxBpQ,KAAKyuN,cAAgB,CAACr+M,MAMrBs+M,EAAUhuN,MAAMV,KAAMW,YAG7B,iBAAkB2B,EAAO2oJ,kBAAkBhqJ,YAC/CqB,EAAO2oJ,kBAAkBhqJ,UAAU4pK,aACjC,SAAsBz6J,GACfpQ,KAAKyuN,gBACRzuN,KAAKyuN,cAAgB,IAEvB,MAAMnkN,EAAQtK,KAAKyuN,cAAcprN,QAAQ+M,GACzC,IAAe,IAAX9F,EACF,OAEFtK,KAAKyuN,cAAcjrN,OAAO8G,EAAO,GACjC,MAAMm9J,EAASr3J,EAAOk9F,YACtBttG,KAAKkrK,aAAa3qK,SAAQ2wG,IACpBu2D,EAAOhqD,SAASvM,EAAO/4B,QACzBn4E,KAAKo0J,YAAYljD,SAOtB,SAASy9G,EAAqBrsN,GACnC,GAAsB,iBAAXA,GAAwBA,EAAO2oJ,oBAGpC,qBAAsB3oJ,EAAO2oJ,kBAAkBhqJ,YACnDqB,EAAO2oJ,kBAAkBhqJ,UAAU2tN,iBACjC,WACE,OAAO5uN,KAAK6uN,eAAiB7uN,KAAK6uN,eAAiB,OAGnD,gBAAiBvsN,EAAO2oJ,kBAAkBhqJ,YAAY,CAC1Db,OAAO0kB,eAAexiB,EAAO2oJ,kBAAkBhqJ,UAAW,cAAe,CACvE+jB,MACE,OAAOhlB,KAAK8uN,cAEd5pM,IAAIkP,GACEp0B,KAAK8uN,eACP9uN,KAAKusC,oBAAoB,YAAavsC,KAAK8uN,cAC3C9uN,KAAKusC,oBAAoB,QAASvsC,KAAK+uN,mBAEzC/uN,KAAKqsC,iBAAiB,YAAarsC,KAAK8uN,aAAe16L,GACvDp0B,KAAKqsC,iBAAiB,QAASrsC,KAAK+uN,iBAAoBhiN,IACtDA,EAAEi1H,QAAQzhI,SAAQ6P,IAIhB,GAHKpQ,KAAK6uN,iBACR7uN,KAAK6uN,eAAiB,IAEpB7uN,KAAK6uN,eAAepxG,SAASrtG,GAC/B,OAEFpQ,KAAK6uN,eAAe3sN,KAAKkO,GACzB,MAAMkoB,EAAQ,IAAIgyB,MAAM,aACxBhyB,EAAMloB,OAASA,EACfpQ,KAAKgpN,cAAc1wL,WAK3B,MAAMuwL,EACJvmN,EAAO2oJ,kBAAkBhqJ,UAAUs3I,qBACrCj2I,EAAO2oJ,kBAAkBhqJ,UAAUs3I,qBACjC,WACE,MAAM3rD,EAAK5sF,KAiBX,OAhBKA,KAAK+uN,kBACR/uN,KAAKqsC,iBAAiB,QAASrsC,KAAK+uN,iBAAmB,SAAShiN,GAC9DA,EAAEi1H,QAAQzhI,SAAQ6P,IAIhB,GAHKw8E,EAAGiiI,iBACNjiI,EAAGiiI,eAAiB,IAElBjiI,EAAGiiI,eAAexrN,QAAQ+M,IAAW,EACvC,OAEFw8E,EAAGiiI,eAAe3sN,KAAKkO,GACvB,MAAMkoB,EAAQ,IAAIgyB,MAAM,aACxBhyB,EAAMloB,OAASA,EACfw8E,EAAGo8H,cAAc1wL,QAIhBuwL,EAAyBnoN,MAAMksF,EAAIjsF,aAK3C,SAASquN,EAAiB1sN,GAC/B,GAAsB,iBAAXA,IAAwBA,EAAO2oJ,kBACxC,OAEF,MAAMhqJ,EAAYqB,EAAO2oJ,kBAAkBhqJ,UACrCmtN,EAAkBntN,EAAU6yI,YAC5By6E,EAAmBttN,EAAUu3I,aAC7BxE,EAAsB/yI,EAAU+yI,oBAChCuE,EAAuBt3I,EAAUs3I,qBACjC3F,EAAkB3xI,EAAU2xI,gBAElC3xI,EAAU6yI,YACR,SAAqB+e,EAAiB7lC,GACpC,MAAMjtH,EAAWY,UAAUe,QAAU,EAAKf,UAAU,GAAKA,UAAU,GAC7D+/C,EAAU0tK,EAAgB1tN,MAAMV,KAAM,CAACD,IAC7C,OAAKitH,GAGLtsE,EAAQE,KAAKiyG,EAAiB7lC,GACvBjjF,QAAQC,WAHN0W,GAMbz/C,EAAUu3I,aACR,SAAsBqa,EAAiB7lC,GACrC,MAAMjtH,EAAWY,UAAUe,QAAU,EAAKf,UAAU,GAAKA,UAAU,GAC7D+/C,EAAU6tK,EAAiB7tN,MAAMV,KAAM,CAACD,IAC9C,OAAKitH,GAGLtsE,EAAQE,KAAKiyG,EAAiB7lC,GACvBjjF,QAAQC,WAHN0W,GAMb,IAAIuuK,EAAe,SAASn5I,EAAa+8E,EAAiB7lC,GACxD,MAAMtsE,EAAUszF,EAAoBtzI,MAAMV,KAAM,CAAC81E,IACjD,OAAKk3C,GAGLtsE,EAAQE,KAAKiyG,EAAiB7lC,GACvBjjF,QAAQC,WAHN0W,GAKXz/C,EAAU+yI,oBAAsBi7E,EAEhCA,EAAe,SAASn5I,EAAa+8E,EAAiB7lC,GACpD,MAAMtsE,EAAU63F,EAAqB73I,MAAMV,KAAM,CAAC81E,IAClD,OAAKk3C,GAGLtsE,EAAQE,KAAKiyG,EAAiB7lC,GACvBjjF,QAAQC,WAHN0W,GAKXz/C,EAAUs3I,qBAAuB02E,EAEjCA,EAAe,SAASv9I,EAAWmhF,EAAiB7lC,GAClD,MAAMtsE,EAAUkyF,EAAgBlyI,MAAMV,KAAM,CAAC0xE,IAC7C,OAAKs7C,GAGLtsE,EAAQE,KAAKiyG,EAAiB7lC,GACvBjjF,QAAQC,WAHN0W,GAKXz/C,EAAU2xI,gBAAkBq8E,EAGvB,SAAS,EAAiB3sN,GAC/B,MAAM+hF,EAAY/hF,GAAUA,EAAO+hF,UAEnC,GAAIA,EAAUkD,cAAgBlD,EAAUkD,aAAaC,aAAc,CAEjE,MAAMD,EAAelD,EAAUkD,aACzBwkE,EAAgBxkE,EAAaC,aAAa5mF,KAAK2mF,GACrDlD,EAAUkD,aAAaC,aAAgB/G,GAC9BsrE,EAAcmjE,EAAgBzuI,KAIpC4D,EAAUmD,cAAgBnD,EAAUkD,cACvClD,EAAUkD,aAAaC,eACvBnD,EAAUmD,aAAe,SAAsB/G,EAAaukD,EAAImqF,GAC9D9qI,EAAUkD,aAAaC,aAAa/G,GACnC7/B,KAAKokF,EAAImqF,IACVvuN,KAAKyjF,IAIJ,SAAS6qI,EAAgBzuI,GAC9B,OAAIA,QAAqC10E,IAAtB00E,EAAYG,MACtBxgF,OAAOqmC,OAAO,GACnBg6C,EACA,CAACG,MAAO,EAAoBH,EAAYG,SAIrCH,EAGF,SAAS2uI,EAAqB9sN,GACnC,IAAKA,EAAO2oJ,kBACV,OAGF,MAAMokE,EAAqB/sN,EAAO2oJ,kBAClC3oJ,EAAO2oJ,kBACL,SAA2B5e,EAAUmf,GACnC,GAAInf,GAAYA,EAAS+R,WAAY,CACnC,MAAMkxE,EAAgB,GACtB,IAAK,IAAI9tN,EAAI,EAAGA,EAAI6qI,EAAS+R,WAAW18I,OAAQF,IAAK,CACnD,IAAIkuF,EAAS28C,EAAS+R,WAAW58I,IAC5BkuF,EAAOj3E,eAAe,SACvBi3E,EAAOj3E,eAAe,QACxB,EAAiB,mBAAoB,qBACrCi3E,EAAStuF,KAAKwJ,MAAMxJ,KAAKF,UAAUwuF,IACnCA,EAAOuuD,KAAOvuD,EAAOvnD,WACdunD,EAAOvnD,IACdmnL,EAAcptN,KAAKwtF,IAEnB4/H,EAAcptN,KAAKmqI,EAAS+R,WAAW58I,IAG3C6qI,EAAS+R,WAAakxE,EAExB,OAAO,IAAID,EAAmBhjF,EAAUmf,IAE5ClpJ,EAAO2oJ,kBAAkBhqJ,UAAYouN,EAAmBpuN,UAEpD,wBAAyBouN,GAC3BjvN,OAAO0kB,eAAexiB,EAAO2oJ,kBAAmB,sBAAuB,CACrEjmI,IAAG,IACMqqM,EAAmBE,sBAM3B,SAASC,EAA0BltN,GAElB,iBAAXA,GAAuBA,EAAOuqN,eACrC,aAAcvqN,EAAOuqN,cAAc5rN,aACjC,gBAAiBqB,EAAOuqN,cAAc5rN,YAC1Cb,OAAO0kB,eAAexiB,EAAOuqN,cAAc5rN,UAAW,cAAe,CACnE+jB,MACE,MAAO,CAACqkB,SAAUrpC,KAAKqpC,aAMxB,SAASomL,EAAsBntN,GACpC,MAAM8rN,EAAkB9rN,EAAO2oJ,kBAAkBhqJ,UAAU6yI,YAC3DxxI,EAAO2oJ,kBAAkBhqJ,UAAU6yI,YACjC,SAAqB47E,GACnB,GAAIA,EAAc,MACgC,IAArCA,EAAa/yE,sBAEtB+yE,EAAa/yE,sBACT+yE,EAAa/yE,qBAEnB,MAAMgzE,EAAmB3vN,KAAK6iK,kBAAkBx6J,MAAKw7J,GACf,UAApCA,EAAYx6H,SAAS8uC,MAAM5B,QACY,IAArCm5I,EAAa/yE,qBAAiCgzE,EACb,aAA/BA,EAAiBvjN,UACfujN,EAAiBC,aACnBD,EAAiBC,aAAa,YAE9BD,EAAiBvjN,UAAY,WAES,aAA/BujN,EAAiBvjN,YACtBujN,EAAiBC,aACnBD,EAAiBC,aAAa,YAE9BD,EAAiBvjN,UAAY,aAGa,IAArCsjN,EAAa/yE,qBACnBgzE,GACH3vN,KAAKmjK,eAAe,QAAS,CAAC/2J,UAAW,kBAGK,IAArCsjN,EAAa9yE,sBAEtB8yE,EAAa9yE,sBACT8yE,EAAa9yE,qBAEnB,MAAMizE,EAAmB7vN,KAAK6iK,kBAAkBx6J,MAAKw7J,GACf,UAApCA,EAAYx6H,SAAS8uC,MAAM5B,QACY,IAArCm5I,EAAa9yE,qBAAiCizE,EACb,aAA/BA,EAAiBzjN,UACfyjN,EAAiBD,aACnBC,EAAiBD,aAAa,YAE9BC,EAAiBzjN,UAAY,WAES,aAA/ByjN,EAAiBzjN,YACtByjN,EAAiBD,aACnBC,EAAiBD,aAAa,YAE9BC,EAAiBzjN,UAAY,aAGa,IAArCsjN,EAAa9yE,qBACnBizE,GACH7vN,KAAKmjK,eAAe,QAAS,CAAC/2J,UAAW,aAG7C,OAAOgiN,EAAgB1tN,MAAMV,KAAMW,YAIlC,SAASmvN,EAAiBxtN,GACT,iBAAXA,GAAuBA,EAAO2uF,eAGzC3uF,EAAO2uF,aAAe3uF,EAAO4uF,0CCjVxB,SAAS6+H,GAAoBztN,GAGlC,IAAKA,EAAOowI,iBAAoBpwI,EAAOowI,iBAAmB,eACtDpwI,EAAOowI,gBAAgBzxI,UACzB,OAGF,MAAM+uN,EAAwB1tN,EAAOowI,gBACrCpwI,EAAOowI,gBAAkB,SAAyBjuI,GAQhD,GANoB,iBAATA,GAAqBA,EAAKitE,WACA,IAAjCjtE,EAAKitE,UAAUruE,QAAQ,SACzBoB,EAAOrD,KAAKwJ,MAAMxJ,KAAKF,UAAUuD,KAC5BitE,UAAYjtE,EAAKitE,UAAUrtE,OAAO,IAGrCI,EAAKitE,WAAajtE,EAAKitE,UAAUhwE,OAAQ,CAE3C,MAAMuuN,EAAkB,IAAID,EAAsBvrN,GAC5CyrN,EAAkB,mBAAwBzrN,EAAKitE,WAC/Cy+I,EAAqB/vN,OAAOqmC,OAAOwpL,EACrCC,GAWJ,OARAC,EAAmBC,OAAS,WAC1B,MAAO,CACL1+I,UAAWy+I,EAAmBz+I,UAC9BwgE,OAAQi+E,EAAmBj+E,OAC3BL,cAAes+E,EAAmBt+E,cAClC3/D,iBAAkBi+I,EAAmBj+I,mBAGlCi+I,EAET,OAAO,IAAIH,EAAsBvrN,IAEnCnC,EAAOowI,gBAAgBzxI,UAAY+uN,EAAsB/uN,UAIzD,EAA8BqB,EAAQ,gBAAgByK,IAChDA,EAAE2kE,WACJtxE,OAAO0kB,eAAe/X,EAAG,YAAa,CACpC5F,MAAO,IAAI7E,EAAOowI,gBAAgB3lI,EAAE2kE,WACpC1sC,SAAU,UAGPj4B,KAIJ,SAASsjN,GAAmB/tN,EAAQmkN,GACzC,IAAKnkN,EAAO2oJ,kBACV,OAGI,SAAU3oJ,EAAO2oJ,kBAAkBhqJ,WACvCb,OAAO0kB,eAAexiB,EAAO2oJ,kBAAkBhqJ,UAAW,OAAQ,CAChE+jB,MACE,YAA6B,IAAfhlB,KAAKswN,MAAwB,KAAOtwN,KAAKswN,SAK7D,MAAMC,EAAoB,SAASz6I,GACjC,IAAKA,IAAgBA,EAAY/tE,IAC/B,OAAO,EAET,MAAMupE,EAAW,kBAAuBwE,EAAY/tE,KAEpD,OADAupE,EAASnkC,QACFmkC,EAAS1lE,MAAKqoE,IACnB,MAAMttE,EAAQ,eAAoBstE,GAClC,OAAOttE,GAAwB,gBAAfA,EAAM4vE,OACqB,IAApC5vE,EAAMirE,SAASvuE,QAAQ,YAI5BmtN,EAA0B,SAAS16I,GAEvC,MAAM1xE,EAAQ0xE,EAAY/tE,IAAI3D,MAAM,mCACpC,GAAc,OAAVA,GAAkBA,EAAM1C,OAAS,EACnC,OAAQ,EAEV,MAAMuP,EAAUxI,SAASrE,EAAM,GAAI,IAEnC,OAAO6M,GAAYA,GAAW,EAAIA,GAG9Bw/M,EAA2B,SAASC,GAKxC,IAAIC,EAAwB,MAwB5B,MAvB+B,YAA3BlK,EAAelhL,UAKborL,EAJAlK,EAAex1M,QAAU,IACF,IAArBy/M,EAGsB,MAIA,WAEjBjK,EAAex1M,QAAU,GAML,KAA3Bw1M,EAAex1M,QAAiB,MAAQ,MAGlB,YAGrB0/M,GAGHC,EAAoB,SAAS96I,EAAa46I,GAG9C,IAAI3iN,EAAiB,MAKU,YAA3B04M,EAAelhL,SACgB,KAA3BkhL,EAAex1M,UACrBlD,EAAiB,OAGnB,MAAM3J,EAAQ,gBAAqB0xE,EAAY/tE,IAC7C,uBAUF,OATI3D,EAAM1C,OAAS,EACjBqM,EAAiBtF,SAASrE,EAAM,GAAGC,OAAO,IAAK,IACX,YAA3BoiN,EAAelhL,UACO,IAArBmrL,IAIV3iN,EAAiB,YAEZA,GAGH86M,EACFvmN,EAAO2oJ,kBAAkBhqJ,UAAUs3I,qBACvCj2I,EAAO2oJ,kBAAkBhqJ,UAAUs3I,qBACjC,WAKE,GAJAv4I,KAAKswN,MAAQ,KAIkB,WAA3B7J,EAAelhL,SAAwBkhL,EAAex1M,SAAW,GAAI,CACvE,MAAM,aAACihK,GAAgBlyK,KAAKssN,mBACP,WAAjBp6C,GACF9xK,OAAO0kB,eAAe9kB,KAAM,OAAQ,CAClCglB,MACE,YAA6B,IAAfhlB,KAAKswN,MAAwB,KAAOtwN,KAAKswN,OAEzD9xL,YAAY,EACZuG,cAAc,IAKpB,GAAIwrL,EAAkB5vN,UAAU,IAAK,CAEnC,MAAM0lF,EAAYmqI,EAAwB7vN,UAAU,IAG9CkwN,EAAaJ,EAAyBpqI,GAGtCyqI,EAAYF,EAAkBjwN,UAAU,GAAI0lF,GAGlD,IAAIt4E,EAEFA,EADiB,IAAf8iN,GAAkC,IAAdC,EACLhiN,OAAOiiN,kBACA,IAAfF,GAAkC,IAAdC,EACZ7mN,KAAKotB,IAAIw5L,EAAYC,GAErB7mN,KAAK6uB,IAAI+3L,EAAYC,GAKxC,MAAMj4I,EAAO,GACbz4E,OAAO0kB,eAAe+zD,EAAM,iBAAkB,CAC5C7zD,IAAG,IACMjX,IAGX/N,KAAKswN,MAAQz3I,EAGf,OAAOgwI,EAAyBnoN,MAAMV,KAAMW,YAI3C,SAASqwN,GAAuB1uN,GACrC,IAAMA,EAAO2oJ,qBACT,sBAAuB3oJ,EAAO2oJ,kBAAkBhqJ,WAClD,OAOF,SAASgwN,EAAWC,EAAItkI,GACtB,MAAMukI,EAAsBD,EAAG5tG,KAC/B4tG,EAAG5tG,KAAO,WACR,MAAM7sG,EAAO9V,UAAU,GACjBe,EAAS+U,EAAK/U,QAAU+U,EAAKuuD,MAAQvuD,EAAKymB,WAChD,GAAsB,SAAlBg0L,EAAG1oL,YACHokD,EAAG/T,MAAQn3E,EAASkrF,EAAG/T,KAAK9qE,eAC9B,MAAM,IAAIg9B,UAAU,4CAClB6hD,EAAG/T,KAAK9qE,eAAiB,WAE7B,OAAOojN,EAAoBzwN,MAAMwwN,EAAIvwN,YAGzC,MAAMywN,EACJ9uN,EAAO2oJ,kBAAkBhqJ,UAAUglJ,kBACrC3jJ,EAAO2oJ,kBAAkBhqJ,UAAUglJ,kBACjC,WACE,MAAMorE,EAAcD,EAAsB1wN,MAAMV,KAAMW,WAEtD,OADAswN,EAAWI,EAAarxN,MACjBqxN,GAEX,EAA8B/uN,EAAQ,eAAeyK,IACnDkkN,EAAWlkN,EAAE+6I,QAAS/6I,EAAEyJ,QACjBzJ,KAYJ,SAASukN,GAAoBhvN,GAClC,IAAKA,EAAO2oJ,mBACR,oBAAqB3oJ,EAAO2oJ,kBAAkBhqJ,UAChD,OAEF,MAAMmvC,EAAQ9tC,EAAO2oJ,kBAAkBhqJ,UACvCb,OAAO0kB,eAAesrB,EAAO,kBAAmB,CAC9CprB,MACE,MAAO,CACL++B,UAAW,YACXwtK,SAAU,cACVvxN,KAAK0wI,qBAAuB1wI,KAAK0wI,oBAErClyG,YAAY,EACZuG,cAAc,IAEhB3kC,OAAO0kB,eAAesrB,EAAO,0BAA2B,CACtDprB,MACE,OAAOhlB,KAAKwxN,0BAA4B,MAE1CtsM,IAAI8/G,GACEhlI,KAAKwxN,2BACPxxN,KAAKusC,oBAAoB,wBACrBvsC,KAAKwxN,iCACFxxN,KAAKwxN,0BAEVxsF,GACFhlI,KAAKqsC,iBAAiB,wBAClBrsC,KAAKwxN,yBAA2BxsF,IAGxCxmG,YAAY,EACZuG,cAAc,IAGhB,CAAC,sBAAuB,wBAAwBxkC,SAASkgD,IACvD,MAAMgxK,EAAarhL,EAAMqQ,GACzBrQ,EAAMqQ,GAAU,WAcd,OAbKzgD,KAAK0xN,6BACR1xN,KAAK0xN,2BAA6B3kN,IAChC,MAAM6/E,EAAK7/E,EAAEyJ,OACb,GAAIo2E,EAAG+kI,uBAAyB/kI,EAAG2jD,gBAAiB,CAClD3jD,EAAG+kI,qBAAuB/kI,EAAG2jD,gBAC7B,MAAMqhF,EAAW,IAAItnK,MAAM,wBAAyBv9C,GACpD6/E,EAAGo8H,cAAc4I,GAEnB,OAAO7kN,GAET/M,KAAKqsC,iBAAiB,2BACpBrsC,KAAK0xN,6BAEFD,EAAW/wN,MAAMV,KAAMW,eAK7B,SAASkxN,GAAuBvvN,EAAQmkN,GAE7C,IAAKnkN,EAAO2oJ,kBACV,OAEF,GAA+B,WAA3Bw7D,EAAelhL,SAAwBkhL,EAAex1M,SAAW,GACnE,OAEF,GAA+B,WAA3Bw1M,EAAelhL,SAAwBkhL,EAAex1M,SAAW,IACnE,OAEF,MAAM6gN,EAAYxvN,EAAO2oJ,kBAAkBhqJ,UAAUs3I,qBACrDj2I,EAAO2oJ,kBAAkBhqJ,UAAUs3I,qBACnC,SAA8BzwI,GAC5B,GAAIA,GAAQA,EAAKC,MAAuD,IAAhDD,EAAKC,IAAI1E,QAAQ,0BAAkC,CACzE,MAAM0E,EAAMD,EAAKC,IAAI7D,MAAM,MAAM6C,QAAQjD,GAChB,yBAAhBA,EAAKs6D,SACX70D,KAAK,MAEJjH,EAAO2J,uBACPnE,aAAgBxF,EAAO2J,sBACzBtL,UAAU,GAAK,IAAI2B,EAAO2J,sBAAsB,CAC9CrE,KAAME,EAAKF,KACXG,IAAAA,IAGFD,EAAKC,IAAMA,EAGf,OAAO+pN,EAAUpxN,MAAMV,KAAMW,YAI1B,SAASoxN,GAA+BzvN,EAAQmkN,GAKrD,IAAMnkN,EAAO2oJ,oBAAqB3oJ,EAAO2oJ,kBAAkBhqJ,UACzD,OAEF,MAAM+wN,EACF1vN,EAAO2oJ,kBAAkBhqJ,UAAU2xI,gBAClCo/E,GAA0D,IAAjCA,EAAsBtwN,SAGpDY,EAAO2oJ,kBAAkBhqJ,UAAU2xI,gBACjC,WACE,OAAKjyI,UAAU,IAWkB,WAA3B8lN,EAAelhL,SAAwBkhL,EAAex1M,QAAU,IAClC,YAA3Bw1M,EAAelhL,SACZkhL,EAAex1M,QAAU,IACD,WAA3Bw1M,EAAelhL,UACjB5kC,UAAU,IAAiC,KAA3BA,UAAU,GAAG+wE,UAC3B3nC,QAAQC,UAEVgoL,EAAsBtxN,MAAMV,KAAMW,YAjBnCA,UAAU,IACZA,UAAU,GAAGD,MAAM,MAEdqpC,QAAQC,aAoBhB,SAASioL,GAAqC3vN,EAAQmkN,GAC3D,IAAMnkN,EAAO2oJ,oBAAqB3oJ,EAAO2oJ,kBAAkBhqJ,UACzD,OAEF,MAAMixN,EACF5vN,EAAO2oJ,kBAAkBhqJ,UAAU+yI,oBAClCk+E,GAAkE,IAArCA,EAA0BxwN,SAG5DY,EAAO2oJ,kBAAkBhqJ,UAAU+yI,oBACjC,WACE,IAAIlsI,EAAOnH,UAAU,IAAM,GAC3B,GAAoB,iBAATmH,GAAsBA,EAAKF,MAAQE,EAAKC,IACjD,OAAOmqN,EAA0BxxN,MAAMV,KAAMW,WAU/C,GADAmH,EAAO,CAACF,KAAME,EAAKF,KAAMG,IAAKD,EAAKC,MAC9BD,EAAKF,KACR,OAAQ5H,KAAKswI,gBACX,IAAK,SACL,IAAK,mBACL,IAAK,uBACHxoI,EAAKF,KAAO,QACZ,MACF,QACEE,EAAKF,KAAO,SAIlB,GAAIE,EAAKC,KAAsB,UAAdD,EAAKF,MAAkC,WAAdE,EAAKF,KAC7C,OAAOsqN,EAA0BxxN,MAAMV,KAAM,CAAC8H,IAEhD,MAAM65C,EAAqB,UAAd75C,EAAKF,KAAmB5H,KAAK8zI,YAAc9zI,KAAKw4I,aAC7D,OAAO72F,EAAKjhD,MAAMV,MACf4gD,MAAK5mB,GAAKk4L,EAA0BxxN,MAAMV,KAAM,CAACg6B,QCja1D,MAAMm4L,GCIC,UAAwB,OAAC7vN,GAAU,GAAIvC,EAAU,CACtDqyN,YAAY,EACZC,aAAa,EACbC,YAAY,IAGZ,MAAM7Q,EAAU,EACVgF,EV8HD,SAAuBnkN,GAE5B,MAAMg3B,EAAS,CAACiM,QAAS,KAAMt0B,QAAS,MAGxC,QAAsB,IAAX3O,IAA2BA,EAAO+hF,UAE3C,OADA/qD,EAAOiM,QAAU,iBACVjM,EAGT,MAAM,UAAC+qD,GAAa/hF,EAEpB,GAAI+hF,EAAUkuI,gBACZj5L,EAAOiM,QAAU,UACjBjM,EAAOroB,QAAU6zM,EAAezgI,EAAUD,UACtC,mBAAoB,QACnB,GAAIC,EAAU6jI,qBACW,IAA3B5lN,EAAOkwN,iBAA6BlwN,EAAO8pN,0BAC1C9pN,EAAOmwN,eAKXn5L,EAAOiM,QAAU,SACjBjM,EAAOroB,QAAU6zM,EAAezgI,EAAUD,UACtC,wBAAyB,OACxB,KAAI9hF,EAAO2oJ,oBACd5mE,EAAUD,UAAUhgF,MAAM,wBAQ5B,OADAk1B,EAAOiM,QAAU,2BACVjM,EAPPA,EAAOiM,QAAU,SACjBjM,EAAOroB,QAAU6zM,EAAezgI,EAAUD,UACtC,uBAAwB,GAC5B9qD,EAAOuwD,oBAAsBvnF,EAAOmlF,mBAChC,qBAAsBnlF,EAAOmlF,kBAAkBxmF,UAMrD,OAAOq4B,EUpKgB,CAAoBh3B,GAErC6vN,EAAU,CACd1L,eAAAA,EACAiM,WAAU,EACV5N,eAAgB,EAChBY,WAAY,EACZC,gBAAiB,EAEjB59M,IAAG,GAIL,OAAQ0+M,EAAelhL,SACrB,IAAK,SACH,IAAK,IAAe,IACfxlC,EAAQqyN,WAEX,OADA3Q,EAAQ,wDACD0Q,EAET,GAA+B,OAA3B1L,EAAex1M,QAEjB,OADAwwM,EAAQ,wDACD0Q,EAET1Q,EAAQ,+BAER0Q,EAAQQ,YAAc,EAGtB,GAA0CrwN,EAAQmkN,GAClD,GAAgDnkN,GAEhD,EAA4BA,EAAQmkN,GACpC,EAA2BnkN,GAC3B,EAA8BA,EAAQmkN,GACtC,EAAuBnkN,GACvB,EAAmCA,EAAQmkN,GAC3C,EAAkCnkN,GAClC,EAAwBA,GACxB,EAAsCA,GACtC,EAAgCA,EAAQmkN,GAExC,GAA+BnkN,GAC/B,GAA+BA,GAC/B,GAA8BA,EAAQmkN,GACtC,GAAkCnkN,GAClC,GAAkCA,EAAQmkN,GAC1C,MACF,IAAK,UACH,IAAK,IAAgB,IAChB1mN,EAAQsyN,YAEX,OADA5Q,EAAQ,yDACD0Q,EAET1Q,EAAQ,gCAER0Q,EAAQQ,YAAc,EAGtB,GAA0CrwN,EAAQmkN,GAClD,GAAgDnkN,GAEhD,EAA6BA,EAAQmkN,GACrC,EAA+BnkN,EAAQmkN,GACvC,EAAwBnkN,GACxB,EAA6BA,GAC7B,EAA+BA,GAC/B,EAAiCA,GACjC,EAA+BA,GAC/B,EAA+BA,GAC/B,EAA8BA,GAC9B,EAA4BA,GAC5B,EAA6BA,GAE7B,GAA+BA,GAC/B,GAA+BA,GAC/B,GAA8BA,EAAQmkN,GACtC,GAAkCnkN,GAClC,MACF,IAAK,SACH,IAAK,IAAevC,EAAQuyN,WAE1B,OADA7Q,EAAQ,wDACD0Q,EAET1Q,EAAQ,+BAER0Q,EAAQQ,YAAc,EAGtB,GAA0CrwN,EAAQmkN,GAClD,GAAgDnkN,GAEhD,EAAgCA,GAChC,EAAiCA,GACjC,EAA4BA,GAC5B,EAA+BA,GAC/B,EAAgCA,GAChC,EAAqCA,GACrC,EAA4BA,GAC5B,EAA4BA,GAE5B,GAA+BA,GAC/B,GAA8BA,EAAQmkN,GACtC,GAAkCnkN,GAClC,GAAkCA,EAAQmkN,GAC1C,MACF,QACEhF,EAAQ,wBAIZ,OAAO0Q,EDzHPS,CAAe,CAACtwN,OAA0B,oBAAXA,YAAyByJ,EAAYzJ,SACtE,2BEbA9C,EAAOD,QAAU,WACf,MAAM,IAAIyE,MACR,4FCHA6uN,yBAA2B,GAG/B,SAASC,oBAAoBC,GAE5B,IAAIC,EAAeH,yBAAyBE,GAC5C,QAAqBhnN,IAAjBinN,EACH,OAAOA,EAAazzN,QAGrB,IAAIC,EAASqzN,yBAAyBE,GAAY,CACjD1tN,GAAI0tN,EACJE,QAAQ,EACR1zN,QAAS,IAUV,OANA2zN,oBAAoBH,GAAUnuN,KAAKpF,EAAOD,QAASC,EAAQA,EAAOD,QAASuzN,qBAG3EtzN,EAAOyzN,QAAS,EAGTzzN,EAAOD,QCxBfuzN,oBAAoBK,KAAO,GCC3BL,oBAAoBjiN,EAAKrR,IACxB,IAAIi5D,EAASj5D,GAAUA,EAAOm/B,WAC7B,IAAOn/B,EAAiB,QACxB,IAAM,EAEP,OADAszN,oBAAoB94L,EAAEy+B,EAAQ,CAAEprD,EAAGorD,IAC5BA,GCLRq6J,oBAAoB94L,EAAI,CAACz6B,EAAS6zN,KACjC,IAAI,IAAIllN,KAAOklN,EACXN,oBAAoBpmN,EAAE0mN,EAAYllN,KAAS4kN,oBAAoBpmN,EAAEnN,EAAS2O,IAC5E9N,OAAO0kB,eAAevlB,EAAS2O,EAAK,CAAEswB,YAAY,EAAMxZ,IAAKouM,EAAWllN,MCJ3E4kN,oBAAoB/zJ,EAAI,WACvB,GAA0B,iBAAfs0J,WAAyB,OAAOA,WAC3C,IACC,OAAOrzN,MAAQ,IAAI4Q,SAAS,cAAb,GACd,MAAO7D,GACR,GAAsB,iBAAXzK,OAAqB,OAAOA,QALjB,GCAxBwwN,oBAAoBpmN,EAAI,CAACyB,EAAKge,IAAU/rB,OAAOa,UAAUwX,eAAe7T,KAAKuJ,EAAKge,GCClF2mM,oBAAoB5lN,EAAK3N,IACH,oBAAXk/B,QAA0BA,OAAOC,aAC1Ct+B,OAAO0kB,eAAevlB,EAASk/B,OAAOC,YAAa,CAAEv3B,MAAO,WAE7D/G,OAAO0kB,eAAevlB,EAAS,aAAc,CAAE4H,OAAO,KCLvD2rN,oBAAoBQ,IAAO9zN,IAC1BA,EAAO+zN,MAAQ,GACV/zN,EAAO2/C,WAAU3/C,EAAO2/C,SAAW,IACjC3/C,GCAR,IAAIg0N,oBAAsBV,oBAAoB","sources":["webpack://JitsiMeetJS/webpack/universalModuleDefinition","webpack://JitsiMeetJS/./node_modules/@jitsi/logger/lib/LogCollector.js","webpack://JitsiMeetJS/./node_modules/@jitsi/logger/lib/Logger.js","webpack://JitsiMeetJS/./node_modules/@jitsi/logger/lib/index.js","webpack://JitsiMeetJS/./node_modules/@jitsi/sdp-simulcast/lib/index.js","webpack://JitsiMeetJS/./node_modules/@jitsi/sdp-simulcast/lib/transform-utils.js","webpack://JitsiMeetJS/./node_modules/@jitsi/sdp-simulcast/node_modules/sdp-transform/lib/grammar.js","webpack://JitsiMeetJS/./node_modules/@jitsi/sdp-simulcast/node_modules/sdp-transform/lib/index.js","webpack://JitsiMeetJS/./node_modules/@jitsi/sdp-simulcast/node_modules/sdp-transform/lib/parser.js","webpack://JitsiMeetJS/./node_modules/@jitsi/sdp-simulcast/node_modules/sdp-transform/lib/writer.js","webpack://JitsiMeetJS/./node_modules/@xmldom/xmldom/lib/conventions.js","webpack://JitsiMeetJS/./node_modules/@xmldom/xmldom/lib/dom-parser.js","webpack://JitsiMeetJS/./node_modules/@xmldom/xmldom/lib/dom.js","webpack://JitsiMeetJS/./node_modules/@xmldom/xmldom/lib/entities.js","webpack://JitsiMeetJS/./node_modules/@xmldom/xmldom/lib/index.js","webpack://JitsiMeetJS/./node_modules/@xmldom/xmldom/lib/sax.js","webpack://JitsiMeetJS/./index.js","webpack://JitsiMeetJS/./modules/util/AuthUtil.js","webpack://JitsiMeetJS/./modules/util/EventEmitterForwarder.js","webpack://JitsiMeetJS/./modules/util/GlobalOnErrorHandler.js","webpack://JitsiMeetJS/./modules/util/RandomUtil.js","webpack://JitsiMeetJS/./modules/util/ScriptUtil.js","webpack://JitsiMeetJS/./modules/util/StringUtils.js","webpack://JitsiMeetJS/./modules/util/UsernameGenerator.js","webpack://JitsiMeetJS/./service/RTC/RTCEvents.ts","webpack://JitsiMeetJS/./service/RTC/Resolutions.js","webpack://JitsiMeetJS/./service/RTC/VideoType.ts","webpack://JitsiMeetJS/./service/authentication/AuthenticationEvents.js","webpack://JitsiMeetJS/./service/xmpp/XMPPEvents.ts","webpack://JitsiMeetJS/./node_modules/base64-js/index.js","webpack://JitsiMeetJS/./node_modules/bowser/es5.js","webpack://JitsiMeetJS/./node_modules/current-executing-script/dist/currentExecutingScript.js","webpack://JitsiMeetJS/./node_modules/events/events.js","webpack://JitsiMeetJS/./node_modules/jquery/dist/jquery.slim.js","webpack://JitsiMeetJS/./node_modules/js-md5/src/md5.js","webpack://JitsiMeetJS/./node_modules/lodash.clonedeep/index.js","webpack://JitsiMeetJS/./node_modules/lodash.debounce/index.js","webpack://JitsiMeetJS/./node_modules/lodash.isequal/index.js","webpack://JitsiMeetJS/./node_modules/sdp-transform/lib/grammar.js","webpack://JitsiMeetJS/./node_modules/sdp-transform/lib/index.js","webpack://JitsiMeetJS/./node_modules/sdp-transform/lib/parser.js","webpack://JitsiMeetJS/./node_modules/sdp-transform/lib/writer.js","webpack://JitsiMeetJS/./node_modules/sdp/sdp.js","webpack://JitsiMeetJS/./JitsiConferenceErrors.ts","webpack://JitsiMeetJS/./JitsiConferenceEvents.ts","webpack://JitsiMeetJS/./modules/statistics/constants.js","webpack://JitsiMeetJS/./JitsiTrackErrors.ts","webpack://JitsiMeetJS/./JitsiTrackError.js","webpack://JitsiMeetJS/./service/statistics/AnalyticsEvents.ts","webpack://JitsiMeetJS/./service/statistics/Events.ts","webpack://JitsiMeetJS/./node_modules/@jitsi/js-utils/browser-detection/browsers.js","webpack://JitsiMeetJS/./node_modules/@jitsi/js-utils/browser-detection/BrowserDetection.js","webpack://JitsiMeetJS/./node_modules/@jitsi/js-utils/jitsi-local-storage/index.js","webpack://JitsiMeetJS/./modules/browser/BrowserCapabilities.js","webpack://JitsiMeetJS/./modules/browser/index.js","webpack://JitsiMeetJS/./modules/statistics/AnalyticsAdapter.js","webpack://JitsiMeetJS/./modules/statistics/CallStats.js","webpack://JitsiMeetJS/./modules/statistics/LocalStatsCollector.js","webpack://JitsiMeetJS/./modules/util/MathUtil.js","webpack://JitsiMeetJS/./modules/statistics/PerformanceObserverStats.js","webpack://JitsiMeetJS/./service/RTC/MediaType.ts","webpack://JitsiMeetJS/./modules/statistics/RTPStatsCollector.js","webpack://JitsiMeetJS/./modules/statistics/statistics.js","webpack://JitsiMeetJS/./JitsiConferenceEventManager.js","webpack://JitsiMeetJS/./JitsiTrackEvents.ts","webpack://JitsiMeetJS/./modules/connectivity/ParticipantConnectionStatus.js","webpack://JitsiMeetJS/./JitsiParticipant.js","webpack://JitsiMeetJS/./JitsiConnectionEvents.ts","webpack://JitsiMeetJS/./JitsiConnectionErrors.ts","webpack://JitsiMeetJS/./modules/util/Deferred.js","webpack://JitsiMeetJS/./modules/util/Listenable.js","webpack://JitsiMeetJS/./modules/e2ee/E2EEContext.js","webpack://JitsiMeetJS/./modules/e2ee/KeyHandler.js","webpack://JitsiMeetJS/./modules/e2ee/ExternallyManagedKeyHandler.js","webpack://JitsiMeetJS/./node_modules/uuid/dist/esm-browser/rng.js","webpack://JitsiMeetJS/./node_modules/uuid/dist/esm-browser/regex.js","webpack://JitsiMeetJS/./node_modules/uuid/dist/esm-browser/validate.js","webpack://JitsiMeetJS/./node_modules/uuid/dist/esm-browser/stringify.js","webpack://JitsiMeetJS/./node_modules/uuid/dist/esm-browser/v4.js","webpack://JitsiMeetJS/./modules/e2ee/OlmAdapter.js","webpack://JitsiMeetJS/./modules/e2ee/ManagedKeyHandler.js","webpack://JitsiMeetJS/./modules/e2ee/crypto-utils.js","webpack://JitsiMeetJS/./modules/e2ee/E2EEncryption.js","webpack://JitsiMeetJS/./modules/xmpp/Caps.js","webpack://JitsiMeetJS/./modules/connectivity/NetworkInfo.js","webpack://JitsiMeetJS/./modules/xmpp/ResumeTask.js","webpack://JitsiMeetJS/./modules/util/Retry.js","webpack://JitsiMeetJS/./modules/xmpp/StropheLastSuccess.js","webpack://JitsiMeetJS/./modules/xmpp/ConnectionPlugin.js","webpack://JitsiMeetJS/./modules/xmpp/strophe.ping.js","webpack://JitsiMeetJS/./modules/xmpp/XmppConnection.js","webpack://JitsiMeetJS/./JitsiTranscriptionStatus.ts","webpack://JitsiMeetJS/./modules/xmpp/AVModeration.js","webpack://JitsiMeetJS/./modules/xmpp/BreakoutRooms.js","webpack://JitsiMeetJS/./modules/xmpp/Lobby.js","webpack://JitsiMeetJS/./modules/settings/Settings.js","webpack://JitsiMeetJS/./modules/xmpp/moderator.js","webpack://JitsiMeetJS/./modules/xmpp/ChatRoom.js","webpack://JitsiMeetJS/./modules/xmpp/strophe.emuc.js","webpack://JitsiMeetJS/./modules/flags/FeatureFlags.js","webpack://JitsiMeetJS/./modules/xmpp/JingleHelperFunctions.js","webpack://JitsiMeetJS/./service/RTC/CodecMimeType.js","webpack://JitsiMeetJS/./service/RTC/MediaDirection.js","webpack://JitsiMeetJS/./modules/RTC/ScreenObtainer.js","webpack://JitsiMeetJS/./modules/sdp/SDPUtil.js","webpack://JitsiMeetJS/./modules/sdp/SDP.js","webpack://JitsiMeetJS/./modules/sdp/SDPDiffer.js","webpack://JitsiMeetJS/./node_modules/async/dist/async.mjs","webpack://JitsiMeetJS/./modules/util/AsyncQueue.js","webpack://JitsiMeetJS/./modules/xmpp/JingleSessionState.ts","webpack://JitsiMeetJS/./modules/xmpp/JingleSession.js","webpack://JitsiMeetJS/./modules/xmpp/MediaSessionEvents.ts","webpack://JitsiMeetJS/./modules/xmpp/JingleSessionPC.js","webpack://JitsiMeetJS/./modules/xmpp/strophe.jingle.js","webpack://JitsiMeetJS/./modules/xmpp/strophe.logger.js","webpack://JitsiMeetJS/./modules/xmpp/strophe.rayo.js","webpack://JitsiMeetJS/./modules/xmpp/strophe.util.js","webpack://JitsiMeetJS/./modules/xmpp/xmpp.js","webpack://JitsiMeetJS/./authenticateAndUpgradeRole.js","webpack://JitsiMeetJS/./modules/RTC/CodecSelection.js","webpack://JitsiMeetJS/./service/RTC/BridgeVideoType.js","webpack://JitsiMeetJS/./modules/RTC/BridgeChannel.js","webpack://JitsiMeetJS/./service/RTC/CameraFacingMode.js","webpack://JitsiMeetJS/./modules/RTC/RTCUtils.js","webpack://JitsiMeetJS/./modules/RTC/JitsiTrack.js","webpack://JitsiMeetJS/./modules/RTC/JitsiLocalTrack.js","webpack://JitsiMeetJS/./node_modules/@jitsi/sdp-interop/lib/transform.js","webpack://JitsiMeetJS/./node_modules/@jitsi/sdp-interop/lib/interop.js","webpack://JitsiMeetJS/./service/RTC/SignalingEvents.ts","webpack://JitsiMeetJS/./service/RTC/SignalingLayer.js","webpack://JitsiMeetJS/./modules/sdp/SdpTransformUtil.js","webpack://JitsiMeetJS/./modules/sdp/LocalSdpMunger.js","webpack://JitsiMeetJS/./modules/sdp/RtxModifier.js","webpack://JitsiMeetJS/./modules/sdp/SdpConsistency.js","webpack://JitsiMeetJS/./modules/sdp/SdpSimulcast.ts","webpack://JitsiMeetJS/./modules/connectivity/TrackStreamingStatus.ts","webpack://JitsiMeetJS/./modules/RTC/JitsiRemoteTrack.js","webpack://JitsiMeetJS/./modules/RTC/TPCUtils.js","webpack://JitsiMeetJS/./modules/RTC/TraceablePeerConnection.js","webpack://JitsiMeetJS/./modules/RTC/RTC.js","webpack://JitsiMeetJS/./service/connectivity/ConnectionQualityEvents.ts","webpack://JitsiMeetJS/./modules/connectivity/ConnectionQuality.js","webpack://JitsiMeetJS/./modules/connectivity/IceFailedHandling.js","webpack://JitsiMeetJS/./modules/detection/DetectionEvents.ts","webpack://JitsiMeetJS/./modules/detection/NoAudioSignalDetection.js","webpack://JitsiMeetJS/./modules/detection/P2PDominantSpeakerDetection.js","webpack://JitsiMeetJS/./modules/webaudio/WebAudioUtils.js","webpack://JitsiMeetJS/./modules/detection/TrackVADEmitter.js","webpack://JitsiMeetJS/./modules/detection/VADAudioAnalyser.js","webpack://JitsiMeetJS/./modules/detection/VADNoiseDetection.js","webpack://JitsiMeetJS/./modules/detection/VADTalkMutedDetection.js","webpack://JitsiMeetJS/./service/e2eping/E2ePingEvents.ts","webpack://JitsiMeetJS/./modules/e2eping/e2eping.js","webpack://JitsiMeetJS/./modules/event/Jvb121EventGenerator.js","webpack://JitsiMeetJS/./modules/qualitycontrol/ReceiveVideoController.js","webpack://JitsiMeetJS/./modules/qualitycontrol/SendVideoController.js","webpack://JitsiMeetJS/./modules/recording/recordingXMLUtils.js","webpack://JitsiMeetJS/./modules/recording/JibriSession.js","webpack://JitsiMeetJS/./modules/recording/RecordingManager.js","webpack://JitsiMeetJS/./modules/statistics/AudioOutputProblemDetector.js","webpack://JitsiMeetJS/./modules/statistics/AvgRTPStatsReporter.js","webpack://JitsiMeetJS/./modules/statistics/SpeakerStats.ts","webpack://JitsiMeetJS/./modules/statistics/SpeakerStatsCollector.js","webpack://JitsiMeetJS/./modules/transcription/recordingResult.js","webpack://JitsiMeetJS/./modules/transcription/trackRecorder.js","webpack://JitsiMeetJS/./modules/transcription/audioRecorder.js","webpack://JitsiMeetJS/./modules/transcription/word.js","webpack://JitsiMeetJS/./modules/transcription/transcriptionServices/SphinxTranscriptionService.js","webpack://JitsiMeetJS/./modules/transcription/transcriptionServices/AbstractTranscriptionService.js","webpack://JitsiMeetJS/./modules/transcription/transcriber.js","webpack://JitsiMeetJS/./modules/version/ComponentsVersions.js","webpack://JitsiMeetJS/./modules/videosipgw/VideoSIPGWConstants.ts","webpack://JitsiMeetJS/./modules/videosipgw/JitsiVideoSIPGWSession.js","webpack://JitsiMeetJS/./modules/videosipgw/VideoSIPGW.js","webpack://JitsiMeetJS/./modules/xmpp/SignalingLayerImpl.js","webpack://JitsiMeetJS/./JitsiConference.js","webpack://JitsiMeetJS/./JitsiConnection.js","webpack://JitsiMeetJS/./JitsiMediaDevicesEvents.ts","webpack://JitsiMeetJS/./JitsiMediaDevices.js","webpack://JitsiMeetJS/./modules/detection/ActiveDeviceDetector.js","webpack://JitsiMeetJS/./modules/proxyconnection/constants.ts","webpack://JitsiMeetJS/./modules/proxyconnection/ProxyConnectionPC.js","webpack://JitsiMeetJS/./modules/proxyconnection/ProxyConnectionService.js","webpack://JitsiMeetJS/./modules/statistics/PrecallTest.js","webpack://JitsiMeetJS/./modules/webaudio/AudioMixer.js","webpack://JitsiMeetJS/./JitsiMeetJS.js","webpack://JitsiMeetJS/./modules/recording/recordingConstants.js","webpack://JitsiMeetJS/./node_modules/strophe.js/dist/strophe.umd.js","webpack://JitsiMeetJS/./node_modules/strophejs-plugin-disco/lib/strophe.disco.js","webpack://JitsiMeetJS/./node_modules/strophejs-plugin-stream-management/lib/strophe.stream-management.js","webpack://JitsiMeetJS/./node_modules/webrtc-adapter/src/js/utils.js","webpack://JitsiMeetJS/./node_modules/webrtc-adapter/src/js/chrome/getusermedia.js","webpack://JitsiMeetJS/./node_modules/webrtc-adapter/src/js/chrome/getdisplaymedia.js","webpack://JitsiMeetJS/./node_modules/webrtc-adapter/src/js/chrome/chrome_shim.js","webpack://JitsiMeetJS/./node_modules/webrtc-adapter/src/js/firefox/getusermedia.js","webpack://JitsiMeetJS/./node_modules/webrtc-adapter/src/js/firefox/getdisplaymedia.js","webpack://JitsiMeetJS/./node_modules/webrtc-adapter/src/js/firefox/firefox_shim.js","webpack://JitsiMeetJS/./node_modules/webrtc-adapter/src/js/safari/safari_shim.js","webpack://JitsiMeetJS/./node_modules/webrtc-adapter/src/js/common_shim.js","webpack://JitsiMeetJS/./node_modules/webrtc-adapter/src/js/adapter_core.js","webpack://JitsiMeetJS/./node_modules/webrtc-adapter/src/js/adapter_factory.js","webpack://JitsiMeetJS/./node_modules/ws/browser.js","webpack://JitsiMeetJS/webpack/bootstrap","webpack://JitsiMeetJS/webpack/runtime/amd options","webpack://JitsiMeetJS/webpack/runtime/compat get default export","webpack://JitsiMeetJS/webpack/runtime/define property getters","webpack://JitsiMeetJS/webpack/runtime/global","webpack://JitsiMeetJS/webpack/runtime/hasOwnProperty shorthand","webpack://JitsiMeetJS/webpack/runtime/make namespace object","webpack://JitsiMeetJS/webpack/runtime/node module decorator","webpack://JitsiMeetJS/webpack/startup"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"JitsiMeetJS\"] = factory();\n\telse\n\t\troot[\"JitsiMeetJS\"] = factory();\n})(self, function() {\nreturn ","/* Copyright @ 2016-present 8x8, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nvar Logger = require('./Logger.js');\n\n/**\n * Creates new <tt>LogCollector</tt>. Class implements <tt>LoggerTransport</tt>\n * and thus can be added as global transport in order to capture all the logs.\n *\n * It captures subsequent log lines created whenever <tt>Logger</tt> logs\n * a message and stores them in a queue in order to batch log entries. There are\n * time and size limit constraints which determine how often batch entries are\n * stored. Whenever one of these limits is exceeded the <tt>LogCollector</tt>\n * will use the <tt>logStorage</tt> object given as an argument to save\n * the batch log entry.\n *\n * @param {Object} logStorage an object which allows to store the logs collected\n * @param {function(string|object[])} logStorage.storeLogs a method called when\n * this <tt>LogCollector</tt> requests log entry storage. The method's argument\n * is an array which can contain <tt>string</tt>s and <tt>object</tt>s. If given\n * item is an object it means that it's an aggregated message. That is a message\n * which is the same as the previous one and it's representation has\n * the following format:\n * {\n *   {string} text: 'the text of some duplicated message'\n *   {number} count: 3 // how many times the message appeared in a row\n * }\n * If a message \"B\" after an aggregated message \"A\" is different, then it breaks\n * the sequence of \"A\". Which means that even if the next message \"C\" is\n * the same as \"A\" it will start a new aggregated message \"C\".\n * @param {function()} logStorage.isReady a method which should return\n * a <tt>boolean</tt> to tell the collector that it's ready to store. During the\n * time storage is not ready log batches will be cached and stored on the next\n * occasion (flush or interval timeout).\n *\n * @param {Object} options the <tt>LogCollector</tt> configuration options.\n * @param {number} options.maxEntryLength the size limit for a single log entry\n * to be stored. The <tt>LogCollector</tt> will push the entry as soon as it\n * reaches or exceeds this limit given that <tt>logStorage.isReady</tt>\n * returns <tt>true</tt>. Otherwise the log entry will be cached until the log\n * storage becomes ready. Note that the \"is ready\" condition is checked every\n * <tt>options.storeInterval</tt> milliseconds.\n * @param {number} options.storeInterval how often the logs should be stored in\n * case <tt>maxEntryLength</tt> was not exceeded.\n * @param {boolean} options.stringifyObjects indicates whether or not object\n * arguments should be \"stringified\" with <tt>JSON.stringify</tt> when a log\n * message is composed. Note that objects logged on the error log level are\n * always stringified.\n *\n * @constructor\n */\nfunction LogCollector(logStorage, options) {\n    this.logStorage = logStorage;\n    this.stringifyObjects = options && options.stringifyObjects ? options.stringifyObjects : false;\n    this.storeInterval = options && options.storeInterval ? options.storeInterval: 30000;\n    this.maxEntryLength = options && options.maxEntryLength ? options.maxEntryLength : 10000;\n    // Bind the log method for each level to the corresponding method name\n    // in order to implement \"global log transport\" object.\n    Object.keys(Logger.levels).forEach(\n    function (logLevel) {\n        var methodName = Logger.levels[logLevel];\n        this[methodName] = function () {\n            this._log.apply(this, arguments);\n        }.bind(this, logLevel);\n    }.bind(this));\n    /**\n     * The ID of store logs interval if one is currently scheduled or\n     * <tt>null</tt> otherwise.\n     * @type {number|null}\n     */\n    this.storeLogsIntervalID = null;\n    /**\n     * The log messages that are to be batched into log entry when\n     * {@link LogCollector._flush} method is called.\n     * @type {string[]}\n     */\n    this.queue = [];\n    /**\n     * The total length of all messages currently stored in the {@link queue}.\n     * @type {number}\n     */\n    this.totalLen = 0;\n    /**\n     * An array used to temporarily store log batches, before the storage gets\n     * ready.\n     * @type {string[]}\n     */\n    this.outputCache = [];\n}\n\n/**\n * Method called inside of {@link formatLogMessage} in order to covert an\n * <tt>Object</tt> argument to string. The conversion will happen when either\n * 'stringifyObjects' option is enabled or on the {@link Logger.levels.ERROR}\n * log level. The default implementation uses <tt>JSON.stringify</tt> and\n * returns \"[object with circular refs?]\" instead of an object if it fails.\n *\n * @param {object} someObject the <tt>object</tt> to be stringified.\n *\n * @return {string} the result of <tt>JSON.stringify</tt> or\n * \"[object with circular refs?]\" if any error occurs during \"stringification\".\n *\n * @protected\n */\nLogCollector.prototype.stringify = function (someObject) {\n    try {\n        return JSON.stringify(someObject);\n    } catch (error) {\n        return '[object with circular refs?]';\n    }\n};\n\n/**\n * Formats log entry for the given logging level and arguments passed to the\n * <tt>Logger</tt>'s log method. The first argument is log level and the next\n * arguments have to be captured using JS built-in 'arguments' variable.\n *\n * @param {Logger.levels} logLevel provides the logging level of the message to\n * be logged.\n * @param {Date} timestamp - The {@code Date} when a message has been logged.\n *\n * @return {string|null} a non-empty string representation of the log entry\n * crafted from the log arguments. If the return value is <tt>null</tt> then\n * the message wil be discarded by this <tt>LogCollector</tt>.\n *\n * @protected\n */\nLogCollector.prototype.formatLogMessage = function (\nlogLevel /* timestamp, arg2, arg3, arg4... */) {\n    var msg = '';\n    for (var i = 1, len = arguments.length; i < len; i++) {\n        var arg = arguments[i];\n        // objects logged on error level are always converted to JSON\n        if ((this.stringifyObjects || logLevel === Logger.levels.ERROR) &&\n            typeof arg === 'object') {\n            arg = this.stringify(arg);\n        }\n        msg += arg;\n        if (i !== len - 1) {\n            msg += ' ';\n        }\n    }\n    return msg.length ? msg : null;\n};\n\n/**\n * The log method bound to each of the logging levels in order to implement\n * \"global log transport\" object.\n *\n * @private\n */\nLogCollector.prototype._log = function() {\n\n    // var logLevel = arguments[0]; first argument is the log level\n    var timestamp = arguments[1];\n    var msg = this.formatLogMessage.apply(this, arguments);\n    if (msg) {\n        // The same as the previous message aggregation logic\n        var prevMessage = this.queue[this.queue.length - 1];\n        var prevMessageText = prevMessage && prevMessage.text;\n        if (prevMessageText === msg) {\n            prevMessage.count += 1;\n        } else {\n            this.queue.push({\n                text: msg,\n                timestamp: timestamp,\n                count: 1\n            });\n            this.totalLen += msg.length;\n        }\n    }\n\n    if (this.totalLen >= this.maxEntryLength) {\n        this._flush(true /* force */, true /* reschedule */);\n    }\n};\n\n/**\n * Starts periodical \"store logs\" task which will be triggered at the interval\n * specified in the constructor options.\n */\nLogCollector.prototype.start = function () {\n    this._reschedulePublishInterval();\n};\n\n/**\n * Reschedules the periodical \"store logs\" task which will store the next batch\n * log entry in the storage.\n * @private\n */\nLogCollector.prototype._reschedulePublishInterval = function () {\n    if (this.storeLogsIntervalID) {\n        window.clearTimeout(this.storeLogsIntervalID);\n        this.storeLogsIntervalID = null;\n    }\n    // It's actually a timeout, because it is rescheduled on every flush\n    this.storeLogsIntervalID = window.setTimeout(\n        this._flush.bind(\n            this, false /* do not force */, true /* reschedule */),\n        this.storeInterval);\n};\n\n/**\n * Call this method to flush the log entry buffer and store it in the log\n * storage immediately (given that the storage is ready).\n */\nLogCollector.prototype.flush = function() {\n    this._flush(\n        false /* do not force, as it will not be stored anyway */,\n        true /* reschedule next update */ );\n};\n\n/**\n * Stores the next batch log entry in the log storage.\n * @param {boolean} force enforce current logs batch to be stored or cached if\n * there is anything to be logged, but the storage is not ready yet. One of\n * legitimate reasons to force is when the logs length exceeds size limit which\n * could result in truncation.\n * @param {boolean} reschedule <tt>true</tt> if the next periodic task should be\n * scheduled after the log entry is stored. <tt>false</tt> will end the periodic\n * task cycle.\n * @private\n */\nLogCollector.prototype._flush = function(force, reschedule) {\n    // Publish only if there's anything to be logged\n    if (this.totalLen > 0 && (this.logStorage.isReady() || force)) {\n        //FIXME avoid truncating\n        // right now we don't care if the message size is \"slightly\" exceeded\n        if (this.logStorage.isReady()) {\n            // Sends all cached logs\n            if (this.outputCache.length) {\n                this.outputCache.forEach(\n                    function (cachedQueue) {\n                        this.logStorage.storeLogs(cachedQueue);\n                    }.bind(this)\n                );\n                // Clear the cache\n                this.outputCache = [];\n            }\n            // Send current batch\n            this.logStorage.storeLogs(this.queue);\n        } else {\n            this.outputCache.push(this.queue);\n        }\n\n        this.queue = [];\n        this.totalLen = 0;\n    }\n\n    if (reschedule) {\n        this._reschedulePublishInterval();\n    }\n};\n\n/**\n * Stops the periodical \"store logs\" task and immediately stores any pending\n * log entries as a batch.\n */\nLogCollector.prototype.stop = function() {\n    // Flush and stop publishing logs\n    this._flush(false /* do not force */, false /* do not reschedule */);\n};\n\nmodule.exports = LogCollector;\n","/* Copyright @ 2015-present 8x8, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/*jslint latedef:false*/\n\n/**\n * Ordered log levels.\n */\nvar levels = {\n    \"trace\": 0,\n    \"debug\": 1,\n    \"info\": 2,\n    \"log\": 3,\n    \"warn\": 4,\n    \"error\": 5\n};\n\n/**\n * The default transport - console\n * @type LoggerTransport\n */\nLogger.consoleTransport = console;\n\n/**\n * The array which stores currently registered global transports.\n * @type {[LoggerTransport]}\n */\nvar globalTransports = [ Logger.consoleTransport ];\n\n/**\n * Adds given {@link LoggerTransport} instance to the list of global\n * transports which means that it'll be used by all {@link Logger}s\n * @param {LoggerTransport} transport\n */\nLogger.addGlobalTransport = function(transport) {\n    if (globalTransports.indexOf(transport) === -1) {\n        globalTransports.push(transport);\n    }\n};\n\n/**\n * Removes given {@link LoggerTransport} instance from the list of global\n * transports\n * @param {LoggerTransport} transport\n */\nLogger.removeGlobalTransport = function(transport) {\n    var transportIdx = globalTransports.indexOf(transport);\n    if (transportIdx !== -1) {\n        globalTransports.splice(transportIdx, 1);\n    }\n};\n\n/**\n * The global configuration options.\n */\nvar globalOptions = {};\n\n/**\n * Sets global options which will be used by all loggers. Changing these works\n * even after other loggers are created.\n */\nLogger.setGlobalOptions = function(options) {\n    globalOptions = options || {};\n};\n\n/**\n * Parses Error's object stack trace and extracts information about the last\n * caller before the log method was called.\n * @returns JS object with info about the caller - method name, file location,\n * line and column.\n */\nfunction getCallerInfo() {\n    var callerInfo = {\n        methodName: \"\",\n        fileLocation: \"\",\n        line: null,\n        column: null\n    };\n    //gets the part of the stack without the logger wrappers\n    var error = new Error();\n    var stack = error.stack? error.stack.split(\"\\n\") : [];\n    if(!stack || stack.length < 3) {\n        return callerInfo;\n    }\n    var m = null;\n    if(stack[3]) {\n        m = stack[3].match(/\\s*at\\s*(.+?)\\s*\\((\\S*)\\s*:(\\d*)\\s*:(\\d*)\\)/);\n    }\n    if(!m || m.length <= 4) {\n        //Firefox && Safari\n        if(stack[2].indexOf(\"log@\") === 0){\n            //Safari\n            callerInfo.methodName = stack[3].substr(0, stack[3].indexOf(\"@\"));\n        } else {\n            //Firefox\n            callerInfo.methodName = stack[2].substr(0, stack[2].indexOf(\"@\"));\n        }\n        return callerInfo;\n    }\n\n    callerInfo.methodName = m[1];\n    callerInfo.fileLocation = m[2];\n    callerInfo.line = m[3];\n    callerInfo.column = m[4];\n    return callerInfo;\n}\n\n/**\n * Logs messages using the transports and level from the logger.\n * @param logger a logger instance.\n * @param level the log level of the message. See the levels variable.\n * @param arguments array with arguments that will be logged.\n */\nfunction log() {\n    var logger = arguments[0], level = arguments[1],\n        args = Array.prototype.slice.call(arguments, 2);\n    if(levels[level] < logger.level) {\n        return;\n    }\n\n    var callerInfo\n        = !(logger.options.disableCallerInfo || globalOptions.disableCallerInfo) &&\n            getCallerInfo();\n    var transports = globalTransports.concat(logger.transports);\n    for(var i = 0; i < transports.length; i++) {\n        var t = transports[i];\n        var l = t[level];\n        if(l && typeof(l) === \"function\") {\n            var logPrefixes = [];\n\n            logPrefixes.push(new Date().toISOString());\n\n            if (logger.id) {\n                logPrefixes.push(\"[\" + logger.id + \"]\");\n            }\n\n            if (callerInfo && callerInfo.methodName.length > 1) {\n                logPrefixes.push(\"<\" + callerInfo.methodName + \">: \");\n            }\n\n            var fullLogParts = logPrefixes.concat(args);\n\n            l.bind(t).apply(t, fullLogParts);\n        }\n    }\n}\n\n/**\n *\n * Constructs new logger object.\n * @param level the logging level for the new logger\n * @param id optional identifier for the logger instance.\n * @param {LoggerTransport} transports optional list of handlers(objects) for\n * the logs. The handlers must support - log, warn, error, debug, info, trace.\n * @param options optional configuration file for how the logger should behave.\n * @param {boolean} options.disableCallerInfo Whether the call site of a logger\n * method invocation should be included in the log. Defaults to false, so the\n * call site will be included.\n */\nfunction Logger(level, id, transports, options) {\n    this.id = id;\n    this.options = options || {};\n    this.transports = transports;\n    if(!this.transports) {\n        this.transports = [];\n    }\n    this.level = levels[level];\n    var methods = Object.keys(levels);\n    for(var i = 0; i < methods.length; i++){\n        this[methods[i]] =\n            log.bind(null, this, methods[i]);\n    }\n}\n\n/**\n * Sets the log level for the logger.\n * @param level the new log level.\n */\nLogger.prototype.setLevel = function (level) {\n    this.level = levels[level];\n};\nmodule.exports = Logger;\n\n/**\n * Enum for the supported log levels.\n */\nLogger.levels = {\n    TRACE: \"trace\",\n    DEBUG: \"debug\",\n    INFO: \"info\",\n    LOG: \"log\",\n    WARN: \"warn\",\n    ERROR: \"error\"\n};\n","/* Copyright @ 2015-present 8x8, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nvar Logger = require(\"./Logger\");\nvar LogCollector = require(\"./LogCollector\");\n\n/**\n * Definition of the log method\n * @name log_method\n * @function\n * @param {...*} log_args the arguments to be logged\n */\n/**\n * The logger's transport type definition.\n *\n * @typedef {object} LoggerTransport\n *\n * @property {log_method} trace method called to log on {@link Logger.levels.TRACE} logging level\n * @property {log_method} debug method called to log on {@link Logger.levels.DEBUG} logging level\n * @property {log_method} info method called to log on {@link Logger.levels.INFO} logging level\n * @property {log_method} log method called to log on {@link Logger.levels.LOG} logging level\n * @property {log_method} warn method called to log on {@link Logger.levels.WARN} logging level\n * @property {log_method} error method called to log on {@link Logger.levels.ERROR} logging level\n */\n\n/**\n * Map with the created loggers with ID.\n */\nvar idLoggers = {};\n\n/**\n * Array with the loggers without id.\n */\nvar loggers = [];\n\n/**\n * Log level for the lbrary.\n */\nvar curLevel = Logger.levels.TRACE;\n\n\nmodule.exports = {\n    /**\n     * Adds given {@link LoggerTransport} instance to the list of global\n     * transports which means that it'll be used by all {@link Logger}s\n     * @param {LoggerTransport} transport\n     */\n    addGlobalTransport: function(transport) {\n        Logger.addGlobalTransport(transport);\n    },\n    /**\n     * Removes given {@link LoggerTransport} instance from the list of global\n     * transports\n     * @param {LoggerTransport} transport\n     */\n    removeGlobalTransport: function(transport) {\n        Logger.removeGlobalTransport(transport);\n    },\n    /**\n    * Sets global options which will be used by all loggers. Changing these\n    * works even after other loggers are created.\n    */\n    setGlobalOptions: function(options) {\n        Logger.setGlobalOptions(options);\n    },\n    /**\n     * Creates new logger.\n     * @arguments the same as Logger constructor\n     */\n    getLogger: function(id, transports, options) {\n        var logger = new Logger(curLevel, id, transports, options);\n        if(id) {\n            idLoggers[id] = idLoggers[id] || [];\n            idLoggers[id].push(logger);\n        } else {\n            loggers.push(logger);\n        }\n        return logger;\n    },\n    /**\n     * Creates a new Logger, without keeping track of it in the loggers list\n     * @arguments the same as Logger constructor\n     */\n    getUntrackedLogger: function(id, transports, options) {\n        return new Logger(curLevel, id, transports, options);\n    },\n    /**\n     * Changes the log level for the existing loggers by id.\n     * @param level the new log level.\n     * @param id if specified the level will be changed only for loggers with the\n     * same id. Otherwise the operation will affect all loggers that don't\n     * have id.\n     */\n    setLogLevelById: function(level, id) {\n        var l = id? (idLoggers[id] || []) : loggers;\n        for(var i = 0; i < l.length; i++) {\n            l[i].setLevel(level);\n        }\n    },\n    /**\n     * Changes the log level for all existing loggers.\n     * @param level the new log level.\n     */\n    setLogLevel: function (level) {\n        curLevel = level;\n        var i = 0;\n        for(; i < loggers.length; i++) {\n            loggers[i].setLevel(level);\n        }\n\n        for(var id in idLoggers) {\n            var l = idLoggers[id] || [];\n            for(i = 0; i < l.length; i++) {\n                l[i].setLevel(level);\n            }\n        }\n    },\n    /**\n     * The supported log levels.\n     */\n    levels: Logger.levels,\n    /**\n     * Exports the <tt>LogCollector</tt>.\n     */\n    LogCollector: LogCollector\n};\n","/* Copyright @ 2016 Atlassian Pty Ltd\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nvar transform = require('sdp-transform');\nvar transformUtils = require('./transform-utils');\nvar parseSsrcs = transformUtils.parseSsrcs;\nvar writeSsrcs = transformUtils.writeSsrcs;\n\n//region Constants\n\nvar DEFAULT_NUM_OF_LAYERS = 3;\n\n//endregion\n\nfunction getSsrcAttribute (mLine, ssrc, attributeName) {\n    return mLine\n        .ssrcs\n        .filter(function(ssrcInfo) { return ssrcInfo.id === ssrc; })\n        .filter(function(ssrcInfo) { return ssrcInfo.attribute === attributeName; })\n        .map(function(ssrcInfo) { return ssrcInfo.value; })[0];\n}\n\n//region Ctor\n\nfunction Simulcast(options) {\n\n    this.options = options ? options : {};\n\n    if (!this.options.numOfLayers) {\n        this.options.numOfLayers = DEFAULT_NUM_OF_LAYERS;\n    }\n    console.log(\"SdpSimulcast: using \" + this.options.numOfLayers + \" layers\");\n\n    /**\n     * An IN-ORDER list of the simulcast ssrcs\n     * @type {list<number>}\n     */\n    this.ssrcCache = [];\n}\n\n//endregion\n\n//region Stateless private utility functions\n\n/**\n * Returns a random integer between min (included) and max (excluded)\n * Using Math.round() gives a non-uniform distribution!\n * @returns {number}\n */\nfunction generateSSRC() {\n    var min = 0, max = 0xffffffff;\n    return Math.floor(Math.random() * (max - min)) + min;\n};\n\nfunction processVideo(session, action) {\n    if (session == null || !Array.isArray(session.media)) {\n        return;\n    }\n\n    session.media.forEach(function (mLine) {\n        if (mLine.type === 'video') {\n            action(mLine);\n        }\n    });\n};\n\nfunction validateDescription(desc)\n{\n    return desc && desc != null\n        && desc.type && desc.type != ''\n        && desc.sdp && desc.sdp != '';\n}\n\nfunction explodeRemoteSimulcast(mLine) {\n\n    if (!mLine || !Array.isArray(mLine.ssrcGroups)) {\n        return;\n    }\n\n    var sources = parseSsrcs(mLine);\n    var order = [];\n\n    // Find the SIM group and explode its sources.\n    var j = mLine.ssrcGroups.length;\n    while (j--) {\n\n        if (mLine.ssrcGroups[j].semantics !== 'SIM') {\n            continue;\n        }\n\n        var simulcastSsrcs = mLine.ssrcGroups[j].ssrcs.split(' ');\n\n        for (var i = 0; i < simulcastSsrcs.length; i++) {\n\n            var ssrc = simulcastSsrcs[i];\n            order.push(ssrc);\n\n            var parts = sources[ssrc].msid.split(' ');\n            sources[ssrc].msid = [parts[0], '/', i, ' ', parts[1], '/', i].join('');\n            sources[ssrc].cname = [sources[ssrc].cname, '/', i].join('');\n\n            // Remove all the groups that this SSRC participates in.\n            mLine.ssrcGroups.forEach(function (relatedGroup) {\n                if (relatedGroup.semantics === 'SIM') {\n                    return;\n                }\n\n                var relatedSsrcs = relatedGroup.ssrcs.split(' ');\n                if (relatedSsrcs.indexOf(ssrc) === -1) {\n                    return;\n                }\n\n                // Nuke all the related SSRCs.\n                relatedSsrcs.forEach(function (relatedSSRC) {\n                    sources[relatedSSRC].msid = sources[ssrc].msid;\n                    sources[relatedSSRC].cname = sources[ssrc].cname;\n                    if (relatedSSRC !== ssrc) {\n                        order.push(relatedSSRC);\n                    }\n                });\n\n                // Schedule the related group for nuking.\n            })\n        }\n\n        mLine.ssrcs = writeSsrcs(sources, order);\n        mLine.ssrcGroups.splice(j, 1);\n    };\n}\n\nfunction implodeRemoteSimulcast(mLine) {\n\n    if (!mLine || !Array.isArray(mLine.ssrcGroups)) {\n        console.info('Halt: There are no SSRC groups in the remote ' +\n                'description.');\n        return;\n    }\n\n    var sources = parseSsrcs(mLine);\n\n    // Find the SIM group and nuke it.\n    mLine.ssrcGroups.forEach(function (simulcastGroup) {\n        if (simulcastGroup.semantics !== 'SIM') {\n            return;\n        }\n\n        console.info(\"Imploding SIM group: \" + simulcastGroup.ssrcs);\n        // Schedule the SIM group for nuking.\n        simulcastGroup.nuke = true;\n\n        var simulcastSsrcs = simulcastGroup.ssrcs.split(' ');\n\n        // Nuke all the higher layer SSRCs.\n        for (var i = 1; i < simulcastSsrcs.length; i++) {\n\n            var ssrc = simulcastSsrcs[i];\n            delete sources[ssrc];\n\n            // Remove all the groups that this SSRC participates in.\n            mLine.ssrcGroups.forEach(function (relatedGroup) {\n                if (relatedGroup.semantics === 'SIM') {\n                    return;\n                }\n\n                var relatedSsrcs = relatedGroup.ssrcs.split(' ');\n                if (relatedSsrcs.indexOf(ssrc) === -1) {\n                    return;\n                }\n\n                // Nuke all the related SSRCs.\n                relatedSsrcs.forEach(function (relatedSSRC) {\n                    delete sources[relatedSSRC];\n                });\n\n                // Schedule the related group for nuking.\n                relatedGroup.nuke = true;\n            })\n        }\n\n        return;\n    });\n\n    mLine.ssrcs = writeSsrcs(sources);\n\n    // Nuke all the scheduled groups.\n    var i = mLine.ssrcGroups.length;\n    while (i--) {\n        if (mLine.ssrcGroups[i].nuke) {\n            mLine.ssrcGroups.splice(i, 1);\n        }\n    }\n}\n\nfunction removeGoogConference(mLine) {\n    if (!mLine || typeof mLine.xGoogleFlag === 'undefined') {\n        return;\n    }\n\n    mLine.xGoogleFlag = undefined;\n}\n\nfunction assertGoogConference(mLine) {\n    if (!mLine) {\n        return;\n    }\n\n    if (!Array.isArray(mLine.invalid)) {\n        mLine.invalid = [];\n    }\n\n    if (!mLine.invalid.some(\n            function (i) { return i.value === 'x-google-flag:conference' })) {\n        mLine.invalid.push({'value': 'x-google-flag:conference'});\n    }\n}\n\nSimulcast.prototype.clearSsrcCache = function() {\n    this.ssrcCache = [];\n}\n\n/**\n * When we start as video muted, all of the video\n *  ssrcs get generated so we can include them as part\n *  of the original session-accept.  That means we\n *  need this library to restore to those same ssrcs\n *  the first time we unmute, so we need the ability to\n *  force its cache\n */\nSimulcast.prototype.setSsrcCache = function(ssrcs) {\n    this.ssrcCache = ssrcs;\n}\n\n//endregion\n\n//region \"Private\" functions\n\n/**\n * Given a video mLine, return a list of the video ssrcs\n *  in simulcast layer order (returns a list of just\n *  the primary ssrc if there are no simulcast layers)\n */\nSimulcast.prototype._parseSimLayers = function (mLine) {\n    var simGroup = mLine.ssrcGroups &&\n        mLine.ssrcGroups.find(function(group) { return group.semantics === \"SIM\"; });\n    if (simGroup) {\n        return simGroup.ssrcs\n            .split(\" \")\n            .map(function(ssrcStr) { return parseInt(ssrcStr) });\n    } else {\n        return [mLine.ssrcs[0].id];\n    }\n}\n\nSimulcast.prototype._buildNewToOldSsrcMap = function (newSsrcList, oldSsrcList) {\n    var ssrcMap = {};\n    for (var i = 0; i < newSsrcList.length; ++i) {\n        var newSsrc = newSsrcList[i];\n        var oldSsrc = oldSsrcList[i] || null;\n        ssrcMap[newSsrc] = oldSsrc;\n    }\n    return ssrcMap;\n}\n\nSimulcast.prototype._fillInSourceDataFromCache = function(mLine) {\n    console.log(\"SdpSimulcast restoring from cache: \", this.ssrcCache);\n    var newSimSsrcs = this._parseSimLayers(mLine);\n    console.log(\"SdpSimulcast Parsed new sim ssrcs: \", newSimSsrcs);\n    var newMsid = getSsrcAttribute(mLine, newSimSsrcs[0], \"msid\");\n    var newCname = getSsrcAttribute(mLine, newSimSsrcs[0], \"cname\");\n    var ssrcsToReplace = this._buildNewToOldSsrcMap(newSimSsrcs, this.ssrcCache);\n    console.log(\"SdpSimulcast built replacement map: \", ssrcsToReplace);\n    // New sdp might only have 1 layer, so not every cached ssrc will have a new one\n    //  to replace directly\n    var ssrcsToAdd = this.ssrcCache\n        .filter(function(ssrc) { return Object.values(ssrcsToReplace).indexOf(ssrc) === -1; });\n    console.log(\"SdpSimulcast built ssrcs to add: \", ssrcsToAdd);\n\n    // First do the replacements\n    mLine.ssrcs.forEach(function(ssrc) {\n        if (ssrcsToReplace[ssrc.id]) {\n            ssrc.id = ssrcsToReplace[ssrc.id];\n        }\n    });\n    // Now the adds\n    ssrcsToAdd.forEach(function(ssrc) {\n        mLine.ssrcs.push({\n            id: ssrc,\n            attribute: \"msid\",\n            value: newMsid\n        });\n        mLine.ssrcs.push({\n            id: ssrc,\n            attribute: \"cname\",\n            value: newCname\n        });\n    });\n    mLine.ssrcGroups = mLine.ssrcGroups || [];\n    mLine.ssrcGroups.push({\n        semantics: \"SIM\",\n        ssrcs: this.ssrcCache.join(\" \")\n    });\n    return mLine;\n}\n\nSimulcast.prototype._generateSourceData = function(mLine, primarySsrc) {\n    var addAssociatedStream = function(mLine, ssrc) {\n        mLine.ssrcs.push({\n            id: ssrc,\n            attribute: \"cname\",\n            value: primarySsrcCname\n        });\n        mLine.ssrcs.push({\n            id: ssrc,\n            attribute: \"msid\",\n            value: primarySsrcMsid\n        });\n    }\n    var primarySsrcMsid = getSsrcAttribute(mLine, primarySsrc, \"msid\");\n    var primarySsrcCname = getSsrcAttribute(mLine, primarySsrc, \"cname\");\n\n    // In Unified-plan mode, the a=ssrc lines with the msid attribute are not present\n    // in the answers that Chrome and Safari generate for an offer received from Jicofo.\n    // Generate these a=ssrc lines using the msid values from the a=msid line.\n    if (this.options.usesUnifiedPlan && !primarySsrcMsid) {\n        primarySsrcMsid = mLine.msid;\n        var primarySsrcs = mLine.ssrcs;\n        primarySsrcs.forEach(ssrc => {\n            mLine.ssrcs.push({\n                id: ssrc.id,\n                attribute: \"msid\",\n                value: primarySsrcMsid\n            });\n        });\n    }\n\n    // Generate sim layers\n    var simSsrcs = [];\n    for (var i = 0; i < this.options.numOfLayers - 1; ++i) {\n        var simSsrc = generateSSRC();\n        addAssociatedStream(mLine, simSsrc);\n        simSsrcs.push(simSsrc);\n    }\n    mLine.ssrcGroups = mLine.ssrcGroups || [];\n    mLine.ssrcGroups.push({\n        semantics: \"SIM\",\n        ssrcs: primarySsrc + \" \" + simSsrcs.join(\" \")\n    });\n    return mLine;\n}\n\n\n\n// Assumptions:\n//  1) 'mLine' contains only a single primary video source\n//   (i.e. it will not already have simulcast streams inserted)\n//  2) 'mLine' MAY already contain an RTX stream for its video source\n//  3) 'mLine' is in sendrecv or sendonly state\n// Guarantees:\n//  1) return mLine will contain 2 additional simulcast layers\n//   generated\n//  2) if the base video ssrc in mLine has been seen before,\n//   then the same generated simulcast streams from before will\n//   be used again\n//  3) if rtx is enabled for the mLine, all generated simulcast\n//   streams will have rtx streams generated as well\n//  4) if rtx has been generated for a src before, we will generate\n//   the same rtx stream again\nSimulcast.prototype._restoreSimulcast = function(mLine) {\n    // First, find the primary video source in the given\n    // mLine and see if we've seen it before.\n    var primarySsrc;\n    var numSsrcs = mLine.ssrcs && mLine.ssrcs\n        .map(function(ssrcInfo) { return ssrcInfo.id; })\n        .filter(function(ssrc, index, array) {\n            return array.indexOf(ssrc) === index;\n        })\n        .length || 0;\n    var numGroups = (mLine.ssrcGroups && mLine.ssrcGroups.length) || 0;\n\n    if (numSsrcs === 0 || numSsrcs > 2) {\n        // Unsupported scenario\n        return mLine;\n    }\n    if (numSsrcs == 2 && numGroups === 0) {\n        // Unsupported scenario\n        return mLine;\n    }\n\n    if (numSsrcs === 1) {\n        primarySsrc = mLine.ssrcs[0].id;\n    } else {\n        // There must be an FID group, so parse\n        //  that and pull the primary ssrc from there\n        var fidGroup = mLine.ssrcGroups.filter(function(group) { return group.semantics === \"FID\"; })[0];\n        if (fidGroup) {\n            primarySsrc = parseInt(fidGroup.ssrcs.split(\" \")[0]);\n        } else {\n            // Unsupported scenario\n            return mLine;\n        }\n    }\n    console.log(\"SdpSimulcast: current ssrc cache: \", this.ssrcCache);\n    console.log(\"SdpSimulcast: parsed primary ssrc \" + primarySsrc);\n\n    var seenPrimarySsrc = this.ssrcCache.indexOf(primarySsrc) !== -1;\n\n    if (seenPrimarySsrc) {\n        console.log(\"SdpSimulcast: Have seen primary ssrc before, \" +\n            \"filling in data from cache\");\n        mLine = this._fillInSourceDataFromCache(mLine);\n    } else {\n        console.log(\"SdpSimulcast: Have not seen primary ssrc before, \" +\n            \"generating source data\");\n        mLine = this._generateSourceData(mLine, primarySsrc);\n    }\n    // Now update the cache to match whatever we've just put into this sdp\n    this.ssrcCache = this._parseSimLayers(mLine);\n    return mLine;\n}\n\n//endregion\n\n//region \"Public\" functions\n\n/**\n *\n * @param desc\n * @param enableConferenceFlag\n * @returns {RTCSessionDescription}\n */\nSimulcast.prototype.mungeRemoteDescription = function (desc, enableConferenceFlag) {\n\n    if (!validateDescription(desc)) {\n        return desc;\n    }\n\n    var session = transform.parse(desc.sdp);\n\n    var self = this;\n    processVideo(session, function (mLine) {\n\n        // Handle simulcast reception.\n        if (self.options.explodeRemoteSimulcast) {\n            explodeRemoteSimulcast(mLine);\n        } else {\n            implodeRemoteSimulcast(mLine);\n        }\n\n        // Add or remove \"x-google-conference\" from the remote description based on whether the client\n        // has enabled simulcast for the local video source. For cases where we disable simulcast for desktop share,\n        // it is necessary to remove the flag so that Chrome stops sending T1 temporal layers. It also fixes other\n        // issues related to screensharing like https://bugs.chromium.org/p/chromium/issues/detail?id=1093819.\n        if (!self.options.usesUnifiedPlan && enableConferenceFlag) {\n            assertGoogConference(mLine);\n        } else {\n            removeGoogConference(mLine);\n        }\n    });\n\n    return new RTCSessionDescription({\n        type: desc.type,\n        sdp: transform.write(session)\n    });\n};\n\n/**\n *\n * NOTE this method should be called only if simulcast is supported by\n * the current browser, otherwise local SDP should not be munged.\n * @param desc\n * @returns {RTCSessionDescription}\n */\nSimulcast.prototype.mungeLocalDescription = function (desc) {\n\n    if (!validateDescription(desc)) {\n        return desc;\n    }\n\n    var session = transform.parse(desc.sdp);\n\n    var self = this;\n    processVideo(session, function (mLine) {\n        if (mLine.direction == 'recvonly' || mLine.direction == 'inactive')\n        {\n            return;\n        }\n        self._restoreSimulcast(mLine);\n    });\n\n    return new RTCSessionDescription({\n        type: desc.type,\n        sdp: transform.write(session)\n    });\n};\n\n//endregion\n\nmodule.exports = Simulcast;\n","/* Copyright @ 2015 Atlassian Pty Ltd\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * FIXME\n * @param sources FIXME\n * @param order An array of SSRCs which will be used to order the entries in\n * the returned array. Sources whose SSRC appears in 'order' will be added first,\n * in the specified order, and all other sources will be added afterwards (in\n * no specific order).\n * @returns {Array} FIXME\n */\nexports.writeSsrcs = function(sources, order) {\n  var ssrcs = [];\n\n  // expand sources to ssrcs\n  if (typeof sources !== 'undefined' &&\n      Object.keys(sources).length !== 0) {\n\n    if (!Array.isArray(order)) {\n      order = []\n    }\n\n    // Add the sources that appear in 'order' first.\n    for (var i = 0; i < order.length; i++) {\n      var ssrc = order[i];\n      var source = sources[ssrc];\n      Object.keys(source).forEach(function (attribute) {\n        ssrcs.push({\n          id: ssrc,\n          attribute: attribute,\n          value: source[attribute]\n        });\n      });\n    }\n\n    // Now add the rest of the sources.\n    Object.keys(sources).forEach(function (ssrc) {\n      ssrc = parseInt(ssrc); // Object.keys() returns string\n      if (order.indexOf(ssrc) >= 0) {\n        // Already added.\n        return;\n      }\n\n      var source = sources[ssrc];\n      Object.keys(source).forEach(function (attribute) {\n        ssrcs.push({\n          id: ssrc,\n          attribute: attribute,\n          value: source[attribute]\n        });\n      });\n    });\n  }\n\n  return ssrcs;\n};\n\nexports.parseSsrcs = function (mLine) {\n  var sources = {};\n  // group sources attributes by ssrc.\n  if (typeof mLine.ssrcs !== 'undefined' && Array.isArray(mLine.ssrcs)) {\n    mLine.ssrcs.forEach(function (ssrc) {\n      if (!sources[ssrc.id])\n        sources[ssrc.id] = {};\n      sources[ssrc.id][ssrc.attribute] = ssrc.value;\n    });\n  }\n  return sources;\n};\n\n","var grammar = module.exports = {\n  v: [{\n    name: 'version',\n    reg: /^(\\d*)$/\n  }],\n  o: [{ //o=- 20518 0 IN IP4 203.0.113.1\n    // NB: sessionId will be a String in most cases because it is huge\n    name: 'origin',\n    reg: /^(\\S*) (\\d*) (\\d*) (\\S*) IP(\\d) (\\S*)/,\n    names: ['username', 'sessionId', 'sessionVersion', 'netType', 'ipVer', 'address'],\n    format: '%s %s %d %s IP%d %s'\n  }],\n  // default parsing of these only (though some of these feel outdated)\n  s: [{ name: 'name' }],\n  i: [{ name: 'description' }],\n  u: [{ name: 'uri' }],\n  e: [{ name: 'email' }],\n  p: [{ name: 'phone' }],\n  z: [{ name: 'timezones' }], // TODO: this one can actually be parsed properly..\n  r: [{ name: 'repeats' }],   // TODO: this one can also be parsed properly\n  //k: [{}], // outdated thing ignored\n  t: [{ //t=0 0\n    name: 'timing',\n    reg: /^(\\d*) (\\d*)/,\n    names: ['start', 'stop'],\n    format: '%d %d'\n  }],\n  c: [{ //c=IN IP4 10.47.197.26\n    name: 'connection',\n    reg: /^IN IP(\\d) (\\S*)/,\n    names: ['version', 'ip'],\n    format: 'IN IP%d %s'\n  }],\n  b: [{ //b=AS:4000\n    push: 'bandwidth',\n    reg: /^(TIAS|AS|CT|RR|RS):(\\d*)/,\n    names: ['type', 'limit'],\n    format: '%s:%s'\n  }],\n  m: [{ //m=video 51744 RTP/AVP 126 97 98 34 31\n    // NB: special - pushes to session\n    // TODO: rtp/fmtp should be filtered by the payloads found here?\n    reg: /^(\\w*) (\\d*) ([\\w\\/]*)(?: (.*))?/,\n    names: ['type', 'port', 'protocol', 'payloads'],\n    format: '%s %d %s %s'\n  }],\n  a: [\n    { //a=rtpmap:110 opus/48000/2\n      push: 'rtp',\n      reg: /^rtpmap:(\\d*) ([\\w\\-\\.]*)(?:\\s*\\/(\\d*)(?:\\s*\\/(\\S*))?)?/,\n      names: ['payload', 'codec', 'rate', 'encoding'],\n      format: function (o) {\n        return (o.encoding) ?\n          'rtpmap:%d %s/%s/%s':\n          o.rate ?\n          'rtpmap:%d %s/%s':\n          'rtpmap:%d %s';\n      }\n    },\n    { //a=fmtp:108 profile-level-id=24;object=23;bitrate=64000\n      //a=fmtp:111 minptime=10; useinbandfec=1\n      push: 'fmtp',\n      reg: /^fmtp:(\\d*) ([\\S| ]*)/,\n      names: ['payload', 'config'],\n      format: 'fmtp:%d %s'\n    },\n    { //a=control:streamid=0\n      name: 'control',\n      reg: /^control:(.*)/,\n      format: 'control:%s'\n    },\n    { //a=rtcp:65179 IN IP4 193.84.77.194\n      name: 'rtcp',\n      reg: /^rtcp:(\\d*)(?: (\\S*) IP(\\d) (\\S*))?/,\n      names: ['port', 'netType', 'ipVer', 'address'],\n      format: function (o) {\n        return (o.address != null) ?\n          'rtcp:%d %s IP%d %s':\n          'rtcp:%d';\n      }\n    },\n    { //a=rtcp-fb:98 trr-int 100\n      push: 'rtcpFbTrrInt',\n      reg: /^rtcp-fb:(\\*|\\d*) trr-int (\\d*)/,\n      names: ['payload', 'value'],\n      format: 'rtcp-fb:%d trr-int %d'\n    },\n    { //a=rtcp-fb:98 nack rpsi\n      push: 'rtcpFb',\n      reg: /^rtcp-fb:(\\*|\\d*) ([\\w-_]*)(?: ([\\w-_]*))?/,\n      names: ['payload', 'type', 'subtype'],\n      format: function (o) {\n        return (o.subtype != null) ?\n          'rtcp-fb:%s %s %s':\n          'rtcp-fb:%s %s';\n      }\n    },\n    { //a=extmap:2 urn:ietf:params:rtp-hdrext:toffset\n      //a=extmap:1/recvonly URI-gps-string\n      push: 'ext',\n      reg: /^extmap:(\\d+)(?:\\/(\\w+))? (\\S*)(?: (\\S*))?/,\n      names: ['value', 'direction', 'uri', 'config'],\n      format: function (o) {\n        return 'extmap:%d' + (o.direction ? '/%s' : '%v') + ' %s' + (o.config ? ' %s' : '');\n      }\n    },\n    { //a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:PS1uQCVeeCFCanVmcjkpPywjNWhcYD0mXXtxaVBR|2^20|1:32\n      push: 'crypto',\n      reg: /^crypto:(\\d*) ([\\w_]*) (\\S*)(?: (\\S*))?/,\n      names: ['id', 'suite', 'config', 'sessionConfig'],\n      format: function (o) {\n        return (o.sessionConfig != null) ?\n          'crypto:%d %s %s %s':\n          'crypto:%d %s %s';\n      }\n    },\n    { //a=setup:actpass\n      name: 'setup',\n      reg: /^setup:(\\w*)/,\n      format: 'setup:%s'\n    },\n    { //a=mid:1\n      name: 'mid',\n      reg: /^mid:([^\\s]*)/,\n      format: 'mid:%s'\n    },\n    { //a=msid:0c8b064d-d807-43b4-b434-f92a889d8587 98178685-d409-46e0-8e16-7ef0db0db64a\n      name: 'msid',\n      reg: /^msid:(.*)/,\n      format: 'msid:%s'\n    },\n    { //a=ptime:20\n      name: 'ptime',\n      reg: /^ptime:(\\d*)/,\n      format: 'ptime:%d'\n    },\n    { //a=maxptime:60\n      name: 'maxptime',\n      reg: /^maxptime:(\\d*)/,\n      format: 'maxptime:%d'\n    },\n    { //a=sendrecv\n      name: 'direction',\n      reg: /^(sendrecv|recvonly|sendonly|inactive)/\n    },\n    { //a=ice-lite\n      name: 'icelite',\n      reg: /^(ice-lite)/\n    },\n    { //a=ice-ufrag:F7gI\n      name: 'iceUfrag',\n      reg: /^ice-ufrag:(\\S*)/,\n      format: 'ice-ufrag:%s'\n    },\n    { //a=ice-pwd:x9cml/YzichV2+XlhiMu8g\n      name: 'icePwd',\n      reg: /^ice-pwd:(\\S*)/,\n      format: 'ice-pwd:%s'\n    },\n    { //a=fingerprint:SHA-1 00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33\n      name: 'fingerprint',\n      reg: /^fingerprint:(\\S*) (\\S*)/,\n      names: ['type', 'hash'],\n      format: 'fingerprint:%s %s'\n    },\n    { //a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host\n      //a=candidate:1162875081 1 udp 2113937151 192.168.34.75 60017 typ host generation 0 network-id 3 network-cost 10\n      //a=candidate:3289912957 2 udp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 generation 0 network-id 3 network-cost 10\n      //a=candidate:229815620 1 tcp 1518280447 192.168.150.19 60017 typ host tcptype active generation 0 network-id 3 network-cost 10\n      //a=candidate:3289912957 2 tcp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 tcptype passive generation 0 network-id 3 network-cost 10\n      push:'candidates',\n      reg: /^candidate:(\\S*) (\\d*) (\\S*) (\\d*) (\\S*) (\\d*) typ (\\S*)(?: raddr (\\S*) rport (\\d*))?(?: tcptype (\\S*))?(?: generation (\\d*))?(?: network-id (\\d*))?(?: network-cost (\\d*))?/,\n      names: ['foundation', 'component', 'transport', 'priority', 'ip', 'port', 'type', 'raddr', 'rport', 'tcptype', 'generation', 'network-id', 'network-cost'],\n      format: function (o) {\n        var str = 'candidate:%s %d %s %d %s %d typ %s';\n\n        str += (o.raddr != null) ? ' raddr %s rport %d' : '%v%v';\n\n        // NB: candidate has three optional chunks, so %void middles one if it's missing\n        str += (o.tcptype != null) ? ' tcptype %s' : '%v';\n\n        if (o.generation != null) {\n          str += ' generation %d';\n        }\n\n        str += (o['network-id'] != null) ? ' network-id %d' : '%v';\n        str += (o['network-cost'] != null) ? ' network-cost %d' : '%v';\n        return str;\n      }\n    },\n    { //a=end-of-candidates (keep after the candidates line for readability)\n      name: 'endOfCandidates',\n      reg: /^(end-of-candidates)/\n    },\n    { //a=remote-candidates:1 203.0.113.1 54400 2 203.0.113.1 54401 ...\n      name: 'remoteCandidates',\n      reg: /^remote-candidates:(.*)/,\n      format: 'remote-candidates:%s'\n    },\n    { //a=ice-options:google-ice\n      name: 'iceOptions',\n      reg: /^ice-options:(\\S*)/,\n      format: 'ice-options:%s'\n    },\n    { //a=ssrc:2566107569 cname:t9YU8M1UxTF8Y1A1\n      push: 'ssrcs',\n      reg: /^ssrc:(\\d*) ([\\w_]*)(?::(.*))?/,\n      names: ['id', 'attribute', 'value'],\n      format: function (o) {\n        var str = 'ssrc:%d';\n        if (o.attribute != null) {\n          str += ' %s';\n          if (o.value != null) {\n            str += ':%s';\n          }\n        }\n        return str;\n      }\n    },\n    { //a=ssrc-group:FEC 1 2\n      //a=ssrc-group:FEC-FR 3004364195 1080772241\n      push: 'ssrcGroups',\n      // token-char = %x21 / %x23-27 / %x2A-2B / %x2D-2E / %x30-39 / %x41-5A / %x5E-7E\n      reg: /^ssrc-group:([\\x21\\x23\\x24\\x25\\x26\\x27\\x2A\\x2B\\x2D\\x2E\\w]*) (.*)/,\n      names: ['semantics', 'ssrcs'],\n      format: 'ssrc-group:%s %s'\n    },\n    { //a=msid-semantic: WMS Jvlam5X3SX1OP6pn20zWogvaKJz5Hjf9OnlV\n      name: 'msidSemantic',\n      reg: /^msid-semantic:\\s?(\\w*) (\\S*)/,\n      names: ['semantic', 'token'],\n      format: 'msid-semantic: %s %s' // space after ':' is not accidental\n    },\n    { //a=group:BUNDLE audio video\n      push: 'groups',\n      reg: /^group:(\\w*) (.*)/,\n      names: ['type', 'mids'],\n      format: 'group:%s %s'\n    },\n    { //a=rtcp-mux\n      name: 'rtcpMux',\n      reg: /^(rtcp-mux)/\n    },\n    { //a=rtcp-rsize\n      name: 'rtcpRsize',\n      reg: /^(rtcp-rsize)/\n    },\n    { //a=sctpmap:5000 webrtc-datachannel 1024\n      name: 'sctpmap',\n      reg: /^sctpmap:([\\w_\\/]*) (\\S*)(?: (\\S*))?/,\n      names: ['sctpmapNumber', 'app', 'maxMessageSize'],\n      format: function (o) {\n        return (o.maxMessageSize != null) ?\n          'sctpmap:%s %s %s' :\n          'sctpmap:%s %s';\n      }\n    },\n    { //a=x-google-flag:conference\n      name: 'xGoogleFlag',\n      reg: /^x-google-flag:([^\\s]*)/,\n      format: 'x-google-flag:%s'\n    },\n    { //a=rid:1 send max-width=1280;max-height=720;max-fps=30;depend=0\n      push: 'rids',\n      reg: /^rid:([\\d\\w]+) (\\w+)(?: ([\\S| ]*))?/,\n      names: ['id', 'direction', 'params'],\n      format: function (o) {\n        return (o.params) ? 'rid:%s %s %s' : 'rid:%s %s';\n      }\n    },\n    { //a=imageattr:97 send [x=800,y=640,sar=1.1,q=0.6] [x=480,y=320] recv [x=330,y=250]\n      //a=imageattr:* send [x=800,y=640] recv *\n      //a=imageattr:100 recv [x=320,y=240]\n      push: 'imageattrs',\n      reg: new RegExp(\n        //a=imageattr:97\n        '^imageattr:(\\\\d+|\\\\*)' +\n        //send [x=800,y=640,sar=1.1,q=0.6] [x=480,y=320]\n        '[\\\\s\\\\t]+(send|recv)[\\\\s\\\\t]+(\\\\*|\\\\[\\\\S+\\\\](?:[\\\\s\\\\t]+\\\\[\\\\S+\\\\])*)' +\n        //recv [x=330,y=250]\n        '(?:[\\\\s\\\\t]+(recv|send)[\\\\s\\\\t]+(\\\\*|\\\\[\\\\S+\\\\](?:[\\\\s\\\\t]+\\\\[\\\\S+\\\\])*))?'\n      ),\n      names: ['pt', 'dir1', 'attrs1', 'dir2', 'attrs2'],\n      format: function (o) {\n        return 'imageattr:%s %s %s' + (o.dir2 ? ' %s %s' : '');\n      }\n    },\n    { //a=simulcast:send 1,2,3;~4,~5 recv 6;~7,~8\n      //a=simulcast:recv 1;4,5 send 6;7\n      name: 'simulcast',\n      reg: new RegExp(\n        //a=simulcast:\n        '^simulcast:' +\n        //send 1,2,3;~4,~5\n        '(send|recv) ([a-zA-Z0-9\\\\-_~;,]+)' +\n        //space + recv 6;~7,~8\n        '(?:\\\\s?(send|recv) ([a-zA-Z0-9\\\\-_~;,]+))?' +\n        //end\n        '$'\n      ),\n      names: ['dir1', 'list1', 'dir2', 'list2'],\n      format: function (o) {\n        return 'simulcast:%s %s' + (o.dir2 ? ' %s %s' : '');\n      }\n    },\n    { //Old simulcast draft 03 (implemented by Firefox)\n      //  https://tools.ietf.org/html/draft-ietf-mmusic-sdp-simulcast-03\n      //a=simulcast: recv pt=97;98 send pt=97\n      //a=simulcast: send rid=5;6;7 paused=6,7\n      name: 'simulcast_03',\n      reg: /^simulcast:[\\s\\t]+([\\S+\\s\\t]+)$/,\n      names: ['value'],\n      format: 'simulcast: %s'\n    },\n    {\n      //a=framerate:25\n      //a=framerate:29.97\n      name: 'framerate',\n      reg: /^framerate:(\\d+(?:$|\\.\\d+))/,\n      format: 'framerate:%s'\n    },\n    { // any a= that we don't understand is kepts verbatim on media.invalid\n      push: 'invalid',\n      names: ['value']\n    }\n  ]\n};\n\n// set sensible defaults to avoid polluting the grammar with boring details\nObject.keys(grammar).forEach(function (key) {\n  var objs = grammar[key];\n  objs.forEach(function (obj) {\n    if (!obj.reg) {\n      obj.reg = /(.*)/;\n    }\n    if (!obj.format) {\n      obj.format = '%s';\n    }\n  });\n});\n","var parser = require('./parser');\nvar writer = require('./writer');\n\nexports.write = writer;\nexports.parse = parser.parse;\nexports.parseFmtpConfig = parser.parseFmtpConfig;\nexports.parseParams = parser.parseParams;\nexports.parsePayloads = parser.parsePayloads;\nexports.parseRemoteCandidates = parser.parseRemoteCandidates;\nexports.parseImageAttributes = parser.parseImageAttributes;\nexports.parseSimulcastStreamList = parser.parseSimulcastStreamList;\n","var toIntIfInt = function (v) {\n  return String(Number(v)) === v ? Number(v) : v;\n};\n\nvar attachProperties = function (match, location, names, rawName) {\n  if (rawName && !names) {\n    location[rawName] = toIntIfInt(match[1]);\n  }\n  else {\n    for (var i = 0; i < names.length; i += 1) {\n      if (match[i+1] != null) {\n        location[names[i]] = toIntIfInt(match[i+1]);\n      }\n    }\n  }\n};\n\nvar parseReg = function (obj, location, content) {\n  var needsBlank = obj.name && obj.names;\n  if (obj.push && !location[obj.push]) {\n    location[obj.push] = [];\n  }\n  else if (needsBlank && !location[obj.name]) {\n    location[obj.name] = {};\n  }\n  var keyLocation = obj.push ?\n    {} :  // blank object that will be pushed\n    needsBlank ? location[obj.name] : location; // otherwise, named location or root\n\n  attachProperties(content.match(obj.reg), keyLocation, obj.names, obj.name);\n\n  if (obj.push) {\n    location[obj.push].push(keyLocation);\n  }\n};\n\nvar grammar = require('./grammar');\nvar validLine = RegExp.prototype.test.bind(/^([a-z])=(.*)/);\n\nexports.parse = function (sdp) {\n  var session = {}\n    , media = []\n    , location = session; // points at where properties go under (one of the above)\n\n  // parse lines we understand\n  sdp.split(/(\\r\\n|\\r|\\n)/).filter(validLine).forEach(function (l) {\n    var type = l[0];\n    var content = l.slice(2);\n    if (type === 'm') {\n      media.push({rtp: [], fmtp: []});\n      location = media[media.length-1]; // point at latest media line\n    }\n\n    for (var j = 0; j < (grammar[type] || []).length; j += 1) {\n      var obj = grammar[type][j];\n      if (obj.reg.test(content)) {\n        return parseReg(obj, location, content);\n      }\n    }\n  });\n\n  session.media = media; // link it up\n  return session;\n};\n\nvar paramReducer = function (acc, expr) {\n  var s = expr.split(/=(.+)/, 2);\n  if (s.length === 2) {\n    acc[s[0]] = toIntIfInt(s[1]);\n  }\n  return acc;\n};\n\nexports.parseParams = function (str) {\n  return str.split(/\\;\\s?/).reduce(paramReducer, {});\n};\n\n// For backward compatibility - alias will be removed in 3.0.0\nexports.parseFmtpConfig = exports.parseParams;\n\nexports.parsePayloads = function (str) {\n  return str.split(' ').map(Number);\n};\n\nexports.parseRemoteCandidates = function (str) {\n  var candidates = [];\n  var parts = str.split(' ').map(toIntIfInt);\n  for (var i = 0; i < parts.length; i += 3) {\n    candidates.push({\n      component: parts[i],\n      ip: parts[i + 1],\n      port: parts[i + 2]\n    });\n  }\n  return candidates;\n};\n\nexports.parseImageAttributes = function (str) {\n  return str.split(' ').map(function (item) {\n    return item.substring(1, item.length-1).split(',').reduce(paramReducer, {});\n  });\n};\n\nexports.parseSimulcastStreamList = function (str) {\n  return str.split(';').map(function (stream) {\n    return stream.split(',').map(function (format) {\n      var scid, paused = false;\n\n      if (format[0] !== '~') {\n        scid = toIntIfInt(format);\n      } else {\n        scid = toIntIfInt(format.substring(1, format.length));\n        paused = true;\n      }\n\n      return {\n        scid: scid,\n        paused: paused\n      };\n    });\n  });\n};\n","var grammar = require('./grammar');\n\n// customized util.format - discards excess arguments and can void middle ones\nvar formatRegExp = /%[sdv%]/g;\nvar format = function (formatStr) {\n  var i = 1;\n  var args = arguments;\n  var len = args.length;\n  return formatStr.replace(formatRegExp, function (x) {\n    if (i >= len) {\n      return x; // missing argument\n    }\n    var arg = args[i];\n    i += 1;\n    switch (x) {\n    case '%%':\n      return '%';\n    case '%s':\n      return String(arg);\n    case '%d':\n      return Number(arg);\n    case '%v':\n      return '';\n    }\n  });\n  // NB: we discard excess arguments - they are typically undefined from makeLine\n};\n\nvar makeLine = function (type, obj, location) {\n  var str = obj.format instanceof Function ?\n    (obj.format(obj.push ? location : location[obj.name])) :\n    obj.format;\n\n  var args = [type + '=' + str];\n  if (obj.names) {\n    for (var i = 0; i < obj.names.length; i += 1) {\n      var n = obj.names[i];\n      if (obj.name) {\n        args.push(location[obj.name][n]);\n      }\n      else { // for mLine and push attributes\n        args.push(location[obj.names[i]]);\n      }\n    }\n  }\n  else {\n    args.push(location[obj.name]);\n  }\n  return format.apply(null, args);\n};\n\n// RFC specified order\n// TODO: extend this with all the rest\nvar defaultOuterOrder = [\n  'v', 'o', 's', 'i',\n  'u', 'e', 'p', 'c',\n  'b', 't', 'r', 'z', 'a'\n];\nvar defaultInnerOrder = ['i', 'c', 'b', 'a'];\n\n\nmodule.exports = function (session, opts) {\n  opts = opts || {};\n  // ensure certain properties exist\n  if (session.version == null) {\n    session.version = 0; // 'v=0' must be there (only defined version atm)\n  }\n  if (session.name == null) {\n    session.name = ' '; // 's= ' must be there if no meaningful name set\n  }\n  session.media.forEach(function (mLine) {\n    if (mLine.payloads == null) {\n      mLine.payloads = '';\n    }\n  });\n\n  var outerOrder = opts.outerOrder || defaultOuterOrder;\n  var innerOrder = opts.innerOrder || defaultInnerOrder;\n  var sdp = [];\n\n  // loop through outerOrder for matching properties on session\n  outerOrder.forEach(function (type) {\n    grammar[type].forEach(function (obj) {\n      if (obj.name in session && session[obj.name] != null) {\n        sdp.push(makeLine(type, obj, session));\n      }\n      else if (obj.push in session && session[obj.push] != null) {\n        session[obj.push].forEach(function (el) {\n          sdp.push(makeLine(type, obj, el));\n        });\n      }\n    });\n  });\n\n  // then for each media line, follow the innerOrder\n  session.media.forEach(function (mLine) {\n    sdp.push(makeLine('m', grammar.m[0], mLine));\n\n    innerOrder.forEach(function (type) {\n      grammar[type].forEach(function (obj) {\n        if (obj.name in mLine && mLine[obj.name] != null) {\n          sdp.push(makeLine(type, obj, mLine));\n        }\n        else if (obj.push in mLine && mLine[obj.push] != null) {\n          mLine[obj.push].forEach(function (el) {\n            sdp.push(makeLine(type, obj, el));\n          });\n        }\n      });\n    });\n  });\n\n  return sdp.join('\\r\\n') + '\\r\\n';\n};\n","'use strict'\n\n/**\n * \"Shallow freezes\" an object to render it immutable.\n * Uses `Object.freeze` if available,\n * otherwise the immutability is only in the type.\n *\n * Is used to create \"enum like\" objects.\n *\n * @template T\n * @param {T} object the object to freeze\n * @param {Pick<ObjectConstructor, 'freeze'> = Object} oc `Object` by default,\n * \t\t\t\tallows to inject custom object constructor for tests\n * @returns {Readonly<T>}\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze\n */\nfunction freeze(object, oc) {\n\tif (oc === undefined) {\n\t\toc = Object\n\t}\n\treturn oc && typeof oc.freeze === 'function' ? oc.freeze(object) : object\n}\n\n/**\n * All mime types that are allowed as input to `DOMParser.parseFromString`\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString#Argument02 MDN\n * @see https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#domparsersupportedtype WHATWG HTML Spec\n * @see DOMParser.prototype.parseFromString\n */\nvar MIME_TYPE = freeze({\n\t/**\n\t * `text/html`, the only mime type that triggers treating an XML document as HTML.\n\t *\n\t * @see DOMParser.SupportedType.isHTML\n\t * @see https://www.iana.org/assignments/media-types/text/html IANA MimeType registration\n\t * @see https://en.wikipedia.org/wiki/HTML Wikipedia\n\t * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString MDN\n\t * @see https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-domparser-parsefromstring WHATWG HTML Spec\n\t */\n\tHTML: 'text/html',\n\n\t/**\n\t * Helper method to check a mime type if it indicates an HTML document\n\t *\n\t * @param {string} [value]\n\t * @returns {boolean}\n\t *\n\t * @see https://www.iana.org/assignments/media-types/text/html IANA MimeType registration\n\t * @see https://en.wikipedia.org/wiki/HTML Wikipedia\n\t * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString MDN\n\t * @see https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-domparser-parsefromstring \t */\n\tisHTML: function (value) {\n\t\treturn value === MIME_TYPE.HTML\n\t},\n\n\t/**\n\t * `application/xml`, the standard mime type for XML documents.\n\t *\n\t * @see https://www.iana.org/assignments/media-types/application/xml IANA MimeType registration\n\t * @see https://tools.ietf.org/html/rfc7303#section-9.1 RFC 7303\n\t * @see https://en.wikipedia.org/wiki/XML_and_MIME Wikipedia\n\t */\n\tXML_APPLICATION: 'application/xml',\n\n\t/**\n\t * `text/html`, an alias for `application/xml`.\n\t *\n\t * @see https://tools.ietf.org/html/rfc7303#section-9.2 RFC 7303\n\t * @see https://www.iana.org/assignments/media-types/text/xml IANA MimeType registration\n\t * @see https://en.wikipedia.org/wiki/XML_and_MIME Wikipedia\n\t */\n\tXML_TEXT: 'text/xml',\n\n\t/**\n\t * `application/xhtml+xml`, indicates an XML document that has the default HTML namespace,\n\t * but is parsed as an XML document.\n\t *\n\t * @see https://www.iana.org/assignments/media-types/application/xhtml+xml IANA MimeType registration\n\t * @see https://dom.spec.whatwg.org/#dom-domimplementation-createdocument WHATWG DOM Spec\n\t * @see https://en.wikipedia.org/wiki/XHTML Wikipedia\n\t */\n\tXML_XHTML_APPLICATION: 'application/xhtml+xml',\n\n\t/**\n\t * `image/svg+xml`,\n\t *\n\t * @see https://www.iana.org/assignments/media-types/image/svg+xml IANA MimeType registration\n\t * @see https://www.w3.org/TR/SVG11/ W3C SVG 1.1\n\t * @see https://en.wikipedia.org/wiki/Scalable_Vector_Graphics Wikipedia\n\t */\n\tXML_SVG_IMAGE: 'image/svg+xml',\n})\n\n/**\n * Namespaces that are used in this code base.\n *\n * @see http://www.w3.org/TR/REC-xml-names\n */\nvar NAMESPACE = freeze({\n\t/**\n\t * The XHTML namespace.\n\t *\n\t * @see http://www.w3.org/1999/xhtml\n\t */\n\tHTML: 'http://www.w3.org/1999/xhtml',\n\n\t/**\n\t * Checks if `uri` equals `NAMESPACE.HTML`.\n\t *\n\t * @param {string} [uri]\n\t *\n\t * @see NAMESPACE.HTML\n\t */\n\tisHTML: function (uri) {\n\t\treturn uri === NAMESPACE.HTML\n\t},\n\n\t/**\n\t * The SVG namespace.\n\t *\n\t * @see http://www.w3.org/2000/svg\n\t */\n\tSVG: 'http://www.w3.org/2000/svg',\n\n\t/**\n\t * The `xml:` namespace.\n\t *\n\t * @see http://www.w3.org/XML/1998/namespace\n\t */\n\tXML: 'http://www.w3.org/XML/1998/namespace',\n\n\t/**\n\t * The `xmlns:` namespace\n\t *\n\t * @see https://www.w3.org/2000/xmlns/\n\t */\n\tXMLNS: 'http://www.w3.org/2000/xmlns/',\n})\n\nexports.freeze = freeze;\nexports.MIME_TYPE = MIME_TYPE;\nexports.NAMESPACE = NAMESPACE;\n","var conventions = require(\"./conventions\");\nvar dom = require('./dom')\nvar entities = require('./entities');\nvar sax = require('./sax');\n\nvar DOMImplementation = dom.DOMImplementation;\n\nvar NAMESPACE = conventions.NAMESPACE;\n\nvar ParseError = sax.ParseError;\nvar XMLReader = sax.XMLReader;\n\nfunction DOMParser(options){\n\tthis.options = options ||{locator:{}};\n}\n\nDOMParser.prototype.parseFromString = function(source,mimeType){\n\tvar options = this.options;\n\tvar sax =  new XMLReader();\n\tvar domBuilder = options.domBuilder || new DOMHandler();//contentHandler and LexicalHandler\n\tvar errorHandler = options.errorHandler;\n\tvar locator = options.locator;\n\tvar defaultNSMap = options.xmlns||{};\n\tvar isHTML = /\\/x?html?$/.test(mimeType);//mimeType.toLowerCase().indexOf('html') > -1;\n  \tvar entityMap = isHTML ? entities.HTML_ENTITIES : entities.XML_ENTITIES;\n\tif(locator){\n\t\tdomBuilder.setDocumentLocator(locator)\n\t}\n\n\tsax.errorHandler = buildErrorHandler(errorHandler,domBuilder,locator);\n\tsax.domBuilder = options.domBuilder || domBuilder;\n\tif(isHTML){\n\t\tdefaultNSMap[''] = NAMESPACE.HTML;\n\t}\n\tdefaultNSMap.xml = defaultNSMap.xml || NAMESPACE.XML;\n\tif(source && typeof source === 'string'){\n\t\tsax.parse(source,defaultNSMap,entityMap);\n\t}else{\n\t\tsax.errorHandler.error(\"invalid doc source\");\n\t}\n\treturn domBuilder.doc;\n}\nfunction buildErrorHandler(errorImpl,domBuilder,locator){\n\tif(!errorImpl){\n\t\tif(domBuilder instanceof DOMHandler){\n\t\t\treturn domBuilder;\n\t\t}\n\t\terrorImpl = domBuilder ;\n\t}\n\tvar errorHandler = {}\n\tvar isCallback = errorImpl instanceof Function;\n\tlocator = locator||{}\n\tfunction build(key){\n\t\tvar fn = errorImpl[key];\n\t\tif(!fn && isCallback){\n\t\t\tfn = errorImpl.length == 2?function(msg){errorImpl(key,msg)}:errorImpl;\n\t\t}\n\t\terrorHandler[key] = fn && function(msg){\n\t\t\tfn('[xmldom '+key+']\\t'+msg+_locator(locator));\n\t\t}||function(){};\n\t}\n\tbuild('warning');\n\tbuild('error');\n\tbuild('fatalError');\n\treturn errorHandler;\n}\n\n//console.log('#\\n\\n\\n\\n\\n\\n\\n####')\n/**\n * +ContentHandler+ErrorHandler\n * +LexicalHandler+EntityResolver2\n * -DeclHandler-DTDHandler\n *\n * DefaultHandler:EntityResolver, DTDHandler, ContentHandler, ErrorHandler\n * DefaultHandler2:DefaultHandler,LexicalHandler, DeclHandler, EntityResolver2\n * @link http://www.saxproject.org/apidoc/org/xml/sax/helpers/DefaultHandler.html\n */\nfunction DOMHandler() {\n    this.cdata = false;\n}\nfunction position(locator,node){\n\tnode.lineNumber = locator.lineNumber;\n\tnode.columnNumber = locator.columnNumber;\n}\n/**\n * @see org.xml.sax.ContentHandler#startDocument\n * @link http://www.saxproject.org/apidoc/org/xml/sax/ContentHandler.html\n */\nDOMHandler.prototype = {\n\tstartDocument : function() {\n    \tthis.doc = new DOMImplementation().createDocument(null, null, null);\n    \tif (this.locator) {\n        \tthis.doc.documentURI = this.locator.systemId;\n    \t}\n\t},\n\tstartElement:function(namespaceURI, localName, qName, attrs) {\n\t\tvar doc = this.doc;\n\t    var el = doc.createElementNS(namespaceURI, qName||localName);\n\t    var len = attrs.length;\n\t    appendElement(this, el);\n\t    this.currentElement = el;\n\n\t\tthis.locator && position(this.locator,el)\n\t    for (var i = 0 ; i < len; i++) {\n\t        var namespaceURI = attrs.getURI(i);\n\t        var value = attrs.getValue(i);\n\t        var qName = attrs.getQName(i);\n\t\t\tvar attr = doc.createAttributeNS(namespaceURI, qName);\n\t\t\tthis.locator &&position(attrs.getLocator(i),attr);\n\t\t\tattr.value = attr.nodeValue = value;\n\t\t\tel.setAttributeNode(attr)\n\t    }\n\t},\n\tendElement:function(namespaceURI, localName, qName) {\n\t\tvar current = this.currentElement\n\t\tvar tagName = current.tagName;\n\t\tthis.currentElement = current.parentNode;\n\t},\n\tstartPrefixMapping:function(prefix, uri) {\n\t},\n\tendPrefixMapping:function(prefix) {\n\t},\n\tprocessingInstruction:function(target, data) {\n\t    var ins = this.doc.createProcessingInstruction(target, data);\n\t    this.locator && position(this.locator,ins)\n\t    appendElement(this, ins);\n\t},\n\tignorableWhitespace:function(ch, start, length) {\n\t},\n\tcharacters:function(chars, start, length) {\n\t\tchars = _toString.apply(this,arguments)\n\t\t//console.log(chars)\n\t\tif(chars){\n\t\t\tif (this.cdata) {\n\t\t\t\tvar charNode = this.doc.createCDATASection(chars);\n\t\t\t} else {\n\t\t\t\tvar charNode = this.doc.createTextNode(chars);\n\t\t\t}\n\t\t\tif(this.currentElement){\n\t\t\t\tthis.currentElement.appendChild(charNode);\n\t\t\t}else if(/^\\s*$/.test(chars)){\n\t\t\t\tthis.doc.appendChild(charNode);\n\t\t\t\t//process xml\n\t\t\t}\n\t\t\tthis.locator && position(this.locator,charNode)\n\t\t}\n\t},\n\tskippedEntity:function(name) {\n\t},\n\tendDocument:function() {\n\t\tthis.doc.normalize();\n\t},\n\tsetDocumentLocator:function (locator) {\n\t    if(this.locator = locator){// && !('lineNumber' in locator)){\n\t    \tlocator.lineNumber = 0;\n\t    }\n\t},\n\t//LexicalHandler\n\tcomment:function(chars, start, length) {\n\t\tchars = _toString.apply(this,arguments)\n\t    var comm = this.doc.createComment(chars);\n\t    this.locator && position(this.locator,comm)\n\t    appendElement(this, comm);\n\t},\n\n\tstartCDATA:function() {\n\t    //used in characters() methods\n\t    this.cdata = true;\n\t},\n\tendCDATA:function() {\n\t    this.cdata = false;\n\t},\n\n\tstartDTD:function(name, publicId, systemId) {\n\t\tvar impl = this.doc.implementation;\n\t    if (impl && impl.createDocumentType) {\n\t        var dt = impl.createDocumentType(name, publicId, systemId);\n\t        this.locator && position(this.locator,dt)\n\t        appendElement(this, dt);\n\t\t\t\t\tthis.doc.doctype = dt;\n\t    }\n\t},\n\t/**\n\t * @see org.xml.sax.ErrorHandler\n\t * @link http://www.saxproject.org/apidoc/org/xml/sax/ErrorHandler.html\n\t */\n\twarning:function(error) {\n\t\tconsole.warn('[xmldom warning]\\t'+error,_locator(this.locator));\n\t},\n\terror:function(error) {\n\t\tconsole.error('[xmldom error]\\t'+error,_locator(this.locator));\n\t},\n\tfatalError:function(error) {\n\t\tthrow new ParseError(error, this.locator);\n\t}\n}\nfunction _locator(l){\n\tif(l){\n\t\treturn '\\n@'+(l.systemId ||'')+'#[line:'+l.lineNumber+',col:'+l.columnNumber+']'\n\t}\n}\nfunction _toString(chars,start,length){\n\tif(typeof chars == 'string'){\n\t\treturn chars.substr(start,length)\n\t}else{//java sax connect width xmldom on rhino(what about: \"? && !(chars instanceof String)\")\n\t\tif(chars.length >= start+length || start){\n\t\t\treturn new java.lang.String(chars,start,length)+'';\n\t\t}\n\t\treturn chars;\n\t}\n}\n\n/*\n * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/LexicalHandler.html\n * used method of org.xml.sax.ext.LexicalHandler:\n *  #comment(chars, start, length)\n *  #startCDATA()\n *  #endCDATA()\n *  #startDTD(name, publicId, systemId)\n *\n *\n * IGNORED method of org.xml.sax.ext.LexicalHandler:\n *  #endDTD()\n *  #startEntity(name)\n *  #endEntity(name)\n *\n *\n * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/DeclHandler.html\n * IGNORED method of org.xml.sax.ext.DeclHandler\n * \t#attributeDecl(eName, aName, type, mode, value)\n *  #elementDecl(name, model)\n *  #externalEntityDecl(name, publicId, systemId)\n *  #internalEntityDecl(name, value)\n * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/EntityResolver2.html\n * IGNORED method of org.xml.sax.EntityResolver2\n *  #resolveEntity(String name,String publicId,String baseURI,String systemId)\n *  #resolveEntity(publicId, systemId)\n *  #getExternalSubset(name, baseURI)\n * @link http://www.saxproject.org/apidoc/org/xml/sax/DTDHandler.html\n * IGNORED method of org.xml.sax.DTDHandler\n *  #notationDecl(name, publicId, systemId) {};\n *  #unparsedEntityDecl(name, publicId, systemId, notationName) {};\n */\n\"endDTD,startEntity,endEntity,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,resolveEntity,getExternalSubset,notationDecl,unparsedEntityDecl\".replace(/\\w+/g,function(key){\n\tDOMHandler.prototype[key] = function(){return null}\n})\n\n/* Private static helpers treated below as private instance methods, so don't need to add these to the public API; we might use a Relator to also get rid of non-standard public properties */\nfunction appendElement (hander,node) {\n    if (!hander.currentElement) {\n        hander.doc.appendChild(node);\n    } else {\n        hander.currentElement.appendChild(node);\n    }\n}//appendChild and setAttributeNS are preformance key\n\nexports.__DOMHandler = DOMHandler;\nexports.DOMParser = DOMParser;\n\n/**\n * @deprecated Import/require from main entry point instead\n */\nexports.DOMImplementation = dom.DOMImplementation;\n\n/**\n * @deprecated Import/require from main entry point instead\n */\nexports.XMLSerializer = dom.XMLSerializer;\n","var conventions = require(\"./conventions\");\n\nvar NAMESPACE = conventions.NAMESPACE;\n\n/**\n * A prerequisite for `[].filter`, to drop elements that are empty\n * @param {string} input\n * @returns {boolean}\n */\nfunction notEmptyString (input) {\n\treturn input !== ''\n}\n/**\n * @see https://infra.spec.whatwg.org/#split-on-ascii-whitespace\n * @see https://infra.spec.whatwg.org/#ascii-whitespace\n *\n * @param {string} input\n * @returns {string[]} (can be empty)\n */\nfunction splitOnASCIIWhitespace(input) {\n\t// U+0009 TAB, U+000A LF, U+000C FF, U+000D CR, U+0020 SPACE\n\treturn input ? input.split(/[\\t\\n\\f\\r ]+/).filter(notEmptyString) : []\n}\n\n/**\n * Adds element as a key to current if it is not already present.\n *\n * @param {Record<string, boolean | undefined>} current\n * @param {string} element\n * @returns {Record<string, boolean | undefined>}\n */\nfunction orderedSetReducer (current, element) {\n\tif (!current.hasOwnProperty(element)) {\n\t\tcurrent[element] = true;\n\t}\n\treturn current;\n}\n\n/**\n * @see https://infra.spec.whatwg.org/#ordered-set\n * @param {string} input\n * @returns {string[]}\n */\nfunction toOrderedSet(input) {\n\tif (!input) return [];\n\tvar list = splitOnASCIIWhitespace(input);\n\treturn Object.keys(list.reduce(orderedSetReducer, {}))\n}\n\n/**\n * Uses `list.indexOf` to implement something like `Array.prototype.includes`,\n * which we can not rely on being available.\n *\n * @param {any[]} list\n * @returns {function(any): boolean}\n */\nfunction arrayIncludes (list) {\n\treturn function(element) {\n\t\treturn list && list.indexOf(element) !== -1;\n\t}\n}\n\nfunction copy(src,dest){\n\tfor(var p in src){\n\t\tdest[p] = src[p];\n\t}\n}\n\n/**\n^\\w+\\.prototype\\.([_\\w]+)\\s*=\\s*((?:.*\\{\\s*?[\\r\\n][\\s\\S]*?^})|\\S.*?(?=[;\\r\\n]));?\n^\\w+\\.prototype\\.([_\\w]+)\\s*=\\s*(\\S.*?(?=[;\\r\\n]));?\n */\nfunction _extends(Class,Super){\n\tvar pt = Class.prototype;\n\tif(!(pt instanceof Super)){\n\t\tfunction t(){};\n\t\tt.prototype = Super.prototype;\n\t\tt = new t();\n\t\tcopy(pt,t);\n\t\tClass.prototype = pt = t;\n\t}\n\tif(pt.constructor != Class){\n\t\tif(typeof Class != 'function'){\n\t\t\tconsole.error(\"unknown Class:\"+Class)\n\t\t}\n\t\tpt.constructor = Class\n\t}\n}\n\n// Node Types\nvar NodeType = {}\nvar ELEMENT_NODE                = NodeType.ELEMENT_NODE                = 1;\nvar ATTRIBUTE_NODE              = NodeType.ATTRIBUTE_NODE              = 2;\nvar TEXT_NODE                   = NodeType.TEXT_NODE                   = 3;\nvar CDATA_SECTION_NODE          = NodeType.CDATA_SECTION_NODE          = 4;\nvar ENTITY_REFERENCE_NODE       = NodeType.ENTITY_REFERENCE_NODE       = 5;\nvar ENTITY_NODE                 = NodeType.ENTITY_NODE                 = 6;\nvar PROCESSING_INSTRUCTION_NODE = NodeType.PROCESSING_INSTRUCTION_NODE = 7;\nvar COMMENT_NODE                = NodeType.COMMENT_NODE                = 8;\nvar DOCUMENT_NODE               = NodeType.DOCUMENT_NODE               = 9;\nvar DOCUMENT_TYPE_NODE          = NodeType.DOCUMENT_TYPE_NODE          = 10;\nvar DOCUMENT_FRAGMENT_NODE      = NodeType.DOCUMENT_FRAGMENT_NODE      = 11;\nvar NOTATION_NODE               = NodeType.NOTATION_NODE               = 12;\n\n// ExceptionCode\nvar ExceptionCode = {}\nvar ExceptionMessage = {};\nvar INDEX_SIZE_ERR              = ExceptionCode.INDEX_SIZE_ERR              = ((ExceptionMessage[1]=\"Index size error\"),1);\nvar DOMSTRING_SIZE_ERR          = ExceptionCode.DOMSTRING_SIZE_ERR          = ((ExceptionMessage[2]=\"DOMString size error\"),2);\nvar HIERARCHY_REQUEST_ERR       = ExceptionCode.HIERARCHY_REQUEST_ERR       = ((ExceptionMessage[3]=\"Hierarchy request error\"),3);\nvar WRONG_DOCUMENT_ERR          = ExceptionCode.WRONG_DOCUMENT_ERR          = ((ExceptionMessage[4]=\"Wrong document\"),4);\nvar INVALID_CHARACTER_ERR       = ExceptionCode.INVALID_CHARACTER_ERR       = ((ExceptionMessage[5]=\"Invalid character\"),5);\nvar NO_DATA_ALLOWED_ERR         = ExceptionCode.NO_DATA_ALLOWED_ERR         = ((ExceptionMessage[6]=\"No data allowed\"),6);\nvar NO_MODIFICATION_ALLOWED_ERR = ExceptionCode.NO_MODIFICATION_ALLOWED_ERR = ((ExceptionMessage[7]=\"No modification allowed\"),7);\nvar NOT_FOUND_ERR               = ExceptionCode.NOT_FOUND_ERR               = ((ExceptionMessage[8]=\"Not found\"),8);\nvar NOT_SUPPORTED_ERR           = ExceptionCode.NOT_SUPPORTED_ERR           = ((ExceptionMessage[9]=\"Not supported\"),9);\nvar INUSE_ATTRIBUTE_ERR         = ExceptionCode.INUSE_ATTRIBUTE_ERR         = ((ExceptionMessage[10]=\"Attribute in use\"),10);\n//level2\nvar INVALID_STATE_ERR        \t= ExceptionCode.INVALID_STATE_ERR        \t= ((ExceptionMessage[11]=\"Invalid state\"),11);\nvar SYNTAX_ERR               \t= ExceptionCode.SYNTAX_ERR               \t= ((ExceptionMessage[12]=\"Syntax error\"),12);\nvar INVALID_MODIFICATION_ERR \t= ExceptionCode.INVALID_MODIFICATION_ERR \t= ((ExceptionMessage[13]=\"Invalid modification\"),13);\nvar NAMESPACE_ERR            \t= ExceptionCode.NAMESPACE_ERR           \t= ((ExceptionMessage[14]=\"Invalid namespace\"),14);\nvar INVALID_ACCESS_ERR       \t= ExceptionCode.INVALID_ACCESS_ERR      \t= ((ExceptionMessage[15]=\"Invalid access\"),15);\n\n/**\n * DOM Level 2\n * Object DOMException\n * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/ecma-script-binding.html\n * @see http://www.w3.org/TR/REC-DOM-Level-1/ecma-script-language-binding.html\n */\nfunction DOMException(code, message) {\n\tif(message instanceof Error){\n\t\tvar error = message;\n\t}else{\n\t\terror = this;\n\t\tError.call(this, ExceptionMessage[code]);\n\t\tthis.message = ExceptionMessage[code];\n\t\tif(Error.captureStackTrace) Error.captureStackTrace(this, DOMException);\n\t}\n\terror.code = code;\n\tif(message) this.message = this.message + \": \" + message;\n\treturn error;\n};\nDOMException.prototype = Error.prototype;\ncopy(ExceptionCode,DOMException)\n\n/**\n * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-536297177\n * The NodeList interface provides the abstraction of an ordered collection of nodes, without defining or constraining how this collection is implemented. NodeList objects in the DOM are live.\n * The items in the NodeList are accessible via an integral index, starting from 0.\n */\nfunction NodeList() {\n};\nNodeList.prototype = {\n\t/**\n\t * The number of nodes in the list. The range of valid child node indices is 0 to length-1 inclusive.\n\t * @standard level1\n\t */\n\tlength:0, \n\t/**\n\t * Returns the indexth item in the collection. If index is greater than or equal to the number of nodes in the list, this returns null.\n\t * @standard level1\n\t * @param index  unsigned long \n\t *   Index into the collection.\n\t * @return Node\n\t * \tThe node at the indexth position in the NodeList, or null if that is not a valid index. \n\t */\n\titem: function(index) {\n\t\treturn this[index] || null;\n\t},\n\ttoString:function(isHTML,nodeFilter){\n\t\tfor(var buf = [], i = 0;i<this.length;i++){\n\t\t\tserializeToString(this[i],buf,isHTML,nodeFilter);\n\t\t}\n\t\treturn buf.join('');\n\t}\n};\n\nfunction LiveNodeList(node,refresh){\n\tthis._node = node;\n\tthis._refresh = refresh\n\t_updateLiveList(this);\n}\nfunction _updateLiveList(list){\n\tvar inc = list._node._inc || list._node.ownerDocument._inc;\n\tif(list._inc != inc){\n\t\tvar ls = list._refresh(list._node);\n\t\t//console.log(ls.length)\n\t\t__set__(list,'length',ls.length);\n\t\tcopy(ls,list);\n\t\tlist._inc = inc;\n\t}\n}\nLiveNodeList.prototype.item = function(i){\n\t_updateLiveList(this);\n\treturn this[i];\n}\n\n_extends(LiveNodeList,NodeList);\n\n/**\n * Objects implementing the NamedNodeMap interface are used\n * to represent collections of nodes that can be accessed by name.\n * Note that NamedNodeMap does not inherit from NodeList;\n * NamedNodeMaps are not maintained in any particular order.\n * Objects contained in an object implementing NamedNodeMap may also be accessed by an ordinal index,\n * but this is simply to allow convenient enumeration of the contents of a NamedNodeMap,\n * and does not imply that the DOM specifies an order to these Nodes.\n * NamedNodeMap objects in the DOM are live.\n * used for attributes or DocumentType entities \n */\nfunction NamedNodeMap() {\n};\n\nfunction _findNodeIndex(list,node){\n\tvar i = list.length;\n\twhile(i--){\n\t\tif(list[i] === node){return i}\n\t}\n}\n\nfunction _addNamedNode(el,list,newAttr,oldAttr){\n\tif(oldAttr){\n\t\tlist[_findNodeIndex(list,oldAttr)] = newAttr;\n\t}else{\n\t\tlist[list.length++] = newAttr;\n\t}\n\tif(el){\n\t\tnewAttr.ownerElement = el;\n\t\tvar doc = el.ownerDocument;\n\t\tif(doc){\n\t\t\toldAttr && _onRemoveAttribute(doc,el,oldAttr);\n\t\t\t_onAddAttribute(doc,el,newAttr);\n\t\t}\n\t}\n}\nfunction _removeNamedNode(el,list,attr){\n\t//console.log('remove attr:'+attr)\n\tvar i = _findNodeIndex(list,attr);\n\tif(i>=0){\n\t\tvar lastIndex = list.length-1\n\t\twhile(i<lastIndex){\n\t\t\tlist[i] = list[++i]\n\t\t}\n\t\tlist.length = lastIndex;\n\t\tif(el){\n\t\t\tvar doc = el.ownerDocument;\n\t\t\tif(doc){\n\t\t\t\t_onRemoveAttribute(doc,el,attr);\n\t\t\t\tattr.ownerElement = null;\n\t\t\t}\n\t\t}\n\t}else{\n\t\tthrow DOMException(NOT_FOUND_ERR,new Error(el.tagName+'@'+attr))\n\t}\n}\nNamedNodeMap.prototype = {\n\tlength:0,\n\titem:NodeList.prototype.item,\n\tgetNamedItem: function(key) {\n//\t\tif(key.indexOf(':')>0 || key == 'xmlns'){\n//\t\t\treturn null;\n//\t\t}\n\t\t//console.log()\n\t\tvar i = this.length;\n\t\twhile(i--){\n\t\t\tvar attr = this[i];\n\t\t\t//console.log(attr.nodeName,key)\n\t\t\tif(attr.nodeName == key){\n\t\t\t\treturn attr;\n\t\t\t}\n\t\t}\n\t},\n\tsetNamedItem: function(attr) {\n\t\tvar el = attr.ownerElement;\n\t\tif(el && el!=this._ownerElement){\n\t\t\tthrow new DOMException(INUSE_ATTRIBUTE_ERR);\n\t\t}\n\t\tvar oldAttr = this.getNamedItem(attr.nodeName);\n\t\t_addNamedNode(this._ownerElement,this,attr,oldAttr);\n\t\treturn oldAttr;\n\t},\n\t/* returns Node */\n\tsetNamedItemNS: function(attr) {// raises: WRONG_DOCUMENT_ERR,NO_MODIFICATION_ALLOWED_ERR,INUSE_ATTRIBUTE_ERR\n\t\tvar el = attr.ownerElement, oldAttr;\n\t\tif(el && el!=this._ownerElement){\n\t\t\tthrow new DOMException(INUSE_ATTRIBUTE_ERR);\n\t\t}\n\t\toldAttr = this.getNamedItemNS(attr.namespaceURI,attr.localName);\n\t\t_addNamedNode(this._ownerElement,this,attr,oldAttr);\n\t\treturn oldAttr;\n\t},\n\n\t/* returns Node */\n\tremoveNamedItem: function(key) {\n\t\tvar attr = this.getNamedItem(key);\n\t\t_removeNamedNode(this._ownerElement,this,attr);\n\t\treturn attr;\n\t\t\n\t\t\n\t},// raises: NOT_FOUND_ERR,NO_MODIFICATION_ALLOWED_ERR\n\t\n\t//for level2\n\tremoveNamedItemNS:function(namespaceURI,localName){\n\t\tvar attr = this.getNamedItemNS(namespaceURI,localName);\n\t\t_removeNamedNode(this._ownerElement,this,attr);\n\t\treturn attr;\n\t},\n\tgetNamedItemNS: function(namespaceURI, localName) {\n\t\tvar i = this.length;\n\t\twhile(i--){\n\t\t\tvar node = this[i];\n\t\t\tif(node.localName == localName && node.namespaceURI == namespaceURI){\n\t\t\t\treturn node;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n};\n\n/**\n * The DOMImplementation interface represents an object providing methods\n * which are not dependent on any particular document.\n * Such an object is returned by the `Document.implementation` property.\n *\n * __The individual methods describe the differences compared to the specs.__\n *\n * @constructor\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation MDN\n * @see https://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-102161490 DOM Level 1 Core (Initial)\n * @see https://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-102161490 DOM Level 2 Core\n * @see https://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-102161490 DOM Level 3 Core\n * @see https://dom.spec.whatwg.org/#domimplementation DOM Living Standard\n */\nfunction DOMImplementation() {\n}\n\nDOMImplementation.prototype = {\n\t/**\n\t * The DOMImplementation.hasFeature() method returns a Boolean flag indicating if a given feature is supported.\n\t * The different implementations fairly diverged in what kind of features were reported.\n\t * The latest version of the spec settled to force this method to always return true, where the functionality was accurate and in use.\n\t *\n\t * @deprecated It is deprecated and modern browsers return true in all cases.\n\t *\n\t * @param {string} feature\n\t * @param {string} [version]\n\t * @returns {boolean} always true\n\t *\n\t * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation/hasFeature MDN\n\t * @see https://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-5CED94D7 DOM Level 1 Core\n\t * @see https://dom.spec.whatwg.org/#dom-domimplementation-hasfeature DOM Living Standard\n\t */\n\thasFeature: function(feature, version) {\n\t\t\treturn true;\n\t},\n\t/**\n\t * Creates an XML Document object of the specified type with its document element.\n\t *\n\t * __It behaves slightly different from the description in the living standard__:\n\t * - There is no interface/class `XMLDocument`, it returns a `Document` instance.\n\t * - `contentType`, `encoding`, `mode`, `origin`, `url` fields are currently not declared.\n\t * - this implementation is not validating names or qualified names\n\t *   (when parsing XML strings, the SAX parser takes care of that)\n\t *\n\t * @param {string|null} namespaceURI\n\t * @param {string} qualifiedName\n\t * @param {DocumentType=null} doctype\n\t * @returns {Document}\n\t *\n\t * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation/createDocument MDN\n\t * @see https://www.w3.org/TR/DOM-Level-2-Core/core.html#Level-2-Core-DOM-createDocument DOM Level 2 Core (initial)\n\t * @see https://dom.spec.whatwg.org/#dom-domimplementation-createdocument  DOM Level 2 Core\n\t *\n\t * @see https://dom.spec.whatwg.org/#validate-and-extract DOM: Validate and extract\n\t * @see https://www.w3.org/TR/xml/#NT-NameStartChar XML Spec: Names\n\t * @see https://www.w3.org/TR/xml-names/#ns-qualnames XML Namespaces: Qualified names\n\t */\n\tcreateDocument: function(namespaceURI,  qualifiedName, doctype){\n\t\tvar doc = new Document();\n\t\tdoc.implementation = this;\n\t\tdoc.childNodes = new NodeList();\n\t\tdoc.doctype = doctype || null;\n\t\tif (doctype){\n\t\t\tdoc.appendChild(doctype);\n\t\t}\n\t\tif (qualifiedName){\n\t\t\tvar root = doc.createElementNS(namespaceURI, qualifiedName);\n\t\t\tdoc.appendChild(root);\n\t\t}\n\t\treturn doc;\n\t},\n\t/**\n\t * Returns a doctype, with the given `qualifiedName`, `publicId`, and `systemId`.\n\t *\n\t * __This behavior is slightly different from the in the specs__:\n\t * - this implementation is not validating names or qualified names\n\t *   (when parsing XML strings, the SAX parser takes care of that)\n\t *\n\t * @param {string} qualifiedName\n\t * @param {string} [publicId]\n\t * @param {string} [systemId]\n\t * @returns {DocumentType} which can either be used with `DOMImplementation.createDocument` upon document creation\n\t * \t\t\t\t  or can be put into the document via methods like `Node.insertBefore()` or `Node.replaceChild()`\n\t *\n\t * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation/createDocumentType MDN\n\t * @see https://www.w3.org/TR/DOM-Level-2-Core/core.html#Level-2-Core-DOM-createDocType DOM Level 2 Core\n\t * @see https://dom.spec.whatwg.org/#dom-domimplementation-createdocumenttype DOM Living Standard\n\t *\n\t * @see https://dom.spec.whatwg.org/#validate-and-extract DOM: Validate and extract\n\t * @see https://www.w3.org/TR/xml/#NT-NameStartChar XML Spec: Names\n\t * @see https://www.w3.org/TR/xml-names/#ns-qualnames XML Namespaces: Qualified names\n\t */\n\tcreateDocumentType: function(qualifiedName, publicId, systemId){\n\t\tvar node = new DocumentType();\n\t\tnode.name = qualifiedName;\n\t\tnode.nodeName = qualifiedName;\n\t\tnode.publicId = publicId || '';\n\t\tnode.systemId = systemId || '';\n\n\t\treturn node;\n\t}\n};\n\n\n/**\n * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-1950641247\n */\n\nfunction Node() {\n};\n\nNode.prototype = {\n\tfirstChild : null,\n\tlastChild : null,\n\tpreviousSibling : null,\n\tnextSibling : null,\n\tattributes : null,\n\tparentNode : null,\n\tchildNodes : null,\n\townerDocument : null,\n\tnodeValue : null,\n\tnamespaceURI : null,\n\tprefix : null,\n\tlocalName : null,\n\t// Modified in DOM Level 2:\n\tinsertBefore:function(newChild, refChild){//raises \n\t\treturn _insertBefore(this,newChild,refChild);\n\t},\n\treplaceChild:function(newChild, oldChild){//raises \n\t\tthis.insertBefore(newChild,oldChild);\n\t\tif(oldChild){\n\t\t\tthis.removeChild(oldChild);\n\t\t}\n\t},\n\tremoveChild:function(oldChild){\n\t\treturn _removeChild(this,oldChild);\n\t},\n\tappendChild:function(newChild){\n\t\treturn this.insertBefore(newChild,null);\n\t},\n\thasChildNodes:function(){\n\t\treturn this.firstChild != null;\n\t},\n\tcloneNode:function(deep){\n\t\treturn cloneNode(this.ownerDocument||this,this,deep);\n\t},\n\t// Modified in DOM Level 2:\n\tnormalize:function(){\n\t\tvar child = this.firstChild;\n\t\twhile(child){\n\t\t\tvar next = child.nextSibling;\n\t\t\tif(next && next.nodeType == TEXT_NODE && child.nodeType == TEXT_NODE){\n\t\t\t\tthis.removeChild(next);\n\t\t\t\tchild.appendData(next.data);\n\t\t\t}else{\n\t\t\t\tchild.normalize();\n\t\t\t\tchild = next;\n\t\t\t}\n\t\t}\n\t},\n  \t// Introduced in DOM Level 2:\n\tisSupported:function(feature, version){\n\t\treturn this.ownerDocument.implementation.hasFeature(feature,version);\n\t},\n    // Introduced in DOM Level 2:\n    hasAttributes:function(){\n    \treturn this.attributes.length>0;\n    },\n\t/**\n\t * Look up the prefix associated to the given namespace URI, starting from this node.\n\t * **The default namespace declarations are ignored by this method.**\n\t * See Namespace Prefix Lookup for details on the algorithm used by this method.\n\t *\n\t * _Note: The implementation seems to be incomplete when compared to the algorithm described in the specs._\n\t *\n\t * @param {string | null} namespaceURI\n\t * @returns {string | null}\n\t * @see https://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-lookupNamespacePrefix\n\t * @see https://www.w3.org/TR/DOM-Level-3-Core/namespaces-algorithms.html#lookupNamespacePrefixAlgo\n\t * @see https://dom.spec.whatwg.org/#dom-node-lookupprefix\n\t * @see https://github.com/xmldom/xmldom/issues/322\n\t */\n    lookupPrefix:function(namespaceURI){\n    \tvar el = this;\n    \twhile(el){\n    \t\tvar map = el._nsMap;\n    \t\t//console.dir(map)\n    \t\tif(map){\n    \t\t\tfor(var n in map){\n    \t\t\t\tif(map[n] == namespaceURI){\n    \t\t\t\t\treturn n;\n    \t\t\t\t}\n    \t\t\t}\n    \t\t}\n    \t\tel = el.nodeType == ATTRIBUTE_NODE?el.ownerDocument : el.parentNode;\n    \t}\n    \treturn null;\n    },\n    // Introduced in DOM Level 3:\n    lookupNamespaceURI:function(prefix){\n    \tvar el = this;\n    \twhile(el){\n    \t\tvar map = el._nsMap;\n    \t\t//console.dir(map)\n    \t\tif(map){\n    \t\t\tif(prefix in map){\n    \t\t\t\treturn map[prefix] ;\n    \t\t\t}\n    \t\t}\n    \t\tel = el.nodeType == ATTRIBUTE_NODE?el.ownerDocument : el.parentNode;\n    \t}\n    \treturn null;\n    },\n    // Introduced in DOM Level 3:\n    isDefaultNamespace:function(namespaceURI){\n    \tvar prefix = this.lookupPrefix(namespaceURI);\n    \treturn prefix == null;\n    }\n};\n\n\nfunction _xmlEncoder(c){\n\treturn c == '<' && '&lt;' ||\n         c == '>' && '&gt;' ||\n         c == '&' && '&amp;' ||\n         c == '\"' && '&quot;' ||\n         '&#'+c.charCodeAt()+';'\n}\n\n\ncopy(NodeType,Node);\ncopy(NodeType,Node.prototype);\n\n/**\n * @param callback return true for continue,false for break\n * @return boolean true: break visit;\n */\nfunction _visitNode(node,callback){\n\tif(callback(node)){\n\t\treturn true;\n\t}\n\tif(node = node.firstChild){\n\t\tdo{\n\t\t\tif(_visitNode(node,callback)){return true}\n        }while(node=node.nextSibling)\n    }\n}\n\n\n\nfunction Document(){\n}\n\nfunction _onAddAttribute(doc,el,newAttr){\n\tdoc && doc._inc++;\n\tvar ns = newAttr.namespaceURI ;\n\tif(ns === NAMESPACE.XMLNS){\n\t\t//update namespace\n\t\tel._nsMap[newAttr.prefix?newAttr.localName:''] = newAttr.value\n\t}\n}\n\nfunction _onRemoveAttribute(doc,el,newAttr,remove){\n\tdoc && doc._inc++;\n\tvar ns = newAttr.namespaceURI ;\n\tif(ns === NAMESPACE.XMLNS){\n\t\t//update namespace\n\t\tdelete el._nsMap[newAttr.prefix?newAttr.localName:'']\n\t}\n}\n\nfunction _onUpdateChild(doc,el,newChild){\n\tif(doc && doc._inc){\n\t\tdoc._inc++;\n\t\t//update childNodes\n\t\tvar cs = el.childNodes;\n\t\tif(newChild){\n\t\t\tcs[cs.length++] = newChild;\n\t\t}else{\n\t\t\t//console.log(1)\n\t\t\tvar child = el.firstChild;\n\t\t\tvar i = 0;\n\t\t\twhile(child){\n\t\t\t\tcs[i++] = child;\n\t\t\t\tchild =child.nextSibling;\n\t\t\t}\n\t\t\tcs.length = i;\n\t\t}\n\t}\n}\n\n/**\n * attributes;\n * children;\n * \n * writeable properties:\n * nodeValue,Attr:value,CharacterData:data\n * prefix\n */\nfunction _removeChild(parentNode,child){\n\tvar previous = child.previousSibling;\n\tvar next = child.nextSibling;\n\tif(previous){\n\t\tprevious.nextSibling = next;\n\t}else{\n\t\tparentNode.firstChild = next\n\t}\n\tif(next){\n\t\tnext.previousSibling = previous;\n\t}else{\n\t\tparentNode.lastChild = previous;\n\t}\n\t_onUpdateChild(parentNode.ownerDocument,parentNode);\n\treturn child;\n}\n/**\n * preformance key(refChild == null)\n */\nfunction _insertBefore(parentNode,newChild,nextChild){\n\tvar cp = newChild.parentNode;\n\tif(cp){\n\t\tcp.removeChild(newChild);//remove and update\n\t}\n\tif(newChild.nodeType === DOCUMENT_FRAGMENT_NODE){\n\t\tvar newFirst = newChild.firstChild;\n\t\tif (newFirst == null) {\n\t\t\treturn newChild;\n\t\t}\n\t\tvar newLast = newChild.lastChild;\n\t}else{\n\t\tnewFirst = newLast = newChild;\n\t}\n\tvar pre = nextChild ? nextChild.previousSibling : parentNode.lastChild;\n\n\tnewFirst.previousSibling = pre;\n\tnewLast.nextSibling = nextChild;\n\t\n\t\n\tif(pre){\n\t\tpre.nextSibling = newFirst;\n\t}else{\n\t\tparentNode.firstChild = newFirst;\n\t}\n\tif(nextChild == null){\n\t\tparentNode.lastChild = newLast;\n\t}else{\n\t\tnextChild.previousSibling = newLast;\n\t}\n\tdo{\n\t\tnewFirst.parentNode = parentNode;\n\t}while(newFirst !== newLast && (newFirst= newFirst.nextSibling))\n\t_onUpdateChild(parentNode.ownerDocument||parentNode,parentNode);\n\t//console.log(parentNode.lastChild.nextSibling == null)\n\tif (newChild.nodeType == DOCUMENT_FRAGMENT_NODE) {\n\t\tnewChild.firstChild = newChild.lastChild = null;\n\t}\n\treturn newChild;\n}\nfunction _appendSingleChild(parentNode,newChild){\n\tvar cp = newChild.parentNode;\n\tif(cp){\n\t\tvar pre = parentNode.lastChild;\n\t\tcp.removeChild(newChild);//remove and update\n\t\tvar pre = parentNode.lastChild;\n\t}\n\tvar pre = parentNode.lastChild;\n\tnewChild.parentNode = parentNode;\n\tnewChild.previousSibling = pre;\n\tnewChild.nextSibling = null;\n\tif(pre){\n\t\tpre.nextSibling = newChild;\n\t}else{\n\t\tparentNode.firstChild = newChild;\n\t}\n\tparentNode.lastChild = newChild;\n\t_onUpdateChild(parentNode.ownerDocument,parentNode,newChild);\n\treturn newChild;\n\t//console.log(\"__aa\",parentNode.lastChild.nextSibling == null)\n}\nDocument.prototype = {\n\t//implementation : null,\n\tnodeName :  '#document',\n\tnodeType :  DOCUMENT_NODE,\n\t/**\n\t * The DocumentType node of the document.\n\t *\n\t * @readonly\n\t * @type DocumentType\n\t */\n\tdoctype :  null,\n\tdocumentElement :  null,\n\t_inc : 1,\n\n\tinsertBefore :  function(newChild, refChild){//raises\n\t\tif(newChild.nodeType == DOCUMENT_FRAGMENT_NODE){\n\t\t\tvar child = newChild.firstChild;\n\t\t\twhile(child){\n\t\t\t\tvar next = child.nextSibling;\n\t\t\t\tthis.insertBefore(child,refChild);\n\t\t\t\tchild = next;\n\t\t\t}\n\t\t\treturn newChild;\n\t\t}\n\t\tif(this.documentElement == null && newChild.nodeType == ELEMENT_NODE){\n\t\t\tthis.documentElement = newChild;\n\t\t}\n\n\t\treturn _insertBefore(this,newChild,refChild),(newChild.ownerDocument = this),newChild;\n\t},\n\tremoveChild :  function(oldChild){\n\t\tif(this.documentElement == oldChild){\n\t\t\tthis.documentElement = null;\n\t\t}\n\t\treturn _removeChild(this,oldChild);\n\t},\n\t// Introduced in DOM Level 2:\n\timportNode : function(importedNode,deep){\n\t\treturn importNode(this,importedNode,deep);\n\t},\n\t// Introduced in DOM Level 2:\n\tgetElementById :\tfunction(id){\n\t\tvar rtv = null;\n\t\t_visitNode(this.documentElement,function(node){\n\t\t\tif(node.nodeType == ELEMENT_NODE){\n\t\t\t\tif(node.getAttribute('id') == id){\n\t\t\t\t\trtv = node;\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t\treturn rtv;\n\t},\n\n\t/**\n\t * The `getElementsByClassName` method of `Document` interface returns an array-like object\n\t * of all child elements which have **all** of the given class name(s).\n\t *\n\t * Returns an empty list if `classeNames` is an empty string or only contains HTML white space characters.\n\t *\n\t *\n\t * Warning: This is a live LiveNodeList.\n\t * Changes in the DOM will reflect in the array as the changes occur.\n\t * If an element selected by this array no longer qualifies for the selector,\n\t * it will automatically be removed. Be aware of this for iteration purposes.\n\t *\n\t * @param {string} classNames is a string representing the class name(s) to match; multiple class names are separated by (ASCII-)whitespace\n\t *\n\t * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByClassName\n\t * @see https://dom.spec.whatwg.org/#concept-getelementsbyclassname\n\t */\n\tgetElementsByClassName: function(classNames) {\n\t\tvar classNamesSet = toOrderedSet(classNames)\n\t\treturn new LiveNodeList(this, function(base) {\n\t\t\tvar ls = [];\n\t\t\tif (classNamesSet.length > 0) {\n\t\t\t\t_visitNode(base.documentElement, function(node) {\n\t\t\t\t\tif(node !== base && node.nodeType === ELEMENT_NODE) {\n\t\t\t\t\t\tvar nodeClassNames = node.getAttribute('class')\n\t\t\t\t\t\t// can be null if the attribute does not exist\n\t\t\t\t\t\tif (nodeClassNames) {\n\t\t\t\t\t\t\t// before splitting and iterating just compare them for the most common case\n\t\t\t\t\t\t\tvar matches = classNames === nodeClassNames;\n\t\t\t\t\t\t\tif (!matches) {\n\t\t\t\t\t\t\t\tvar nodeClassNamesSet = toOrderedSet(nodeClassNames)\n\t\t\t\t\t\t\t\tmatches = classNamesSet.every(arrayIncludes(nodeClassNamesSet))\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(matches) {\n\t\t\t\t\t\t\t\tls.push(node);\n\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\treturn ls;\n\t\t});\n\t},\n\n\t//document factory method:\n\tcreateElement :\tfunction(tagName){\n\t\tvar node = new Element();\n\t\tnode.ownerDocument = this;\n\t\tnode.nodeName = tagName;\n\t\tnode.tagName = tagName;\n\t\tnode.localName = tagName;\n\t\tnode.childNodes = new NodeList();\n\t\tvar attrs\t= node.attributes = new NamedNodeMap();\n\t\tattrs._ownerElement = node;\n\t\treturn node;\n\t},\n\tcreateDocumentFragment :\tfunction(){\n\t\tvar node = new DocumentFragment();\n\t\tnode.ownerDocument = this;\n\t\tnode.childNodes = new NodeList();\n\t\treturn node;\n\t},\n\tcreateTextNode :\tfunction(data){\n\t\tvar node = new Text();\n\t\tnode.ownerDocument = this;\n\t\tnode.appendData(data)\n\t\treturn node;\n\t},\n\tcreateComment :\tfunction(data){\n\t\tvar node = new Comment();\n\t\tnode.ownerDocument = this;\n\t\tnode.appendData(data)\n\t\treturn node;\n\t},\n\tcreateCDATASection :\tfunction(data){\n\t\tvar node = new CDATASection();\n\t\tnode.ownerDocument = this;\n\t\tnode.appendData(data)\n\t\treturn node;\n\t},\n\tcreateProcessingInstruction :\tfunction(target,data){\n\t\tvar node = new ProcessingInstruction();\n\t\tnode.ownerDocument = this;\n\t\tnode.tagName = node.target = target;\n\t\tnode.nodeValue= node.data = data;\n\t\treturn node;\n\t},\n\tcreateAttribute :\tfunction(name){\n\t\tvar node = new Attr();\n\t\tnode.ownerDocument\t= this;\n\t\tnode.name = name;\n\t\tnode.nodeName\t= name;\n\t\tnode.localName = name;\n\t\tnode.specified = true;\n\t\treturn node;\n\t},\n\tcreateEntityReference :\tfunction(name){\n\t\tvar node = new EntityReference();\n\t\tnode.ownerDocument\t= this;\n\t\tnode.nodeName\t= name;\n\t\treturn node;\n\t},\n\t// Introduced in DOM Level 2:\n\tcreateElementNS :\tfunction(namespaceURI,qualifiedName){\n\t\tvar node = new Element();\n\t\tvar pl = qualifiedName.split(':');\n\t\tvar attrs\t= node.attributes = new NamedNodeMap();\n\t\tnode.childNodes = new NodeList();\n\t\tnode.ownerDocument = this;\n\t\tnode.nodeName = qualifiedName;\n\t\tnode.tagName = qualifiedName;\n\t\tnode.namespaceURI = namespaceURI;\n\t\tif(pl.length == 2){\n\t\t\tnode.prefix = pl[0];\n\t\t\tnode.localName = pl[1];\n\t\t}else{\n\t\t\t//el.prefix = null;\n\t\t\tnode.localName = qualifiedName;\n\t\t}\n\t\tattrs._ownerElement = node;\n\t\treturn node;\n\t},\n\t// Introduced in DOM Level 2:\n\tcreateAttributeNS :\tfunction(namespaceURI,qualifiedName){\n\t\tvar node = new Attr();\n\t\tvar pl = qualifiedName.split(':');\n\t\tnode.ownerDocument = this;\n\t\tnode.nodeName = qualifiedName;\n\t\tnode.name = qualifiedName;\n\t\tnode.namespaceURI = namespaceURI;\n\t\tnode.specified = true;\n\t\tif(pl.length == 2){\n\t\t\tnode.prefix = pl[0];\n\t\t\tnode.localName = pl[1];\n\t\t}else{\n\t\t\t//el.prefix = null;\n\t\t\tnode.localName = qualifiedName;\n\t\t}\n\t\treturn node;\n\t}\n};\n_extends(Document,Node);\n\n\nfunction Element() {\n\tthis._nsMap = {};\n};\nElement.prototype = {\n\tnodeType : ELEMENT_NODE,\n\thasAttribute : function(name){\n\t\treturn this.getAttributeNode(name)!=null;\n\t},\n\tgetAttribute : function(name){\n\t\tvar attr = this.getAttributeNode(name);\n\t\treturn attr && attr.value || '';\n\t},\n\tgetAttributeNode : function(name){\n\t\treturn this.attributes.getNamedItem(name);\n\t},\n\tsetAttribute : function(name, value){\n\t\tvar attr = this.ownerDocument.createAttribute(name);\n\t\tattr.value = attr.nodeValue = \"\" + value;\n\t\tthis.setAttributeNode(attr)\n\t},\n\tremoveAttribute : function(name){\n\t\tvar attr = this.getAttributeNode(name)\n\t\tattr && this.removeAttributeNode(attr);\n\t},\n\t\n\t//four real opeartion method\n\tappendChild:function(newChild){\n\t\tif(newChild.nodeType === DOCUMENT_FRAGMENT_NODE){\n\t\t\treturn this.insertBefore(newChild,null);\n\t\t}else{\n\t\t\treturn _appendSingleChild(this,newChild);\n\t\t}\n\t},\n\tsetAttributeNode : function(newAttr){\n\t\treturn this.attributes.setNamedItem(newAttr);\n\t},\n\tsetAttributeNodeNS : function(newAttr){\n\t\treturn this.attributes.setNamedItemNS(newAttr);\n\t},\n\tremoveAttributeNode : function(oldAttr){\n\t\t//console.log(this == oldAttr.ownerElement)\n\t\treturn this.attributes.removeNamedItem(oldAttr.nodeName);\n\t},\n\t//get real attribute name,and remove it by removeAttributeNode\n\tremoveAttributeNS : function(namespaceURI, localName){\n\t\tvar old = this.getAttributeNodeNS(namespaceURI, localName);\n\t\told && this.removeAttributeNode(old);\n\t},\n\t\n\thasAttributeNS : function(namespaceURI, localName){\n\t\treturn this.getAttributeNodeNS(namespaceURI, localName)!=null;\n\t},\n\tgetAttributeNS : function(namespaceURI, localName){\n\t\tvar attr = this.getAttributeNodeNS(namespaceURI, localName);\n\t\treturn attr && attr.value || '';\n\t},\n\tsetAttributeNS : function(namespaceURI, qualifiedName, value){\n\t\tvar attr = this.ownerDocument.createAttributeNS(namespaceURI, qualifiedName);\n\t\tattr.value = attr.nodeValue = \"\" + value;\n\t\tthis.setAttributeNode(attr)\n\t},\n\tgetAttributeNodeNS : function(namespaceURI, localName){\n\t\treturn this.attributes.getNamedItemNS(namespaceURI, localName);\n\t},\n\t\n\tgetElementsByTagName : function(tagName){\n\t\treturn new LiveNodeList(this,function(base){\n\t\t\tvar ls = [];\n\t\t\t_visitNode(base,function(node){\n\t\t\t\tif(node !== base && node.nodeType == ELEMENT_NODE && (tagName === '*' || node.tagName == tagName)){\n\t\t\t\t\tls.push(node);\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn ls;\n\t\t});\n\t},\n\tgetElementsByTagNameNS : function(namespaceURI, localName){\n\t\treturn new LiveNodeList(this,function(base){\n\t\t\tvar ls = [];\n\t\t\t_visitNode(base,function(node){\n\t\t\t\tif(node !== base && node.nodeType === ELEMENT_NODE && (namespaceURI === '*' || node.namespaceURI === namespaceURI) && (localName === '*' || node.localName == localName)){\n\t\t\t\t\tls.push(node);\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn ls;\n\t\t\t\n\t\t});\n\t}\n};\nDocument.prototype.getElementsByTagName = Element.prototype.getElementsByTagName;\nDocument.prototype.getElementsByTagNameNS = Element.prototype.getElementsByTagNameNS;\n\n\n_extends(Element,Node);\nfunction Attr() {\n};\nAttr.prototype.nodeType = ATTRIBUTE_NODE;\n_extends(Attr,Node);\n\n\nfunction CharacterData() {\n};\nCharacterData.prototype = {\n\tdata : '',\n\tsubstringData : function(offset, count) {\n\t\treturn this.data.substring(offset, offset+count);\n\t},\n\tappendData: function(text) {\n\t\ttext = this.data+text;\n\t\tthis.nodeValue = this.data = text;\n\t\tthis.length = text.length;\n\t},\n\tinsertData: function(offset,text) {\n\t\tthis.replaceData(offset,0,text);\n\t\n\t},\n\tappendChild:function(newChild){\n\t\tthrow new Error(ExceptionMessage[HIERARCHY_REQUEST_ERR])\n\t},\n\tdeleteData: function(offset, count) {\n\t\tthis.replaceData(offset,count,\"\");\n\t},\n\treplaceData: function(offset, count, text) {\n\t\tvar start = this.data.substring(0,offset);\n\t\tvar end = this.data.substring(offset+count);\n\t\ttext = start + text + end;\n\t\tthis.nodeValue = this.data = text;\n\t\tthis.length = text.length;\n\t}\n}\n_extends(CharacterData,Node);\nfunction Text() {\n};\nText.prototype = {\n\tnodeName : \"#text\",\n\tnodeType : TEXT_NODE,\n\tsplitText : function(offset) {\n\t\tvar text = this.data;\n\t\tvar newText = text.substring(offset);\n\t\ttext = text.substring(0, offset);\n\t\tthis.data = this.nodeValue = text;\n\t\tthis.length = text.length;\n\t\tvar newNode = this.ownerDocument.createTextNode(newText);\n\t\tif(this.parentNode){\n\t\t\tthis.parentNode.insertBefore(newNode, this.nextSibling);\n\t\t}\n\t\treturn newNode;\n\t}\n}\n_extends(Text,CharacterData);\nfunction Comment() {\n};\nComment.prototype = {\n\tnodeName : \"#comment\",\n\tnodeType : COMMENT_NODE\n}\n_extends(Comment,CharacterData);\n\nfunction CDATASection() {\n};\nCDATASection.prototype = {\n\tnodeName : \"#cdata-section\",\n\tnodeType : CDATA_SECTION_NODE\n}\n_extends(CDATASection,CharacterData);\n\n\nfunction DocumentType() {\n};\nDocumentType.prototype.nodeType = DOCUMENT_TYPE_NODE;\n_extends(DocumentType,Node);\n\nfunction Notation() {\n};\nNotation.prototype.nodeType = NOTATION_NODE;\n_extends(Notation,Node);\n\nfunction Entity() {\n};\nEntity.prototype.nodeType = ENTITY_NODE;\n_extends(Entity,Node);\n\nfunction EntityReference() {\n};\nEntityReference.prototype.nodeType = ENTITY_REFERENCE_NODE;\n_extends(EntityReference,Node);\n\nfunction DocumentFragment() {\n};\nDocumentFragment.prototype.nodeName =\t\"#document-fragment\";\nDocumentFragment.prototype.nodeType =\tDOCUMENT_FRAGMENT_NODE;\n_extends(DocumentFragment,Node);\n\n\nfunction ProcessingInstruction() {\n}\nProcessingInstruction.prototype.nodeType = PROCESSING_INSTRUCTION_NODE;\n_extends(ProcessingInstruction,Node);\nfunction XMLSerializer(){}\nXMLSerializer.prototype.serializeToString = function(node,isHtml,nodeFilter){\n\treturn nodeSerializeToString.call(node,isHtml,nodeFilter);\n}\nNode.prototype.toString = nodeSerializeToString;\nfunction nodeSerializeToString(isHtml,nodeFilter){\n\tvar buf = [];\n\tvar refNode = this.nodeType == 9 && this.documentElement || this;\n\tvar prefix = refNode.prefix;\n\tvar uri = refNode.namespaceURI;\n\t\n\tif(uri && prefix == null){\n\t\t//console.log(prefix)\n\t\tvar prefix = refNode.lookupPrefix(uri);\n\t\tif(prefix == null){\n\t\t\t//isHTML = true;\n\t\t\tvar visibleNamespaces=[\n\t\t\t{namespace:uri,prefix:null}\n\t\t\t//{namespace:uri,prefix:''}\n\t\t\t]\n\t\t}\n\t}\n\tserializeToString(this,buf,isHtml,nodeFilter,visibleNamespaces);\n\t//console.log('###',this.nodeType,uri,prefix,buf.join(''))\n\treturn buf.join('');\n}\n\nfunction needNamespaceDefine(node, isHTML, visibleNamespaces) {\n\tvar prefix = node.prefix || '';\n\tvar uri = node.namespaceURI;\n\t// According to [Namespaces in XML 1.0](https://www.w3.org/TR/REC-xml-names/#ns-using) ,\n\t// and more specifically https://www.w3.org/TR/REC-xml-names/#nsc-NoPrefixUndecl :\n\t// > In a namespace declaration for a prefix [...], the attribute value MUST NOT be empty.\n\t// in a similar manner [Namespaces in XML 1.1](https://www.w3.org/TR/xml-names11/#ns-using)\n\t// and more specifically https://www.w3.org/TR/xml-names11/#nsc-NSDeclared :\n\t// > [...] Furthermore, the attribute value [...] must not be an empty string.\n\t// so serializing empty namespace value like xmlns:ds=\"\" would produce an invalid XML document.\n\tif (!uri) {\n\t\treturn false;\n\t}\n\tif (prefix === \"xml\" && uri === NAMESPACE.XML || uri === NAMESPACE.XMLNS) {\n\t\treturn false;\n\t}\n\t\n\tvar i = visibleNamespaces.length \n\twhile (i--) {\n\t\tvar ns = visibleNamespaces[i];\n\t\t// get namespace prefix\n\t\tif (ns.prefix === prefix) {\n\t\t\treturn ns.namespace !== uri;\n\t\t}\n\t}\n\treturn true;\n}\n/**\n * Well-formed constraint: No < in Attribute Values\n * The replacement text of any entity referred to directly or indirectly in an attribute value must not contain a <.\n * @see https://www.w3.org/TR/xml/#CleanAttrVals\n * @see https://www.w3.org/TR/xml/#NT-AttValue\n */\nfunction addSerializedAttribute(buf, qualifiedName, value) {\n\tbuf.push(' ', qualifiedName, '=\"', value.replace(/[<&\"]/g,_xmlEncoder), '\"')\n}\n\nfunction serializeToString(node,buf,isHTML,nodeFilter,visibleNamespaces){\n\tif (!visibleNamespaces) {\n\t\tvisibleNamespaces = [];\n\t}\n\n\tif(nodeFilter){\n\t\tnode = nodeFilter(node);\n\t\tif(node){\n\t\t\tif(typeof node == 'string'){\n\t\t\t\tbuf.push(node);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}else{\n\t\t\treturn;\n\t\t}\n\t\t//buf.sort.apply(attrs, attributeSorter);\n\t}\n\n\tswitch(node.nodeType){\n\tcase ELEMENT_NODE:\n\t\tvar attrs = node.attributes;\n\t\tvar len = attrs.length;\n\t\tvar child = node.firstChild;\n\t\tvar nodeName = node.tagName;\n\t\t\n\t\tisHTML = NAMESPACE.isHTML(node.namespaceURI) || isHTML\n\n\t\tvar prefixedNodeName = nodeName\n\t\tif (!isHTML && !node.prefix && node.namespaceURI) {\n\t\t\tvar defaultNS\n\t\t\t// lookup current default ns from `xmlns` attribute\n\t\t\tfor (var ai = 0; ai < attrs.length; ai++) {\n\t\t\t\tif (attrs.item(ai).name === 'xmlns') {\n\t\t\t\t\tdefaultNS = attrs.item(ai).value\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!defaultNS) {\n\t\t\t\t// lookup current default ns in visibleNamespaces\n\t\t\t\tfor (var nsi = visibleNamespaces.length - 1; nsi >= 0; nsi--) {\n\t\t\t\t\tvar namespace = visibleNamespaces[nsi]\n\t\t\t\t\tif (namespace.prefix === '' && namespace.namespace === node.namespaceURI) {\n\t\t\t\t\t\tdefaultNS = namespace.namespace\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (defaultNS !== node.namespaceURI) {\n\t\t\t\tfor (var nsi = visibleNamespaces.length - 1; nsi >= 0; nsi--) {\n\t\t\t\t\tvar namespace = visibleNamespaces[nsi]\n\t\t\t\t\tif (namespace.namespace === node.namespaceURI) {\n\t\t\t\t\t\tif (namespace.prefix) {\n\t\t\t\t\t\t\tprefixedNodeName = namespace.prefix + ':' + nodeName\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tbuf.push('<', prefixedNodeName);\n\n\t\tfor(var i=0;i<len;i++){\n\t\t\t// add namespaces for attributes\n\t\t\tvar attr = attrs.item(i);\n\t\t\tif (attr.prefix == 'xmlns') {\n\t\t\t\tvisibleNamespaces.push({ prefix: attr.localName, namespace: attr.value });\n\t\t\t}else if(attr.nodeName == 'xmlns'){\n\t\t\t\tvisibleNamespaces.push({ prefix: '', namespace: attr.value });\n\t\t\t}\n\t\t}\n\n\t\tfor(var i=0;i<len;i++){\n\t\t\tvar attr = attrs.item(i);\n\t\t\tif (needNamespaceDefine(attr,isHTML, visibleNamespaces)) {\n\t\t\t\tvar prefix = attr.prefix||'';\n\t\t\t\tvar uri = attr.namespaceURI;\n\t\t\t\taddSerializedAttribute(buf, prefix ? 'xmlns:' + prefix : \"xmlns\", uri);\n\t\t\t\tvisibleNamespaces.push({ prefix: prefix, namespace:uri });\n\t\t\t}\n\t\t\tserializeToString(attr,buf,isHTML,nodeFilter,visibleNamespaces);\n\t\t}\n\n\t\t// add namespace for current node\t\t\n\t\tif (nodeName === prefixedNodeName && needNamespaceDefine(node, isHTML, visibleNamespaces)) {\n\t\t\tvar prefix = node.prefix||'';\n\t\t\tvar uri = node.namespaceURI;\n\t\t\taddSerializedAttribute(buf, prefix ? 'xmlns:' + prefix : \"xmlns\", uri);\n\t\t\tvisibleNamespaces.push({ prefix: prefix, namespace:uri });\n\t\t}\n\t\t\n\t\tif(child || isHTML && !/^(?:meta|link|img|br|hr|input)$/i.test(nodeName)){\n\t\t\tbuf.push('>');\n\t\t\t//if is cdata child node\n\t\t\tif(isHTML && /^script$/i.test(nodeName)){\n\t\t\t\twhile(child){\n\t\t\t\t\tif(child.data){\n\t\t\t\t\t\tbuf.push(child.data);\n\t\t\t\t\t}else{\n\t\t\t\t\t\tserializeToString(child, buf, isHTML, nodeFilter, visibleNamespaces.slice());\n\t\t\t\t\t}\n\t\t\t\t\tchild = child.nextSibling;\n\t\t\t\t}\n\t\t\t}else\n\t\t\t{\n\t\t\t\twhile(child){\n\t\t\t\t\tserializeToString(child, buf, isHTML, nodeFilter, visibleNamespaces.slice());\n\t\t\t\t\tchild = child.nextSibling;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbuf.push('</',prefixedNodeName,'>');\n\t\t}else{\n\t\t\tbuf.push('/>');\n\t\t}\n\t\t// remove added visible namespaces\n\t\t//visibleNamespaces.length = startVisibleNamespaces;\n\t\treturn;\n\tcase DOCUMENT_NODE:\n\tcase DOCUMENT_FRAGMENT_NODE:\n\t\tvar child = node.firstChild;\n\t\twhile(child){\n\t\t\tserializeToString(child, buf, isHTML, nodeFilter, visibleNamespaces.slice());\n\t\t\tchild = child.nextSibling;\n\t\t}\n\t\treturn;\n\tcase ATTRIBUTE_NODE:\n\t\treturn addSerializedAttribute(buf, node.name, node.value);\n\tcase TEXT_NODE:\n\t\t/**\n\t\t * The ampersand character (&) and the left angle bracket (<) must not appear in their literal form,\n\t\t * except when used as markup delimiters, or within a comment, a processing instruction, or a CDATA section.\n\t\t * If they are needed elsewhere, they must be escaped using either numeric character references or the strings\n\t\t * `&amp;` and `&lt;` respectively.\n\t\t * The right angle bracket (>) may be represented using the string \" &gt; \", and must, for compatibility,\n\t\t * be escaped using either `&gt;` or a character reference when it appears in the string `]]>` in content,\n\t\t * when that string is not marking the end of a CDATA section.\n\t\t *\n\t\t * In the content of elements, character data is any string of characters\n\t\t * which does not contain the start-delimiter of any markup\n\t\t * and does not include the CDATA-section-close delimiter, `]]>`.\n\t\t *\n\t\t * @see https://www.w3.org/TR/xml/#NT-CharData\n\t\t */\n\t\treturn buf.push(node.data\n\t\t\t.replace(/[<&]/g,_xmlEncoder)\n\t\t\t.replace(/]]>/g, ']]&gt;')\n\t\t);\n\tcase CDATA_SECTION_NODE:\n\t\treturn buf.push( '<![CDATA[',node.data,']]>');\n\tcase COMMENT_NODE:\n\t\treturn buf.push( \"<!--\",node.data,\"-->\");\n\tcase DOCUMENT_TYPE_NODE:\n\t\tvar pubid = node.publicId;\n\t\tvar sysid = node.systemId;\n\t\tbuf.push('<!DOCTYPE ',node.name);\n\t\tif(pubid){\n\t\t\tbuf.push(' PUBLIC ', pubid);\n\t\t\tif (sysid && sysid!='.') {\n\t\t\t\tbuf.push(' ', sysid);\n\t\t\t}\n\t\t\tbuf.push('>');\n\t\t}else if(sysid && sysid!='.'){\n\t\t\tbuf.push(' SYSTEM ', sysid, '>');\n\t\t}else{\n\t\t\tvar sub = node.internalSubset;\n\t\t\tif(sub){\n\t\t\t\tbuf.push(\" [\",sub,\"]\");\n\t\t\t}\n\t\t\tbuf.push(\">\");\n\t\t}\n\t\treturn;\n\tcase PROCESSING_INSTRUCTION_NODE:\n\t\treturn buf.push( \"<?\",node.target,\" \",node.data,\"?>\");\n\tcase ENTITY_REFERENCE_NODE:\n\t\treturn buf.push( '&',node.nodeName,';');\n\t//case ENTITY_NODE:\n\t//case NOTATION_NODE:\n\tdefault:\n\t\tbuf.push('??',node.nodeName);\n\t}\n}\nfunction importNode(doc,node,deep){\n\tvar node2;\n\tswitch (node.nodeType) {\n\tcase ELEMENT_NODE:\n\t\tnode2 = node.cloneNode(false);\n\t\tnode2.ownerDocument = doc;\n\t\t//var attrs = node2.attributes;\n\t\t//var len = attrs.length;\n\t\t//for(var i=0;i<len;i++){\n\t\t\t//node2.setAttributeNodeNS(importNode(doc,attrs.item(i),deep));\n\t\t//}\n\tcase DOCUMENT_FRAGMENT_NODE:\n\t\tbreak;\n\tcase ATTRIBUTE_NODE:\n\t\tdeep = true;\n\t\tbreak;\n\t//case ENTITY_REFERENCE_NODE:\n\t//case PROCESSING_INSTRUCTION_NODE:\n\t////case TEXT_NODE:\n\t//case CDATA_SECTION_NODE:\n\t//case COMMENT_NODE:\n\t//\tdeep = false;\n\t//\tbreak;\n\t//case DOCUMENT_NODE:\n\t//case DOCUMENT_TYPE_NODE:\n\t//cannot be imported.\n\t//case ENTITY_NODE:\n\t//case NOTATION_NODE：\n\t//can not hit in level3\n\t//default:throw e;\n\t}\n\tif(!node2){\n\t\tnode2 = node.cloneNode(false);//false\n\t}\n\tnode2.ownerDocument = doc;\n\tnode2.parentNode = null;\n\tif(deep){\n\t\tvar child = node.firstChild;\n\t\twhile(child){\n\t\t\tnode2.appendChild(importNode(doc,child,deep));\n\t\t\tchild = child.nextSibling;\n\t\t}\n\t}\n\treturn node2;\n}\n//\n//var _relationMap = {firstChild:1,lastChild:1,previousSibling:1,nextSibling:1,\n//\t\t\t\t\tattributes:1,childNodes:1,parentNode:1,documentElement:1,doctype,};\nfunction cloneNode(doc,node,deep){\n\tvar node2 = new node.constructor();\n\tfor(var n in node){\n\t\tvar v = node[n];\n\t\tif(typeof v != 'object' ){\n\t\t\tif(v != node2[n]){\n\t\t\t\tnode2[n] = v;\n\t\t\t}\n\t\t}\n\t}\n\tif(node.childNodes){\n\t\tnode2.childNodes = new NodeList();\n\t}\n\tnode2.ownerDocument = doc;\n\tswitch (node2.nodeType) {\n\tcase ELEMENT_NODE:\n\t\tvar attrs\t= node.attributes;\n\t\tvar attrs2\t= node2.attributes = new NamedNodeMap();\n\t\tvar len = attrs.length\n\t\tattrs2._ownerElement = node2;\n\t\tfor(var i=0;i<len;i++){\n\t\t\tnode2.setAttributeNode(cloneNode(doc,attrs.item(i),true));\n\t\t}\n\t\tbreak;;\n\tcase ATTRIBUTE_NODE:\n\t\tdeep = true;\n\t}\n\tif(deep){\n\t\tvar child = node.firstChild;\n\t\twhile(child){\n\t\t\tnode2.appendChild(cloneNode(doc,child,deep));\n\t\t\tchild = child.nextSibling;\n\t\t}\n\t}\n\treturn node2;\n}\n\nfunction __set__(object,key,value){\n\tobject[key] = value\n}\n//do dynamic\ntry{\n\tif(Object.defineProperty){\n\t\tObject.defineProperty(LiveNodeList.prototype,'length',{\n\t\t\tget:function(){\n\t\t\t\t_updateLiveList(this);\n\t\t\t\treturn this.$$length;\n\t\t\t}\n\t\t});\n\n\t\tObject.defineProperty(Node.prototype,'textContent',{\n\t\t\tget:function(){\n\t\t\t\treturn getTextContent(this);\n\t\t\t},\n\n\t\t\tset:function(data){\n\t\t\t\tswitch(this.nodeType){\n\t\t\t\tcase ELEMENT_NODE:\n\t\t\t\tcase DOCUMENT_FRAGMENT_NODE:\n\t\t\t\t\twhile(this.firstChild){\n\t\t\t\t\t\tthis.removeChild(this.firstChild);\n\t\t\t\t\t}\n\t\t\t\t\tif(data || String(data)){\n\t\t\t\t\t\tthis.appendChild(this.ownerDocument.createTextNode(data));\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tthis.data = data;\n\t\t\t\t\tthis.value = data;\n\t\t\t\t\tthis.nodeValue = data;\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t\t\n\t\tfunction getTextContent(node){\n\t\t\tswitch(node.nodeType){\n\t\t\tcase ELEMENT_NODE:\n\t\t\tcase DOCUMENT_FRAGMENT_NODE:\n\t\t\t\tvar buf = [];\n\t\t\t\tnode = node.firstChild;\n\t\t\t\twhile(node){\n\t\t\t\t\tif(node.nodeType!==7 && node.nodeType !==8){\n\t\t\t\t\t\tbuf.push(getTextContent(node));\n\t\t\t\t\t}\n\t\t\t\t\tnode = node.nextSibling;\n\t\t\t\t}\n\t\t\t\treturn buf.join('');\n\t\t\tdefault:\n\t\t\t\treturn node.nodeValue;\n\t\t\t}\n\t\t}\n\n\t\t__set__ = function(object,key,value){\n\t\t\t//console.log(value)\n\t\t\tobject['$$'+key] = value\n\t\t}\n\t}\n}catch(e){//ie8\n}\n\n//if(typeof require == 'function'){\n\texports.DocumentType = DocumentType;\n\texports.DOMException = DOMException;\n\texports.DOMImplementation = DOMImplementation;\n\texports.Element = Element;\n\texports.Node = Node;\n\texports.NodeList = NodeList;\n\texports.XMLSerializer = XMLSerializer;\n//}\n","var freeze = require('./conventions').freeze;\n\n/**\n * The entities that are predefined in every XML document.\n *\n * @see https://www.w3.org/TR/2006/REC-xml11-20060816/#sec-predefined-ent W3C XML 1.1\n * @see https://www.w3.org/TR/2008/REC-xml-20081126/#sec-predefined-ent W3C XML 1.0\n * @see https://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references#Predefined_entities_in_XML Wikipedia\n */\nexports.XML_ENTITIES = freeze({amp:'&', apos:\"'\", gt:'>', lt:'<', quot:'\"'})\n\n/**\n * A map of currently 241 entities that are detected in an HTML document.\n * They contain all entries from `XML_ENTITIES`.\n *\n * @see XML_ENTITIES\n * @see DOMParser.parseFromString\n * @see DOMImplementation.prototype.createHTMLDocument\n * @see https://html.spec.whatwg.org/#named-character-references WHATWG HTML(5) Spec\n * @see https://www.w3.org/TR/xml-entity-names/ W3C XML Entity Names\n * @see https://www.w3.org/TR/html4/sgml/entities.html W3C HTML4/SGML\n * @see https://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references#Character_entity_references_in_HTML Wikipedia (HTML)\n * @see https://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references#Entities_representing_special_characters_in_XHTML Wikpedia (XHTML)\n */\nexports.HTML_ENTITIES = freeze({\n       lt: '<',\n       gt: '>',\n       amp: '&',\n       quot: '\"',\n       apos: \"'\",\n       Agrave: \"À\",\n       Aacute: \"Á\",\n       Acirc: \"Â\",\n       Atilde: \"Ã\",\n       Auml: \"Ä\",\n       Aring: \"Å\",\n       AElig: \"Æ\",\n       Ccedil: \"Ç\",\n       Egrave: \"È\",\n       Eacute: \"É\",\n       Ecirc: \"Ê\",\n       Euml: \"Ë\",\n       Igrave: \"Ì\",\n       Iacute: \"Í\",\n       Icirc: \"Î\",\n       Iuml: \"Ï\",\n       ETH: \"Ð\",\n       Ntilde: \"Ñ\",\n       Ograve: \"Ò\",\n       Oacute: \"Ó\",\n       Ocirc: \"Ô\",\n       Otilde: \"Õ\",\n       Ouml: \"Ö\",\n       Oslash: \"Ø\",\n       Ugrave: \"Ù\",\n       Uacute: \"Ú\",\n       Ucirc: \"Û\",\n       Uuml: \"Ü\",\n       Yacute: \"Ý\",\n       THORN: \"Þ\",\n       szlig: \"ß\",\n       agrave: \"à\",\n       aacute: \"á\",\n       acirc: \"â\",\n       atilde: \"ã\",\n       auml: \"ä\",\n       aring: \"å\",\n       aelig: \"æ\",\n       ccedil: \"ç\",\n       egrave: \"è\",\n       eacute: \"é\",\n       ecirc: \"ê\",\n       euml: \"ë\",\n       igrave: \"ì\",\n       iacute: \"í\",\n       icirc: \"î\",\n       iuml: \"ï\",\n       eth: \"ð\",\n       ntilde: \"ñ\",\n       ograve: \"ò\",\n       oacute: \"ó\",\n       ocirc: \"ô\",\n       otilde: \"õ\",\n       ouml: \"ö\",\n       oslash: \"ø\",\n       ugrave: \"ù\",\n       uacute: \"ú\",\n       ucirc: \"û\",\n       uuml: \"ü\",\n       yacute: \"ý\",\n       thorn: \"þ\",\n       yuml: \"ÿ\",\n       nbsp: \"\\u00a0\",\n       iexcl: \"¡\",\n       cent: \"¢\",\n       pound: \"£\",\n       curren: \"¤\",\n       yen: \"¥\",\n       brvbar: \"¦\",\n       sect: \"§\",\n       uml: \"¨\",\n       copy: \"©\",\n       ordf: \"ª\",\n       laquo: \"«\",\n       not: \"¬\",\n       shy: \"­­\",\n       reg: \"®\",\n       macr: \"¯\",\n       deg: \"°\",\n       plusmn: \"±\",\n       sup2: \"²\",\n       sup3: \"³\",\n       acute: \"´\",\n       micro: \"µ\",\n       para: \"¶\",\n       middot: \"·\",\n       cedil: \"¸\",\n       sup1: \"¹\",\n       ordm: \"º\",\n       raquo: \"»\",\n       frac14: \"¼\",\n       frac12: \"½\",\n       frac34: \"¾\",\n       iquest: \"¿\",\n       times: \"×\",\n       divide: \"÷\",\n       forall: \"∀\",\n       part: \"∂\",\n       exist: \"∃\",\n       empty: \"∅\",\n       nabla: \"∇\",\n       isin: \"∈\",\n       notin: \"∉\",\n       ni: \"∋\",\n       prod: \"∏\",\n       sum: \"∑\",\n       minus: \"−\",\n       lowast: \"∗\",\n       radic: \"√\",\n       prop: \"∝\",\n       infin: \"∞\",\n       ang: \"∠\",\n       and: \"∧\",\n       or: \"∨\",\n       cap: \"∩\",\n       cup: \"∪\",\n       'int': \"∫\",\n       there4: \"∴\",\n       sim: \"∼\",\n       cong: \"≅\",\n       asymp: \"≈\",\n       ne: \"≠\",\n       equiv: \"≡\",\n       le: \"≤\",\n       ge: \"≥\",\n       sub: \"⊂\",\n       sup: \"⊃\",\n       nsub: \"⊄\",\n       sube: \"⊆\",\n       supe: \"⊇\",\n       oplus: \"⊕\",\n       otimes: \"⊗\",\n       perp: \"⊥\",\n       sdot: \"⋅\",\n       Alpha: \"Α\",\n       Beta: \"Β\",\n       Gamma: \"Γ\",\n       Delta: \"Δ\",\n       Epsilon: \"Ε\",\n       Zeta: \"Ζ\",\n       Eta: \"Η\",\n       Theta: \"Θ\",\n       Iota: \"Ι\",\n       Kappa: \"Κ\",\n       Lambda: \"Λ\",\n       Mu: \"Μ\",\n       Nu: \"Ν\",\n       Xi: \"Ξ\",\n       Omicron: \"Ο\",\n       Pi: \"Π\",\n       Rho: \"Ρ\",\n       Sigma: \"Σ\",\n       Tau: \"Τ\",\n       Upsilon: \"Υ\",\n       Phi: \"Φ\",\n       Chi: \"Χ\",\n       Psi: \"Ψ\",\n       Omega: \"Ω\",\n       alpha: \"α\",\n       beta: \"β\",\n       gamma: \"γ\",\n       delta: \"δ\",\n       epsilon: \"ε\",\n       zeta: \"ζ\",\n       eta: \"η\",\n       theta: \"θ\",\n       iota: \"ι\",\n       kappa: \"κ\",\n       lambda: \"λ\",\n       mu: \"μ\",\n       nu: \"ν\",\n       xi: \"ξ\",\n       omicron: \"ο\",\n       pi: \"π\",\n       rho: \"ρ\",\n       sigmaf: \"ς\",\n       sigma: \"σ\",\n       tau: \"τ\",\n       upsilon: \"υ\",\n       phi: \"φ\",\n       chi: \"χ\",\n       psi: \"ψ\",\n       omega: \"ω\",\n       thetasym: \"ϑ\",\n       upsih: \"ϒ\",\n       piv: \"ϖ\",\n       OElig: \"Œ\",\n       oelig: \"œ\",\n       Scaron: \"Š\",\n       scaron: \"š\",\n       Yuml: \"Ÿ\",\n       fnof: \"ƒ\",\n       circ: \"ˆ\",\n       tilde: \"˜\",\n       ensp: \" \",\n       emsp: \" \",\n       thinsp: \" \",\n       zwnj: \"‌\",\n       zwj: \"‍\",\n       lrm: \"‎\",\n       rlm: \"‏\",\n       ndash: \"–\",\n       mdash: \"—\",\n       lsquo: \"‘\",\n       rsquo: \"’\",\n       sbquo: \"‚\",\n       ldquo: \"“\",\n       rdquo: \"”\",\n       bdquo: \"„\",\n       dagger: \"†\",\n       Dagger: \"‡\",\n       bull: \"•\",\n       hellip: \"…\",\n       permil: \"‰\",\n       prime: \"′\",\n       Prime: \"″\",\n       lsaquo: \"‹\",\n       rsaquo: \"›\",\n       oline: \"‾\",\n       euro: \"€\",\n       trade: \"™\",\n       larr: \"←\",\n       uarr: \"↑\",\n       rarr: \"→\",\n       darr: \"↓\",\n       harr: \"↔\",\n       crarr: \"↵\",\n       lceil: \"⌈\",\n       rceil: \"⌉\",\n       lfloor: \"⌊\",\n       rfloor: \"⌋\",\n       loz: \"◊\",\n       spades: \"♠\",\n       clubs: \"♣\",\n       hearts: \"♥\",\n       diams: \"♦\"\n});\n\n/**\n * @deprecated use `HTML_ENTITIES` instead\n * @see HTML_ENTITIES\n */\nexports.entityMap = exports.HTML_ENTITIES\n","var dom = require('./dom')\nexports.DOMImplementation = dom.DOMImplementation\nexports.XMLSerializer = dom.XMLSerializer\nexports.DOMParser = require('./dom-parser').DOMParser\n","var NAMESPACE = require(\"./conventions\").NAMESPACE;\n\n//[4]   \tNameStartChar\t   ::=   \t\":\" | [A-Z] | \"_\" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]\n//[4a]   \tNameChar\t   ::=   \tNameStartChar | \"-\" | \".\" | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]\n//[5]   \tName\t   ::=   \tNameStartChar (NameChar)*\nvar nameStartChar = /[A-Z_a-z\\xC0-\\xD6\\xD8-\\xF6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD]///\\u10000-\\uEFFFF\nvar nameChar = new RegExp(\"[\\\\-\\\\.0-9\"+nameStartChar.source.slice(1,-1)+\"\\\\u00B7\\\\u0300-\\\\u036F\\\\u203F-\\\\u2040]\");\nvar tagNamePattern = new RegExp('^'+nameStartChar.source+nameChar.source+'*(?:\\:'+nameStartChar.source+nameChar.source+'*)?$');\n//var tagNamePattern = /^[a-zA-Z_][\\w\\-\\.]*(?:\\:[a-zA-Z_][\\w\\-\\.]*)?$/\n//var handlers = 'resolveEntity,getExternalSubset,characters,endDocument,endElement,endPrefixMapping,ignorableWhitespace,processingInstruction,setDocumentLocator,skippedEntity,startDocument,startElement,startPrefixMapping,notationDecl,unparsedEntityDecl,error,fatalError,warning,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,comment,endCDATA,endDTD,endEntity,startCDATA,startDTD,startEntity'.split(',')\n\n//S_TAG,\tS_ATTR,\tS_EQ,\tS_ATTR_NOQUOT_VALUE\n//S_ATTR_SPACE,\tS_ATTR_END,\tS_TAG_SPACE, S_TAG_CLOSE\nvar S_TAG = 0;//tag name offerring\nvar S_ATTR = 1;//attr name offerring \nvar S_ATTR_SPACE=2;//attr name end and space offer\nvar S_EQ = 3;//=space?\nvar S_ATTR_NOQUOT_VALUE = 4;//attr value(no quot value only)\nvar S_ATTR_END = 5;//attr value end and no space(quot end)\nvar S_TAG_SPACE = 6;//(attr value end || tag end ) && (space offer)\nvar S_TAG_CLOSE = 7;//closed el<el />\n\n/**\n * Creates an error that will not be caught by XMLReader aka the SAX parser.\n *\n * @param {string} message\n * @param {any?} locator Optional, can provide details about the location in the source\n * @constructor\n */\nfunction ParseError(message, locator) {\n\tthis.message = message\n\tthis.locator = locator\n\tif(Error.captureStackTrace) Error.captureStackTrace(this, ParseError);\n}\nParseError.prototype = new Error();\nParseError.prototype.name = ParseError.name\n\nfunction XMLReader(){\n\t\n}\n\nXMLReader.prototype = {\n\tparse:function(source,defaultNSMap,entityMap){\n\t\tvar domBuilder = this.domBuilder;\n\t\tdomBuilder.startDocument();\n\t\t_copy(defaultNSMap ,defaultNSMap = {})\n\t\tparse(source,defaultNSMap,entityMap,\n\t\t\t\tdomBuilder,this.errorHandler);\n\t\tdomBuilder.endDocument();\n\t}\n}\nfunction parse(source,defaultNSMapCopy,entityMap,domBuilder,errorHandler){\n\tfunction fixedFromCharCode(code) {\n\t\t// String.prototype.fromCharCode does not supports\n\t\t// > 2 bytes unicode chars directly\n\t\tif (code > 0xffff) {\n\t\t\tcode -= 0x10000;\n\t\t\tvar surrogate1 = 0xd800 + (code >> 10)\n\t\t\t\t, surrogate2 = 0xdc00 + (code & 0x3ff);\n\n\t\t\treturn String.fromCharCode(surrogate1, surrogate2);\n\t\t} else {\n\t\t\treturn String.fromCharCode(code);\n\t\t}\n\t}\n\tfunction entityReplacer(a){\n\t\tvar k = a.slice(1,-1);\n\t\tif(k in entityMap){\n\t\t\treturn entityMap[k]; \n\t\t}else if(k.charAt(0) === '#'){\n\t\t\treturn fixedFromCharCode(parseInt(k.substr(1).replace('x','0x')))\n\t\t}else{\n\t\t\terrorHandler.error('entity not found:'+a);\n\t\t\treturn a;\n\t\t}\n\t}\n\tfunction appendText(end){//has some bugs\n\t\tif(end>start){\n\t\t\tvar xt = source.substring(start,end).replace(/&#?\\w+;/g,entityReplacer);\n\t\t\tlocator&&position(start);\n\t\t\tdomBuilder.characters(xt,0,end-start);\n\t\t\tstart = end\n\t\t}\n\t}\n\tfunction position(p,m){\n\t\twhile(p>=lineEnd && (m = linePattern.exec(source))){\n\t\t\tlineStart = m.index;\n\t\t\tlineEnd = lineStart + m[0].length;\n\t\t\tlocator.lineNumber++;\n\t\t\t//console.log('line++:',locator,startPos,endPos)\n\t\t}\n\t\tlocator.columnNumber = p-lineStart+1;\n\t}\n\tvar lineStart = 0;\n\tvar lineEnd = 0;\n\tvar linePattern = /.*(?:\\r\\n?|\\n)|.*$/g\n\tvar locator = domBuilder.locator;\n\t\n\tvar parseStack = [{currentNSMap:defaultNSMapCopy}]\n\tvar closeMap = {};\n\tvar start = 0;\n\twhile(true){\n\t\ttry{\n\t\t\tvar tagStart = source.indexOf('<',start);\n\t\t\tif(tagStart<0){\n\t\t\t\tif(!source.substr(start).match(/^\\s*$/)){\n\t\t\t\t\tvar doc = domBuilder.doc;\n\t    \t\t\tvar text = doc.createTextNode(source.substr(start));\n\t    \t\t\tdoc.appendChild(text);\n\t    \t\t\tdomBuilder.currentElement = text;\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif(tagStart>start){\n\t\t\t\tappendText(tagStart);\n\t\t\t}\n\t\t\tswitch(source.charAt(tagStart+1)){\n\t\t\tcase '/':\n\t\t\t\tvar end = source.indexOf('>',tagStart+3);\n\t\t\t\tvar tagName = source.substring(tagStart + 2, end).replace(/[ \\t\\n\\r]+$/g, '');\n\t\t\t\tvar config = parseStack.pop();\n\t\t\t\tif(end<0){\n\t\t\t\t\t\n\t        \t\ttagName = source.substring(tagStart+2).replace(/[\\s<].*/,'');\n\t        \t\terrorHandler.error(\"end tag name: \"+tagName+' is not complete:'+config.tagName);\n\t        \t\tend = tagStart+1+tagName.length;\n\t        \t}else if(tagName.match(/\\s</)){\n\t        \t\ttagName = tagName.replace(/[\\s<].*/,'');\n\t        \t\terrorHandler.error(\"end tag name: \"+tagName+' maybe not complete');\n\t        \t\tend = tagStart+1+tagName.length;\n\t\t\t\t}\n\t\t\t\tvar localNSMap = config.localNSMap;\n\t\t\t\tvar endMatch = config.tagName == tagName;\n\t\t\t\tvar endIgnoreCaseMach = endMatch || config.tagName&&config.tagName.toLowerCase() == tagName.toLowerCase()\n\t\t        if(endIgnoreCaseMach){\n\t\t        \tdomBuilder.endElement(config.uri,config.localName,tagName);\n\t\t\t\t\tif(localNSMap){\n\t\t\t\t\t\tfor(var prefix in localNSMap){\n\t\t\t\t\t\t\tdomBuilder.endPrefixMapping(prefix) ;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif(!endMatch){\n\t\t            \terrorHandler.fatalError(\"end tag name: \"+tagName+' is not match the current start tagName:'+config.tagName ); // No known test case\n\t\t\t\t\t}\n\t\t        }else{\n\t\t        \tparseStack.push(config)\n\t\t        }\n\t\t\t\t\n\t\t\t\tend++;\n\t\t\t\tbreak;\n\t\t\t\t// end elment\n\t\t\tcase '?':// <?...?>\n\t\t\t\tlocator&&position(tagStart);\n\t\t\t\tend = parseInstruction(source,tagStart,domBuilder);\n\t\t\t\tbreak;\n\t\t\tcase '!':// <!doctype,<![CDATA,<!--\n\t\t\t\tlocator&&position(tagStart);\n\t\t\t\tend = parseDCC(source,tagStart,domBuilder,errorHandler);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tlocator&&position(tagStart);\n\t\t\t\tvar el = new ElementAttributes();\n\t\t\t\tvar currentNSMap = parseStack[parseStack.length-1].currentNSMap;\n\t\t\t\t//elStartEnd\n\t\t\t\tvar end = parseElementStartPart(source,tagStart,el,currentNSMap,entityReplacer,errorHandler);\n\t\t\t\tvar len = el.length;\n\t\t\t\t\n\t\t\t\t\n\t\t\t\tif(!el.closed && fixSelfClosed(source,end,el.tagName,closeMap)){\n\t\t\t\t\tel.closed = true;\n\t\t\t\t\tif(!entityMap.nbsp){\n\t\t\t\t\t\terrorHandler.warning('unclosed xml attribute');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif(locator && len){\n\t\t\t\t\tvar locator2 = copyLocator(locator,{});\n\t\t\t\t\t//try{//attribute position fixed\n\t\t\t\t\tfor(var i = 0;i<len;i++){\n\t\t\t\t\t\tvar a = el[i];\n\t\t\t\t\t\tposition(a.offset);\n\t\t\t\t\t\ta.locator = copyLocator(locator,{});\n\t\t\t\t\t}\n\t\t\t\t\tdomBuilder.locator = locator2\n\t\t\t\t\tif(appendElement(el,domBuilder,currentNSMap)){\n\t\t\t\t\t\tparseStack.push(el)\n\t\t\t\t\t}\n\t\t\t\t\tdomBuilder.locator = locator;\n\t\t\t\t}else{\n\t\t\t\t\tif(appendElement(el,domBuilder,currentNSMap)){\n\t\t\t\t\t\tparseStack.push(el)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (NAMESPACE.isHTML(el.uri) && !el.closed) {\n\t\t\t\t\tend = parseHtmlSpecialContent(source,end,el.tagName,entityReplacer,domBuilder)\n\t\t\t\t} else {\n\t\t\t\t\tend++;\n\t\t\t\t}\n\t\t\t}\n\t\t}catch(e){\n\t\t\tif (e instanceof ParseError) {\n\t\t\t\tthrow e;\n\t\t\t}\n\t\t\terrorHandler.error('element parse error: '+e)\n\t\t\tend = -1;\n\t\t}\n\t\tif(end>start){\n\t\t\tstart = end;\n\t\t}else{\n\t\t\t//TODO: 这里有可能sax回退，有位置错误风险\n\t\t\tappendText(Math.max(tagStart,start)+1);\n\t\t}\n\t}\n}\nfunction copyLocator(f,t){\n\tt.lineNumber = f.lineNumber;\n\tt.columnNumber = f.columnNumber;\n\treturn t;\n}\n\n/**\n * @see #appendElement(source,elStartEnd,el,selfClosed,entityReplacer,domBuilder,parseStack);\n * @return end of the elementStartPart(end of elementEndPart for selfClosed el)\n */\nfunction parseElementStartPart(source,start,el,currentNSMap,entityReplacer,errorHandler){\n\n\t/**\n\t * @param {string} qname\n\t * @param {string} value\n\t * @param {number} startIndex\n\t */\n\tfunction addAttribute(qname, value, startIndex) {\n\t\tif (el.attributeNames.hasOwnProperty(qname)) {\n\t\t\terrorHandler.fatalError('Attribute ' + qname + ' redefined')\n\t\t}\n\t\tel.addValue(qname, value, startIndex)\n\t}\n\tvar attrName;\n\tvar value;\n\tvar p = ++start;\n\tvar s = S_TAG;//status\n\twhile(true){\n\t\tvar c = source.charAt(p);\n\t\tswitch(c){\n\t\tcase '=':\n\t\t\tif(s === S_ATTR){//attrName\n\t\t\t\tattrName = source.slice(start,p);\n\t\t\t\ts = S_EQ;\n\t\t\t}else if(s === S_ATTR_SPACE){\n\t\t\t\ts = S_EQ;\n\t\t\t}else{\n\t\t\t\t//fatalError: equal must after attrName or space after attrName\n\t\t\t\tthrow new Error('attribute equal must after attrName'); // No known test case\n\t\t\t}\n\t\t\tbreak;\n\t\tcase '\\'':\n\t\tcase '\"':\n\t\t\tif(s === S_EQ || s === S_ATTR //|| s == S_ATTR_SPACE\n\t\t\t\t){//equal\n\t\t\t\tif(s === S_ATTR){\n\t\t\t\t\terrorHandler.warning('attribute value must after \"=\"')\n\t\t\t\t\tattrName = source.slice(start,p)\n\t\t\t\t}\n\t\t\t\tstart = p+1;\n\t\t\t\tp = source.indexOf(c,start)\n\t\t\t\tif(p>0){\n\t\t\t\t\tvalue = source.slice(start,p).replace(/&#?\\w+;/g,entityReplacer);\n\t\t\t\t\taddAttribute(attrName, value, start-1);\n\t\t\t\t\ts = S_ATTR_END;\n\t\t\t\t}else{\n\t\t\t\t\t//fatalError: no end quot match\n\t\t\t\t\tthrow new Error('attribute value no end \\''+c+'\\' match');\n\t\t\t\t}\n\t\t\t}else if(s == S_ATTR_NOQUOT_VALUE){\n\t\t\t\tvalue = source.slice(start,p).replace(/&#?\\w+;/g,entityReplacer);\n\t\t\t\t//console.log(attrName,value,start,p)\n\t\t\t\taddAttribute(attrName, value, start);\n\t\t\t\t//console.dir(el)\n\t\t\t\terrorHandler.warning('attribute \"'+attrName+'\" missed start quot('+c+')!!');\n\t\t\t\tstart = p+1;\n\t\t\t\ts = S_ATTR_END\n\t\t\t}else{\n\t\t\t\t//fatalError: no equal before\n\t\t\t\tthrow new Error('attribute value must after \"=\"'); // No known test case\n\t\t\t}\n\t\t\tbreak;\n\t\tcase '/':\n\t\t\tswitch(s){\n\t\t\tcase S_TAG:\n\t\t\t\tel.setTagName(source.slice(start,p));\n\t\t\tcase S_ATTR_END:\n\t\t\tcase S_TAG_SPACE:\n\t\t\tcase S_TAG_CLOSE:\n\t\t\t\ts =S_TAG_CLOSE;\n\t\t\t\tel.closed = true;\n\t\t\tcase S_ATTR_NOQUOT_VALUE:\n\t\t\tcase S_ATTR:\n\t\t\tcase S_ATTR_SPACE:\n\t\t\t\tbreak;\n\t\t\t//case S_EQ:\n\t\t\tdefault:\n\t\t\t\tthrow new Error(\"attribute invalid close char('/')\") // No known test case\n\t\t\t}\n\t\t\tbreak;\n\t\tcase ''://end document\n\t\t\terrorHandler.error('unexpected end of input');\n\t\t\tif(s == S_TAG){\n\t\t\t\tel.setTagName(source.slice(start,p));\n\t\t\t}\n\t\t\treturn p;\n\t\tcase '>':\n\t\t\tswitch(s){\n\t\t\tcase S_TAG:\n\t\t\t\tel.setTagName(source.slice(start,p));\n\t\t\tcase S_ATTR_END:\n\t\t\tcase S_TAG_SPACE:\n\t\t\tcase S_TAG_CLOSE:\n\t\t\t\tbreak;//normal\n\t\t\tcase S_ATTR_NOQUOT_VALUE://Compatible state\n\t\t\tcase S_ATTR:\n\t\t\t\tvalue = source.slice(start,p);\n\t\t\t\tif(value.slice(-1) === '/'){\n\t\t\t\t\tel.closed  = true;\n\t\t\t\t\tvalue = value.slice(0,-1)\n\t\t\t\t}\n\t\t\tcase S_ATTR_SPACE:\n\t\t\t\tif(s === S_ATTR_SPACE){\n\t\t\t\t\tvalue = attrName;\n\t\t\t\t}\n\t\t\t\tif(s == S_ATTR_NOQUOT_VALUE){\n\t\t\t\t\terrorHandler.warning('attribute \"'+value+'\" missed quot(\")!');\n\t\t\t\t\taddAttribute(attrName, value.replace(/&#?\\w+;/g,entityReplacer), start)\n\t\t\t\t}else{\n\t\t\t\t\tif(!NAMESPACE.isHTML(currentNSMap['']) || !value.match(/^(?:disabled|checked|selected)$/i)){\n\t\t\t\t\t\terrorHandler.warning('attribute \"'+value+'\" missed value!! \"'+value+'\" instead!!')\n\t\t\t\t\t}\n\t\t\t\t\taddAttribute(value, value, start)\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase S_EQ:\n\t\t\t\tthrow new Error('attribute value missed!!');\n\t\t\t}\n//\t\t\tconsole.log(tagName,tagNamePattern,tagNamePattern.test(tagName))\n\t\t\treturn p;\n\t\t/*xml space '\\x20' | #x9 | #xD | #xA; */\n\t\tcase '\\u0080':\n\t\t\tc = ' ';\n\t\tdefault:\n\t\t\tif(c<= ' '){//space\n\t\t\t\tswitch(s){\n\t\t\t\tcase S_TAG:\n\t\t\t\t\tel.setTagName(source.slice(start,p));//tagName\n\t\t\t\t\ts = S_TAG_SPACE;\n\t\t\t\t\tbreak;\n\t\t\t\tcase S_ATTR:\n\t\t\t\t\tattrName = source.slice(start,p)\n\t\t\t\t\ts = S_ATTR_SPACE;\n\t\t\t\t\tbreak;\n\t\t\t\tcase S_ATTR_NOQUOT_VALUE:\n\t\t\t\t\tvar value = source.slice(start,p).replace(/&#?\\w+;/g,entityReplacer);\n\t\t\t\t\terrorHandler.warning('attribute \"'+value+'\" missed quot(\")!!');\n\t\t\t\t\taddAttribute(attrName, value, start)\n\t\t\t\tcase S_ATTR_END:\n\t\t\t\t\ts = S_TAG_SPACE;\n\t\t\t\t\tbreak;\n\t\t\t\t//case S_TAG_SPACE:\n\t\t\t\t//case S_EQ:\n\t\t\t\t//case S_ATTR_SPACE:\n\t\t\t\t//\tvoid();break;\n\t\t\t\t//case S_TAG_CLOSE:\n\t\t\t\t\t//ignore warning\n\t\t\t\t}\n\t\t\t}else{//not space\n//S_TAG,\tS_ATTR,\tS_EQ,\tS_ATTR_NOQUOT_VALUE\n//S_ATTR_SPACE,\tS_ATTR_END,\tS_TAG_SPACE, S_TAG_CLOSE\n\t\t\t\tswitch(s){\n\t\t\t\t//case S_TAG:void();break;\n\t\t\t\t//case S_ATTR:void();break;\n\t\t\t\t//case S_ATTR_NOQUOT_VALUE:void();break;\n\t\t\t\tcase S_ATTR_SPACE:\n\t\t\t\t\tvar tagName =  el.tagName;\n\t\t\t\t\tif (!NAMESPACE.isHTML(currentNSMap['']) || !attrName.match(/^(?:disabled|checked|selected)$/i)) {\n\t\t\t\t\t\terrorHandler.warning('attribute \"'+attrName+'\" missed value!! \"'+attrName+'\" instead2!!')\n\t\t\t\t\t}\n\t\t\t\t\taddAttribute(attrName, attrName, start);\n\t\t\t\t\tstart = p;\n\t\t\t\t\ts = S_ATTR;\n\t\t\t\t\tbreak;\n\t\t\t\tcase S_ATTR_END:\n\t\t\t\t\terrorHandler.warning('attribute space is required\"'+attrName+'\"!!')\n\t\t\t\tcase S_TAG_SPACE:\n\t\t\t\t\ts = S_ATTR;\n\t\t\t\t\tstart = p;\n\t\t\t\t\tbreak;\n\t\t\t\tcase S_EQ:\n\t\t\t\t\ts = S_ATTR_NOQUOT_VALUE;\n\t\t\t\t\tstart = p;\n\t\t\t\t\tbreak;\n\t\t\t\tcase S_TAG_CLOSE:\n\t\t\t\t\tthrow new Error(\"elements closed character '/' and '>' must be connected to\");\n\t\t\t\t}\n\t\t\t}\n\t\t}//end outer switch\n\t\t//console.log('p++',p)\n\t\tp++;\n\t}\n}\n/**\n * @return true if has new namespace define\n */\nfunction appendElement(el,domBuilder,currentNSMap){\n\tvar tagName = el.tagName;\n\tvar localNSMap = null;\n\t//var currentNSMap = parseStack[parseStack.length-1].currentNSMap;\n\tvar i = el.length;\n\twhile(i--){\n\t\tvar a = el[i];\n\t\tvar qName = a.qName;\n\t\tvar value = a.value;\n\t\tvar nsp = qName.indexOf(':');\n\t\tif(nsp>0){\n\t\t\tvar prefix = a.prefix = qName.slice(0,nsp);\n\t\t\tvar localName = qName.slice(nsp+1);\n\t\t\tvar nsPrefix = prefix === 'xmlns' && localName\n\t\t}else{\n\t\t\tlocalName = qName;\n\t\t\tprefix = null\n\t\t\tnsPrefix = qName === 'xmlns' && ''\n\t\t}\n\t\t//can not set prefix,because prefix !== ''\n\t\ta.localName = localName ;\n\t\t//prefix == null for no ns prefix attribute \n\t\tif(nsPrefix !== false){//hack!!\n\t\t\tif(localNSMap == null){\n\t\t\t\tlocalNSMap = {}\n\t\t\t\t//console.log(currentNSMap,0)\n\t\t\t\t_copy(currentNSMap,currentNSMap={})\n\t\t\t\t//console.log(currentNSMap,1)\n\t\t\t}\n\t\t\tcurrentNSMap[nsPrefix] = localNSMap[nsPrefix] = value;\n\t\t\ta.uri = NAMESPACE.XMLNS\n\t\t\tdomBuilder.startPrefixMapping(nsPrefix, value) \n\t\t}\n\t}\n\tvar i = el.length;\n\twhile(i--){\n\t\ta = el[i];\n\t\tvar prefix = a.prefix;\n\t\tif(prefix){//no prefix attribute has no namespace\n\t\t\tif(prefix === 'xml'){\n\t\t\t\ta.uri = NAMESPACE.XML;\n\t\t\t}if(prefix !== 'xmlns'){\n\t\t\t\ta.uri = currentNSMap[prefix || '']\n\t\t\t\t\n\t\t\t\t//{console.log('###'+a.qName,domBuilder.locator.systemId+'',currentNSMap,a.uri)}\n\t\t\t}\n\t\t}\n\t}\n\tvar nsp = tagName.indexOf(':');\n\tif(nsp>0){\n\t\tprefix = el.prefix = tagName.slice(0,nsp);\n\t\tlocalName = el.localName = tagName.slice(nsp+1);\n\t}else{\n\t\tprefix = null;//important!!\n\t\tlocalName = el.localName = tagName;\n\t}\n\t//no prefix element has default namespace\n\tvar ns = el.uri = currentNSMap[prefix || ''];\n\tdomBuilder.startElement(ns,localName,tagName,el);\n\t//endPrefixMapping and startPrefixMapping have not any help for dom builder\n\t//localNSMap = null\n\tif(el.closed){\n\t\tdomBuilder.endElement(ns,localName,tagName);\n\t\tif(localNSMap){\n\t\t\tfor(prefix in localNSMap){\n\t\t\t\tdomBuilder.endPrefixMapping(prefix) \n\t\t\t}\n\t\t}\n\t}else{\n\t\tel.currentNSMap = currentNSMap;\n\t\tel.localNSMap = localNSMap;\n\t\t//parseStack.push(el);\n\t\treturn true;\n\t}\n}\nfunction parseHtmlSpecialContent(source,elStartEnd,tagName,entityReplacer,domBuilder){\n\tif(/^(?:script|textarea)$/i.test(tagName)){\n\t\tvar elEndStart =  source.indexOf('</'+tagName+'>',elStartEnd);\n\t\tvar text = source.substring(elStartEnd+1,elEndStart);\n\t\tif(/[&<]/.test(text)){\n\t\t\tif(/^script$/i.test(tagName)){\n\t\t\t\t//if(!/\\]\\]>/.test(text)){\n\t\t\t\t\t//lexHandler.startCDATA();\n\t\t\t\t\tdomBuilder.characters(text,0,text.length);\n\t\t\t\t\t//lexHandler.endCDATA();\n\t\t\t\t\treturn elEndStart;\n\t\t\t\t//}\n\t\t\t}//}else{//text area\n\t\t\t\ttext = text.replace(/&#?\\w+;/g,entityReplacer);\n\t\t\t\tdomBuilder.characters(text,0,text.length);\n\t\t\t\treturn elEndStart;\n\t\t\t//}\n\t\t\t\n\t\t}\n\t}\n\treturn elStartEnd+1;\n}\nfunction fixSelfClosed(source,elStartEnd,tagName,closeMap){\n\t//if(tagName in closeMap){\n\tvar pos = closeMap[tagName];\n\tif(pos == null){\n\t\t//console.log(tagName)\n\t\tpos =  source.lastIndexOf('</'+tagName+'>')\n\t\tif(pos<elStartEnd){//忘记闭合\n\t\t\tpos = source.lastIndexOf('</'+tagName)\n\t\t}\n\t\tcloseMap[tagName] =pos\n\t}\n\treturn pos<elStartEnd;\n\t//} \n}\nfunction _copy(source,target){\n\tfor(var n in source){target[n] = source[n]}\n}\nfunction parseDCC(source,start,domBuilder,errorHandler){//sure start with '<!'\n\tvar next= source.charAt(start+2)\n\tswitch(next){\n\tcase '-':\n\t\tif(source.charAt(start + 3) === '-'){\n\t\t\tvar end = source.indexOf('-->',start+4);\n\t\t\t//append comment source.substring(4,end)//<!--\n\t\t\tif(end>start){\n\t\t\t\tdomBuilder.comment(source,start+4,end-start-4);\n\t\t\t\treturn end+3;\n\t\t\t}else{\n\t\t\t\terrorHandler.error(\"Unclosed comment\");\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}else{\n\t\t\t//error\n\t\t\treturn -1;\n\t\t}\n\tdefault:\n\t\tif(source.substr(start+3,6) == 'CDATA['){\n\t\t\tvar end = source.indexOf(']]>',start+9);\n\t\t\tdomBuilder.startCDATA();\n\t\t\tdomBuilder.characters(source,start+9,end-start-9);\n\t\t\tdomBuilder.endCDATA() \n\t\t\treturn end+3;\n\t\t}\n\t\t//<!DOCTYPE\n\t\t//startDTD(java.lang.String name, java.lang.String publicId, java.lang.String systemId) \n\t\tvar matchs = split(source,start);\n\t\tvar len = matchs.length;\n\t\tif(len>1 && /!doctype/i.test(matchs[0][0])){\n\t\t\tvar name = matchs[1][0];\n\t\t\tvar pubid = false;\n\t\t\tvar sysid = false;\n\t\t\tif(len>3){\n\t\t\t\tif(/^public$/i.test(matchs[2][0])){\n\t\t\t\t\tpubid = matchs[3][0];\n\t\t\t\t\tsysid = len>4 && matchs[4][0];\n\t\t\t\t}else if(/^system$/i.test(matchs[2][0])){\n\t\t\t\t\tsysid = matchs[3][0];\n\t\t\t\t}\n\t\t\t}\n\t\t\tvar lastMatch = matchs[len-1]\n\t\t\tdomBuilder.startDTD(name, pubid, sysid);\n\t\t\tdomBuilder.endDTD();\n\t\t\t\n\t\t\treturn lastMatch.index+lastMatch[0].length\n\t\t}\n\t}\n\treturn -1;\n}\n\n\n\nfunction parseInstruction(source,start,domBuilder){\n\tvar end = source.indexOf('?>',start);\n\tif(end){\n\t\tvar match = source.substring(start,end).match(/^<\\?(\\S*)\\s*([\\s\\S]*?)\\s*$/);\n\t\tif(match){\n\t\t\tvar len = match[0].length;\n\t\t\tdomBuilder.processingInstruction(match[1], match[2]) ;\n\t\t\treturn end+2;\n\t\t}else{//error\n\t\t\treturn -1;\n\t\t}\n\t}\n\treturn -1;\n}\n\nfunction ElementAttributes(){\n\tthis.attributeNames = {}\n}\nElementAttributes.prototype = {\n\tsetTagName:function(tagName){\n\t\tif(!tagNamePattern.test(tagName)){\n\t\t\tthrow new Error('invalid tagName:'+tagName)\n\t\t}\n\t\tthis.tagName = tagName\n\t},\n\taddValue:function(qName, value, offset) {\n\t\tif(!tagNamePattern.test(qName)){\n\t\t\tthrow new Error('invalid attribute:'+qName)\n\t\t}\n\t\tthis.attributeNames[qName] = this.length;\n\t\tthis[this.length++] = {qName:qName,value:value,offset:offset}\n\t},\n\tlength:0,\n\tgetLocalName:function(i){return this[i].localName},\n\tgetLocator:function(i){return this[i].locator},\n\tgetQName:function(i){return this[i].qName},\n\tgetURI:function(i){return this[i].uri},\n\tgetValue:function(i){return this[i].value}\n//\t,getIndex:function(uri, localName)){\n//\t\tif(localName){\n//\t\t\t\n//\t\t}else{\n//\t\t\tvar qName = uri\n//\t\t}\n//\t},\n//\tgetValue:function(){return this.getValue(this.getIndex.apply(this,arguments))},\n//\tgetType:function(uri,localName){}\n//\tgetType:function(i){},\n}\n\n\n\nfunction split(source,start){\n\tvar match;\n\tvar buf = [];\n\tvar reg = /'[^']+'|\"[^\"]+\"|[^\\s<>\\/=]+=?|(\\/?\\s*>|<)/g;\n\treg.lastIndex = start;\n\treg.exec(source);//skip <\n\twhile(match = reg.exec(source)){\n\t\tbuf.push(match);\n\t\tif(match[1])return buf;\n\t}\n}\n\nexports.XMLReader = XMLReader;\nexports.ParseError = ParseError;\n","// For legacy purposes, preserve the UMD of the public API of the Jitsi Meet\n// library (a.k.a. JitsiMeetJS).\nmodule.exports = require('./JitsiMeetJS').default;\n","const AuthUtil = {\n    /**\n     * Creates the URL pointing to JWT token authentication service. It is\n     * formatted from the 'urlPattern' argument which can contain the following\n     * constants:\n     * '{room}' - name of the conference room passed as <tt>roomName</tt>\n     * argument to this method.\n     * '{roleUpgrade}' - will contain 'true' if the URL will be used for\n     * the role upgrade scenario, where user connects from anonymous domain and\n     * then gets upgraded to the moderator by logging-in from the popup window.\n     *\n     * @param urlPattern a URL pattern pointing to the login service\n     * @param roomName the name of the conference room for which the user will\n     * be authenticated\n     * @param {bool} roleUpgrade <tt>true</tt> if the URL will be used for role\n     * upgrade scenario, where the user logs-in from the popup window in order\n     * to have the moderator rights granted\n     *\n     * @returns {string|null} the URL pointing to JWT login service or\n     * <tt>null</tt> if 'urlPattern' is not a string and the URL can not be\n     * constructed.\n     */\n    getTokenAuthUrl(urlPattern, roomName, roleUpgrade) {\n        const url = urlPattern;\n\n        if (typeof url !== 'string') {\n            return null;\n        }\n\n        return url.replace('{room}', roomName)\n            .replace('{roleUpgrade}', roleUpgrade === true);\n    }\n};\n\nmodule.exports = AuthUtil;\n","/**\n * Implements utility to forward events from one eventEmitter to another.\n * @param src {object} instance of EventEmitter or another class that implements\n * addListener method which will register listener to EventEmitter instance.\n * @param dest {object} instance of EventEmitter or another class that\n * implements emit method which will emit an event.\n */\nfunction EventEmitterForwarder(src, dest) {\n    if (!src || !dest || typeof src.addListener !== 'function'\n        || typeof dest.emit !== 'function') {\n        throw new Error('Invalid arguments passed to EventEmitterForwarder');\n    }\n    this.src = src;\n    this.dest = dest;\n}\n\n/**\n * Adds event to be forwarded from src to dest.\n * @param srcEvent {string} the event that EventEmitterForwarder is listening\n * for.\n * @param dstEvent {string} the event that will be fired from dest.\n * @param arguments all other passed arguments are going to be fired with\n * dstEvent.\n */\nEventEmitterForwarder.prototype.forward = function(...args) {\n    const srcEvent = args[0];\n\n    // This will be the \"this\" value for emit function.\n\n    args[0] = this.dest;\n\n    // Using bind.apply to pass the arguments as Array-like object (\"arguments\")\n    this.src.addListener(\n        srcEvent,\n        Function.prototype.bind.apply(this.dest.emit, args));\n};\n\nmodule.exports = EventEmitterForwarder;\n","/**\n * This utility class defines custom onerror and onunhandledrejection functions.\n * The custom error handlers respect the previously-defined error handlers.\n * GlobalOnErrorHandler class provides utilities to add many custom error\n * handlers and to execute the error handlers directly.\n */\n\n\n/**\n * List with global error handlers that will be executed.\n */\nconst handlers = [];\n\n// If an old handler exists, also fire its events.\nconst oldOnErrorHandler = window.onerror;\n\n/**\n * Custom error handler that calls the old global error handler and executes\n * all handlers that were previously added.\n */\nfunction JitsiGlobalErrorHandler(...args) {\n    handlers.forEach(handler => handler(...args));\n    oldOnErrorHandler && oldOnErrorHandler(...args);\n}\n\n// If an old handler exists, also fire its events.\nconst oldOnUnhandledRejection = window.onunhandledrejection;\n\n/**\n * Custom handler that calls the old global handler and executes all handlers\n * that were previously added. This handler handles rejected Promises.\n */\nfunction JitsiGlobalUnhandledRejection(event) {\n    handlers.forEach(handler => handler(null, null, null, null, event.reason));\n    oldOnUnhandledRejection && oldOnUnhandledRejection(event);\n}\n\n// Setting the custom error handlers.\nwindow.onerror = JitsiGlobalErrorHandler;\nwindow.onunhandledrejection = JitsiGlobalUnhandledRejection;\n\nconst GlobalOnErrorHandler = {\n    /**\n     * Adds new error handlers.\n     * @param handler the new handler.\n     */\n    addHandler(handler) {\n        handlers.push(handler);\n    },\n\n    /**\n     * Calls the global error handler if there is one.\n     * @param error the error to pass to the error handler\n     */\n    callErrorHandler(error) {\n        const errHandler = window.onerror;\n\n        if (!errHandler) {\n            return;\n        }\n        errHandler(null, null, null, null, error);\n    },\n\n    /**\n     * Calls the global rejection handler if there is one.\n     * @param error the error to pass to the rejection handler.\n     */\n    callUnhandledRejectionHandler(error) {\n        const errHandler = window.onunhandledrejection;\n\n        if (!errHandler) {\n            return;\n        }\n        errHandler(error);\n    }\n};\n\n\nmodule.exports = GlobalOnErrorHandler;\n","/**\n * @const\n */\nconst ALPHANUM\n    = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';\n\n/**\n * Hexadecimal digits.\n * @const\n */\nconst HEX_DIGITS = '0123456789abcdef';\n\n/**\n * Generates random int within the range [min, max]\n * @param min the minimum value for the generated number\n * @param max the maximum value for the generated number\n * @returns random int number\n */\nfunction randomInt(min, max) {\n    return Math.floor(Math.random() * (max - min + 1)) + min;\n}\n\n/**\n * Get random element from array or string.\n * @param {Array|string} arr source\n * @returns array element or string character\n */\nfunction randomElement(arr) {\n    return arr[randomInt(0, arr.length - 1)];\n}\n\n/**\n * Generate random alphanumeric string.\n * @param {number} length expected string length\n * @returns {string} random string of specified length\n */\nfunction randomAlphanumStr(length) {\n    let result = '';\n\n    for (let i = 0; i < length; i += 1) {\n        result += randomElement(ALPHANUM);\n    }\n\n    return result;\n}\n\n/**\n * Exported interface.\n */\nconst RandomUtil = {\n    /**\n     * Returns a random hex digit.\n     * @returns {*}\n     */\n    randomHexDigit() {\n        return randomElement(HEX_DIGITS);\n    },\n\n    /**\n     * Returns a random string of hex digits with length 'len'.\n     * @param len the length.\n     */\n    randomHexString(len) {\n        let ret = '';\n\n        while (len--) { // eslint-disable-line no-param-reassign\n            ret += this.randomHexDigit();\n        }\n\n        return ret;\n    },\n    randomElement,\n    randomAlphanumStr,\n    randomInt\n};\n\nmodule.exports = RandomUtil;\n","const currentExecutingScript = require('current-executing-script');\n\n/* eslint-disable max-params */\n\n/**\n * Implements utility functions which facilitate the dealing with scripts such\n * as the download and execution of a JavaScript file.\n */\nconst ScriptUtil = {\n    /**\n     * Loads a script from a specific source.\n     *\n     * @param src the source from the which the script is to be (down)loaded\n     * @param async true to asynchronously load the script or false to\n     * synchronously load the script\n     * @param prepend true to schedule the loading of the script as soon as\n     * possible or false to schedule the loading of the script at the end of the\n     * scripts known at the time\n     * @param relativeURL whether we need load the library from url relative\n     * to the url that lib-jitsi-meet was loaded. Useful when sourcing the\n     * library from different location than the app that is using it\n     * @param loadCallback on load callback function\n     * @param errorCallback callback to be called on error loading the script\n     */\n    loadScript(\n            src,\n            async,\n            prepend,\n            relativeURL,\n            loadCallback,\n            errorCallback) {\n        const d = document;\n        const tagName = 'script';\n        const script = d.createElement(tagName);\n        const referenceNode = d.getElementsByTagName(tagName)[0];\n\n        script.async = async;\n\n        if (relativeURL) {\n            // finds the src url of the current loaded script\n            // and use it as base of the src supplied argument\n            const scriptEl = currentExecutingScript();\n\n            if (scriptEl) {\n                const scriptSrc = scriptEl.src;\n                const baseScriptSrc\n                    = scriptSrc.substring(0, scriptSrc.lastIndexOf('/') + 1);\n\n                if (scriptSrc && baseScriptSrc) {\n                    // eslint-disable-next-line no-param-reassign\n                    src = baseScriptSrc + src;\n                }\n            }\n        }\n\n        if (loadCallback) {\n            script.onload = loadCallback;\n        }\n        if (errorCallback) {\n            script.onerror = errorCallback;\n        }\n\n        script.src = src;\n        if (prepend) {\n            referenceNode.parentNode.insertBefore(script, referenceNode);\n        } else {\n            referenceNode.parentNode.appendChild(script);\n        }\n    }\n};\n\n/* eslint-enable max-params */\n\nmodule.exports = ScriptUtil;\n","/**\n * Implements a simple hash code for a string (see\n * https://en.wikipedia.org/wiki/Java_hashCode()).\n *\n * @param {string} The string to return a hash of.\n * @return {Number} the integer hash code of the string.\n */\nfunction integerHash(string) {\n    if (!string) {\n        return 0;\n    }\n\n    let char, hash = 0, i;\n\n    for (i = 0; i < string.length; i++) {\n        char = string.charCodeAt(i);\n        hash += char * Math.pow(31, string.length - 1 - i);\n        hash = Math.abs(hash | 0); // eslint-disable-line no-bitwise\n    }\n\n    return hash;\n}\n\nmodule.exports = { integerHash };\n","const RandomUtil = require('./RandomUtil');\n\n/**\n * from faker.js - Copyright (c) 2014-2015 Matthew Bergman & Marak Squires\n * MIT License\n * http://github.com/marak/faker.js/\n *\n * @const\n */\nconst names = [\n    'Aaliyah', 'Aaron', 'Abagail', 'Abbey', 'Abbie', 'Abbigail', 'Abby',\n    'Abdiel', 'Abdul', 'Abdullah', 'Abe', 'Abel', 'Abelardo', 'Abigail',\n    'Abigale', 'Abigayle', 'Abner', 'Abraham', 'Ada', 'Adah', 'Adalberto',\n    'Adaline', 'Adam', 'Adan', 'Addie', 'Addison', 'Adela', 'Adelbert', 'Adele',\n    'Adelia', 'Adeline', 'Adell', 'Adella', 'Adelle', 'Aditya', 'Adolf',\n    'Adolfo', 'Adolph', 'Adolphus', 'Adonis', 'Adrain', 'Adrian', 'Adriana',\n    'Adrianna', 'Adriel', 'Adrien', 'Adrienne', 'Afton', 'Aglae', 'Agnes',\n    'Agustin', 'Agustina', 'Ahmad', 'Ahmed', 'Aida', 'Aidan', 'Aiden', 'Aileen',\n    'Aisha', 'Aiyana', 'Akeem', 'Al', 'Alaina', 'Alan', 'Alana', 'Alanis',\n    'Alanna', 'Alayna', 'Alba', 'Albert', 'Alberta', 'Albertha', 'Alberto',\n    'Albin', 'Albina', 'Alda', 'Alden', 'Alec', 'Aleen', 'Alejandra',\n    'Alejandrin', 'Alek', 'Alena', 'Alene', 'Alessandra', 'Alessandro',\n    'Alessia', 'Aletha', 'Alex', 'Alexa', 'Alexander', 'Alexandra', 'Alexandre',\n    'Alexandrea', 'Alexandria', 'Alexandrine', 'Alexandro', 'Alexane',\n    'Alexanne', 'Alexie', 'Alexis', 'Alexys', 'Alexzander', 'Alf', 'Alfonso',\n    'Alfonzo', 'Alford', 'Alfred', 'Alfreda', 'Alfredo', 'Ali', 'Alia', 'Alice',\n    'Alicia', 'Alisa', 'Alisha', 'Alison', 'Alivia', 'Aliya', 'Aliyah', 'Aliza',\n    'Alize', 'Allan', 'Allen', 'Allene', 'Allie', 'Allison', 'Ally', 'Alphonso',\n    'Alta', 'Althea', 'Alva', 'Alvah', 'Alvena', 'Alvera', 'Alverta', 'Alvina',\n    'Alvis', 'Alyce', 'Alycia', 'Alysa', 'Alysha', 'Alyson', 'Alysson',\n    'Amalia', 'Amanda', 'Amani', 'Amara', 'Amari', 'Amaya', 'Amber', 'Ambrose',\n    'Amelia', 'Amelie', 'Amely', 'America', 'Americo', 'Amie', 'Amina', 'Amir',\n    'Amira', 'Amiya', 'Amos', 'Amparo', 'Amy', 'Amya', 'Ana', 'Anabel',\n    'Anabelle', 'Anahi', 'Anais', 'Anastacio', 'Anastasia', 'Anderson', 'Andre',\n    'Andreane', 'Andreanne', 'Andres', 'Andrew', 'Andy', 'Angel', 'Angela',\n    'Angelica', 'Angelina', 'Angeline', 'Angelita', 'Angelo', 'Angie', 'Angus',\n    'Anibal', 'Anika', 'Anissa', 'Anita', 'Aniya', 'Aniyah', 'Anjali', 'Anna',\n    'Annabel', 'Annabell', 'Annabelle', 'Annalise', 'Annamae', 'Annamarie',\n    'Anne', 'Annetta', 'Annette', 'Annie', 'Ansel', 'Ansley', 'Anthony',\n    'Antoinette', 'Antone', 'Antonetta', 'Antonette', 'Antonia', 'Antonietta',\n    'Antonina', 'Antonio', 'Antwan', 'Antwon', 'Anya', 'April', 'Ara',\n    'Araceli', 'Aracely', 'Arch', 'Archibald', 'Ardella', 'Arden', 'Ardith',\n    'Arely', 'Ari', 'Ariane', 'Arianna', 'Aric', 'Ariel', 'Arielle', 'Arjun',\n    'Arlene', 'Arlie', 'Arlo', 'Armand', 'Armando', 'Armani', 'Arnaldo', 'Arne',\n    'Arno', 'Arnold', 'Arnoldo', 'Arnulfo', 'Aron', 'Art', 'Arthur', 'Arturo',\n    'Arvel', 'Arvid', 'Arvilla', 'Aryanna', 'Asa', 'Asha', 'Ashlee', 'Ashleigh',\n    'Ashley', 'Ashly', 'Ashlynn', 'Ashton', 'Ashtyn', 'Asia', 'Assunta',\n    'Astrid', 'Athena', 'Aubree', 'Aubrey', 'Audie', 'Audra', 'Audreanne',\n    'Audrey', 'August', 'Augusta', 'Augustine', 'Augustus', 'Aurelia',\n    'Aurelie', 'Aurelio', 'Aurore', 'Austen', 'Austin', 'Austyn', 'Autumn',\n    'Ava', 'Avery', 'Avis', 'Axel', 'Ayana', 'Ayden', 'Ayla', 'Aylin', 'Baby',\n    'Bailee', 'Bailey', 'Barbara', 'Barney', 'Baron', 'Barrett', 'Barry',\n    'Bart', 'Bartholome', 'Barton', 'Baylee', 'Beatrice', 'Beau', 'Beaulah',\n    'Bell', 'Bella', 'Belle', 'Ben', 'Benedict', 'Benjamin', 'Bennett',\n    'Bennie', 'Benny', 'Benton', 'Berenice', 'Bernadette', 'Bernadine',\n    'Bernard', 'Bernardo', 'Berneice', 'Bernhard', 'Bernice', 'Bernie',\n    'Berniece', 'Bernita', 'Berry', 'Bert', 'Berta', 'Bertha', 'Bertram',\n    'Bertrand', 'Beryl', 'Bessie', 'Beth', 'Bethany', 'Bethel', 'Betsy',\n    'Bette', 'Bettie', 'Betty', 'Bettye', 'Beulah', 'Beverly', 'Bianka', 'Bill',\n    'Billie', 'Billy', 'Birdie', 'Blair', 'Blaise', 'Blake', 'Blanca',\n    'Blanche', 'Blaze', 'Bo', 'Bobbie', 'Bobby', 'Bonita', 'Bonnie', 'Boris',\n    'Boyd', 'Brad', 'Braden', 'Bradford', 'Bradley', 'Bradly', 'Brady',\n    'Braeden', 'Brain', 'Brandi', 'Brando', 'Brandon', 'Brandt', 'Brandy',\n    'Brandyn', 'Brannon', 'Branson', 'Brant', 'Braulio', 'Braxton', 'Brayan',\n    'Breana', 'Breanna', 'Breanne', 'Brenda', 'Brendan', 'Brenden', 'Brendon',\n    'Brenna', 'Brennan', 'Brennon', 'Brent', 'Bret', 'Brett', 'Bria', 'Brian',\n    'Briana', 'Brianne', 'Brice', 'Bridget', 'Bridgette', 'Bridie', 'Brielle',\n    'Brigitte', 'Brionna', 'Brisa', 'Britney', 'Brittany', 'Brock', 'Broderick',\n    'Brody', 'Brook', 'Brooke', 'Brooklyn', 'Brooks', 'Brown', 'Bruce',\n    'Bryana', 'Bryce', 'Brycen', 'Bryon', 'Buck', 'Bud', 'Buddy', 'Buford',\n    'Bulah', 'Burdette', 'Burley', 'Burnice', 'Buster', 'Cade', 'Caden',\n    'Caesar', 'Caitlyn', 'Cale', 'Caleb', 'Caleigh', 'Cali', 'Calista',\n    'Callie', 'Camden', 'Cameron', 'Camila', 'Camilla', 'Camille', 'Camren',\n    'Camron', 'Camryn', 'Camylle', 'Candace', 'Candelario', 'Candice',\n    'Candida', 'Candido', 'Cara', 'Carey', 'Carissa', 'Carlee', 'Carleton',\n    'Carley', 'Carli', 'Carlie', 'Carlo', 'Carlos', 'Carlotta', 'Carmel',\n    'Carmela', 'Carmella', 'Carmelo', 'Carmen', 'Carmine', 'Carol', 'Carolanne',\n    'Carole', 'Carolina', 'Caroline', 'Carolyn', 'Carolyne', 'Carrie',\n    'Carroll', 'Carson', 'Carter', 'Cary', 'Casandra', 'Casey', 'Casimer',\n    'Casimir', 'Casper', 'Cassandra', 'Cassandre', 'Cassidy', 'Cassie',\n    'Catalina', 'Caterina', 'Catharine', 'Catherine', 'Cathrine', 'Cathryn',\n    'Cathy', 'Cayla', 'Ceasar', 'Cecelia', 'Cecil', 'Cecile', 'Cecilia',\n    'Cedrick', 'Celestine', 'Celestino', 'Celia', 'Celine', 'Cesar', 'Chad',\n    'Chadd', 'Chadrick', 'Chaim', 'Chance', 'Chandler', 'Chanel', 'Chanelle',\n    'Charity', 'Charlene', 'Charles', 'Charley', 'Charlie', 'Charlotte',\n    'Chase', 'Chasity', 'Chauncey', 'Chaya', 'Chaz', 'Chelsea', 'Chelsey',\n    'Chelsie', 'Chesley', 'Chester', 'Chet', 'Cheyanne', 'Cheyenne', 'Chloe',\n    'Chris', 'Christ', 'Christa', 'Christelle', 'Christian', 'Christiana',\n    'Christina', 'Christine', 'Christop', 'Christophe', 'Christopher',\n    'Christy', 'Chyna', 'Ciara', 'Cicero', 'Cielo', 'Cierra', 'Cindy',\n    'Citlalli', 'Clair', 'Claire', 'Clara', 'Clarabelle', 'Clare', 'Clarissa',\n    'Clark', 'Claud', 'Claude', 'Claudia', 'Claudie', 'Claudine', 'Clay',\n    'Clemens', 'Clement', 'Clementina', 'Clementine', 'Clemmie', 'Cleo',\n    'Cleora', 'Cleta', 'Cletus', 'Cleve', 'Cleveland', 'Clifford', 'Clifton',\n    'Clint', 'Clinton', 'Clotilde', 'Clovis', 'Cloyd', 'Clyde', 'Coby', 'Cody',\n    'Colby', 'Cole', 'Coleman', 'Colin', 'Colleen', 'Collin', 'Colt', 'Colten',\n    'Colton', 'Columbus', 'Concepcion', 'Conner', 'Connie', 'Connor', 'Conor',\n    'Conrad', 'Constance', 'Constantin', 'Consuelo', 'Cooper', 'Cora',\n    'Coralie', 'Corbin', 'Cordelia', 'Cordell', 'Cordia', 'Cordie', 'Corene',\n    'Corine', 'Cornelius', 'Cornell', 'Corrine', 'Cortez', 'Cortney', 'Cory',\n    'Coty', 'Courtney', 'Coy', 'Craig', 'Crawford', 'Creola', 'Cristal',\n    'Cristian', 'Cristina', 'Cristobal', 'Cristopher', 'Cruz', 'Crystal',\n    'Crystel', 'Cullen', 'Curt', 'Curtis', 'Cydney', 'Cynthia', 'Cyril',\n    'Cyrus', 'Dagmar', 'Dahlia', 'Daija', 'Daisha', 'Daisy', 'Dakota', 'Dale',\n    'Dallas', 'Dallin', 'Dalton', 'Damaris', 'Dameon', 'Damian', 'Damien',\n    'Damion', 'Damon', 'Dan', 'Dana', 'Dandre', 'Dane', 'D\\'angelo', 'Dangelo',\n    'Danial', 'Daniela', 'Daniella', 'Danielle', 'Danika', 'Dannie', 'Danny',\n    'Dante', 'Danyka', 'Daphne', 'Daphnee', 'Daphney', 'Darby', 'Daren',\n    'Darian', 'Dariana', 'Darien', 'Dario', 'Darion', 'Darius', 'Darlene',\n    'Daron', 'Darrel', 'Darrell', 'Darren', 'Darrick', 'Darrin', 'Darrion',\n    'Darron', 'Darryl', 'Darwin', 'Daryl', 'Dashawn', 'Dasia', 'Dave', 'David',\n    'Davin', 'Davion', 'Davon', 'Davonte', 'Dawn', 'Dawson', 'Dax', 'Dayana',\n    'Dayna', 'Dayne', 'Dayton', 'Dean', 'Deangelo', 'Deanna', 'Deborah',\n    'Declan', 'Dedric', 'Dedrick', 'Dee', 'Deion', 'Deja', 'Dejah', 'Dejon',\n    'Dejuan', 'Delaney', 'Delbert', 'Delfina', 'Delia', 'Delilah', 'Dell',\n    'Della', 'Delmer', 'Delores', 'Delpha', 'Delphia', 'Delphine', 'Delta',\n    'Demarco', 'Demarcus', 'Demario', 'Demetris', 'Demetrius', 'Demond', 'Dena',\n    'Denis', 'Dennis', 'Deon', 'Deondre', 'Deontae', 'Deonte', 'Dereck',\n    'Derek', 'Derick', 'Deron', 'Derrick', 'Deshaun', 'Deshawn', 'Desiree',\n    'Desmond', 'Dessie', 'Destany', 'Destin', 'Destinee', 'Destiney', 'Destini',\n    'Destiny', 'Devan', 'Devante', 'Deven', 'Devin', 'Devon', 'Devonte',\n    'Devyn', 'Dewayne', 'Dewitt', 'Dexter', 'Diamond', 'Diana', 'Dianna',\n    'Diego', 'Dillan', 'Dillon', 'Dimitri', 'Dina', 'Dino', 'Dion', 'Dixie',\n    'Dock', 'Dolly', 'Dolores', 'Domenic', 'Domenica', 'Domenick', 'Domenico',\n    'Domingo', 'Dominic', 'Dominique', 'Don', 'Donald', 'Donato', 'Donavon',\n    'Donna', 'Donnell', 'Donnie', 'Donny', 'Dora', 'Dorcas', 'Dorian', 'Doris',\n    'Dorothea', 'Dorothy', 'Dorris', 'Dortha', 'Dorthy', 'Doug', 'Douglas',\n    'Dovie', 'Doyle', 'Drake', 'Drew', 'Duane', 'Dudley', 'Dulce', 'Duncan',\n    'Durward', 'Dustin', 'Dusty', 'Dwight', 'Dylan', 'Earl', 'Earlene',\n    'Earline', 'Earnest', 'Earnestine', 'Easter', 'Easton', 'Ebba', 'Ebony',\n    'Ed', 'Eda', 'Edd', 'Eddie', 'Eden', 'Edgar', 'Edgardo', 'Edison', 'Edmond',\n    'Edmund', 'Edna', 'Eduardo', 'Edward', 'Edwardo', 'Edwin', 'Edwina',\n    'Edyth', 'Edythe', 'Effie', 'Efrain', 'Efren', 'Eileen', 'Einar', 'Eino',\n    'Eladio', 'Elaina', 'Elbert', 'Elda', 'Eldon', 'Eldora', 'Eldred',\n    'Eldridge', 'Eleanora', 'Eleanore', 'Eleazar', 'Electa', 'Elena', 'Elenor',\n    'Elenora', 'Eleonore', 'Elfrieda', 'Eli', 'Elian', 'Eliane', 'Elias',\n    'Eliezer', 'Elijah', 'Elinor', 'Elinore', 'Elisa', 'Elisabeth', 'Elise',\n    'Eliseo', 'Elisha', 'Elissa', 'Eliza', 'Elizabeth', 'Ella', 'Ellen',\n    'Ellie', 'Elliot', 'Elliott', 'Ellis', 'Ellsworth', 'Elmer', 'Elmira',\n    'Elmo', 'Elmore', 'Elna', 'Elnora', 'Elody', 'Eloisa', 'Eloise', 'Elouise',\n    'Eloy', 'Elroy', 'Elsa', 'Else', 'Elsie', 'Elta', 'Elton', 'Elva', 'Elvera',\n    'Elvie', 'Elvis', 'Elwin', 'Elwyn', 'Elyse', 'Elyssa', 'Elza', 'Emanuel',\n    'Emelia', 'Emelie', 'Emely', 'Emerald', 'Emerson', 'Emery', 'Emie', 'Emil',\n    'Emile', 'Emilia', 'Emiliano', 'Emilie', 'Emilio', 'Emily', 'Emma',\n    'Emmalee', 'Emmanuel', 'Emmanuelle', 'Emmet', 'Emmett', 'Emmie', 'Emmitt',\n    'Emmy', 'Emory', 'Ena', 'Enid', 'Enoch', 'Enola', 'Enos', 'Enrico',\n    'Enrique', 'Ephraim', 'Era', 'Eriberto', 'Eric', 'Erica', 'Erich', 'Erick',\n    'Ericka', 'Erik', 'Erika', 'Erin', 'Erling', 'Erna', 'Ernest', 'Ernestina',\n    'Ernestine', 'Ernesto', 'Ernie', 'Ervin', 'Erwin', 'Eryn', 'Esmeralda',\n    'Esperanza', 'Esta', 'Esteban', 'Estefania', 'Estel', 'Estell', 'Estella',\n    'Estelle', 'Estevan', 'Esther', 'Estrella', 'Etha', 'Ethan', 'Ethel',\n    'Ethelyn', 'Ethyl', 'Ettie', 'Eudora', 'Eugene', 'Eugenia', 'Eula', 'Eulah',\n    'Eulalia', 'Euna', 'Eunice', 'Eusebio', 'Eva', 'Evalyn', 'Evan',\n    'Evangeline', 'Evans', 'Eve', 'Eveline', 'Evelyn', 'Everardo', 'Everett',\n    'Everette', 'Evert', 'Evie', 'Ewald', 'Ewell', 'Ezekiel', 'Ezequiel',\n    'Ezra', 'Fabian', 'Fabiola', 'Fae', 'Fannie', 'Fanny', 'Fatima', 'Faustino',\n    'Fausto', 'Favian', 'Fay', 'Faye', 'Federico', 'Felicia', 'Felicita',\n    'Felicity', 'Felipa', 'Felipe', 'Felix', 'Felton', 'Fermin', 'Fern',\n    'Fernando', 'Ferne', 'Fidel', 'Filiberto', 'Filomena', 'Finn', 'Fiona',\n    'Flavie', 'Flavio', 'Fleta', 'Fletcher', 'Flo', 'Florence', 'Florencio',\n    'Florian', 'Florida', 'Florine', 'Flossie', 'Floy', 'Floyd', 'Ford',\n    'Forest', 'Forrest', 'Foster', 'Frances', 'Francesca', 'Francesco',\n    'Francis', 'Francisca', 'Francisco', 'Franco', 'Frank', 'Frankie', 'Franz',\n    'Fred', 'Freda', 'Freddie', 'Freddy', 'Frederic', 'Frederick', 'Frederik',\n    'Frederique', 'Fredrick', 'Fredy', 'Freeda', 'Freeman', 'Freida', 'Frida',\n    'Frieda', 'Friedrich', 'Fritz', 'Furman', 'Gabe', 'Gabriel', 'Gabriella',\n    'Gabrielle', 'Gaetano', 'Gage', 'Gail', 'Gardner', 'Garett', 'Garfield',\n    'Garland', 'Garnet', 'Garnett', 'Garret', 'Garrett', 'Garrick', 'Garrison',\n    'Garry', 'Garth', 'Gaston', 'Gavin', 'Gay', 'Gayle', 'Gaylord', 'Gene',\n    'General', 'Genesis', 'Genevieve', 'Gennaro', 'Genoveva', 'Geo', 'Geoffrey',\n    'George', 'Georgette', 'Georgiana', 'Georgianna', 'Geovanni', 'Geovanny',\n    'Geovany', 'Gerald', 'Geraldine', 'Gerard', 'Gerardo', 'Gerda', 'Gerhard',\n    'Germaine', 'German', 'Gerry', 'Gerson', 'Gertrude', 'Gia', 'Gianni',\n    'Gideon', 'Gilbert', 'Gilberto', 'Gilda', 'Giles', 'Gillian', 'Gina',\n    'Gino', 'Giovani', 'Giovanna', 'Giovanni', 'Giovanny', 'Gisselle',\n    'Giuseppe', 'Gladyce', 'Gladys', 'Glen', 'Glenda', 'Glenna', 'Glennie',\n    'Gloria', 'Godfrey', 'Golda', 'Golden', 'Gonzalo', 'Gordon', 'Grace',\n    'Gracie', 'Graciela', 'Grady', 'Graham', 'Grant', 'Granville', 'Grayce',\n    'Grayson', 'Green', 'Greg', 'Gregg', 'Gregoria', 'Gregorio', 'Gregory',\n    'Greta', 'Gretchen', 'Greyson', 'Griffin', 'Grover', 'Guadalupe', 'Gudrun',\n    'Guido', 'Guillermo', 'Guiseppe', 'Gunnar', 'Gunner', 'Gus', 'Gussie',\n    'Gust', 'Gustave', 'Guy', 'Gwen', 'Gwendolyn', 'Hadley', 'Hailee', 'Hailey',\n    'Hailie', 'Hal', 'Haleigh', 'Haley', 'Halie', 'Halle', 'Hallie', 'Hank',\n    'Hanna', 'Hannah', 'Hans', 'Hardy', 'Harley', 'Harmon', 'Harmony', 'Harold',\n    'Harrison', 'Harry', 'Harvey', 'Haskell', 'Hassan', 'Hassie', 'Hattie',\n    'Haven', 'Hayden', 'Haylee', 'Hayley', 'Haylie', 'Hazel', 'Hazle', 'Heath',\n    'Heather', 'Heaven', 'Heber', 'Hector', 'Heidi', 'Helen', 'Helena',\n    'Helene', 'Helga', 'Hellen', 'Helmer', 'Heloise', 'Henderson', 'Henri',\n    'Henriette', 'Henry', 'Herbert', 'Herman', 'Hermann', 'Hermina', 'Herminia',\n    'Herminio', 'Hershel', 'Herta', 'Hertha', 'Hester', 'Hettie', 'Hilario',\n    'Hilbert', 'Hilda', 'Hildegard', 'Hillard', 'Hillary', 'Hilma', 'Hilton',\n    'Hipolito', 'Hiram', 'Hobart', 'Holden', 'Hollie', 'Hollis', 'Holly',\n    'Hope', 'Horace', 'Horacio', 'Hortense', 'Hosea', 'Houston', 'Howard',\n    'Howell', 'Hoyt', 'Hubert', 'Hudson', 'Hugh', 'Hulda', 'Humberto', 'Hunter',\n    'Hyman', 'Ian', 'Ibrahim', 'Icie', 'Ida', 'Idell', 'Idella', 'Ignacio',\n    'Ignatius', 'Ike', 'Ila', 'Ilene', 'Iliana', 'Ima', 'Imani', 'Imelda',\n    'Immanuel', 'Imogene', 'Ines', 'Irma', 'Irving', 'Irwin', 'Isaac', 'Isabel',\n    'Isabell', 'Isabella', 'Isabelle', 'Isac', 'Isadore', 'Isai', 'Isaiah',\n    'Isaias', 'Isidro', 'Ismael', 'Isobel', 'Isom', 'Israel', 'Issac', 'Itzel',\n    'Iva', 'Ivah', 'Ivory', 'Ivy', 'Izabella', 'Izaiah', 'Jabari', 'Jace',\n    'Jacey', 'Jacinthe', 'Jacinto', 'Jack', 'Jackeline', 'Jackie', 'Jacklyn',\n    'Jackson', 'Jacky', 'Jaclyn', 'Jacquelyn', 'Jacques', 'Jacynthe', 'Jada',\n    'Jade', 'Jaden', 'Jadon', 'Jadyn', 'Jaeden', 'Jaida', 'Jaiden', 'Jailyn',\n    'Jaime', 'Jairo', 'Jakayla', 'Jake', 'Jakob', 'Jaleel', 'Jalen', 'Jalon',\n    'Jalyn', 'Jamaal', 'Jamal', 'Jamar', 'Jamarcus', 'Jamel', 'Jameson',\n    'Jamey', 'Jamie', 'Jamil', 'Jamir', 'Jamison', 'Jammie', 'Jan', 'Jana',\n    'Janae', 'Jane', 'Janelle', 'Janessa', 'Janet', 'Janice', 'Janick', 'Janie',\n    'Janis', 'Janiya', 'Jannie', 'Jany', 'Jaquan', 'Jaquelin', 'Jaqueline',\n    'Jared', 'Jaren', 'Jarod', 'Jaron', 'Jarred', 'Jarrell', 'Jarret',\n    'Jarrett', 'Jarrod', 'Jarvis', 'Jasen', 'Jasmin', 'Jason', 'Jasper',\n    'Jaunita', 'Javier', 'Javon', 'Javonte', 'Jay', 'Jayce', 'Jaycee', 'Jayda',\n    'Jayde', 'Jayden', 'Jaydon', 'Jaylan', 'Jaylen', 'Jaylin', 'Jaylon',\n    'Jayme', 'Jayne', 'Jayson', 'Jazlyn', 'Jazmin', 'Jazmyn', 'Jazmyne', 'Jean',\n    'Jeanette', 'Jeanie', 'Jeanne', 'Jed', 'Jedediah', 'Jedidiah', 'Jeff',\n    'Jefferey', 'Jeffery', 'Jeffrey', 'Jeffry', 'Jena', 'Jenifer', 'Jennie',\n    'Jennifer', 'Jennings', 'Jennyfer', 'Jensen', 'Jerad', 'Jerald', 'Jeramie',\n    'Jeramy', 'Jerel', 'Jeremie', 'Jeremy', 'Jermain', 'Jermaine', 'Jermey',\n    'Jerod', 'Jerome', 'Jeromy', 'Jerrell', 'Jerrod', 'Jerrold', 'Jerry',\n    'Jess', 'Jesse', 'Jessica', 'Jessie', 'Jessika', 'Jessy', 'Jessyca',\n    'Jesus', 'Jett', 'Jettie', 'Jevon', 'Jewel', 'Jewell', 'Jillian', 'Jimmie',\n    'Jimmy', 'Jo', 'Joan', 'Joana', 'Joanie', 'Joanne', 'Joannie', 'Joanny',\n    'Joany', 'Joaquin', 'Jocelyn', 'Jodie', 'Jody', 'Joe', 'Joel', 'Joelle',\n    'Joesph', 'Joey', 'Johan', 'Johann', 'Johanna', 'Johathan', 'John',\n    'Johnathan', 'Johnathon', 'Johnnie', 'Johnny', 'Johnpaul', 'Johnson',\n    'Jolie', 'Jon', 'Jonas', 'Jonatan', 'Jonathan', 'Jonathon', 'Jordan',\n    'Jordane', 'Jordi', 'Jordon', 'Jordy', 'Jordyn', 'Jorge', 'Jose', 'Josefa',\n    'Josefina', 'Joseph', 'Josephine', 'Josh', 'Joshua', 'Joshuah', 'Josiah',\n    'Josiane', 'Josianne', 'Josie', 'Josue', 'Jovan', 'Jovani', 'Jovanny',\n    'Jovany', 'Joy', 'Joyce', 'Juana', 'Juanita', 'Judah', 'Judd', 'Jude',\n    'Judge', 'Judson', 'Judy', 'Jules', 'Julia', 'Julian', 'Juliana',\n    'Julianne', 'Julie', 'Julien', 'Juliet', 'Julio', 'Julius', 'June',\n    'Junior', 'Junius', 'Justen', 'Justice', 'Justina', 'Justine', 'Juston',\n    'Justus', 'Justyn', 'Juvenal', 'Juwan', 'Kacey', 'Kaci', 'Kacie', 'Kade',\n    'Kaden', 'Kadin', 'Kaela', 'Kaelyn', 'Kaia', 'Kailee', 'Kailey', 'Kailyn',\n    'Kaitlin', 'Kaitlyn', 'Kale', 'Kaleb', 'Kaleigh', 'Kaley', 'Kali', 'Kallie',\n    'Kameron', 'Kamille', 'Kamren', 'Kamron', 'Kamryn', 'Kane', 'Kara',\n    'Kareem', 'Karelle', 'Karen', 'Kari', 'Kariane', 'Karianne', 'Karina',\n    'Karine', 'Karl', 'Karlee', 'Karley', 'Karli', 'Karlie', 'Karolann',\n    'Karson', 'Kasandra', 'Kasey', 'Kassandra', 'Katarina', 'Katelin',\n    'Katelyn', 'Katelynn', 'Katharina', 'Katherine', 'Katheryn', 'Kathleen',\n    'Kathlyn', 'Kathryn', 'Kathryne', 'Katlyn', 'Katlynn', 'Katrina', 'Katrine',\n    'Kattie', 'Kavon', 'Kay', 'Kaya', 'Kaycee', 'Kayden', 'Kayla', 'Kaylah',\n    'Kaylee', 'Kayleigh', 'Kayley', 'Kayli', 'Kaylie', 'Kaylin', 'Keagan',\n    'Keanu', 'Keara', 'Keaton', 'Keegan', 'Keeley', 'Keely', 'Keenan', 'Keira',\n    'Keith', 'Kellen', 'Kelley', 'Kelli', 'Kellie', 'Kelly', 'Kelsi', 'Kelsie',\n    'Kelton', 'Kelvin', 'Ken', 'Kendall', 'Kendra', 'Kendrick', 'Kenna',\n    'Kennedi', 'Kennedy', 'Kenneth', 'Kennith', 'Kenny', 'Kenton', 'Kenya',\n    'Kenyatta', 'Kenyon', 'Keon', 'Keshaun', 'Keshawn', 'Keven', 'Kevin',\n    'Kevon', 'Keyon', 'Keyshawn', 'Khalid', 'Khalil', 'Kian', 'Kiana', 'Kianna',\n    'Kiara', 'Kiarra', 'Kiel', 'Kiera', 'Kieran', 'Kiley', 'Kim', 'Kimberly',\n    'King', 'Kip', 'Kira', 'Kirk', 'Kirsten', 'Kirstin', 'Kitty', 'Kobe',\n    'Koby', 'Kody', 'Kolby', 'Kole', 'Korbin', 'Korey', 'Kory', 'Kraig', 'Kris',\n    'Krista', 'Kristian', 'Kristin', 'Kristina', 'Kristofer', 'Kristoffer',\n    'Kristopher', 'Kristy', 'Krystal', 'Krystel', 'Krystina', 'Kurt', 'Kurtis',\n    'Kyla', 'Kyle', 'Kylee', 'Kyleigh', 'Kyler', 'Kylie', 'Kyra', 'Lacey',\n    'Lacy', 'Ladarius', 'Lafayette', 'Laila', 'Laisha', 'Lamar', 'Lambert',\n    'Lamont', 'Lance', 'Landen', 'Lane', 'Laney', 'Larissa', 'Laron', 'Larry',\n    'Larue', 'Laura', 'Laurel', 'Lauren', 'Laurence', 'Lauretta', 'Lauriane',\n    'Laurianne', 'Laurie', 'Laurine', 'Laury', 'Lauryn', 'Lavada', 'Lavern',\n    'Laverna', 'Laverne', 'Lavina', 'Lavinia', 'Lavon', 'Lavonne', 'Lawrence',\n    'Lawson', 'Layla', 'Layne', 'Lazaro', 'Lea', 'Leann', 'Leanna', 'Leanne',\n    'Leatha', 'Leda', 'Lee', 'Leif', 'Leila', 'Leilani', 'Lela', 'Lelah',\n    'Leland', 'Lelia', 'Lempi', 'Lemuel', 'Lenna', 'Lennie', 'Lenny', 'Lenora',\n    'Lenore', 'Leo', 'Leola', 'Leon', 'Leonard', 'Leonardo', 'Leone', 'Leonel',\n    'Leonie', 'Leonor', 'Leonora', 'Leopold', 'Leopoldo', 'Leora', 'Lera',\n    'Lesley', 'Leslie', 'Lesly', 'Lessie', 'Lester', 'Leta', 'Letha', 'Letitia',\n    'Levi', 'Lew', 'Lewis', 'Lexi', 'Lexie', 'Lexus', 'Lia', 'Liam', 'Liana',\n    'Libbie', 'Libby', 'Lila', 'Lilian', 'Liliana', 'Liliane', 'Lilla',\n    'Lillian', 'Lilliana', 'Lillie', 'Lilly', 'Lily', 'Lilyan', 'Lina',\n    'Lincoln', 'Linda', 'Lindsay', 'Lindsey', 'Linnea', 'Linnie', 'Linwood',\n    'Lionel', 'Lisa', 'Lisandro', 'Lisette', 'Litzy', 'Liza', 'Lizeth',\n    'Lizzie', 'Llewellyn', 'Lloyd', 'Logan', 'Lois', 'Lola', 'Lolita', 'Loma',\n    'Lon', 'London', 'Lonie', 'Lonnie', 'Lonny', 'Lonzo', 'Lora', 'Loraine',\n    'Loren', 'Lorena', 'Lorenz', 'Lorenza', 'Lorenzo', 'Lori', 'Lorine',\n    'Lorna', 'Lottie', 'Lou', 'Louie', 'Louisa', 'Lourdes', 'Louvenia',\n    'Lowell', 'Loy', 'Loyal', 'Loyce', 'Lucas', 'Luciano', 'Lucie', 'Lucienne',\n    'Lucile', 'Lucinda', 'Lucio', 'Lucious', 'Lucius', 'Lucy', 'Ludie',\n    'Ludwig', 'Lue', 'Luella', 'Luigi', 'Luis', 'Luisa', 'Lukas', 'Lula',\n    'Lulu', 'Luna', 'Lupe', 'Lura', 'Lurline', 'Luther', 'Luz', 'Lyda', 'Lydia',\n    'Lyla', 'Lynn', 'Lyric', 'Lysanne', 'Mabel', 'Mabelle', 'Mable', 'Mac',\n    'Macey', 'Maci', 'Macie', 'Mack', 'Mackenzie', 'Macy', 'Madaline',\n    'Madalyn', 'Maddison', 'Madeline', 'Madelyn', 'Madelynn', 'Madge', 'Madie',\n    'Madilyn', 'Madisen', 'Madison', 'Madisyn', 'Madonna', 'Madyson', 'Mae',\n    'Maegan', 'Maeve', 'Mafalda', 'Magali', 'Magdalen', 'Magdalena', 'Maggie',\n    'Magnolia', 'Magnus', 'Maia', 'Maida', 'Maiya', 'Major', 'Makayla',\n    'Makenna', 'Makenzie', 'Malachi', 'Malcolm', 'Malika', 'Malinda', 'Mallie',\n    'Mallory', 'Malvina', 'Mandy', 'Manley', 'Manuel', 'Manuela', 'Mara',\n    'Marc', 'Marcel', 'Marcelina', 'Marcelino', 'Marcella', 'Marcelle',\n    'Marcellus', 'Marcelo', 'Marcia', 'Marco', 'Marcos', 'Marcus', 'Margaret',\n    'Margarete', 'Margarett', 'Margaretta', 'Margarette', 'Margarita', 'Marge',\n    'Margie', 'Margot', 'Margret', 'Marguerite', 'Maria', 'Mariah', 'Mariam',\n    'Marian', 'Mariana', 'Mariane', 'Marianna', 'Marianne', 'Mariano',\n    'Maribel', 'Marie', 'Mariela', 'Marielle', 'Marietta', 'Marilie', 'Marilou',\n    'Marilyne', 'Marina', 'Mario', 'Marion', 'Marisa', 'Marisol', 'Maritza',\n    'Marjolaine', 'Marjorie', 'Marjory', 'Mark', 'Markus', 'Marlee', 'Marlen',\n    'Marlene', 'Marley', 'Marlin', 'Marlon', 'Marques', 'Marquis', 'Marquise',\n    'Marshall', 'Marta', 'Martin', 'Martina', 'Martine', 'Marty', 'Marvin',\n    'Mary', 'Maryam', 'Maryjane', 'Maryse', 'Mason', 'Mateo', 'Mathew',\n    'Mathias', 'Mathilde', 'Matilda', 'Matilde', 'Matt', 'Matteo', 'Mattie',\n    'Maud', 'Maude', 'Maudie', 'Maureen', 'Maurice', 'Mauricio', 'Maurine',\n    'Maverick', 'Mavis', 'Max', 'Maxie', 'Maxime', 'Maximilian', 'Maximillia',\n    'Maximillian', 'Maximo', 'Maximus', 'Maxine', 'Maxwell', 'May', 'Maya',\n    'Maybell', 'Maybelle', 'Maye', 'Maymie', 'Maynard', 'Mayra', 'Mazie',\n    'Mckayla', 'Mckenna', 'Mckenzie', 'Meagan', 'Meaghan', 'Meda', 'Megane',\n    'Meggie', 'Meghan', 'Mekhi', 'Melany', 'Melba', 'Melisa', 'Melissa',\n    'Mellie', 'Melody', 'Melvin', 'Melvina', 'Melyna', 'Melyssa', 'Mercedes',\n    'Meredith', 'Merl', 'Merle', 'Merlin', 'Merritt', 'Mertie', 'Mervin',\n    'Meta', 'Mia', 'Micaela', 'Micah', 'Michael', 'Michaela', 'Michale',\n    'Micheal', 'Michel', 'Michele', 'Michelle', 'Miguel', 'Mikayla', 'Mike',\n    'Mikel', 'Milan', 'Miles', 'Milford', 'Miller', 'Millie', 'Milo', 'Milton',\n    'Mina', 'Minerva', 'Minnie', 'Miracle', 'Mireille', 'Mireya', 'Misael',\n    'Missouri', 'Misty', 'Mitchel', 'Mitchell', 'Mittie', 'Modesta', 'Modesto',\n    'Mohamed', 'Mohammad', 'Mohammed', 'Moises', 'Mollie', 'Molly', 'Mona',\n    'Monica', 'Monique', 'Monroe', 'Monserrat', 'Monserrate', 'Montana',\n    'Monte', 'Monty', 'Morgan', 'Moriah', 'Morris', 'Mortimer', 'Morton',\n    'Mose', 'Moses', 'Moshe', 'Mossie', 'Mozell', 'Mozelle', 'Muhammad',\n    'Muriel', 'Murl', 'Murphy', 'Murray', 'Mustafa', 'Mya', 'Myah', 'Mylene',\n    'Myles', 'Myra', 'Myriam', 'Myrl', 'Myrna', 'Myron', 'Myrtice', 'Myrtie',\n    'Myrtis', 'Myrtle', 'Nadia', 'Nakia', 'Name', 'Nannie', 'Naomi', 'Naomie',\n    'Napoleon', 'Narciso', 'Nash', 'Nasir', 'Nat', 'Natalia', 'Natalie',\n    'Natasha', 'Nathan', 'Nathanael', 'Nathanial', 'Nathaniel', 'Nathen',\n    'Nayeli', 'Neal', 'Ned', 'Nedra', 'Neha', 'Neil', 'Nelda', 'Nella', 'Nelle',\n    'Nellie', 'Nels', 'Nelson', 'Neoma', 'Nestor', 'Nettie', 'Neva', 'Newell',\n    'Newton', 'Nia', 'Nicholas', 'Nicholaus', 'Nichole', 'Nick', 'Nicklaus',\n    'Nickolas', 'Nico', 'Nicola', 'Nicolas', 'Nicole', 'Nicolette', 'Nigel',\n    'Nikita', 'Nikki', 'Nikko', 'Niko', 'Nikolas', 'Nils', 'Nina', 'Noah',\n    'Noble', 'Noe', 'Noel', 'Noelia', 'Noemi', 'Noemie', 'Noemy', 'Nola',\n    'Nolan', 'Nona', 'Nora', 'Norbert', 'Norberto', 'Norene', 'Norma', 'Norris',\n    'Norval', 'Norwood', 'Nova', 'Novella', 'Nya', 'Nyah', 'Nyasia', 'Obie',\n    'Oceane', 'Ocie', 'Octavia', 'Oda', 'Odell', 'Odessa', 'Odie', 'Ofelia',\n    'Okey', 'Ola', 'Olaf', 'Ole', 'Olen', 'Oleta', 'Olga', 'Olin', 'Oliver',\n    'Ollie', 'Oma', 'Omari', 'Omer', 'Ona', 'Onie', 'Opal', 'Ophelia', 'Ora',\n    'Oral', 'Oran', 'Oren', 'Orie', 'Orin', 'Orion', 'Orland', 'Orlando',\n    'Orlo', 'Orpha', 'Orrin', 'Orval', 'Orville', 'Osbaldo', 'Osborne', 'Oscar',\n    'Osvaldo', 'Oswald', 'Oswaldo', 'Otha', 'Otho', 'Otilia', 'Otis', 'Ottilie',\n    'Ottis', 'Otto', 'Ova', 'Owen', 'Ozella', 'Pablo', 'Paige', 'Palma',\n    'Pamela', 'Pansy', 'Paolo', 'Paris', 'Parker', 'Pascale', 'Pasquale', 'Pat',\n    'Patience', 'Patricia', 'Patrick', 'Patsy', 'Pattie', 'Paul', 'Paula',\n    'Pauline', 'Paxton', 'Payton', 'Pearl', 'Pearlie', 'Pearline', 'Pedro',\n    'Peggie', 'Penelope', 'Percival', 'Percy', 'Perry', 'Pete', 'Peter',\n    'Petra', 'Peyton', 'Philip', 'Phoebe', 'Phyllis', 'Pierce', 'Pierre',\n    'Pietro', 'Pink', 'Pinkie', 'Piper', 'Polly', 'Porter', 'Precious',\n    'Presley', 'Preston', 'Price', 'Prince', 'Princess', 'Priscilla',\n    'Providenci', 'Prudence', 'Queen', 'Queenie', 'Quentin', 'Quincy', 'Quinn',\n    'Quinten', 'Quinton', 'Rachael', 'Rachel', 'Rachelle', 'Rae', 'Raegan',\n    'Rafael', 'Rafaela', 'Raheem', 'Rahsaan', 'Rahul', 'Raina', 'Raleigh',\n    'Ralph', 'Ramiro', 'Ramon', 'Ramona', 'Randal', 'Randall', 'Randi', 'Randy',\n    'Ransom', 'Raoul', 'Raphael', 'Raphaelle', 'Raquel', 'Rashad', 'Rashawn',\n    'Rasheed', 'Raul', 'Raven', 'Ray', 'Raymond', 'Raymundo', 'Reagan',\n    'Reanna', 'Reba', 'Rebeca', 'Rebecca', 'Rebeka', 'Rebekah', 'Reece', 'Reed',\n    'Reese', 'Regan', 'Reggie', 'Reginald', 'Reid', 'Reilly', 'Reina',\n    'Reinhold', 'Remington', 'Rene', 'Renee', 'Ressie', 'Reta', 'Retha',\n    'Retta', 'Reuben', 'Reva', 'Rex', 'Rey', 'Reyes', 'Reymundo', 'Reyna',\n    'Reynold', 'Rhea', 'Rhett', 'Rhianna', 'Rhiannon', 'Rhoda', 'Ricardo',\n    'Richard', 'Richie', 'Richmond', 'Rick', 'Rickey', 'Rickie', 'Ricky',\n    'Rico', 'Rigoberto', 'Riley', 'Rita', 'River', 'Robb', 'Robbie', 'Robert',\n    'Roberta', 'Roberto', 'Robin', 'Robyn', 'Rocio', 'Rocky', 'Rod', 'Roderick',\n    'Rodger', 'Rodolfo', 'Rodrick', 'Rodrigo', 'Roel', 'Rogelio', 'Roger',\n    'Rogers', 'Rolando', 'Rollin', 'Roma', 'Romaine', 'Roman', 'Ron', 'Ronaldo',\n    'Ronny', 'Roosevelt', 'Rory', 'Rosa', 'Rosalee', 'Rosalia', 'Rosalind',\n    'Rosalinda', 'Rosalyn', 'Rosamond', 'Rosanna', 'Rosario', 'Roscoe', 'Rose',\n    'Rosella', 'Roselyn', 'Rosemarie', 'Rosemary', 'Rosendo', 'Rosetta',\n    'Rosie', 'Rosina', 'Roslyn', 'Ross', 'Rossie', 'Rowan', 'Rowena', 'Rowland',\n    'Roxane', 'Roxanne', 'Roy', 'Royal', 'Royce', 'Rozella', 'Ruben', 'Rubie',\n    'Ruby', 'Rubye', 'Rudolph', 'Rudy', 'Rupert', 'Russ', 'Russel', 'Russell',\n    'Rusty', 'Ruth', 'Ruthe', 'Ruthie', 'Ryan', 'Ryann', 'Ryder', 'Rylan',\n    'Rylee', 'Ryleigh', 'Ryley', 'Sabina', 'Sabrina', 'Sabryna', 'Sadie',\n    'Sadye', 'Sage', 'Saige', 'Sallie', 'Sally', 'Salma', 'Salvador',\n    'Salvatore', 'Sam', 'Samanta', 'Samantha', 'Samara', 'Samir', 'Sammie',\n    'Sammy', 'Samson', 'Sandra', 'Sandrine', 'Sandy', 'Sanford', 'Santa',\n    'Santiago', 'Santina', 'Santino', 'Santos', 'Sarah', 'Sarai', 'Sarina',\n    'Sasha', 'Saul', 'Savanah', 'Savanna', 'Savannah', 'Savion', 'Scarlett',\n    'Schuyler', 'Scot', 'Scottie', 'Scotty', 'Seamus', 'Sean', 'Sebastian',\n    'Sedrick', 'Selena', 'Selina', 'Selmer', 'Serena', 'Serenity', 'Seth',\n    'Shad', 'Shaina', 'Shakira', 'Shana', 'Shane', 'Shanel', 'Shanelle',\n    'Shania', 'Shanie', 'Shaniya', 'Shanna', 'Shannon', 'Shanny', 'Shanon',\n    'Shany', 'Sharon', 'Shaun', 'Shawn', 'Shawna', 'Shaylee', 'Shayna',\n    'Shayne', 'Shea', 'Sheila', 'Sheldon', 'Shemar', 'Sheridan', 'Sherman',\n    'Sherwood', 'Shirley', 'Shyann', 'Shyanne', 'Sibyl', 'Sid', 'Sidney',\n    'Sienna', 'Sierra', 'Sigmund', 'Sigrid', 'Sigurd', 'Silas', 'Sim', 'Simeon',\n    'Simone', 'Sincere', 'Sister', 'Skye', 'Skyla', 'Skylar', 'Sofia',\n    'Soledad', 'Solon', 'Sonia', 'Sonny', 'Sonya', 'Sophia', 'Sophie',\n    'Spencer', 'Stacey', 'Stacy', 'Stan', 'Stanford', 'Stanley', 'Stanton',\n    'Stefan', 'Stefanie', 'Stella', 'Stephan', 'Stephania', 'Stephanie',\n    'Stephany', 'Stephen', 'Stephon', 'Sterling', 'Steve', 'Stevie', 'Stewart',\n    'Stone', 'Stuart', 'Summer', 'Sunny', 'Susan', 'Susana', 'Susanna', 'Susie',\n    'Suzanne', 'Sven', 'Syble', 'Sydnee', 'Sydney', 'Sydni', 'Sydnie', 'Sylvan',\n    'Sylvester', 'Sylvia', 'Tabitha', 'Tad', 'Talia', 'Talon', 'Tamara',\n    'Tamia', 'Tania', 'Tanner', 'Tanya', 'Tara', 'Taryn', 'Tate', 'Tatum',\n    'Tatyana', 'Taurean', 'Tavares', 'Taya', 'Taylor', 'Teagan', 'Ted', 'Telly',\n    'Terence', 'Teresa', 'Terrance', 'Terrell', 'Terrence', 'Terrill', 'Terry',\n    'Tess', 'Tessie', 'Tevin', 'Thad', 'Thaddeus', 'Thalia', 'Thea', 'Thelma',\n    'Theo', 'Theodora', 'Theodore', 'Theresa', 'Therese', 'Theresia', 'Theron',\n    'Thomas', 'Thora', 'Thurman', 'Tia', 'Tiana', 'Tianna', 'Tiara', 'Tierra',\n    'Tiffany', 'Tillman', 'Timmothy', 'Timmy', 'Timothy', 'Tina', 'Tito',\n    'Titus', 'Tobin', 'Toby', 'Tod', 'Tom', 'Tomas', 'Tomasa', 'Tommie',\n    'Toney', 'Toni', 'Tony', 'Torey', 'Torrance', 'Torrey', 'Toy', 'Trace',\n    'Tracey', 'Tracy', 'Travis', 'Travon', 'Tre', 'Tremaine', 'Tremayne',\n    'Trent', 'Trenton', 'Tressa', 'Tressie', 'Treva', 'Trever', 'Trevion',\n    'Trevor', 'Trey', 'Trinity', 'Trisha', 'Tristian', 'Tristin', 'Triston',\n    'Troy', 'Trudie', 'Trycia', 'Trystan', 'Turner', 'Twila', 'Tyler', 'Tyra',\n    'Tyree', 'Tyreek', 'Tyrel', 'Tyrell', 'Tyrese', 'Tyrique', 'Tyshawn',\n    'Tyson', 'Ubaldo', 'Ulices', 'Ulises', 'Una', 'Unique', 'Urban', 'Uriah',\n    'Uriel', 'Ursula', 'Vada', 'Valentin', 'Valentina', 'Valentine', 'Valerie',\n    'Vallie', 'Van', 'Vance', 'Vanessa', 'Vaughn', 'Veda', 'Velda', 'Vella',\n    'Velma', 'Velva', 'Vena', 'Verda', 'Verdie', 'Vergie', 'Verla', 'Verlie',\n    'Vern', 'Verna', 'Verner', 'Vernice', 'Vernie', 'Vernon', 'Verona',\n    'Veronica', 'Vesta', 'Vicenta', 'Vicente', 'Vickie', 'Vicky', 'Victor',\n    'Victoria', 'Vida', 'Vidal', 'Vilma', 'Vince', 'Vincent', 'Vincenza',\n    'Vincenzo', 'Vinnie', 'Viola', 'Violet', 'Violette', 'Virgie', 'Virgil',\n    'Virginia', 'Virginie', 'Vita', 'Vito', 'Viva', 'Vivian', 'Viviane',\n    'Vivianne', 'Vivien', 'Vivienne', 'Vladimir', 'Wade', 'Waino', 'Waldo',\n    'Walker', 'Wallace', 'Walter', 'Walton', 'Wanda', 'Ward', 'Warren',\n    'Watson', 'Wava', 'Waylon', 'Wayne', 'Webster', 'Weldon', 'Wellington',\n    'Wendell', 'Wendy', 'Werner', 'Westley', 'Weston', 'Whitney', 'Wilber',\n    'Wilbert', 'Wilburn', 'Wiley', 'Wilford', 'Wilfred', 'Wilfredo', 'Wilfrid',\n    'Wilhelm', 'Wilhelmine', 'Will', 'Willa', 'Willard', 'William', 'Willie',\n    'Willis', 'Willow', 'Willy', 'Wilma', 'Wilmer', 'Wilson', 'Wilton',\n    'Winfield', 'Winifred', 'Winnifred', 'Winona', 'Winston', 'Woodrow',\n    'Wyatt', 'Wyman', 'Xander', 'Xavier', 'Xzavier', 'Yadira', 'Yasmeen',\n    'Yasmin', 'Yasmine', 'Yazmin', 'Yesenia', 'Yessenia', 'Yolanda', 'Yoshiko',\n    'Yvette', 'Yvonne', 'Zachariah', 'Zachary', 'Zachery', 'Zack', 'Zackary',\n    'Zackery', 'Zakary', 'Zander', 'Zane', 'Zaria', 'Zechariah', 'Zelda',\n    'Zella', 'Zelma', 'Zena', 'Zetta', 'Zion', 'Zita', 'Zoe', 'Zoey', 'Zoie',\n    'Zoila', 'Zola', 'Zora', 'Zula'\n];\n\n/**\n * Generate random username.\n * @returns {string} random username\n */\nfunction generateUsername() {\n    const name = RandomUtil.randomElement(names);\n    const suffix = RandomUtil.randomAlphanumStr(3);\n\n    return `${name}-${suffix}`;\n}\n\nmodule.exports = {\n    generateUsername\n};\n","export enum RTCEvents {\n    /**\n     * Indicates error while create answer call.\n     */\n    CREATE_ANSWER_FAILED = 'rtc.create_answer_failed',\n\n    /**\n     * Indicates error while create offer call.\n     */\n    CREATE_OFFER_FAILED = 'rtc.create_offer_failed',\n    DATA_CHANNEL_OPEN = 'rtc.data_channel_open',\n    ENDPOINT_CONN_STATUS_CHANGED = 'rtc.endpoint_conn_status_changed',\n    DOMINANT_SPEAKER_CHANGED = 'rtc.dominant_speaker_changed',\n    LASTN_ENDPOINT_CHANGED = 'rtc.lastn_endpoint_changed',\n    FORWARDED_SOURCES_CHANGED = 'rtc.forwarded_sources_changed',\n\n    /**\n     * Event emitted when the user granted/blocked a permission for the camera / mic.\n     * Used to keep track of the granted permissions on browsers which don't\n     * support the Permissions API.\n     */\n    PERMISSIONS_CHANGED = 'rtc.permissions_changed',\n\n    SENDER_VIDEO_CONSTRAINTS_CHANGED = 'rtc.sender_video_constraints_changed',\n\n    /**\n     * Event emitted when {@link RTC.setLastN} method is called to update with\n     * the new value set.\n     * The first argument is the value passed to {@link RTC.setLastN}.\n     */\n    LASTN_VALUE_CHANGED = 'rtc.lastn_value_changed',\n\n    /**\n     * Event emitted when ssrc for a local track is extracted and stored\n     * in {@link TraceablePeerConnection}.\n     * @param {JitsiLocalTrack} track which ssrc was updated\n     * @param {string} ssrc that was stored\n     */\n    LOCAL_TRACK_SSRC_UPDATED = 'rtc.local_track_ssrc_updated',\n\n    /**\n     * The max enabled resolution of a local video track was changed.\n     */\n    LOCAL_TRACK_MAX_ENABLED_RESOLUTION_CHANGED = 'rtc.local_track_max_enabled_resolution_changed',\n\n    TRACK_ATTACHED = 'rtc.track_attached',\n\n    /**\n     * Event fired when we remote track is added to the conference.\n     * 1st event argument is the added <tt>JitsiRemoteTrack</tt> instance.\n     **/\n    REMOTE_TRACK_ADDED = 'rtc.remote_track_added',\n\n    // FIXME get rid of this event in favour of NO_DATA_FROM_SOURCE event\n    // (currently implemented for local tracks only)\n    REMOTE_TRACK_MUTE = 'rtc.remote_track_mute',\n\n    /**\n     * Indicates that the remote track has been removed from the conference.\n     * 1st event argument is the removed {@link JitsiRemoteTrack} instance.\n     */\n    REMOTE_TRACK_REMOVED = 'rtc.remote_track_removed',\n\n    // FIXME get rid of this event in favour of NO_DATA_FROM_SOURCE event\n    // (currently implemented for local tracks only)\n    REMOTE_TRACK_UNMUTE = 'rtc.remote_track_unmute',\n\n    /**\n     * Indicates error while set local description.\n     */\n    SET_LOCAL_DESCRIPTION_FAILED = 'rtc.set_local_description_failed',\n\n    /**\n     * Indicates error while set remote description.\n     */\n    SET_REMOTE_DESCRIPTION_FAILED = 'rtc.set_remote_description_failed',\n    AUDIO_OUTPUT_DEVICE_CHANGED = 'rtc.audio_output_device_changed',\n    DEVICE_LIST_CHANGED = 'rtc.device_list_changed',\n\n    /**\n     * Indicates that the list with available devices will change.\n     */\n    DEVICE_LIST_WILL_CHANGE = 'rtc.device_list_will_change',\n    DEVICE_LIST_AVAILABLE = 'rtc.device_list_available',\n\n    /**\n     * Indicates that a message from another participant is received on\n     * data channel.\n     */\n    ENDPOINT_MESSAGE_RECEIVED = 'rtc.endpoint_message_received',\n\n    /**\n     * Indicates that the remote endpoint stats have been received on data channel.\n     */\n    ENDPOINT_STATS_RECEIVED = 'rtc.endpoint_stats_received',\n\n    /**\n     * Designates an event indicating that the local ICE username fragment of\n     * the jingle session has changed.\n     * The first argument of the vent is <tt>TraceablePeerConnection</tt> which\n     * is the source of the event.\n     * The second argument is the actual \"ufrag\" string.\n     */\n    LOCAL_UFRAG_CHANGED = 'rtc.local_ufrag_changed',\n\n    /**\n     * Designates an event indicating that the local ICE username fragment of\n     * the jingle session has changed.\n     * The first argument of the vent is <tt>TraceablePeerConnection</tt> which\n     * is the source of the event.\n     * The second argument is the actual \"ufrag\" string.\n     */\n    REMOTE_UFRAG_CHANGED = 'rtc.remote_ufrag_changed'\n};\n\nexport const CREATE_ANSWER_FAILED = RTCEvents.CREATE_ANSWER_FAILED;\nexport const CREATE_OFFER_FAILED = RTCEvents.CREATE_OFFER_FAILED;\nexport const DATA_CHANNEL_OPEN = RTCEvents.DATA_CHANNEL_OPEN;\nexport const ENDPOINT_CONN_STATUS_CHANGED = RTCEvents.ENDPOINT_CONN_STATUS_CHANGED;\nexport const DOMINANT_SPEAKER_CHANGED = RTCEvents.DOMINANT_SPEAKER_CHANGED;\nexport const LASTN_ENDPOINT_CHANGED = RTCEvents.LASTN_ENDPOINT_CHANGED;\nexport const FORWARDED_SOURCES_CHANGED = RTCEvents.FORWARDED_SOURCES_CHANGED;\nexport const PERMISSIONS_CHANGED = RTCEvents.PERMISSIONS_CHANGED;\nexport const SENDER_VIDEO_CONSTRAINTS_CHANGED = RTCEvents.SENDER_VIDEO_CONSTRAINTS_CHANGED;\nexport const LASTN_VALUE_CHANGED = RTCEvents.LASTN_VALUE_CHANGED;\nexport const LOCAL_TRACK_SSRC_UPDATED = RTCEvents.LOCAL_TRACK_SSRC_UPDATED;\nexport const LOCAL_TRACK_MAX_ENABLED_RESOLUTION_CHANGED = RTCEvents.LOCAL_TRACK_MAX_ENABLED_RESOLUTION_CHANGED;\nexport const TRACK_ATTACHED = RTCEvents.TRACK_ATTACHED;\nexport const REMOTE_TRACK_ADDED = RTCEvents.REMOTE_TRACK_ADDED;\nexport const REMOTE_TRACK_MUTE = RTCEvents.REMOTE_TRACK_MUTE;\nexport const REMOTE_TRACK_REMOVED = RTCEvents.REMOTE_TRACK_REMOVED;\nexport const REMOTE_TRACK_UNMUTE = RTCEvents.REMOTE_TRACK_UNMUTE;\nexport const SET_LOCAL_DESCRIPTION_FAILED = RTCEvents.SET_LOCAL_DESCRIPTION_FAILED;\nexport const SET_REMOTE_DESCRIPTION_FAILED = RTCEvents.SET_REMOTE_DESCRIPTION_FAILED;\nexport const AUDIO_OUTPUT_DEVICE_CHANGED = RTCEvents.AUDIO_OUTPUT_DEVICE_CHANGED;\nexport const DEVICE_LIST_CHANGED = RTCEvents.DEVICE_LIST_CHANGED;\nexport const DEVICE_LIST_WILL_CHANGE = RTCEvents.DEVICE_LIST_WILL_CHANGE;\nexport const DEVICE_LIST_AVAILABLE = RTCEvents.DEVICE_LIST_AVAILABLE;\nexport const ENDPOINT_MESSAGE_RECEIVED = RTCEvents.ENDPOINT_MESSAGE_RECEIVED;\nexport const ENDPOINT_STATS_RECEIVED = RTCEvents.ENDPOINT_STATS_RECEIVED;\nexport const LOCAL_UFRAG_CHANGED = RTCEvents.LOCAL_UFRAG_CHANGED;\nexport const REMOTE_UFRAG_CHANGED = RTCEvents.REMOTE_UFRAG_CHANGED;\n\n// TODO: this was a pre-ES6 module using module.exports = RTCEvents which doesn't translate well\n// it is used in a number of places and should be updated to use the named export\n\nexport default RTCEvents;","export const Resolutions = {\n    '2160': {\n        width: 3840,\n        height: 2160\n    },\n    '4k': {\n        width: 3840,\n        height: 2160\n    },\n    '1080': {\n        width: 1920,\n        height: 1080\n    },\n    'fullhd': {\n        width: 1920,\n        height: 1080\n    },\n    '720': {\n        width: 1280,\n        height: 720\n    },\n    'hd': {\n        width: 1280,\n        height: 720\n    },\n    '540': {\n        width: 960,\n        height: 540\n    },\n    'qhd': {\n        width: 960,\n        height: 540\n    },\n    '480': {\n        width: 640,\n        height: 480\n    },\n    'vga': {\n        width: 640,\n        height: 480\n    },\n    '360': {\n        width: 640,\n        height: 360\n    },\n    '240': {\n        width: 320,\n        height: 240\n    },\n    '180': {\n        width: 320,\n        height: 180\n    }\n};\n\nexport default Resolutions;\n","/**\n * Enumeration of the video types\n */\nexport enum VideoType {\n    /**\n     * The camera video type.\n     */\n    CAMERA = 'camera',\n\n    /**\n     * The desktop video type.\n     */\n    DESKTOP = 'desktop'\n};\n","export const AuthenticationEvents = {\n    /**\n     * Event callback arguments:\n     * function(authenticationEnabled, userIdentity)\n     * authenticationEnabled - indicates whether authentication has been enabled\n     *                         in this session\n     * userIdentity - if user has been logged in then it contains user name. If\n     *                contains 'null' or 'undefined' then user is not logged in.\n     */\n    IDENTITY_UPDATED: 'authentication.identity_updated'\n};\n\nexport default AuthenticationEvents;\n","export enum XMPPEvents {\n    /**\n     * Indicates error while adding ice candidate.\n     */\n    ADD_ICE_CANDIDATE_FAILED = 'xmpp.add_ice_candidate_failed',\n\n    // Designates an event indicating that the focus has asked us to mute our\n    // audio.\n    AUDIO_MUTED_BY_FOCUS = 'xmpp.audio_muted_by_focus',\n\n    // Designates an event indicating that the focus has asked us to disable our\n    // camera.\n    VIDEO_MUTED_BY_FOCUS = 'xmpp.video_muted_by_focus',\n    AUTHENTICATION_REQUIRED = 'xmpp.authentication_required',\n    BRIDGE_DOWN = 'xmpp.bridge_down',\n\n    /**\n     * Triggered when 'session-accept' is received from the responder.\n     */\n    CALL_ACCEPTED = 'xmpp.callaccepted.jingle',\n\n    // Designates an event indicating that an offer (e.g. Jingle\n    // session-initiate) was received.\n    CALL_INCOMING = 'xmpp.callincoming.jingle',\n\n    // Triggered when Jicofo kills our media session, this can happen while\n    // we're still in the MUC, when it decides to terminate the media session.\n    // For example when the session is idle for too long, because we're the only\n    // person in the conference room.\n    CALL_ENDED = 'xmpp.callended.jingle',\n    CHAT_ERROR_RECEIVED = 'xmpp.chat_error_received',\n    SETTINGS_ERROR_RECEIVED = 'xmpp.settings_error_received',\n\n    // The conference properties (as advertised by jicofo) have changed\n    CONFERENCE_PROPERTIES_CHANGED = 'xmpp.conference_properties_changed',\n\n    /**\n     * This event is triggered when the ICE connects for the first time.\n     */\n    CONNECTION_ESTABLISHED = 'xmpp.connection.connected',\n\n    // Designates an event indicating that the connection to the XMPP server\n    // failed.\n    CONNECTION_FAILED = 'xmpp.connection.failed',\n\n    // Designates an event indicating that the media (ICE) connection was\n    // interrupted. This should go to the RTC module.\n    CONNECTION_INTERRUPTED = 'xmpp.connection.interrupted',\n\n    // Designates an event indicating that the media (ICE) connection was\n    // restored. This should go to the RTC module.\n    CONNECTION_RESTORED = 'xmpp.connection.restored',\n\n    // Designates an event indicating that the media (ICE) connection failed.\n    // This should go to the RTC module.\n    CONNECTION_ICE_FAILED = 'xmpp.connection.ice.failed',\n\n    // Designates an event indicating that the call has been migrated to a different\n    // bridge and that the client needs to be restarted for a successful transition.\n    CONNECTION_RESTARTED = 'xmpp.connection.restart',\n\n    /**\n     * Designates an event indicating connection status changes.\n     */\n    CONNECTION_STATUS_CHANGED = 'xmpp.connection.status.changed',\n\n    // Designates an event indicating that the display name of a participant\n    // has changed.\n    DISPLAY_NAME_CHANGED = 'xmpp.display_name_changed',\n\n    /**\n     * Chat room instance have been added to Strophe.emuc plugin.\n     */\n    EMUC_ROOM_ADDED = 'xmpp.emuc_room_added',\n\n    /**\n     * Chat room instance have been removed from Strophe.emuc plugin.\n     */\n    EMUC_ROOM_REMOVED = 'xmpp.emuc_room_removed',\n    ETHERPAD = 'xmpp.etherpad',\n    FOCUS_DISCONNECTED = 'xmpp.focus_disconnected',\n    FOCUS_LEFT = 'xmpp.focus_left',\n    GRACEFUL_SHUTDOWN = 'xmpp.graceful_shutdown',\n\n    /**\n     * Event fired when 'transport-replace' Jingle message has been received,\n     * before the new offer is set on the PeerConnection.\n     */\n    ICE_RESTARTING = 'rtc.ice_restarting',\n\n    /**\n     * Event fired after the 'transport-replace' message has been processed\n     * and the new offer has been set successfully.\n     */\n    ICE_RESTART_SUCCESS = 'rtc.ice_restart_success',\n\n    /**\n     * Designates an event indicating that we were kicked from the XMPP MUC.\n     * @param {boolean} isSelfPresence - whether it is for local participant\n     * or another participant.\n     * @param {string} actorJid - the jid of the participant who was initiator\n     * of the kick.\n     * @param {?string} participantJid - when it is not a kick for local participant,\n     * this is the jid of the participant which was kicked.\n     */\n    KICKED = 'xmpp.kicked',\n\n    // Designates an event indicating that our role in the XMPP MUC has changed.\n    LOCAL_ROLE_CHANGED = 'xmpp.localrole_changed',\n\n    /**\n     * Event fired when the unique meeting id is set.\n     */\n    MEETING_ID_SET = 'xmpp.meeting_id_set',\n\n    // Designates an event indicating that an XMPP message in the MUC was\n    // received.\n    MESSAGE_RECEIVED = 'xmpp.message_received',\n\n    // Designates an event indicating that an invite XMPP message in the MUC was\n    // received.\n    INVITE_MESSAGE_RECEIVED = 'xmpp.invite_message_received',\n\n    // Designates an event indicating that a private XMPP message in the MUC was\n    // received.\n    PRIVATE_MESSAGE_RECEIVED = 'xmpp.private_message_received',\n\n    // Designates an event indicating that a bot participant type had changed\n    MUC_MEMBER_BOT_TYPE_CHANGED = 'xmpp.muc_member_bot_type_changed',\n\n    // Designates an event indicating that the XMPP MUC was destroyed.\n    MUC_DESTROYED = 'xmpp.muc_destroyed',\n\n    // Designates an event indicating that we are currently in process of joining the XMPP MUC.\n    MUC_JOIN_IN_PROGRESS = 'xmpp.muc_join_in_progress',\n\n    // Designates an event indicating that we have joined the XMPP MUC.\n    MUC_JOINED = 'xmpp.muc_joined',\n\n    // Designates an event indicating that a participant joined the XMPP MUC.\n    MUC_MEMBER_JOINED = 'xmpp.muc_member_joined',\n\n    // Designates an event indicating that a participant left the XMPP MUC.\n    MUC_MEMBER_LEFT = 'xmpp.muc_member_left',\n\n    // Designates an event indicating that a participant joined the lobby XMPP MUC.\n    MUC_LOBBY_MEMBER_JOINED = 'xmpp.muc_lobby_member_joined',\n\n    // Designates an event indicating that a participant in the lobby XMPP MUC has been updated\n    MUC_LOBBY_MEMBER_UPDATED = 'xmpp.muc_lobby_member_updated',\n\n    // Designates an event indicating that a participant left the XMPP MUC.\n    MUC_LOBBY_MEMBER_LEFT = 'xmpp.muc_lobby_member_left',\n\n    // Designates an event indicating that a participant was denied access to a conference from the lobby XMPP MUC.\n    MUC_DENIED_ACCESS = 'xmpp.muc_denied access',\n\n    // Designates an event indicating that local participant left the muc\n    MUC_LEFT = 'xmpp.muc_left',\n\n    // Designates an event indicating that the MUC role of a participant has\n    // changed.\n    MUC_ROLE_CHANGED = 'xmpp.muc_role_changed',\n\n    // Designates an event indicating that the MUC has been locked or unlocked.\n    MUC_LOCK_CHANGED = 'xmpp.muc_lock_changed',\n\n    // Designates an event indicating that the MUC members only config has changed.\n    MUC_MEMBERS_ONLY_CHANGED = 'xmpp.muc_members_only_changed',\n\n    // Designates an event indicating that a participant in the XMPP MUC has\n    // advertised that they have audio muted (or unmuted).\n    PARTICIPANT_AUDIO_MUTED = 'xmpp.audio_muted',\n\n    // Designates an event indicating that a participant in the XMPP MUC has\n    // advertised that they have video muted (or unmuted).\n    PARTICIPANT_VIDEO_MUTED = 'xmpp.video_muted',\n\n    // Designates an event indicating that the video type (e.g. 'camera' or\n    // 'screen') for a participant has changed.\n    // Note = currently this event fires every time we receive presence from\n    // someone (regardless of whether or not the \"video type\" changed).\n    PARTICIPANT_VIDEO_TYPE_CHANGED = 'xmpp.video_type',\n\n    /**\n     * Indicates that the features of the participant has been changed.\n     */\n    PARTICIPANT_FEATURES_CHANGED = 'xmpp.participant_features_changed',\n    PASSWORD_REQUIRED = 'xmpp.password_required',\n\n    /**\n     * Indicates that phone number changed.\n     */\n    PHONE_NUMBER_CHANGED = 'conference.phoneNumberChanged',\n    PRESENCE_RECEIVED = 'xmpp.presence_received',\n    PRESENCE_STATUS = 'xmpp.presence_status',\n    PROMPT_FOR_LOGIN = 'xmpp.prompt_for_login',\n\n    // xmpp is connected and obtained user media\n    READY_TO_JOIN = 'xmpp.ready_to_join',\n\n    /**\n     * Indicates that recording state changed.\n     */\n    RECORDER_STATE_CHANGED = 'xmpp.recorderStateChanged',\n\n    // Designates an event indicating that we received statistics from a\n    // participant in the MUC.\n    REMOTE_STATS = 'xmpp.remote_stats',\n\n    /**\n     * Indicates that the offer / answer renegotiation has failed.\n     */\n    RENEGOTIATION_FAILED = 'xmpp.renegotiation_failed',\n    RESERVATION_ERROR = 'xmpp.room_reservation_error',\n    ROOM_CONNECT_ERROR = 'xmpp.room_connect_error',\n    ROOM_CONNECT_NOT_ALLOWED_ERROR = 'xmpp.room_connect_error.not_allowed',\n    ROOM_JOIN_ERROR = 'xmpp.room_join_error',\n    ROOM_CONNECT_MEMBERS_ONLY_ERROR = 'xmpp.room_connect_error.members_only',\n\n    /**\n     * Indicates that max users limit has been reached.\n     */\n    ROOM_MAX_USERS_ERROR = 'xmpp.room_max_users_error',\n\n    // Designates an event indicating that we sent an XMPP message to the MUC.\n    SENDING_CHAT_MESSAGE = 'xmpp.sending_chat_message',\n\n    // Designates an event indicating that we sent a private XMPP message to\n    // a specific user of the muc.\n    SENDING_PRIVATE_CHAT_MESSAGE = 'xmpp.sending_private_chat_message',\n\n    /**\n     * Event fired after receiving the confirmation about session accept.\n     */\n    SESSION_ACCEPT = 'xmpp.session_accept',\n\n    /**\n     * Event fired if we receive an error after sending the session accept.\n     */\n    SESSION_ACCEPT_ERROR = 'xmpp.session_accept_error',\n\n    /**\n     * Event fired when we do not get our 'session-accept' acknowledged by\n     * Jicofo. It most likely means that there is serious problem with our\n     * connection or XMPP server and we should reload the conference.\n     *\n     * We have seen that to happen in BOSH requests race condition when the BOSH\n     * request table containing the 'session-accept' was discarded by Prosody.\n     * Jicofo does send the RESULT immediately without any condition, so missing\n     * packets means that most likely it has never seen our IQ.\n     */\n    SESSION_ACCEPT_TIMEOUT = 'xmpp.session_accept_timeout',\n\n    /**\n     * Event fired after successful sending of jingle source-add.\n     */\n    SOURCE_ADD = 'xmpp.source_add',\n\n    /**\n     * Event fired after receiving an error sending of jingle source-add.\n     */\n    SOURCE_ADD_ERROR = 'xmpp.source_add_error',\n\n    /**\n     * Event fired after successful sending of jingle source-remove.\n     */\n    SOURCE_REMOVE = 'xmpp.source_remove',\n\n    /**\n     * Event fired after receiving an error sending of jingle source-remove.\n     */\n    SOURCE_REMOVE_ERROR = 'xmpp.source_remove_error',\n\n    /**\n     * Event fired when speaker stats update message is received.\n     */\n    SPEAKER_STATS_RECEIVED = 'xmpp.speaker_stats_received',\n\n    /**\n     * Event fired when conference creation timestamp is received.\n     */\n    CONFERENCE_TIMESTAMP_RECEIVED = 'xmpp.conference_timestamp_received',\n\n    /**\n     * Event fired when we receive a message for AV moderation approved for the local participant.\n     */\n    AV_MODERATION_APPROVED = 'xmpp.av_moderation.approved',\n\n    /**\n    * Event fired when we receive a message for AV moderation rejected for the local participant.\n    */\n    AV_MODERATION_REJECTED = 'xmpp.av_moderation.rejected',\n\n    /**\n     * Event fired when we receive a message for AV moderation.\n     */\n    AV_MODERATION_RECEIVED = 'xmpp.av_moderation.received',\n\n    /**\n     * Event fired when the moderation enable/disable changes.\n     */\n    AV_MODERATION_CHANGED = 'xmpp.av_moderation.changed',\n\n    /**\n     * Event fired when we receive message that a new jid was approved.\n     */\n    AV_MODERATION_PARTICIPANT_APPROVED = 'xmpp.av_moderation.participant.approved',\n\n    /**\n     * Event fired when we receive message that a new jid was approved.\n     */\n    AV_MODERATION_PARTICIPANT_REJECTED = 'xmpp.av_moderation.participant.rejected',\n\n    /**\n     * Event fired when a participant is requested to join a given (breakout) room.\n     */\n    BREAKOUT_ROOMS_MOVE_TO_ROOM = 'xmpp.breakout-rooms.move-to-room',\n\n    /**\n     * Event fired when we receive a message for breakout rooms.\n     */\n    BREAKOUT_ROOMS_EVENT = 'xmpp.breakout-rooms.event',\n\n    /**\n     * Event fired when the breakout rooms data was updated.\n     */\n    BREAKOUT_ROOMS_UPDATED = 'xmpp.breakout-rooms.updated',\n\n    // Designates an event indicating that we should join the conference with\n    // audio and/or video muted.\n    START_MUTED_FROM_FOCUS = 'xmpp.start_muted_from_focus',\n\n    // Designates an event indicating that the subject of the XMPP MUC has\n    // changed.\n    SUBJECT_CHANGED = 'xmpp.subject_changed',\n\n    // FIXME: how does it belong to XMPP ? - it's detected by the PeerConnection\n    // suspending detected\n    SUSPEND_DETECTED = 'xmpp.suspend_detected',\n\n    /**\n     * Notifies for transcription status changes. The event provides the\n     * following parameters to its listeners:\n     *\n     * @param {String} status - The new status.\n     */\n    TRANSCRIPTION_STATUS_CHANGED = 'xmpp.transcription_status_changed',\n\n    /**\n     * Event fired when 'transport-info' with new ICE candidates is received.\n     */\n    TRANSPORT_INFO = 'xmpp.transportinfo.jingle',\n\n    /**\n     * Indicates that video SIP GW state changed.\n     *\n     * @param {VideoSIPGWConstants} status - Any of the following statuses:\n     * STATUS_BUSY, STATUS_AVAILABLE or STATUS_UNDEFINED.\n     */\n    VIDEO_SIP_GW_AVAILABILITY_CHANGED = 'xmpp.videoSIPGWAvailabilityChanged',\n\n    /**\n     * Indicates that video SIP GW Session state changed.\n     * The statuses are any of the following statuses:\n     * STATE_ON, STATE_OFF, STATE_PENDING, STATE_RETRYING, STATE_FAILED.\n     * {@see VideoSIPGWConstants}\n     *\n     * @param {options} event - {address, oldState, newState, displayName}.\n     */\n    VIDEO_SIP_GW_SESSION_STATE_CHANGED = 'xmpp.videoSIPGWSessionStateChanged',\n\n    // Designates an event indicating that the local ICE connection state has\n    // changed.\n    ICE_CONNECTION_STATE_CHANGED = 'xmpp.ice_connection_state_changed',\n\n    /**\n     * Event which is emitted when the body in an XMPP message in the MUC\n     * contains JSON\n     * TODO: this event contains a typo (xmmp vs xmpp) but it's unlikely this can be changed now\n     */\n    JSON_MESSAGE_RECEIVED = 'xmmp.json_message_received'\n};\n","'use strict'\n\nexports.byteLength = byteLength\nexports.toByteArray = toByteArray\nexports.fromByteArray = fromByteArray\n\nvar lookup = []\nvar revLookup = []\nvar Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array\n\nvar code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'\nfor (var i = 0, len = code.length; i < len; ++i) {\n  lookup[i] = code[i]\n  revLookup[code.charCodeAt(i)] = i\n}\n\n// Support decoding URL-safe base64 strings, as Node.js does.\n// See: https://en.wikipedia.org/wiki/Base64#URL_applications\nrevLookup['-'.charCodeAt(0)] = 62\nrevLookup['_'.charCodeAt(0)] = 63\n\nfunction getLens (b64) {\n  var len = b64.length\n\n  if (len % 4 > 0) {\n    throw new Error('Invalid string. Length must be a multiple of 4')\n  }\n\n  // Trim off extra bytes after placeholder bytes are found\n  // See: https://github.com/beatgammit/base64-js/issues/42\n  var validLen = b64.indexOf('=')\n  if (validLen === -1) validLen = len\n\n  var placeHoldersLen = validLen === len\n    ? 0\n    : 4 - (validLen % 4)\n\n  return [validLen, placeHoldersLen]\n}\n\n// base64 is 4/3 + up to two characters of the original data\nfunction byteLength (b64) {\n  var lens = getLens(b64)\n  var validLen = lens[0]\n  var placeHoldersLen = lens[1]\n  return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen\n}\n\nfunction _byteLength (b64, validLen, placeHoldersLen) {\n  return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen\n}\n\nfunction toByteArray (b64) {\n  var tmp\n  var lens = getLens(b64)\n  var validLen = lens[0]\n  var placeHoldersLen = lens[1]\n\n  var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen))\n\n  var curByte = 0\n\n  // if there are placeholders, only get up to the last complete 4 chars\n  var len = placeHoldersLen > 0\n    ? validLen - 4\n    : validLen\n\n  var i\n  for (i = 0; i < len; i += 4) {\n    tmp =\n      (revLookup[b64.charCodeAt(i)] << 18) |\n      (revLookup[b64.charCodeAt(i + 1)] << 12) |\n      (revLookup[b64.charCodeAt(i + 2)] << 6) |\n      revLookup[b64.charCodeAt(i + 3)]\n    arr[curByte++] = (tmp >> 16) & 0xFF\n    arr[curByte++] = (tmp >> 8) & 0xFF\n    arr[curByte++] = tmp & 0xFF\n  }\n\n  if (placeHoldersLen === 2) {\n    tmp =\n      (revLookup[b64.charCodeAt(i)] << 2) |\n      (revLookup[b64.charCodeAt(i + 1)] >> 4)\n    arr[curByte++] = tmp & 0xFF\n  }\n\n  if (placeHoldersLen === 1) {\n    tmp =\n      (revLookup[b64.charCodeAt(i)] << 10) |\n      (revLookup[b64.charCodeAt(i + 1)] << 4) |\n      (revLookup[b64.charCodeAt(i + 2)] >> 2)\n    arr[curByte++] = (tmp >> 8) & 0xFF\n    arr[curByte++] = tmp & 0xFF\n  }\n\n  return arr\n}\n\nfunction tripletToBase64 (num) {\n  return lookup[num >> 18 & 0x3F] +\n    lookup[num >> 12 & 0x3F] +\n    lookup[num >> 6 & 0x3F] +\n    lookup[num & 0x3F]\n}\n\nfunction encodeChunk (uint8, start, end) {\n  var tmp\n  var output = []\n  for (var i = start; i < end; i += 3) {\n    tmp =\n      ((uint8[i] << 16) & 0xFF0000) +\n      ((uint8[i + 1] << 8) & 0xFF00) +\n      (uint8[i + 2] & 0xFF)\n    output.push(tripletToBase64(tmp))\n  }\n  return output.join('')\n}\n\nfunction fromByteArray (uint8) {\n  var tmp\n  var len = uint8.length\n  var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes\n  var parts = []\n  var maxChunkLength = 16383 // must be multiple of 3\n\n  // go through the array every three bytes, we'll deal with trailing stuff later\n  for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {\n    parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)))\n  }\n\n  // pad the end with zeros, but make sure to not forget the extra bytes\n  if (extraBytes === 1) {\n    tmp = uint8[len - 1]\n    parts.push(\n      lookup[tmp >> 2] +\n      lookup[(tmp << 4) & 0x3F] +\n      '=='\n    )\n  } else if (extraBytes === 2) {\n    tmp = (uint8[len - 2] << 8) + uint8[len - 1]\n    parts.push(\n      lookup[tmp >> 10] +\n      lookup[(tmp >> 4) & 0x3F] +\n      lookup[(tmp << 2) & 0x3F] +\n      '='\n    )\n  }\n\n  return parts.join('')\n}\n","!function(e,t){\"object\"==typeof exports&&\"object\"==typeof module?module.exports=t():\"function\"==typeof define&&define.amd?define([],t):\"object\"==typeof exports?exports.bowser=t():e.bowser=t()}(this,(function(){return function(e){var t={};function r(i){if(t[i])return t[i].exports;var n=t[i]={i:i,l:!1,exports:{}};return e[i].call(n.exports,n,n.exports,r),n.l=!0,n.exports}return r.m=e,r.c=t,r.d=function(e,t,i){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},r.r=function(e){\"undefined\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\"Module\"}),Object.defineProperty(e,\"__esModule\",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&\"object\"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(r.r(i),Object.defineProperty(i,\"default\",{enumerable:!0,value:e}),2&t&&\"string\"!=typeof e)for(var n in e)r.d(i,n,function(t){return e[t]}.bind(null,n));return i},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,\"a\",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p=\"\",r(r.s=90)}({17:function(e,t,r){\"use strict\";t.__esModule=!0,t.default=void 0;var i=r(18),n=function(){function e(){}return e.getFirstMatch=function(e,t){var r=t.match(e);return r&&r.length>0&&r[1]||\"\"},e.getSecondMatch=function(e,t){var r=t.match(e);return r&&r.length>1&&r[2]||\"\"},e.matchAndReturnConst=function(e,t,r){if(e.test(t))return r},e.getWindowsVersionName=function(e){switch(e){case\"NT\":return\"NT\";case\"XP\":return\"XP\";case\"NT 5.0\":return\"2000\";case\"NT 5.1\":return\"XP\";case\"NT 5.2\":return\"2003\";case\"NT 6.0\":return\"Vista\";case\"NT 6.1\":return\"7\";case\"NT 6.2\":return\"8\";case\"NT 6.3\":return\"8.1\";case\"NT 10.0\":return\"10\";default:return}},e.getMacOSVersionName=function(e){var t=e.split(\".\").splice(0,2).map((function(e){return parseInt(e,10)||0}));if(t.push(0),10===t[0])switch(t[1]){case 5:return\"Leopard\";case 6:return\"Snow Leopard\";case 7:return\"Lion\";case 8:return\"Mountain Lion\";case 9:return\"Mavericks\";case 10:return\"Yosemite\";case 11:return\"El Capitan\";case 12:return\"Sierra\";case 13:return\"High Sierra\";case 14:return\"Mojave\";case 15:return\"Catalina\";default:return}},e.getAndroidVersionName=function(e){var t=e.split(\".\").splice(0,2).map((function(e){return parseInt(e,10)||0}));if(t.push(0),!(1===t[0]&&t[1]<5))return 1===t[0]&&t[1]<6?\"Cupcake\":1===t[0]&&t[1]>=6?\"Donut\":2===t[0]&&t[1]<2?\"Eclair\":2===t[0]&&2===t[1]?\"Froyo\":2===t[0]&&t[1]>2?\"Gingerbread\":3===t[0]?\"Honeycomb\":4===t[0]&&t[1]<1?\"Ice Cream Sandwich\":4===t[0]&&t[1]<4?\"Jelly Bean\":4===t[0]&&t[1]>=4?\"KitKat\":5===t[0]?\"Lollipop\":6===t[0]?\"Marshmallow\":7===t[0]?\"Nougat\":8===t[0]?\"Oreo\":9===t[0]?\"Pie\":void 0},e.getVersionPrecision=function(e){return e.split(\".\").length},e.compareVersions=function(t,r,i){void 0===i&&(i=!1);var n=e.getVersionPrecision(t),s=e.getVersionPrecision(r),o=Math.max(n,s),a=0,u=e.map([t,r],(function(t){var r=o-e.getVersionPrecision(t),i=t+new Array(r+1).join(\".0\");return e.map(i.split(\".\"),(function(e){return new Array(20-e.length).join(\"0\")+e})).reverse()}));for(i&&(a=o-Math.min(n,s)),o-=1;o>=a;){if(u[0][o]>u[1][o])return 1;if(u[0][o]===u[1][o]){if(o===a)return 0;o-=1}else if(u[0][o]<u[1][o])return-1}},e.map=function(e,t){var r,i=[];if(Array.prototype.map)return Array.prototype.map.call(e,t);for(r=0;r<e.length;r+=1)i.push(t(e[r]));return i},e.getBrowserAlias=function(e){return i.BROWSER_ALIASES_MAP[e]},e.getBrowserTypeByAlias=function(e){return i.BROWSER_MAP[e]||\"\"},e}();t.default=n,e.exports=t.default},18:function(e,t,r){\"use strict\";t.__esModule=!0,t.ENGINE_MAP=t.OS_MAP=t.PLATFORMS_MAP=t.BROWSER_MAP=t.BROWSER_ALIASES_MAP=void 0;t.BROWSER_ALIASES_MAP={\"Amazon Silk\":\"amazon_silk\",\"Android Browser\":\"android\",Bada:\"bada\",BlackBerry:\"blackberry\",Chrome:\"chrome\",Chromium:\"chromium\",Epiphany:\"epiphany\",Firefox:\"firefox\",Focus:\"focus\",Generic:\"generic\",\"Google Search\":\"google_search\",Googlebot:\"googlebot\",\"Internet Explorer\":\"ie\",\"K-Meleon\":\"k_meleon\",Maxthon:\"maxthon\",\"Microsoft Edge\":\"edge\",\"MZ Browser\":\"mz\",\"NAVER Whale Browser\":\"naver\",Opera:\"opera\",\"Opera Coast\":\"opera_coast\",PhantomJS:\"phantomjs\",Puffin:\"puffin\",QupZilla:\"qupzilla\",QQ:\"qq\",QQLite:\"qqlite\",Safari:\"safari\",Sailfish:\"sailfish\",\"Samsung Internet for Android\":\"samsung_internet\",SeaMonkey:\"seamonkey\",Sleipnir:\"sleipnir\",Swing:\"swing\",Tizen:\"tizen\",\"UC Browser\":\"uc\",Vivaldi:\"vivaldi\",\"WebOS Browser\":\"webos\",WeChat:\"wechat\",\"Yandex Browser\":\"yandex\",Roku:\"roku\"};t.BROWSER_MAP={amazon_silk:\"Amazon Silk\",android:\"Android Browser\",bada:\"Bada\",blackberry:\"BlackBerry\",chrome:\"Chrome\",chromium:\"Chromium\",epiphany:\"Epiphany\",firefox:\"Firefox\",focus:\"Focus\",generic:\"Generic\",googlebot:\"Googlebot\",google_search:\"Google Search\",ie:\"Internet Explorer\",k_meleon:\"K-Meleon\",maxthon:\"Maxthon\",edge:\"Microsoft Edge\",mz:\"MZ Browser\",naver:\"NAVER Whale Browser\",opera:\"Opera\",opera_coast:\"Opera Coast\",phantomjs:\"PhantomJS\",puffin:\"Puffin\",qupzilla:\"QupZilla\",qq:\"QQ Browser\",qqlite:\"QQ Browser Lite\",safari:\"Safari\",sailfish:\"Sailfish\",samsung_internet:\"Samsung Internet for Android\",seamonkey:\"SeaMonkey\",sleipnir:\"Sleipnir\",swing:\"Swing\",tizen:\"Tizen\",uc:\"UC Browser\",vivaldi:\"Vivaldi\",webos:\"WebOS Browser\",wechat:\"WeChat\",yandex:\"Yandex Browser\"};t.PLATFORMS_MAP={tablet:\"tablet\",mobile:\"mobile\",desktop:\"desktop\",tv:\"tv\"};t.OS_MAP={WindowsPhone:\"Windows Phone\",Windows:\"Windows\",MacOS:\"macOS\",iOS:\"iOS\",Android:\"Android\",WebOS:\"WebOS\",BlackBerry:\"BlackBerry\",Bada:\"Bada\",Tizen:\"Tizen\",Linux:\"Linux\",ChromeOS:\"Chrome OS\",PlayStation4:\"PlayStation 4\",Roku:\"Roku\"};t.ENGINE_MAP={EdgeHTML:\"EdgeHTML\",Blink:\"Blink\",Trident:\"Trident\",Presto:\"Presto\",Gecko:\"Gecko\",WebKit:\"WebKit\"}},90:function(e,t,r){\"use strict\";t.__esModule=!0,t.default=void 0;var i,n=(i=r(91))&&i.__esModule?i:{default:i},s=r(18);function o(e,t){for(var r=0;r<t.length;r++){var i=t[r];i.enumerable=i.enumerable||!1,i.configurable=!0,\"value\"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}var a=function(){function e(){}var t,r,i;return e.getParser=function(e,t){if(void 0===t&&(t=!1),\"string\"!=typeof e)throw new Error(\"UserAgent should be a string\");return new n.default(e,t)},e.parse=function(e){return new n.default(e).getResult()},t=e,i=[{key:\"BROWSER_MAP\",get:function(){return s.BROWSER_MAP}},{key:\"ENGINE_MAP\",get:function(){return s.ENGINE_MAP}},{key:\"OS_MAP\",get:function(){return s.OS_MAP}},{key:\"PLATFORMS_MAP\",get:function(){return s.PLATFORMS_MAP}}],(r=null)&&o(t.prototype,r),i&&o(t,i),e}();t.default=a,e.exports=t.default},91:function(e,t,r){\"use strict\";t.__esModule=!0,t.default=void 0;var i=u(r(92)),n=u(r(93)),s=u(r(94)),o=u(r(95)),a=u(r(17));function u(e){return e&&e.__esModule?e:{default:e}}var d=function(){function e(e,t){if(void 0===t&&(t=!1),null==e||\"\"===e)throw new Error(\"UserAgent parameter can't be empty\");this._ua=e,this.parsedResult={},!0!==t&&this.parse()}var t=e.prototype;return t.getUA=function(){return this._ua},t.test=function(e){return e.test(this._ua)},t.parseBrowser=function(){var e=this;this.parsedResult.browser={};var t=i.default.find((function(t){if(\"function\"==typeof t.test)return t.test(e);if(t.test instanceof Array)return t.test.some((function(t){return e.test(t)}));throw new Error(\"Browser's test function is not valid\")}));return t&&(this.parsedResult.browser=t.describe(this.getUA())),this.parsedResult.browser},t.getBrowser=function(){return this.parsedResult.browser?this.parsedResult.browser:this.parseBrowser()},t.getBrowserName=function(e){return e?String(this.getBrowser().name).toLowerCase()||\"\":this.getBrowser().name||\"\"},t.getBrowserVersion=function(){return this.getBrowser().version},t.getOS=function(){return this.parsedResult.os?this.parsedResult.os:this.parseOS()},t.parseOS=function(){var e=this;this.parsedResult.os={};var t=n.default.find((function(t){if(\"function\"==typeof t.test)return t.test(e);if(t.test instanceof Array)return t.test.some((function(t){return e.test(t)}));throw new Error(\"Browser's test function is not valid\")}));return t&&(this.parsedResult.os=t.describe(this.getUA())),this.parsedResult.os},t.getOSName=function(e){var t=this.getOS().name;return e?String(t).toLowerCase()||\"\":t||\"\"},t.getOSVersion=function(){return this.getOS().version},t.getPlatform=function(){return this.parsedResult.platform?this.parsedResult.platform:this.parsePlatform()},t.getPlatformType=function(e){void 0===e&&(e=!1);var t=this.getPlatform().type;return e?String(t).toLowerCase()||\"\":t||\"\"},t.parsePlatform=function(){var e=this;this.parsedResult.platform={};var t=s.default.find((function(t){if(\"function\"==typeof t.test)return t.test(e);if(t.test instanceof Array)return t.test.some((function(t){return e.test(t)}));throw new Error(\"Browser's test function is not valid\")}));return t&&(this.parsedResult.platform=t.describe(this.getUA())),this.parsedResult.platform},t.getEngine=function(){return this.parsedResult.engine?this.parsedResult.engine:this.parseEngine()},t.getEngineName=function(e){return e?String(this.getEngine().name).toLowerCase()||\"\":this.getEngine().name||\"\"},t.parseEngine=function(){var e=this;this.parsedResult.engine={};var t=o.default.find((function(t){if(\"function\"==typeof t.test)return t.test(e);if(t.test instanceof Array)return t.test.some((function(t){return e.test(t)}));throw new Error(\"Browser's test function is not valid\")}));return t&&(this.parsedResult.engine=t.describe(this.getUA())),this.parsedResult.engine},t.parse=function(){return this.parseBrowser(),this.parseOS(),this.parsePlatform(),this.parseEngine(),this},t.getResult=function(){return Object.assign({},this.parsedResult)},t.satisfies=function(e){var t=this,r={},i=0,n={},s=0;if(Object.keys(e).forEach((function(t){var o=e[t];\"string\"==typeof o?(n[t]=o,s+=1):\"object\"==typeof o&&(r[t]=o,i+=1)})),i>0){var o=Object.keys(r),a=o.find((function(e){return t.isOS(e)}));if(a){var u=this.satisfies(r[a]);if(void 0!==u)return u}var d=o.find((function(e){return t.isPlatform(e)}));if(d){var c=this.satisfies(r[d]);if(void 0!==c)return c}}if(s>0){var f=Object.keys(n).find((function(e){return t.isBrowser(e,!0)}));if(void 0!==f)return this.compareVersion(n[f])}},t.isBrowser=function(e,t){void 0===t&&(t=!1);var r=this.getBrowserName().toLowerCase(),i=e.toLowerCase(),n=a.default.getBrowserTypeByAlias(i);return t&&n&&(i=n.toLowerCase()),i===r},t.compareVersion=function(e){var t=[0],r=e,i=!1,n=this.getBrowserVersion();if(\"string\"==typeof n)return\">\"===e[0]||\"<\"===e[0]?(r=e.substr(1),\"=\"===e[1]?(i=!0,r=e.substr(2)):t=[],\">\"===e[0]?t.push(1):t.push(-1)):\"=\"===e[0]?r=e.substr(1):\"~\"===e[0]&&(i=!0,r=e.substr(1)),t.indexOf(a.default.compareVersions(n,r,i))>-1},t.isOS=function(e){return this.getOSName(!0)===String(e).toLowerCase()},t.isPlatform=function(e){return this.getPlatformType(!0)===String(e).toLowerCase()},t.isEngine=function(e){return this.getEngineName(!0)===String(e).toLowerCase()},t.is=function(e){return this.isBrowser(e)||this.isOS(e)||this.isPlatform(e)},t.some=function(e){var t=this;return void 0===e&&(e=[]),e.some((function(e){return t.is(e)}))},e}();t.default=d,e.exports=t.default},92:function(e,t,r){\"use strict\";t.__esModule=!0,t.default=void 0;var i,n=(i=r(17))&&i.__esModule?i:{default:i};var s=/version\\/(\\d+(\\.?_?\\d+)+)/i,o=[{test:[/googlebot/i],describe:function(e){var t={name:\"Googlebot\"},r=n.default.getFirstMatch(/googlebot\\/(\\d+(\\.\\d+))/i,e)||n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/opera/i],describe:function(e){var t={name:\"Opera\"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/(?:opera)[\\s/](\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/opr\\/|opios/i],describe:function(e){var t={name:\"Opera\"},r=n.default.getFirstMatch(/(?:opr|opios)[\\s/](\\S+)/i,e)||n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/SamsungBrowser/i],describe:function(e){var t={name:\"Samsung Internet for Android\"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/(?:SamsungBrowser)[\\s/](\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/Whale/i],describe:function(e){var t={name:\"NAVER Whale Browser\"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/(?:whale)[\\s/](\\d+(?:\\.\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/MZBrowser/i],describe:function(e){var t={name:\"MZ Browser\"},r=n.default.getFirstMatch(/(?:MZBrowser)[\\s/](\\d+(?:\\.\\d+)+)/i,e)||n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/focus/i],describe:function(e){var t={name:\"Focus\"},r=n.default.getFirstMatch(/(?:focus)[\\s/](\\d+(?:\\.\\d+)+)/i,e)||n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/swing/i],describe:function(e){var t={name:\"Swing\"},r=n.default.getFirstMatch(/(?:swing)[\\s/](\\d+(?:\\.\\d+)+)/i,e)||n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/coast/i],describe:function(e){var t={name:\"Opera Coast\"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/(?:coast)[\\s/](\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/yabrowser/i],describe:function(e){var t={name:\"Yandex Browser\"},r=n.default.getFirstMatch(/(?:yabrowser)[\\s/](\\d+(\\.?_?\\d+)+)/i,e)||n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/ucbrowser/i],describe:function(e){var t={name:\"UC Browser\"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/(?:ucbrowser)[\\s/](\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/Maxthon|mxios/i],describe:function(e){var t={name:\"Maxthon\"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/(?:Maxthon|mxios)[\\s/](\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/epiphany/i],describe:function(e){var t={name:\"Epiphany\"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/(?:epiphany)[\\s/](\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/puffin/i],describe:function(e){var t={name:\"Puffin\"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/(?:puffin)[\\s/](\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/sleipnir/i],describe:function(e){var t={name:\"Sleipnir\"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/(?:sleipnir)[\\s/](\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/k-meleon/i],describe:function(e){var t={name:\"K-Meleon\"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/(?:k-meleon)[\\s/](\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/micromessenger/i],describe:function(e){var t={name:\"WeChat\"},r=n.default.getFirstMatch(/(?:micromessenger)[\\s/](\\d+(\\.?_?\\d+)+)/i,e)||n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/qqbrowser/i],describe:function(e){var t={name:/qqbrowserlite/i.test(e)?\"QQ Browser Lite\":\"QQ Browser\"},r=n.default.getFirstMatch(/(?:qqbrowserlite|qqbrowser)[/](\\d+(\\.?_?\\d+)+)/i,e)||n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/msie|trident/i],describe:function(e){var t={name:\"Internet Explorer\"},r=n.default.getFirstMatch(/(?:msie |rv:)(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/\\sedg\\//i],describe:function(e){var t={name:\"Microsoft Edge\"},r=n.default.getFirstMatch(/\\sedg\\/(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/edg([ea]|ios)/i],describe:function(e){var t={name:\"Microsoft Edge\"},r=n.default.getSecondMatch(/edg([ea]|ios)\\/(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/vivaldi/i],describe:function(e){var t={name:\"Vivaldi\"},r=n.default.getFirstMatch(/vivaldi\\/(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/seamonkey/i],describe:function(e){var t={name:\"SeaMonkey\"},r=n.default.getFirstMatch(/seamonkey\\/(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/sailfish/i],describe:function(e){var t={name:\"Sailfish\"},r=n.default.getFirstMatch(/sailfish\\s?browser\\/(\\d+(\\.\\d+)?)/i,e);return r&&(t.version=r),t}},{test:[/silk/i],describe:function(e){var t={name:\"Amazon Silk\"},r=n.default.getFirstMatch(/silk\\/(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/phantom/i],describe:function(e){var t={name:\"PhantomJS\"},r=n.default.getFirstMatch(/phantomjs\\/(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/slimerjs/i],describe:function(e){var t={name:\"SlimerJS\"},r=n.default.getFirstMatch(/slimerjs\\/(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/blackberry|\\bbb\\d+/i,/rim\\stablet/i],describe:function(e){var t={name:\"BlackBerry\"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/blackberry[\\d]+\\/(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/(web|hpw)[o0]s/i],describe:function(e){var t={name:\"WebOS Browser\"},r=n.default.getFirstMatch(s,e)||n.default.getFirstMatch(/w(?:eb)?[o0]sbrowser\\/(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/bada/i],describe:function(e){var t={name:\"Bada\"},r=n.default.getFirstMatch(/dolfin\\/(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/tizen/i],describe:function(e){var t={name:\"Tizen\"},r=n.default.getFirstMatch(/(?:tizen\\s?)?browser\\/(\\d+(\\.?_?\\d+)+)/i,e)||n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/qupzilla/i],describe:function(e){var t={name:\"QupZilla\"},r=n.default.getFirstMatch(/(?:qupzilla)[\\s/](\\d+(\\.?_?\\d+)+)/i,e)||n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/firefox|iceweasel|fxios/i],describe:function(e){var t={name:\"Firefox\"},r=n.default.getFirstMatch(/(?:firefox|iceweasel|fxios)[\\s/](\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/chromium/i],describe:function(e){var t={name:\"Chromium\"},r=n.default.getFirstMatch(/(?:chromium)[\\s/](\\d+(\\.?_?\\d+)+)/i,e)||n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/chrome|crios|crmo/i],describe:function(e){var t={name:\"Chrome\"},r=n.default.getFirstMatch(/(?:chrome|crios|crmo)\\/(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/GSA/i],describe:function(e){var t={name:\"Google Search\"},r=n.default.getFirstMatch(/(?:GSA)\\/(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:function(e){var t=!e.test(/like android/i),r=e.test(/android/i);return t&&r},describe:function(e){var t={name:\"Android Browser\"},r=n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/playstation 4/i],describe:function(e){var t={name:\"PlayStation 4\"},r=n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/safari|applewebkit/i],describe:function(e){var t={name:\"Safari\"},r=n.default.getFirstMatch(s,e);return r&&(t.version=r),t}},{test:[/.*/i],describe:function(e){var t=-1!==e.search(\"\\\\(\")?/^(.*)\\/(.*)[ \\t]\\((.*)/:/^(.*)\\/(.*) /;return{name:n.default.getFirstMatch(t,e),version:n.default.getSecondMatch(t,e)}}}];t.default=o,e.exports=t.default},93:function(e,t,r){\"use strict\";t.__esModule=!0,t.default=void 0;var i,n=(i=r(17))&&i.__esModule?i:{default:i},s=r(18);var o=[{test:[/Roku\\/DVP/],describe:function(e){var t=n.default.getFirstMatch(/Roku\\/DVP-(\\d+\\.\\d+)/i,e);return{name:s.OS_MAP.Roku,version:t}}},{test:[/windows phone/i],describe:function(e){var t=n.default.getFirstMatch(/windows phone (?:os)?\\s?(\\d+(\\.\\d+)*)/i,e);return{name:s.OS_MAP.WindowsPhone,version:t}}},{test:[/windows/i],describe:function(e){var t=n.default.getFirstMatch(/Windows ((NT|XP)( \\d\\d?.\\d)?)/i,e),r=n.default.getWindowsVersionName(t);return{name:s.OS_MAP.Windows,version:t,versionName:r}}},{test:[/macintosh/i],describe:function(e){var t=n.default.getFirstMatch(/mac os x (\\d+(\\.?_?\\d+)+)/i,e).replace(/[_\\s]/g,\".\"),r=n.default.getMacOSVersionName(t),i={name:s.OS_MAP.MacOS,version:t};return r&&(i.versionName=r),i}},{test:[/(ipod|iphone|ipad)/i],describe:function(e){var t=n.default.getFirstMatch(/os (\\d+([_\\s]\\d+)*) like mac os x/i,e).replace(/[_\\s]/g,\".\");return{name:s.OS_MAP.iOS,version:t}}},{test:function(e){var t=!e.test(/like android/i),r=e.test(/android/i);return t&&r},describe:function(e){var t=n.default.getFirstMatch(/android[\\s/-](\\d+(\\.\\d+)*)/i,e),r=n.default.getAndroidVersionName(t),i={name:s.OS_MAP.Android,version:t};return r&&(i.versionName=r),i}},{test:[/(web|hpw)[o0]s/i],describe:function(e){var t=n.default.getFirstMatch(/(?:web|hpw)[o0]s\\/(\\d+(\\.\\d+)*)/i,e),r={name:s.OS_MAP.WebOS};return t&&t.length&&(r.version=t),r}},{test:[/blackberry|\\bbb\\d+/i,/rim\\stablet/i],describe:function(e){var t=n.default.getFirstMatch(/rim\\stablet\\sos\\s(\\d+(\\.\\d+)*)/i,e)||n.default.getFirstMatch(/blackberry\\d+\\/(\\d+([_\\s]\\d+)*)/i,e)||n.default.getFirstMatch(/\\bbb(\\d+)/i,e);return{name:s.OS_MAP.BlackBerry,version:t}}},{test:[/bada/i],describe:function(e){var t=n.default.getFirstMatch(/bada\\/(\\d+(\\.\\d+)*)/i,e);return{name:s.OS_MAP.Bada,version:t}}},{test:[/tizen/i],describe:function(e){var t=n.default.getFirstMatch(/tizen[/\\s](\\d+(\\.\\d+)*)/i,e);return{name:s.OS_MAP.Tizen,version:t}}},{test:[/linux/i],describe:function(){return{name:s.OS_MAP.Linux}}},{test:[/CrOS/],describe:function(){return{name:s.OS_MAP.ChromeOS}}},{test:[/PlayStation 4/],describe:function(e){var t=n.default.getFirstMatch(/PlayStation 4[/\\s](\\d+(\\.\\d+)*)/i,e);return{name:s.OS_MAP.PlayStation4,version:t}}}];t.default=o,e.exports=t.default},94:function(e,t,r){\"use strict\";t.__esModule=!0,t.default=void 0;var i,n=(i=r(17))&&i.__esModule?i:{default:i},s=r(18);var o=[{test:[/googlebot/i],describe:function(){return{type:\"bot\",vendor:\"Google\"}}},{test:[/huawei/i],describe:function(e){var t=n.default.getFirstMatch(/(can-l01)/i,e)&&\"Nova\",r={type:s.PLATFORMS_MAP.mobile,vendor:\"Huawei\"};return t&&(r.model=t),r}},{test:[/nexus\\s*(?:7|8|9|10).*/i],describe:function(){return{type:s.PLATFORMS_MAP.tablet,vendor:\"Nexus\"}}},{test:[/ipad/i],describe:function(){return{type:s.PLATFORMS_MAP.tablet,vendor:\"Apple\",model:\"iPad\"}}},{test:[/kftt build/i],describe:function(){return{type:s.PLATFORMS_MAP.tablet,vendor:\"Amazon\",model:\"Kindle Fire HD 7\"}}},{test:[/silk/i],describe:function(){return{type:s.PLATFORMS_MAP.tablet,vendor:\"Amazon\"}}},{test:[/tablet(?! pc)/i],describe:function(){return{type:s.PLATFORMS_MAP.tablet}}},{test:function(e){var t=e.test(/ipod|iphone/i),r=e.test(/like (ipod|iphone)/i);return t&&!r},describe:function(e){var t=n.default.getFirstMatch(/(ipod|iphone)/i,e);return{type:s.PLATFORMS_MAP.mobile,vendor:\"Apple\",model:t}}},{test:[/nexus\\s*[0-6].*/i,/galaxy nexus/i],describe:function(){return{type:s.PLATFORMS_MAP.mobile,vendor:\"Nexus\"}}},{test:[/[^-]mobi/i],describe:function(){return{type:s.PLATFORMS_MAP.mobile}}},{test:function(e){return\"blackberry\"===e.getBrowserName(!0)},describe:function(){return{type:s.PLATFORMS_MAP.mobile,vendor:\"BlackBerry\"}}},{test:function(e){return\"bada\"===e.getBrowserName(!0)},describe:function(){return{type:s.PLATFORMS_MAP.mobile}}},{test:function(e){return\"windows phone\"===e.getBrowserName()},describe:function(){return{type:s.PLATFORMS_MAP.mobile,vendor:\"Microsoft\"}}},{test:function(e){var t=Number(String(e.getOSVersion()).split(\".\")[0]);return\"android\"===e.getOSName(!0)&&t>=3},describe:function(){return{type:s.PLATFORMS_MAP.tablet}}},{test:function(e){return\"android\"===e.getOSName(!0)},describe:function(){return{type:s.PLATFORMS_MAP.mobile}}},{test:function(e){return\"macos\"===e.getOSName(!0)},describe:function(){return{type:s.PLATFORMS_MAP.desktop,vendor:\"Apple\"}}},{test:function(e){return\"windows\"===e.getOSName(!0)},describe:function(){return{type:s.PLATFORMS_MAP.desktop}}},{test:function(e){return\"linux\"===e.getOSName(!0)},describe:function(){return{type:s.PLATFORMS_MAP.desktop}}},{test:function(e){return\"playstation 4\"===e.getOSName(!0)},describe:function(){return{type:s.PLATFORMS_MAP.tv}}},{test:function(e){return\"roku\"===e.getOSName(!0)},describe:function(){return{type:s.PLATFORMS_MAP.tv}}}];t.default=o,e.exports=t.default},95:function(e,t,r){\"use strict\";t.__esModule=!0,t.default=void 0;var i,n=(i=r(17))&&i.__esModule?i:{default:i},s=r(18);var o=[{test:function(e){return\"microsoft edge\"===e.getBrowserName(!0)},describe:function(e){if(/\\sedg\\//i.test(e))return{name:s.ENGINE_MAP.Blink};var t=n.default.getFirstMatch(/edge\\/(\\d+(\\.?_?\\d+)+)/i,e);return{name:s.ENGINE_MAP.EdgeHTML,version:t}}},{test:[/trident/i],describe:function(e){var t={name:s.ENGINE_MAP.Trident},r=n.default.getFirstMatch(/trident\\/(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:function(e){return e.test(/presto/i)},describe:function(e){var t={name:s.ENGINE_MAP.Presto},r=n.default.getFirstMatch(/presto\\/(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:function(e){var t=e.test(/gecko/i),r=e.test(/like gecko/i);return t&&!r},describe:function(e){var t={name:s.ENGINE_MAP.Gecko},r=n.default.getFirstMatch(/gecko\\/(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}},{test:[/(apple)?webkit\\/537\\.36/i],describe:function(){return{name:s.ENGINE_MAP.Blink}}},{test:[/(apple)?webkit/i],describe:function(e){var t={name:s.ENGINE_MAP.WebKit},r=n.default.getFirstMatch(/webkit\\/(\\d+(\\.?_?\\d+)+)/i,e);return r&&(t.version=r),t}}];t.default=o,e.exports=t.default}})}));","/*!\n * currentExecutingScript\n * Get the currently executing script, regardless of its source/trigger/synchronicity. Similar to HTML5's `document.currentScript` but arguably much more useful!\n * Copyright (c) 2015 James M. Greene\n * Licensed MIT\n * https://github.com/JamesMGreene/currentExecutingScript\n * v0.1.3\n */\n(function(root, factory) {\n  if (typeof define === \"function\" && define.amd) {\n    // AMD. Register as an anonymous module.\n    define([], factory);\n  } else if (typeof exports === \"object\") {\n    // CommonJS-like environments that support `module.exports`,\n    // like Node.js. Does not work with strict CommonJS!\n    module.exports = factory();\n  } else {\n    // Browser globals (`root` is `window`)\n    root.currentExecutingScript = factory();\n  }\n}(\n  // Current context/scope\n  this || window,\n\n  // Factory function to return the export\n  function() {\n\nvar scriptReadyRegex = /^(interactive|loaded|complete)$/;\n\n// This page's URL (minus query string and fragment identifer hash, if any)\nvar fullPageUrl = !!window.location ? window.location.href : null;\nvar pageUrl = fullPageUrl ? fullPageUrl.replace(/#.*$/, \"\").replace(/\\?.*$/, \"\") || null : null;\n\n// Live NodeList collection\nvar scripts = document.getElementsByTagName(\"script\");\n\n// Check if the browser supports the `readyState` property on `script` elements\nvar supportsScriptReadyState = \"readyState\" in (scripts[0] || document.createElement(\"script\"));\n\n// Lousy browser detection for [not] Opera\nvar isNotOpera = !window.opera || window.opera.toString() !== \"[object Opera]\";\n\n// Detect if `document.currentScript` is supported\nvar hasNativeCurrentScriptAccessor = \"currentScript\" in document;\n\nvar originalStackDepthConfig;\n// Detect if the V8 Error Stack Trace API is supported\nif (\"stackTraceLimit\" in Error && Error.stackTraceLimit !== Infinity) {\n  originalStackDepthConfig = Error.stackTraceLimit;\n  Error.stackTraceLimit = Infinity;\n}\n\n\n// In some browsers (e.g. Chrome), you can get the current stack from an Error\n// object instance without needing to throw it. Avoiding an unnecessary\n// use of `throw` saves time and performance.\nvar hasStackBeforeThrowing = false,\n    hasStackAfterThrowing = false;\n(function() {\n  try {\n    var err = new Error();\n    hasStackBeforeThrowing = typeof err.stack === \"string\" && !!err.stack;\n    throw err;\n  }\n  catch (thrownErr) {\n    hasStackAfterThrowing = typeof thrownErr.stack === \"string\" && !!thrownErr.stack;\n  }\n})();\n\n\n// Normalize whitespace within a string\nfunction normalizeWhitespace(str) {\n  return str ? str.replace(/^\\s+$|\\s+$/g, \"\").replace(/\\s\\s+/g, \" \") : \"\";\n}\n\n// Get script object based on the `src` URL\nfunction getScriptFromUrl(url, eligibleScripts) {\n  var i,\n      script = null;\n\n  eligibleScripts = eligibleScripts || scripts;\n\n  if (typeof url === \"string\" && url) {\n    for (i = eligibleScripts.length; i--; ) {\n      if (eligibleScripts[i].src === url) {\n        // NOTE: Could check if the same script URL is used by more than one `script` element\n        // here... but let's not. That would yield less useful results in \"loose\" detection. ;)\n        script = eligibleScripts[i];\n        break;\n      }\n    }\n  }\n  return script;\n}\n\n// Get script object based on the caller function's source code body (text)\nfunction getInlineScriptFromCallerSource(callerFnSource, eligibleScripts) {\n  var i, inlineScriptText,\n      script = null,\n      callerSourceText = normalizeWhitespace(callerFnSource);\n\n  eligibleScripts = eligibleScripts || scripts;\n\n  if (callerFnSource && callerSourceText) {\n    for (i = eligibleScripts.length; i--; ) {\n      // Only look at inline scripts\n      if (!eligibleScripts[i].hasAttribute(\"src\")) {\n        inlineScriptText = normalizeWhitespace(eligibleScripts[i].text);\n        if (inlineScriptText.indexOf(callerSourceText) !== -1) {\n          // If more than one match is found, don't return any\n          if (script) {\n            script = null;\n            break;\n          }\n          script = eligibleScripts[i];\n        }\n      }\n    }\n  }\n\n  return script;\n}\n\n// If there is only a single inline script on the page, return it; otherwise `null`\nfunction getSoleInlineScript(eligibleScripts) {\n  var i, len,\n      script = null;\n  eligibleScripts = eligibleScripts || scripts;\n  for (i = 0, len = eligibleScripts.length; i < len; i++) {\n    if (!eligibleScripts[i].hasAttribute(\"src\")) {\n      if (script) {\n        script = null;\n        break;\n      }\n      script = eligibleScripts[i];\n    }\n  }\n  return script;\n}\n\n// Get the currently executing script URL from an Error stack trace\nfunction getScriptUrlFromStack(stack, skipStackDepth) {\n  var matches, remainingStack,\n      url = null,\n      ignoreMessage = typeof skipStackDepth === \"number\";\n  skipStackDepth = ignoreMessage ? Math.round(skipStackDepth) : 0;\n  if (typeof stack === \"string\" && stack) {\n    if (ignoreMessage) {\n      matches = stack.match(/(data:text\\/javascript(?:;[^,]+)?,.+?|(?:|blob:)(?:http[s]?|file):\\/\\/[\\/]?.+?\\/[^:\\)]*?)(?::\\d+)(?::\\d+)?/);\n    }\n    else {\n      matches = stack.match(/^(?:|[^:@]*@|.+\\)@(?=data:text\\/javascript|blob|http[s]?|file)|.+?\\s+(?: at |@)(?:[^:\\(]+ )*[\\(]?)(data:text\\/javascript(?:;[^,]+)?,.+?|(?:|blob:)(?:http[s]?|file):\\/\\/[\\/]?.+?\\/[^:\\)]*?)(?::\\d+)(?::\\d+)?/);\n\n      if (!(matches && matches[1])) {\n        matches = stack.match(/\\)@(data:text\\/javascript(?:;[^,]+)?,.+?|(?:|blob:)(?:http[s]?|file):\\/\\/[\\/]?.+?\\/[^:\\)]*?)(?::\\d+)(?::\\d+)?/);\n      }\n    }\n\n    if (matches && matches[1]) {\n      if (skipStackDepth > 0) {\n        remainingStack = stack.slice(stack.indexOf(matches[0]) + matches[0].length);\n        url = getScriptUrlFromStack(remainingStack, (skipStackDepth - 1));\n      }\n      else {\n        url = matches[1];\n      }\n    }\n\n    // TODO: Handle more edge cases!\n    // Fixes #1\n    // See https://github.com/JamesMGreene/currentExecutingScript/issues/1\n\n    // ???\n\n  }\n  return url;\n}\n\n\n// Get the farthest currently executing (i.e. yes, EXECUTING) `script` DOM\n// element for the caller function, regardless of whether it is that `script`\n// DOM element is currently being evaluated for the first time. The farthest\n// currently executing `script` DOM element would typically be considered the\n// originator of the current execution stack.\nfunction _farthestExecutingScript() {\n  /*jshint noarg:false */\n\n  // TODO: Implement!\n  // Fixes #3\n  // See https://github.com/JamesMGreene/currentExecutingScript/issues/3\n  return null;\n\n/*\n  // Yes, this IS possible, i.e. if a script removes other scripts (or itself)\n  if (scripts.length === 0) {\n    return null;\n  }\n\n  // Guaranteed accurate in IE 6-10.\n  // Not accurate/supported in any other browsers.\n  if (isNotOpera && supportsScriptReadyState) {\n    for (var i = scripts.length; i--; ) {\n      if (scripts[i].readyState === \"interactive\") {\n        return scripts[i];\n      }\n    }\n  }\n\n  var stack,\n      e = new Error();\n  if (hasStackBeforeThrowing) {\n    stack = e.stack;\n  }\n  if (!stack && hasStackAfterThrowing) {\n    try {\n      throw e;\n    }\n    catch (err) {\n      // NOTE: Cannot use `err.sourceURL` or `err.fileName` as they will always be THIS script\n      stack = err.stack;\n    }\n  }\n  if (stack) {\n    var url = getScriptUrlFromStack(stack, skipStackDepth);\n    var script = getScriptFromUrl(url, scripts );\n    if (!script && pageUrl && url === pageUrl) {\n      // Try to find the correct inline script by searching through\n      // inline scripts' text content for the caller function's source\n      // code to be present. If the caller function's source code is\n      // not available, see if there is only one inline script element\n      // in the DOM and return that (even though it may be wrong)\n\n      // TODO: Implement!\n      // Fixes #4 in part\n      // See https://github.com/JamesMGreene/currentExecutingScript/issues/4\n\n      var callerFn = _farthestExecutingScript.caller || null,\n          callerFnStack = [],\n          callerFnSource = null;\n\n      while (callerFn) {\n        callerFnStack.push(callerFn);\n        callerFn = callerFn.caller || null;\n      }\n      callerFn = callerFnStack.slice(-1)[0];\n      callerFnSource = callerFn ? (\"\" + callerFn) : null;\n\n\n      if (callerFnSource) {\n        script = getInlineScriptFromCallerSource(callerFnSource);\n      }\n      else {\n        // NOTE: This is a loose assumption that could be inaccurate!\n        //\n        // Inaccuracies:\n        //  - If the inline script that initiated the call was also removed from the DOM.\n        //  - If the call was initiated by an element's inline event handler,\n        //    e.g. `<a onclick=\"(function() { alert(currentExecutingScript()); }()\">click</a>`\n        script = getSoleInlineScript();\n      }\n    }\n    return script;\n  }\n\n  // NOTE: This is a loose assumption that could be inaccurate!\n  //\n  // Inaccuracies:\n  //  - If a script is created dynamically and appended to some position\n  //    other than the very end of the document.\n  //  - If multiple scripts are created dynamically and all appended to the\n  //    same position within the document (and do not have their `async` attributes\n  //    set to `false`, at least in browsers that support async script evaluation.\n  //    other than the very end of the document.\n  //  - If any scripts are added with the `async` attribute set to `true` in a browser\n  //    that supports it.\n  //  - May get confused by `script` elements within `svg` elements\n  return scripts[scripts.length - 1] || null;\n*/\n}\n\n\n// Get the originating currently executing (i.e. yes, EXECUTING) `script` DOM\n// element or attribute node (e.g. `onclick`) for the caller function,\n// regardless of whether it is that `script` DOM element is currently being\n// evaluated for the first time. The originating currently executing `script`\n// DOM element [or attribute node] is the originator of the current execution stack.\nfunction _originatingExecutingScript() {\n  // TODO: Implement!\n  // Fixes #2\n  // See https://github.com/JamesMGreene/currentExecutingScript/issues/2\n  return null;\n}\n\n// Get the nearest currently executing (i.e. yes, EXECUTING) `script` DOM\n// element for the caller function, regardless of whether it is that `script`\n// DOM element is currently being evaluated for the first time.\nfunction _nearestExecutingScript() {\n  /*jshint noarg:false */\n\n  // Yes, this IS possible, i.e. if a script removes other scripts (or itself)\n  if (scripts.length === 0) {\n    return null;\n  }\n\n  var i, e, stack, url, script,\n      eligibleScripts = [],\n      skipStackDepth = _nearestExecutingScript.skipStackDepth || 1,\n\n      // TODO: Implement!\n      // Fixes #4 in part\n      // See https://github.com/JamesMGreene/currentExecutingScript/issues/4\n      callerFnSource = null;  //(\"\" + (_nearestExecutingScript.caller || \"\")) || null;\n\n  // This part will only help in IE 6-10.\n  for (i = 0; i < scripts.length; i++) {\n    if (isNotOpera && supportsScriptReadyState) {\n      if (scriptReadyRegex.test(scripts[i].readyState)) {\n        eligibleScripts.push(scripts[i]);\n      }\n    }\n    else {\n      eligibleScripts.push(scripts[i]);\n    }\n  }\n\n  e = new Error();\n  if (hasStackBeforeThrowing) {\n    stack = e.stack;\n  }\n  if (!stack && hasStackAfterThrowing) {\n    try {\n      throw e;\n    }\n    catch (err) {\n      // NOTE: Cannot use `err.sourceURL` or `err.fileName` as they will always be THIS script\n      stack = err.stack;\n    }\n  }\n\n  if (stack) {\n    url = getScriptUrlFromStack(stack, skipStackDepth);\n    script = getScriptFromUrl(url, eligibleScripts);\n\n    if (!script && pageUrl && url === pageUrl) {\n      // Try to find the correct inline script by searching through\n      // inline scripts' text content for the caller function's source\n      // code to be present.\n      if (callerFnSource) {\n        script = getInlineScriptFromCallerSource(callerFnSource, eligibleScripts);\n      }\n      // If the caller function's source code is not available, see if\n      // there is only one inline script element in the DOM and return\n      // that (even though it may be wrong)...\n      else {\n        // NOTE: This is a loose assumption that could be inaccurate!\n        //\n        // Inaccuracies:\n        //  - If the inline script that initiated the call was also removed from the DOM.\n        //  - If the call was initiated by an element's inline event handler,\n        //    e.g. `<a onclick=\"(function() { alert(currentExecutingScript()); }()\">click</a>`\n        script = getSoleInlineScript(eligibleScripts);\n      }\n    }\n  }\n\n  //\n  // Welcome to the Island of Inaccurate Assumptions!\n  // NOTE: ALL of the following are loose assumptions that could be inaccurate!\n  //\n\n  if (!script) {\n    // Inaccuracies:\n    //  - If the inline script that initiated the call was also removed from the DOM.\n    //  - If the call was initiated by an element's inline event handler,\n    //    e.g. `<a onclick=\"(function() { alert(currentExecutingScript()); }()\">click</a>`\n    if (eligibleScripts.length === 1) {\n      script = eligibleScripts[0];\n    }\n  }\n\n  if (!script) {\n    // Inaccuracies:\n    //  - If script currently being synchronously evaluated by the parser is the\n    //    originator of this call stack but NOT the source script of the caller/invocation\n    //    e.g.\n    //    ```html\n    //    <script id=\"a\">\n    //    function getCurrentScriptCallerFn() {\n    //      return currentExecutingScript.near();\n    //    }\n    //    </script>\n    //    <script id=\"b\">\n    //    // Should get `script[id=\"a\"]` but will get `script[id=\"b\"]` instead\n    //    getCurrentScriptCallerFn();\n    //    </script>\n    if (hasNativeCurrentScriptAccessor) {\n      script = document.currentScript;\n    }\n  }\n\n  if (!script) {\n    // Inaccuracies:\n    //  - If script currently being synchronously evaluated by the parser is the\n    //    originator of this call stack but NOT the source script of the caller/invocation\n    //    e.g.\n    //    ```html\n    //    <script id=\"a\">\n    //    function getCurrentScriptCallerFn() {\n    //      return currentExecutingScript.near();\n    //    }\n    //    </script>\n    //    <script id=\"b\">\n    //    // Should get `script[id=\"a\"]` but will get `script[id=\"b\"]` instead\n    //    getCurrentScriptCallerFn();\n    //    </script>\n    if (isNotOpera && supportsScriptReadyState) {\n      for (i = eligibleScripts.length; i--; ) {\n        if (eligibleScripts[i].readyState === \"interactive\") {\n          script = eligibleScripts[i];\n          break;\n        }\n      }\n    }\n  }\n\n  if (!script) {\n    // Inaccuracies:\n    //  - If a script is created dynamically and appended to some position\n    //    other than the very end of the document.\n    //  - If multiple scripts are created dynamically and all appended to the\n    //    same position within the document (and do not have their `async` attributes\n    //    set to `false`, at least in browsers that support async script evaluation.\n    //    other than the very end of the document.\n    //  - If any scripts are added with the `async` attribute set to `true` in a browser\n    //    that supports it.\n    //  - May get confused by `script` elements within `svg` elements\n    //  - If script currently being synchronously evaluated by the parser is the\n    //    originator of this call stack but NOT the source script of the caller/invocation\n    //    e.g.\n    //    ```html\n    //    <script id=\"a\">\n    //    function getCurrentScriptCallerFn() {\n    //      return currentExecutingScript.near();\n    //    }\n    //    </script>\n    //    <script id=\"b\">\n    //    // Should get `script[id=\"a\"]` but will get `script[id=\"b\"]` instead\n    //    getCurrentScriptCallerFn();\n    //    </script>\n    //    ```\n    script = eligibleScripts[eligibleScripts.length - 1] || null;\n  }\n\n  return script;\n}\n\n// Default stack depth to skip over when analyzing call stack frames\n_nearestExecutingScript.skipStackDepth = 1;\n\n\n\n    //\n    // Export the API\n    //\n    var currentExecutingScript    = _nearestExecutingScript;      // default\n    currentExecutingScript.near   = _nearestExecutingScript;\n    currentExecutingScript.far    = _farthestExecutingScript;\n    currentExecutingScript.origin = _originatingExecutingScript;\n\n\n    // Just return a value to define the module export.\n    // This example returns an object, but the module\n    // can return a function as the exported value.\n    return currentExecutingScript;\n  })\n);\n","// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n'use strict';\n\nvar R = typeof Reflect === 'object' ? Reflect : null\nvar ReflectApply = R && typeof R.apply === 'function'\n  ? R.apply\n  : function ReflectApply(target, receiver, args) {\n    return Function.prototype.apply.call(target, receiver, args);\n  }\n\nvar ReflectOwnKeys\nif (R && typeof R.ownKeys === 'function') {\n  ReflectOwnKeys = R.ownKeys\n} else if (Object.getOwnPropertySymbols) {\n  ReflectOwnKeys = function ReflectOwnKeys(target) {\n    return Object.getOwnPropertyNames(target)\n      .concat(Object.getOwnPropertySymbols(target));\n  };\n} else {\n  ReflectOwnKeys = function ReflectOwnKeys(target) {\n    return Object.getOwnPropertyNames(target);\n  };\n}\n\nfunction ProcessEmitWarning(warning) {\n  if (console && console.warn) console.warn(warning);\n}\n\nvar NumberIsNaN = Number.isNaN || function NumberIsNaN(value) {\n  return value !== value;\n}\n\nfunction EventEmitter() {\n  EventEmitter.init.call(this);\n}\nmodule.exports = EventEmitter;\nmodule.exports.once = once;\n\n// Backwards-compat with node 0.10.x\nEventEmitter.EventEmitter = EventEmitter;\n\nEventEmitter.prototype._events = undefined;\nEventEmitter.prototype._eventsCount = 0;\nEventEmitter.prototype._maxListeners = undefined;\n\n// By default EventEmitters will print a warning if more than 10 listeners are\n// added to it. This is a useful default which helps finding memory leaks.\nvar defaultMaxListeners = 10;\n\nfunction checkListener(listener) {\n  if (typeof listener !== 'function') {\n    throw new TypeError('The \"listener\" argument must be of type Function. Received type ' + typeof listener);\n  }\n}\n\nObject.defineProperty(EventEmitter, 'defaultMaxListeners', {\n  enumerable: true,\n  get: function() {\n    return defaultMaxListeners;\n  },\n  set: function(arg) {\n    if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {\n      throw new RangeError('The value of \"defaultMaxListeners\" is out of range. It must be a non-negative number. Received ' + arg + '.');\n    }\n    defaultMaxListeners = arg;\n  }\n});\n\nEventEmitter.init = function() {\n\n  if (this._events === undefined ||\n      this._events === Object.getPrototypeOf(this)._events) {\n    this._events = Object.create(null);\n    this._eventsCount = 0;\n  }\n\n  this._maxListeners = this._maxListeners || undefined;\n};\n\n// Obviously not all Emitters should be limited to 10. This function allows\n// that to be increased. Set to zero for unlimited.\nEventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {\n  if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {\n    throw new RangeError('The value of \"n\" is out of range. It must be a non-negative number. Received ' + n + '.');\n  }\n  this._maxListeners = n;\n  return this;\n};\n\nfunction _getMaxListeners(that) {\n  if (that._maxListeners === undefined)\n    return EventEmitter.defaultMaxListeners;\n  return that._maxListeners;\n}\n\nEventEmitter.prototype.getMaxListeners = function getMaxListeners() {\n  return _getMaxListeners(this);\n};\n\nEventEmitter.prototype.emit = function emit(type) {\n  var args = [];\n  for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);\n  var doError = (type === 'error');\n\n  var events = this._events;\n  if (events !== undefined)\n    doError = (doError && events.error === undefined);\n  else if (!doError)\n    return false;\n\n  // If there is no 'error' event listener then throw.\n  if (doError) {\n    var er;\n    if (args.length > 0)\n      er = args[0];\n    if (er instanceof Error) {\n      // Note: The comments on the `throw` lines are intentional, they show\n      // up in Node's output if this results in an unhandled exception.\n      throw er; // Unhandled 'error' event\n    }\n    // At least give some kind of context to the user\n    var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : ''));\n    err.context = er;\n    throw err; // Unhandled 'error' event\n  }\n\n  var handler = events[type];\n\n  if (handler === undefined)\n    return false;\n\n  if (typeof handler === 'function') {\n    ReflectApply(handler, this, args);\n  } else {\n    var len = handler.length;\n    var listeners = arrayClone(handler, len);\n    for (var i = 0; i < len; ++i)\n      ReflectApply(listeners[i], this, args);\n  }\n\n  return true;\n};\n\nfunction _addListener(target, type, listener, prepend) {\n  var m;\n  var events;\n  var existing;\n\n  checkListener(listener);\n\n  events = target._events;\n  if (events === undefined) {\n    events = target._events = Object.create(null);\n    target._eventsCount = 0;\n  } else {\n    // To avoid recursion in the case that type === \"newListener\"! Before\n    // adding it to the listeners, first emit \"newListener\".\n    if (events.newListener !== undefined) {\n      target.emit('newListener', type,\n                  listener.listener ? listener.listener : listener);\n\n      // Re-assign `events` because a newListener handler could have caused the\n      // this._events to be assigned to a new object\n      events = target._events;\n    }\n    existing = events[type];\n  }\n\n  if (existing === undefined) {\n    // Optimize the case of one listener. Don't need the extra array object.\n    existing = events[type] = listener;\n    ++target._eventsCount;\n  } else {\n    if (typeof existing === 'function') {\n      // Adding the second element, need to change to array.\n      existing = events[type] =\n        prepend ? [listener, existing] : [existing, listener];\n      // If we've already got an array, just append.\n    } else if (prepend) {\n      existing.unshift(listener);\n    } else {\n      existing.push(listener);\n    }\n\n    // Check for listener leak\n    m = _getMaxListeners(target);\n    if (m > 0 && existing.length > m && !existing.warned) {\n      existing.warned = true;\n      // No error code for this since it is a Warning\n      // eslint-disable-next-line no-restricted-syntax\n      var w = new Error('Possible EventEmitter memory leak detected. ' +\n                          existing.length + ' ' + String(type) + ' listeners ' +\n                          'added. Use emitter.setMaxListeners() to ' +\n                          'increase limit');\n      w.name = 'MaxListenersExceededWarning';\n      w.emitter = target;\n      w.type = type;\n      w.count = existing.length;\n      ProcessEmitWarning(w);\n    }\n  }\n\n  return target;\n}\n\nEventEmitter.prototype.addListener = function addListener(type, listener) {\n  return _addListener(this, type, listener, false);\n};\n\nEventEmitter.prototype.on = EventEmitter.prototype.addListener;\n\nEventEmitter.prototype.prependListener =\n    function prependListener(type, listener) {\n      return _addListener(this, type, listener, true);\n    };\n\nfunction onceWrapper() {\n  if (!this.fired) {\n    this.target.removeListener(this.type, this.wrapFn);\n    this.fired = true;\n    if (arguments.length === 0)\n      return this.listener.call(this.target);\n    return this.listener.apply(this.target, arguments);\n  }\n}\n\nfunction _onceWrap(target, type, listener) {\n  var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };\n  var wrapped = onceWrapper.bind(state);\n  wrapped.listener = listener;\n  state.wrapFn = wrapped;\n  return wrapped;\n}\n\nEventEmitter.prototype.once = function once(type, listener) {\n  checkListener(listener);\n  this.on(type, _onceWrap(this, type, listener));\n  return this;\n};\n\nEventEmitter.prototype.prependOnceListener =\n    function prependOnceListener(type, listener) {\n      checkListener(listener);\n      this.prependListener(type, _onceWrap(this, type, listener));\n      return this;\n    };\n\n// Emits a 'removeListener' event if and only if the listener was removed.\nEventEmitter.prototype.removeListener =\n    function removeListener(type, listener) {\n      var list, events, position, i, originalListener;\n\n      checkListener(listener);\n\n      events = this._events;\n      if (events === undefined)\n        return this;\n\n      list = events[type];\n      if (list === undefined)\n        return this;\n\n      if (list === listener || list.listener === listener) {\n        if (--this._eventsCount === 0)\n          this._events = Object.create(null);\n        else {\n          delete events[type];\n          if (events.removeListener)\n            this.emit('removeListener', type, list.listener || listener);\n        }\n      } else if (typeof list !== 'function') {\n        position = -1;\n\n        for (i = list.length - 1; i >= 0; i--) {\n          if (list[i] === listener || list[i].listener === listener) {\n            originalListener = list[i].listener;\n            position = i;\n            break;\n          }\n        }\n\n        if (position < 0)\n          return this;\n\n        if (position === 0)\n          list.shift();\n        else {\n          spliceOne(list, position);\n        }\n\n        if (list.length === 1)\n          events[type] = list[0];\n\n        if (events.removeListener !== undefined)\n          this.emit('removeListener', type, originalListener || listener);\n      }\n\n      return this;\n    };\n\nEventEmitter.prototype.off = EventEmitter.prototype.removeListener;\n\nEventEmitter.prototype.removeAllListeners =\n    function removeAllListeners(type) {\n      var listeners, events, i;\n\n      events = this._events;\n      if (events === undefined)\n        return this;\n\n      // not listening for removeListener, no need to emit\n      if (events.removeListener === undefined) {\n        if (arguments.length === 0) {\n          this._events = Object.create(null);\n          this._eventsCount = 0;\n        } else if (events[type] !== undefined) {\n          if (--this._eventsCount === 0)\n            this._events = Object.create(null);\n          else\n            delete events[type];\n        }\n        return this;\n      }\n\n      // emit removeListener for all listeners on all events\n      if (arguments.length === 0) {\n        var keys = Object.keys(events);\n        var key;\n        for (i = 0; i < keys.length; ++i) {\n          key = keys[i];\n          if (key === 'removeListener') continue;\n          this.removeAllListeners(key);\n        }\n        this.removeAllListeners('removeListener');\n        this._events = Object.create(null);\n        this._eventsCount = 0;\n        return this;\n      }\n\n      listeners = events[type];\n\n      if (typeof listeners === 'function') {\n        this.removeListener(type, listeners);\n      } else if (listeners !== undefined) {\n        // LIFO order\n        for (i = listeners.length - 1; i >= 0; i--) {\n          this.removeListener(type, listeners[i]);\n        }\n      }\n\n      return this;\n    };\n\nfunction _listeners(target, type, unwrap) {\n  var events = target._events;\n\n  if (events === undefined)\n    return [];\n\n  var evlistener = events[type];\n  if (evlistener === undefined)\n    return [];\n\n  if (typeof evlistener === 'function')\n    return unwrap ? [evlistener.listener || evlistener] : [evlistener];\n\n  return unwrap ?\n    unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);\n}\n\nEventEmitter.prototype.listeners = function listeners(type) {\n  return _listeners(this, type, true);\n};\n\nEventEmitter.prototype.rawListeners = function rawListeners(type) {\n  return _listeners(this, type, false);\n};\n\nEventEmitter.listenerCount = function(emitter, type) {\n  if (typeof emitter.listenerCount === 'function') {\n    return emitter.listenerCount(type);\n  } else {\n    return listenerCount.call(emitter, type);\n  }\n};\n\nEventEmitter.prototype.listenerCount = listenerCount;\nfunction listenerCount(type) {\n  var events = this._events;\n\n  if (events !== undefined) {\n    var evlistener = events[type];\n\n    if (typeof evlistener === 'function') {\n      return 1;\n    } else if (evlistener !== undefined) {\n      return evlistener.length;\n    }\n  }\n\n  return 0;\n}\n\nEventEmitter.prototype.eventNames = function eventNames() {\n  return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];\n};\n\nfunction arrayClone(arr, n) {\n  var copy = new Array(n);\n  for (var i = 0; i < n; ++i)\n    copy[i] = arr[i];\n  return copy;\n}\n\nfunction spliceOne(list, index) {\n  for (; index + 1 < list.length; index++)\n    list[index] = list[index + 1];\n  list.pop();\n}\n\nfunction unwrapListeners(arr) {\n  var ret = new Array(arr.length);\n  for (var i = 0; i < ret.length; ++i) {\n    ret[i] = arr[i].listener || arr[i];\n  }\n  return ret;\n}\n\nfunction once(emitter, name) {\n  return new Promise(function (resolve, reject) {\n    function errorListener(err) {\n      emitter.removeListener(name, resolver);\n      reject(err);\n    }\n\n    function resolver() {\n      if (typeof emitter.removeListener === 'function') {\n        emitter.removeListener('error', errorListener);\n      }\n      resolve([].slice.call(arguments));\n    };\n\n    eventTargetAgnosticAddListener(emitter, name, resolver, { once: true });\n    if (name !== 'error') {\n      addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true });\n    }\n  });\n}\n\nfunction addErrorHandlerIfEventEmitter(emitter, handler, flags) {\n  if (typeof emitter.on === 'function') {\n    eventTargetAgnosticAddListener(emitter, 'error', handler, flags);\n  }\n}\n\nfunction eventTargetAgnosticAddListener(emitter, name, listener, flags) {\n  if (typeof emitter.on === 'function') {\n    if (flags.once) {\n      emitter.once(name, listener);\n    } else {\n      emitter.on(name, listener);\n    }\n  } else if (typeof emitter.addEventListener === 'function') {\n    // EventTarget does not have `error` event semantics like Node\n    // EventEmitters, we do not listen for `error` events here.\n    emitter.addEventListener(name, function wrapListener(arg) {\n      // IE does not have builtin `{ once: true }` support so we\n      // have to do it manually.\n      if (flags.once) {\n        emitter.removeEventListener(name, wrapListener);\n      }\n      listener(arg);\n    });\n  } else {\n    throw new TypeError('The \"emitter\" argument must be of type EventEmitter. Received type ' + typeof emitter);\n  }\n}\n","/*!\n * jQuery JavaScript Library v3.6.0 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector\n * https://jquery.com/\n *\n * Includes Sizzle.js\n * https://sizzlejs.com/\n *\n * Copyright OpenJS Foundation and other contributors\n * Released under the MIT license\n * https://jquery.org/license\n *\n * Date: 2021-03-02T17:08Z\n */\n( function( global, factory ) {\n\n\t\"use strict\";\n\n\tif ( typeof module === \"object\" && typeof module.exports === \"object\" ) {\n\n\t\t// For CommonJS and CommonJS-like environments where a proper `window`\n\t\t// is present, execute the factory and get jQuery.\n\t\t// For environments that do not have a `window` with a `document`\n\t\t// (such as Node.js), expose a factory as module.exports.\n\t\t// This accentuates the need for the creation of a real `window`.\n\t\t// e.g. var jQuery = require(\"jquery\")(window);\n\t\t// See ticket #14549 for more info.\n\t\tmodule.exports = global.document ?\n\t\t\tfactory( global, true ) :\n\t\t\tfunction( w ) {\n\t\t\t\tif ( !w.document ) {\n\t\t\t\t\tthrow new Error( \"jQuery requires a window with a document\" );\n\t\t\t\t}\n\t\t\t\treturn factory( w );\n\t\t\t};\n\t} else {\n\t\tfactory( global );\n\t}\n\n// Pass this if window is not defined yet\n} )( typeof window !== \"undefined\" ? window : this, function( window, noGlobal ) {\n\n// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1\n// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode\n// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common\n// enough that all such attempts are guarded in a try block.\n\"use strict\";\n\nvar arr = [];\n\nvar getProto = Object.getPrototypeOf;\n\nvar slice = arr.slice;\n\nvar flat = arr.flat ? function( array ) {\n\treturn arr.flat.call( array );\n} : function( array ) {\n\treturn arr.concat.apply( [], array );\n};\n\n\nvar push = arr.push;\n\nvar indexOf = arr.indexOf;\n\nvar class2type = {};\n\nvar toString = class2type.toString;\n\nvar hasOwn = class2type.hasOwnProperty;\n\nvar fnToString = hasOwn.toString;\n\nvar ObjectFunctionString = fnToString.call( Object );\n\nvar support = {};\n\nvar isFunction = function isFunction( obj ) {\n\n\t\t// Support: Chrome <=57, Firefox <=52\n\t\t// In some browsers, typeof returns \"function\" for HTML <object> elements\n\t\t// (i.e., `typeof document.createElement( \"object\" ) === \"function\"`).\n\t\t// We don't want to classify *any* DOM node as a function.\n\t\t// Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5\n\t\t// Plus for old WebKit, typeof returns \"function\" for HTML collections\n\t\t// (e.g., `typeof document.getElementsByTagName(\"div\") === \"function\"`). (gh-4756)\n\t\treturn typeof obj === \"function\" && typeof obj.nodeType !== \"number\" &&\n\t\t\ttypeof obj.item !== \"function\";\n\t};\n\n\nvar isWindow = function isWindow( obj ) {\n\t\treturn obj != null && obj === obj.window;\n\t};\n\n\nvar document = window.document;\n\n\n\n\tvar preservedScriptAttributes = {\n\t\ttype: true,\n\t\tsrc: true,\n\t\tnonce: true,\n\t\tnoModule: true\n\t};\n\n\tfunction DOMEval( code, node, doc ) {\n\t\tdoc = doc || document;\n\n\t\tvar i, val,\n\t\t\tscript = doc.createElement( \"script\" );\n\n\t\tscript.text = code;\n\t\tif ( node ) {\n\t\t\tfor ( i in preservedScriptAttributes ) {\n\n\t\t\t\t// Support: Firefox 64+, Edge 18+\n\t\t\t\t// Some browsers don't support the \"nonce\" property on scripts.\n\t\t\t\t// On the other hand, just using `getAttribute` is not enough as\n\t\t\t\t// the `nonce` attribute is reset to an empty string whenever it\n\t\t\t\t// becomes browsing-context connected.\n\t\t\t\t// See https://github.com/whatwg/html/issues/2369\n\t\t\t\t// See https://html.spec.whatwg.org/#nonce-attributes\n\t\t\t\t// The `node.getAttribute` check was added for the sake of\n\t\t\t\t// `jQuery.globalEval` so that it can fake a nonce-containing node\n\t\t\t\t// via an object.\n\t\t\t\tval = node[ i ] || node.getAttribute && node.getAttribute( i );\n\t\t\t\tif ( val ) {\n\t\t\t\t\tscript.setAttribute( i, val );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tdoc.head.appendChild( script ).parentNode.removeChild( script );\n\t}\n\n\nfunction toType( obj ) {\n\tif ( obj == null ) {\n\t\treturn obj + \"\";\n\t}\n\n\t// Support: Android <=2.3 only (functionish RegExp)\n\treturn typeof obj === \"object\" || typeof obj === \"function\" ?\n\t\tclass2type[ toString.call( obj ) ] || \"object\" :\n\t\ttypeof obj;\n}\n/* global Symbol */\n// Defining this global in .eslintrc.json would create a danger of using the global\n// unguarded in another place, it seems safer to define global only for this module\n\n\n\nvar\n\tversion = \"3.6.0 -ajax,-ajax/jsonp,-ajax/load,-ajax/script,-ajax/var/location,-ajax/var/nonce,-ajax/var/rquery,-ajax/xhr,-manipulation/_evalUrl,-deprecated/ajax-event-alias,-effects,-effects/Tween,-effects/animatedSelector\",\n\n\t// Define a local copy of jQuery\n\tjQuery = function( selector, context ) {\n\n\t\t// The jQuery object is actually just the init constructor 'enhanced'\n\t\t// Need init if jQuery is called (just allow error to be thrown if not included)\n\t\treturn new jQuery.fn.init( selector, context );\n\t};\n\njQuery.fn = jQuery.prototype = {\n\n\t// The current version of jQuery being used\n\tjquery: version,\n\n\tconstructor: jQuery,\n\n\t// The default length of a jQuery object is 0\n\tlength: 0,\n\n\ttoArray: function() {\n\t\treturn slice.call( this );\n\t},\n\n\t// Get the Nth element in the matched element set OR\n\t// Get the whole matched element set as a clean array\n\tget: function( num ) {\n\n\t\t// Return all the elements in a clean array\n\t\tif ( num == null ) {\n\t\t\treturn slice.call( this );\n\t\t}\n\n\t\t// Return just the one element from the set\n\t\treturn num < 0 ? this[ num + this.length ] : this[ num ];\n\t},\n\n\t// Take an array of elements and push it onto the stack\n\t// (returning the new matched element set)\n\tpushStack: function( elems ) {\n\n\t\t// Build a new jQuery matched element set\n\t\tvar ret = jQuery.merge( this.constructor(), elems );\n\n\t\t// Add the old object onto the stack (as a reference)\n\t\tret.prevObject = this;\n\n\t\t// Return the newly-formed element set\n\t\treturn ret;\n\t},\n\n\t// Execute a callback for every element in the matched set.\n\teach: function( callback ) {\n\t\treturn jQuery.each( this, callback );\n\t},\n\n\tmap: function( callback ) {\n\t\treturn this.pushStack( jQuery.map( this, function( elem, i ) {\n\t\t\treturn callback.call( elem, i, elem );\n\t\t} ) );\n\t},\n\n\tslice: function() {\n\t\treturn this.pushStack( slice.apply( this, arguments ) );\n\t},\n\n\tfirst: function() {\n\t\treturn this.eq( 0 );\n\t},\n\n\tlast: function() {\n\t\treturn this.eq( -1 );\n\t},\n\n\teven: function() {\n\t\treturn this.pushStack( jQuery.grep( this, function( _elem, i ) {\n\t\t\treturn ( i + 1 ) % 2;\n\t\t} ) );\n\t},\n\n\todd: function() {\n\t\treturn this.pushStack( jQuery.grep( this, function( _elem, i ) {\n\t\t\treturn i % 2;\n\t\t} ) );\n\t},\n\n\teq: function( i ) {\n\t\tvar len = this.length,\n\t\t\tj = +i + ( i < 0 ? len : 0 );\n\t\treturn this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );\n\t},\n\n\tend: function() {\n\t\treturn this.prevObject || this.constructor();\n\t},\n\n\t// For internal use only.\n\t// Behaves like an Array's method, not like a jQuery method.\n\tpush: push,\n\tsort: arr.sort,\n\tsplice: arr.splice\n};\n\njQuery.extend = jQuery.fn.extend = function() {\n\tvar options, name, src, copy, copyIsArray, clone,\n\t\ttarget = arguments[ 0 ] || {},\n\t\ti = 1,\n\t\tlength = arguments.length,\n\t\tdeep = false;\n\n\t// Handle a deep copy situation\n\tif ( typeof target === \"boolean\" ) {\n\t\tdeep = target;\n\n\t\t// Skip the boolean and the target\n\t\ttarget = arguments[ i ] || {};\n\t\ti++;\n\t}\n\n\t// Handle case when target is a string or something (possible in deep copy)\n\tif ( typeof target !== \"object\" && !isFunction( target ) ) {\n\t\ttarget = {};\n\t}\n\n\t// Extend jQuery itself if only one argument is passed\n\tif ( i === length ) {\n\t\ttarget = this;\n\t\ti--;\n\t}\n\n\tfor ( ; i < length; i++ ) {\n\n\t\t// Only deal with non-null/undefined values\n\t\tif ( ( options = arguments[ i ] ) != null ) {\n\n\t\t\t// Extend the base object\n\t\t\tfor ( name in options ) {\n\t\t\t\tcopy = options[ name ];\n\n\t\t\t\t// Prevent Object.prototype pollution\n\t\t\t\t// Prevent never-ending loop\n\t\t\t\tif ( name === \"__proto__\" || target === copy ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Recurse if we're merging plain objects or arrays\n\t\t\t\tif ( deep && copy && ( jQuery.isPlainObject( copy ) ||\n\t\t\t\t\t( copyIsArray = Array.isArray( copy ) ) ) ) {\n\t\t\t\t\tsrc = target[ name ];\n\n\t\t\t\t\t// Ensure proper type for the source value\n\t\t\t\t\tif ( copyIsArray && !Array.isArray( src ) ) {\n\t\t\t\t\t\tclone = [];\n\t\t\t\t\t} else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) {\n\t\t\t\t\t\tclone = {};\n\t\t\t\t\t} else {\n\t\t\t\t\t\tclone = src;\n\t\t\t\t\t}\n\t\t\t\t\tcopyIsArray = false;\n\n\t\t\t\t\t// Never move original objects, clone them\n\t\t\t\t\ttarget[ name ] = jQuery.extend( deep, clone, copy );\n\n\t\t\t\t// Don't bring in undefined values\n\t\t\t\t} else if ( copy !== undefined ) {\n\t\t\t\t\ttarget[ name ] = copy;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Return the modified object\n\treturn target;\n};\n\njQuery.extend( {\n\n\t// Unique for each copy of jQuery on the page\n\texpando: \"jQuery\" + ( version + Math.random() ).replace( /\\D/g, \"\" ),\n\n\t// Assume jQuery is ready without the ready module\n\tisReady: true,\n\n\terror: function( msg ) {\n\t\tthrow new Error( msg );\n\t},\n\n\tnoop: function() {},\n\n\tisPlainObject: function( obj ) {\n\t\tvar proto, Ctor;\n\n\t\t// Detect obvious negatives\n\t\t// Use toString instead of jQuery.type to catch host objects\n\t\tif ( !obj || toString.call( obj ) !== \"[object Object]\" ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tproto = getProto( obj );\n\n\t\t// Objects with no prototype (e.g., `Object.create( null )`) are plain\n\t\tif ( !proto ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Objects with prototype are plain iff they were constructed by a global Object function\n\t\tCtor = hasOwn.call( proto, \"constructor\" ) && proto.constructor;\n\t\treturn typeof Ctor === \"function\" && fnToString.call( Ctor ) === ObjectFunctionString;\n\t},\n\n\tisEmptyObject: function( obj ) {\n\t\tvar name;\n\n\t\tfor ( name in obj ) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t},\n\n\t// Evaluates a script in a provided context; falls back to the global one\n\t// if not specified.\n\tglobalEval: function( code, options, doc ) {\n\t\tDOMEval( code, { nonce: options && options.nonce }, doc );\n\t},\n\n\teach: function( obj, callback ) {\n\t\tvar length, i = 0;\n\n\t\tif ( isArrayLike( obj ) ) {\n\t\t\tlength = obj.length;\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tif ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tfor ( i in obj ) {\n\t\t\t\tif ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn obj;\n\t},\n\n\t// results is for internal usage only\n\tmakeArray: function( arr, results ) {\n\t\tvar ret = results || [];\n\n\t\tif ( arr != null ) {\n\t\t\tif ( isArrayLike( Object( arr ) ) ) {\n\t\t\t\tjQuery.merge( ret,\n\t\t\t\t\ttypeof arr === \"string\" ?\n\t\t\t\t\t\t[ arr ] : arr\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tpush.call( ret, arr );\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\tinArray: function( elem, arr, i ) {\n\t\treturn arr == null ? -1 : indexOf.call( arr, elem, i );\n\t},\n\n\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t// push.apply(_, arraylike) throws on ancient WebKit\n\tmerge: function( first, second ) {\n\t\tvar len = +second.length,\n\t\t\tj = 0,\n\t\t\ti = first.length;\n\n\t\tfor ( ; j < len; j++ ) {\n\t\t\tfirst[ i++ ] = second[ j ];\n\t\t}\n\n\t\tfirst.length = i;\n\n\t\treturn first;\n\t},\n\n\tgrep: function( elems, callback, invert ) {\n\t\tvar callbackInverse,\n\t\t\tmatches = [],\n\t\t\ti = 0,\n\t\t\tlength = elems.length,\n\t\t\tcallbackExpect = !invert;\n\n\t\t// Go through the array, only saving the items\n\t\t// that pass the validator function\n\t\tfor ( ; i < length; i++ ) {\n\t\t\tcallbackInverse = !callback( elems[ i ], i );\n\t\t\tif ( callbackInverse !== callbackExpect ) {\n\t\t\t\tmatches.push( elems[ i ] );\n\t\t\t}\n\t\t}\n\n\t\treturn matches;\n\t},\n\n\t// arg is for internal usage only\n\tmap: function( elems, callback, arg ) {\n\t\tvar length, value,\n\t\t\ti = 0,\n\t\t\tret = [];\n\n\t\t// Go through the array, translating each of the items to their new values\n\t\tif ( isArrayLike( elems ) ) {\n\t\t\tlength = elems.length;\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Go through every key on the object,\n\t\t} else {\n\t\t\tfor ( i in elems ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Flatten any nested arrays\n\t\treturn flat( ret );\n\t},\n\n\t// A global GUID counter for objects\n\tguid: 1,\n\n\t// jQuery.support is not used in Core but other projects attach their\n\t// properties to it so it needs to exist.\n\tsupport: support\n} );\n\nif ( typeof Symbol === \"function\" ) {\n\tjQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];\n}\n\n// Populate the class2type map\njQuery.each( \"Boolean Number String Function Array Date RegExp Object Error Symbol\".split( \" \" ),\n\tfunction( _i, name ) {\n\t\tclass2type[ \"[object \" + name + \"]\" ] = name.toLowerCase();\n\t} );\n\nfunction isArrayLike( obj ) {\n\n\t// Support: real iOS 8.2 only (not reproducible in simulator)\n\t// `in` check used to prevent JIT error (gh-2145)\n\t// hasOwn isn't used here due to false negatives\n\t// regarding Nodelist length in IE\n\tvar length = !!obj && \"length\" in obj && obj.length,\n\t\ttype = toType( obj );\n\n\tif ( isFunction( obj ) || isWindow( obj ) ) {\n\t\treturn false;\n\t}\n\n\treturn type === \"array\" || length === 0 ||\n\t\ttypeof length === \"number\" && length > 0 && ( length - 1 ) in obj;\n}\nvar Sizzle =\n/*!\n * Sizzle CSS Selector Engine v2.3.6\n * https://sizzlejs.com/\n *\n * Copyright JS Foundation and other contributors\n * Released under the MIT license\n * https://js.foundation/\n *\n * Date: 2021-02-16\n */\n( function( window ) {\nvar i,\n\tsupport,\n\tExpr,\n\tgetText,\n\tisXML,\n\ttokenize,\n\tcompile,\n\tselect,\n\toutermostContext,\n\tsortInput,\n\thasDuplicate,\n\n\t// Local document vars\n\tsetDocument,\n\tdocument,\n\tdocElem,\n\tdocumentIsHTML,\n\trbuggyQSA,\n\trbuggyMatches,\n\tmatches,\n\tcontains,\n\n\t// Instance-specific data\n\texpando = \"sizzle\" + 1 * new Date(),\n\tpreferredDoc = window.document,\n\tdirruns = 0,\n\tdone = 0,\n\tclassCache = createCache(),\n\ttokenCache = createCache(),\n\tcompilerCache = createCache(),\n\tnonnativeSelectorCache = createCache(),\n\tsortOrder = function( a, b ) {\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t}\n\t\treturn 0;\n\t},\n\n\t// Instance methods\n\thasOwn = ( {} ).hasOwnProperty,\n\tarr = [],\n\tpop = arr.pop,\n\tpushNative = arr.push,\n\tpush = arr.push,\n\tslice = arr.slice,\n\n\t// Use a stripped-down indexOf as it's faster than native\n\t// https://jsperf.com/thor-indexof-vs-for/5\n\tindexOf = function( list, elem ) {\n\t\tvar i = 0,\n\t\t\tlen = list.length;\n\t\tfor ( ; i < len; i++ ) {\n\t\t\tif ( list[ i ] === elem ) {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t},\n\n\tbooleans = \"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|\" +\n\t\t\"ismap|loop|multiple|open|readonly|required|scoped\",\n\n\t// Regular expressions\n\n\t// http://www.w3.org/TR/css3-selectors/#whitespace\n\twhitespace = \"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",\n\n\t// https://www.w3.org/TR/css-syntax-3/#ident-token-diagram\n\tidentifier = \"(?:\\\\\\\\[\\\\da-fA-F]{1,6}\" + whitespace +\n\t\t\"?|\\\\\\\\[^\\\\r\\\\n\\\\f]|[\\\\w-]|[^\\0-\\\\x7f])+\",\n\n\t// Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors\n\tattributes = \"\\\\[\" + whitespace + \"*(\" + identifier + \")(?:\" + whitespace +\n\n\t\t// Operator (capture 2)\n\t\t\"*([*^$|!~]?=)\" + whitespace +\n\n\t\t// \"Attribute values must be CSS identifiers [capture 5]\n\t\t// or strings [capture 3 or capture 4]\"\n\t\t\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\" + identifier + \"))|)\" +\n\t\twhitespace + \"*\\\\]\",\n\n\tpseudos = \":(\" + identifier + \")(?:\\\\((\" +\n\n\t\t// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:\n\t\t// 1. quoted (capture 3; capture 4 or capture 5)\n\t\t\"('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|\" +\n\n\t\t// 2. simple (capture 6)\n\t\t\"((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\" + attributes + \")*)|\" +\n\n\t\t// 3. anything else (capture 2)\n\t\t\".*\" +\n\t\t\")\\\\)|)\",\n\n\t// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter\n\trwhitespace = new RegExp( whitespace + \"+\", \"g\" ),\n\trtrim = new RegExp( \"^\" + whitespace + \"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\" +\n\t\twhitespace + \"+$\", \"g\" ),\n\n\trcomma = new RegExp( \"^\" + whitespace + \"*,\" + whitespace + \"*\" ),\n\trcombinators = new RegExp( \"^\" + whitespace + \"*([>+~]|\" + whitespace + \")\" + whitespace +\n\t\t\"*\" ),\n\trdescend = new RegExp( whitespace + \"|>\" ),\n\n\trpseudo = new RegExp( pseudos ),\n\tridentifier = new RegExp( \"^\" + identifier + \"$\" ),\n\n\tmatchExpr = {\n\t\t\"ID\": new RegExp( \"^#(\" + identifier + \")\" ),\n\t\t\"CLASS\": new RegExp( \"^\\\\.(\" + identifier + \")\" ),\n\t\t\"TAG\": new RegExp( \"^(\" + identifier + \"|[*])\" ),\n\t\t\"ATTR\": new RegExp( \"^\" + attributes ),\n\t\t\"PSEUDO\": new RegExp( \"^\" + pseudos ),\n\t\t\"CHILD\": new RegExp( \"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\" +\n\t\t\twhitespace + \"*(even|odd|(([+-]|)(\\\\d*)n|)\" + whitespace + \"*(?:([+-]|)\" +\n\t\t\twhitespace + \"*(\\\\d+)|))\" + whitespace + \"*\\\\)|)\", \"i\" ),\n\t\t\"bool\": new RegExp( \"^(?:\" + booleans + \")$\", \"i\" ),\n\n\t\t// For use in libraries implementing .is()\n\t\t// We use this for POS matching in `select`\n\t\t\"needsContext\": new RegExp( \"^\" + whitespace +\n\t\t\t\"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\" + whitespace +\n\t\t\t\"*((?:-\\\\d)?\\\\d*)\" + whitespace + \"*\\\\)|)(?=[^-]|$)\", \"i\" )\n\t},\n\n\trhtml = /HTML$/i,\n\trinputs = /^(?:input|select|textarea|button)$/i,\n\trheader = /^h\\d$/i,\n\n\trnative = /^[^{]+\\{\\s*\\[native \\w/,\n\n\t// Easily-parseable/retrievable ID or TAG or CLASS selectors\n\trquickExpr = /^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,\n\n\trsibling = /[+~]/,\n\n\t// CSS escapes\n\t// http://www.w3.org/TR/CSS21/syndata.html#escaped-characters\n\trunescape = new RegExp( \"\\\\\\\\[\\\\da-fA-F]{1,6}\" + whitespace + \"?|\\\\\\\\([^\\\\r\\\\n\\\\f])\", \"g\" ),\n\tfunescape = function( escape, nonHex ) {\n\t\tvar high = \"0x\" + escape.slice( 1 ) - 0x10000;\n\n\t\treturn nonHex ?\n\n\t\t\t// Strip the backslash prefix from a non-hex escape sequence\n\t\t\tnonHex :\n\n\t\t\t// Replace a hexadecimal escape sequence with the encoded Unicode code point\n\t\t\t// Support: IE <=11+\n\t\t\t// For values outside the Basic Multilingual Plane (BMP), manually construct a\n\t\t\t// surrogate pair\n\t\t\thigh < 0 ?\n\t\t\t\tString.fromCharCode( high + 0x10000 ) :\n\t\t\t\tString.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );\n\t},\n\n\t// CSS string/identifier serialization\n\t// https://drafts.csswg.org/cssom/#common-serializing-idioms\n\trcssescape = /([\\0-\\x1f\\x7f]|^-?\\d)|^-$|[^\\0-\\x1f\\x7f-\\uFFFF\\w-]/g,\n\tfcssescape = function( ch, asCodePoint ) {\n\t\tif ( asCodePoint ) {\n\n\t\t\t// U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER\n\t\t\tif ( ch === \"\\0\" ) {\n\t\t\t\treturn \"\\uFFFD\";\n\t\t\t}\n\n\t\t\t// Control characters and (dependent upon position) numbers get escaped as code points\n\t\t\treturn ch.slice( 0, -1 ) + \"\\\\\" +\n\t\t\t\tch.charCodeAt( ch.length - 1 ).toString( 16 ) + \" \";\n\t\t}\n\n\t\t// Other potentially-special ASCII characters get backslash-escaped\n\t\treturn \"\\\\\" + ch;\n\t},\n\n\t// Used for iframes\n\t// See setDocument()\n\t// Removing the function wrapper causes a \"Permission Denied\"\n\t// error in IE\n\tunloadHandler = function() {\n\t\tsetDocument();\n\t},\n\n\tinDisabledFieldset = addCombinator(\n\t\tfunction( elem ) {\n\t\t\treturn elem.disabled === true && elem.nodeName.toLowerCase() === \"fieldset\";\n\t\t},\n\t\t{ dir: \"parentNode\", next: \"legend\" }\n\t);\n\n// Optimize for push.apply( _, NodeList )\ntry {\n\tpush.apply(\n\t\t( arr = slice.call( preferredDoc.childNodes ) ),\n\t\tpreferredDoc.childNodes\n\t);\n\n\t// Support: Android<4.0\n\t// Detect silently failing push.apply\n\t// eslint-disable-next-line no-unused-expressions\n\tarr[ preferredDoc.childNodes.length ].nodeType;\n} catch ( e ) {\n\tpush = { apply: arr.length ?\n\n\t\t// Leverage slice if possible\n\t\tfunction( target, els ) {\n\t\t\tpushNative.apply( target, slice.call( els ) );\n\t\t} :\n\n\t\t// Support: IE<9\n\t\t// Otherwise append directly\n\t\tfunction( target, els ) {\n\t\t\tvar j = target.length,\n\t\t\t\ti = 0;\n\n\t\t\t// Can't trust NodeList.length\n\t\t\twhile ( ( target[ j++ ] = els[ i++ ] ) ) {}\n\t\t\ttarget.length = j - 1;\n\t\t}\n\t};\n}\n\nfunction Sizzle( selector, context, results, seed ) {\n\tvar m, i, elem, nid, match, groups, newSelector,\n\t\tnewContext = context && context.ownerDocument,\n\n\t\t// nodeType defaults to 9, since context defaults to document\n\t\tnodeType = context ? context.nodeType : 9;\n\n\tresults = results || [];\n\n\t// Return early from calls with invalid selector or context\n\tif ( typeof selector !== \"string\" || !selector ||\n\t\tnodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {\n\n\t\treturn results;\n\t}\n\n\t// Try to shortcut find operations (as opposed to filters) in HTML documents\n\tif ( !seed ) {\n\t\tsetDocument( context );\n\t\tcontext = context || document;\n\n\t\tif ( documentIsHTML ) {\n\n\t\t\t// If the selector is sufficiently simple, try using a \"get*By*\" DOM method\n\t\t\t// (excepting DocumentFragment context, where the methods don't exist)\n\t\t\tif ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) {\n\n\t\t\t\t// ID selector\n\t\t\t\tif ( ( m = match[ 1 ] ) ) {\n\n\t\t\t\t\t// Document context\n\t\t\t\t\tif ( nodeType === 9 ) {\n\t\t\t\t\t\tif ( ( elem = context.getElementById( m ) ) ) {\n\n\t\t\t\t\t\t\t// Support: IE, Opera, Webkit\n\t\t\t\t\t\t\t// TODO: identify versions\n\t\t\t\t\t\t\t// getElementById can match elements by name instead of ID\n\t\t\t\t\t\t\tif ( elem.id === m ) {\n\t\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t// Element context\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// Support: IE, Opera, Webkit\n\t\t\t\t\t\t// TODO: identify versions\n\t\t\t\t\t\t// getElementById can match elements by name instead of ID\n\t\t\t\t\t\tif ( newContext && ( elem = newContext.getElementById( m ) ) &&\n\t\t\t\t\t\t\tcontains( context, elem ) &&\n\t\t\t\t\t\t\telem.id === m ) {\n\n\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t// Type selector\n\t\t\t\t} else if ( match[ 2 ] ) {\n\t\t\t\t\tpush.apply( results, context.getElementsByTagName( selector ) );\n\t\t\t\t\treturn results;\n\n\t\t\t\t// Class selector\n\t\t\t\t} else if ( ( m = match[ 3 ] ) && support.getElementsByClassName &&\n\t\t\t\t\tcontext.getElementsByClassName ) {\n\n\t\t\t\t\tpush.apply( results, context.getElementsByClassName( m ) );\n\t\t\t\t\treturn results;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Take advantage of querySelectorAll\n\t\t\tif ( support.qsa &&\n\t\t\t\t!nonnativeSelectorCache[ selector + \" \" ] &&\n\t\t\t\t( !rbuggyQSA || !rbuggyQSA.test( selector ) ) &&\n\n\t\t\t\t// Support: IE 8 only\n\t\t\t\t// Exclude object elements\n\t\t\t\t( nodeType !== 1 || context.nodeName.toLowerCase() !== \"object\" ) ) {\n\n\t\t\t\tnewSelector = selector;\n\t\t\t\tnewContext = context;\n\n\t\t\t\t// qSA considers elements outside a scoping root when evaluating child or\n\t\t\t\t// descendant combinators, which is not what we want.\n\t\t\t\t// In such cases, we work around the behavior by prefixing every selector in the\n\t\t\t\t// list with an ID selector referencing the scope context.\n\t\t\t\t// The technique has to be used as well when a leading combinator is used\n\t\t\t\t// as such selectors are not recognized by querySelectorAll.\n\t\t\t\t// Thanks to Andrew Dupont for this technique.\n\t\t\t\tif ( nodeType === 1 &&\n\t\t\t\t\t( rdescend.test( selector ) || rcombinators.test( selector ) ) ) {\n\n\t\t\t\t\t// Expand context for sibling selectors\n\t\t\t\t\tnewContext = rsibling.test( selector ) && testContext( context.parentNode ) ||\n\t\t\t\t\t\tcontext;\n\n\t\t\t\t\t// We can use :scope instead of the ID hack if the browser\n\t\t\t\t\t// supports it & if we're not changing the context.\n\t\t\t\t\tif ( newContext !== context || !support.scope ) {\n\n\t\t\t\t\t\t// Capture the context ID, setting it first if necessary\n\t\t\t\t\t\tif ( ( nid = context.getAttribute( \"id\" ) ) ) {\n\t\t\t\t\t\t\tnid = nid.replace( rcssescape, fcssescape );\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcontext.setAttribute( \"id\", ( nid = expando ) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prefix every selector in the list\n\t\t\t\t\tgroups = tokenize( selector );\n\t\t\t\t\ti = groups.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tgroups[ i ] = ( nid ? \"#\" + nid : \":scope\" ) + \" \" +\n\t\t\t\t\t\t\ttoSelector( groups[ i ] );\n\t\t\t\t\t}\n\t\t\t\t\tnewSelector = groups.join( \",\" );\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tpush.apply( results,\n\t\t\t\t\t\tnewContext.querySelectorAll( newSelector )\n\t\t\t\t\t);\n\t\t\t\t\treturn results;\n\t\t\t\t} catch ( qsaError ) {\n\t\t\t\t\tnonnativeSelectorCache( selector, true );\n\t\t\t\t} finally {\n\t\t\t\t\tif ( nid === expando ) {\n\t\t\t\t\t\tcontext.removeAttribute( \"id\" );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// All others\n\treturn select( selector.replace( rtrim, \"$1\" ), context, results, seed );\n}\n\n/**\n * Create key-value caches of limited size\n * @returns {function(string, object)} Returns the Object data after storing it on itself with\n *\tproperty name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)\n *\tdeleting the oldest entry\n */\nfunction createCache() {\n\tvar keys = [];\n\n\tfunction cache( key, value ) {\n\n\t\t// Use (key + \" \") to avoid collision with native prototype properties (see Issue #157)\n\t\tif ( keys.push( key + \" \" ) > Expr.cacheLength ) {\n\n\t\t\t// Only keep the most recent entries\n\t\t\tdelete cache[ keys.shift() ];\n\t\t}\n\t\treturn ( cache[ key + \" \" ] = value );\n\t}\n\treturn cache;\n}\n\n/**\n * Mark a function for special use by Sizzle\n * @param {Function} fn The function to mark\n */\nfunction markFunction( fn ) {\n\tfn[ expando ] = true;\n\treturn fn;\n}\n\n/**\n * Support testing using an element\n * @param {Function} fn Passed the created element and returns a boolean result\n */\nfunction assert( fn ) {\n\tvar el = document.createElement( \"fieldset\" );\n\n\ttry {\n\t\treturn !!fn( el );\n\t} catch ( e ) {\n\t\treturn false;\n\t} finally {\n\n\t\t// Remove from its parent by default\n\t\tif ( el.parentNode ) {\n\t\t\tel.parentNode.removeChild( el );\n\t\t}\n\n\t\t// release memory in IE\n\t\tel = null;\n\t}\n}\n\n/**\n * Adds the same handler for all of the specified attrs\n * @param {String} attrs Pipe-separated list of attributes\n * @param {Function} handler The method that will be applied\n */\nfunction addHandle( attrs, handler ) {\n\tvar arr = attrs.split( \"|\" ),\n\t\ti = arr.length;\n\n\twhile ( i-- ) {\n\t\tExpr.attrHandle[ arr[ i ] ] = handler;\n\t}\n}\n\n/**\n * Checks document order of two siblings\n * @param {Element} a\n * @param {Element} b\n * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b\n */\nfunction siblingCheck( a, b ) {\n\tvar cur = b && a,\n\t\tdiff = cur && a.nodeType === 1 && b.nodeType === 1 &&\n\t\t\ta.sourceIndex - b.sourceIndex;\n\n\t// Use IE sourceIndex if available on both nodes\n\tif ( diff ) {\n\t\treturn diff;\n\t}\n\n\t// Check if b follows a\n\tif ( cur ) {\n\t\twhile ( ( cur = cur.nextSibling ) ) {\n\t\t\tif ( cur === b ) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn a ? 1 : -1;\n}\n\n/**\n * Returns a function to use in pseudos for input types\n * @param {String} type\n */\nfunction createInputPseudo( type ) {\n\treturn function( elem ) {\n\t\tvar name = elem.nodeName.toLowerCase();\n\t\treturn name === \"input\" && elem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for buttons\n * @param {String} type\n */\nfunction createButtonPseudo( type ) {\n\treturn function( elem ) {\n\t\tvar name = elem.nodeName.toLowerCase();\n\t\treturn ( name === \"input\" || name === \"button\" ) && elem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for :enabled/:disabled\n * @param {Boolean} disabled true for :disabled; false for :enabled\n */\nfunction createDisabledPseudo( disabled ) {\n\n\t// Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable\n\treturn function( elem ) {\n\n\t\t// Only certain elements can match :enabled or :disabled\n\t\t// https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled\n\t\t// https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled\n\t\tif ( \"form\" in elem ) {\n\n\t\t\t// Check for inherited disabledness on relevant non-disabled elements:\n\t\t\t// * listed form-associated elements in a disabled fieldset\n\t\t\t//   https://html.spec.whatwg.org/multipage/forms.html#category-listed\n\t\t\t//   https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled\n\t\t\t// * option elements in a disabled optgroup\n\t\t\t//   https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled\n\t\t\t// All such elements have a \"form\" property.\n\t\t\tif ( elem.parentNode && elem.disabled === false ) {\n\n\t\t\t\t// Option elements defer to a parent optgroup if present\n\t\t\t\tif ( \"label\" in elem ) {\n\t\t\t\t\tif ( \"label\" in elem.parentNode ) {\n\t\t\t\t\t\treturn elem.parentNode.disabled === disabled;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn elem.disabled === disabled;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Support: IE 6 - 11\n\t\t\t\t// Use the isDisabled shortcut property to check for disabled fieldset ancestors\n\t\t\t\treturn elem.isDisabled === disabled ||\n\n\t\t\t\t\t// Where there is no isDisabled, check manually\n\t\t\t\t\t/* jshint -W018 */\n\t\t\t\t\telem.isDisabled !== !disabled &&\n\t\t\t\t\tinDisabledFieldset( elem ) === disabled;\n\t\t\t}\n\n\t\t\treturn elem.disabled === disabled;\n\n\t\t// Try to winnow out elements that can't be disabled before trusting the disabled property.\n\t\t// Some victims get caught in our net (label, legend, menu, track), but it shouldn't\n\t\t// even exist on them, let alone have a boolean value.\n\t\t} else if ( \"label\" in elem ) {\n\t\t\treturn elem.disabled === disabled;\n\t\t}\n\n\t\t// Remaining elements are neither :enabled nor :disabled\n\t\treturn false;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for positionals\n * @param {Function} fn\n */\nfunction createPositionalPseudo( fn ) {\n\treturn markFunction( function( argument ) {\n\t\targument = +argument;\n\t\treturn markFunction( function( seed, matches ) {\n\t\t\tvar j,\n\t\t\t\tmatchIndexes = fn( [], seed.length, argument ),\n\t\t\t\ti = matchIndexes.length;\n\n\t\t\t// Match elements found at the specified indexes\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( seed[ ( j = matchIndexes[ i ] ) ] ) {\n\t\t\t\t\tseed[ j ] = !( matches[ j ] = seed[ j ] );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t} );\n}\n\n/**\n * Checks a node for validity as a Sizzle context\n * @param {Element|Object=} context\n * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value\n */\nfunction testContext( context ) {\n\treturn context && typeof context.getElementsByTagName !== \"undefined\" && context;\n}\n\n// Expose support vars for convenience\nsupport = Sizzle.support = {};\n\n/**\n * Detects XML nodes\n * @param {Element|Object} elem An element or a document\n * @returns {Boolean} True iff elem is a non-HTML XML node\n */\nisXML = Sizzle.isXML = function( elem ) {\n\tvar namespace = elem && elem.namespaceURI,\n\t\tdocElem = elem && ( elem.ownerDocument || elem ).documentElement;\n\n\t// Support: IE <=8\n\t// Assume HTML when documentElement doesn't yet exist, such as inside loading iframes\n\t// https://bugs.jquery.com/ticket/4833\n\treturn !rhtml.test( namespace || docElem && docElem.nodeName || \"HTML\" );\n};\n\n/**\n * Sets document-related variables once based on the current document\n * @param {Element|Object} [doc] An element or document object to use to set the document\n * @returns {Object} Returns the current document\n */\nsetDocument = Sizzle.setDocument = function( node ) {\n\tvar hasCompare, subWindow,\n\t\tdoc = node ? node.ownerDocument || node : preferredDoc;\n\n\t// Return early if doc is invalid or already selected\n\t// Support: IE 11+, Edge 17 - 18+\n\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t// two documents; shallow comparisons work.\n\t// eslint-disable-next-line eqeqeq\n\tif ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) {\n\t\treturn document;\n\t}\n\n\t// Update global variables\n\tdocument = doc;\n\tdocElem = document.documentElement;\n\tdocumentIsHTML = !isXML( document );\n\n\t// Support: IE 9 - 11+, Edge 12 - 18+\n\t// Accessing iframe documents after unload throws \"permission denied\" errors (jQuery #13936)\n\t// Support: IE 11+, Edge 17 - 18+\n\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t// two documents; shallow comparisons work.\n\t// eslint-disable-next-line eqeqeq\n\tif ( preferredDoc != document &&\n\t\t( subWindow = document.defaultView ) && subWindow.top !== subWindow ) {\n\n\t\t// Support: IE 11, Edge\n\t\tif ( subWindow.addEventListener ) {\n\t\t\tsubWindow.addEventListener( \"unload\", unloadHandler, false );\n\n\t\t// Support: IE 9 - 10 only\n\t\t} else if ( subWindow.attachEvent ) {\n\t\t\tsubWindow.attachEvent( \"onunload\", unloadHandler );\n\t\t}\n\t}\n\n\t// Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only,\n\t// Safari 4 - 5 only, Opera <=11.6 - 12.x only\n\t// IE/Edge & older browsers don't support the :scope pseudo-class.\n\t// Support: Safari 6.0 only\n\t// Safari 6.0 supports :scope but it's an alias of :root there.\n\tsupport.scope = assert( function( el ) {\n\t\tdocElem.appendChild( el ).appendChild( document.createElement( \"div\" ) );\n\t\treturn typeof el.querySelectorAll !== \"undefined\" &&\n\t\t\t!el.querySelectorAll( \":scope fieldset div\" ).length;\n\t} );\n\n\t/* Attributes\n\t---------------------------------------------------------------------- */\n\n\t// Support: IE<8\n\t// Verify that getAttribute really returns attributes and not properties\n\t// (excepting IE8 booleans)\n\tsupport.attributes = assert( function( el ) {\n\t\tel.className = \"i\";\n\t\treturn !el.getAttribute( \"className\" );\n\t} );\n\n\t/* getElement(s)By*\n\t---------------------------------------------------------------------- */\n\n\t// Check if getElementsByTagName(\"*\") returns only elements\n\tsupport.getElementsByTagName = assert( function( el ) {\n\t\tel.appendChild( document.createComment( \"\" ) );\n\t\treturn !el.getElementsByTagName( \"*\" ).length;\n\t} );\n\n\t// Support: IE<9\n\tsupport.getElementsByClassName = rnative.test( document.getElementsByClassName );\n\n\t// Support: IE<10\n\t// Check if getElementById returns elements by name\n\t// The broken getElementById methods don't pick up programmatically-set names,\n\t// so use a roundabout getElementsByName test\n\tsupport.getById = assert( function( el ) {\n\t\tdocElem.appendChild( el ).id = expando;\n\t\treturn !document.getElementsByName || !document.getElementsByName( expando ).length;\n\t} );\n\n\t// ID filter and find\n\tif ( support.getById ) {\n\t\tExpr.filter[ \"ID\" ] = function( id ) {\n\t\t\tvar attrId = id.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn elem.getAttribute( \"id\" ) === attrId;\n\t\t\t};\n\t\t};\n\t\tExpr.find[ \"ID\" ] = function( id, context ) {\n\t\t\tif ( typeof context.getElementById !== \"undefined\" && documentIsHTML ) {\n\t\t\t\tvar elem = context.getElementById( id );\n\t\t\t\treturn elem ? [ elem ] : [];\n\t\t\t}\n\t\t};\n\t} else {\n\t\tExpr.filter[ \"ID\" ] =  function( id ) {\n\t\t\tvar attrId = id.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\tvar node = typeof elem.getAttributeNode !== \"undefined\" &&\n\t\t\t\t\telem.getAttributeNode( \"id\" );\n\t\t\t\treturn node && node.value === attrId;\n\t\t\t};\n\t\t};\n\n\t\t// Support: IE 6 - 7 only\n\t\t// getElementById is not reliable as a find shortcut\n\t\tExpr.find[ \"ID\" ] = function( id, context ) {\n\t\t\tif ( typeof context.getElementById !== \"undefined\" && documentIsHTML ) {\n\t\t\t\tvar node, i, elems,\n\t\t\t\t\telem = context.getElementById( id );\n\n\t\t\t\tif ( elem ) {\n\n\t\t\t\t\t// Verify the id attribute\n\t\t\t\t\tnode = elem.getAttributeNode( \"id\" );\n\t\t\t\t\tif ( node && node.value === id ) {\n\t\t\t\t\t\treturn [ elem ];\n\t\t\t\t\t}\n\n\t\t\t\t\t// Fall back on getElementsByName\n\t\t\t\t\telems = context.getElementsByName( id );\n\t\t\t\t\ti = 0;\n\t\t\t\t\twhile ( ( elem = elems[ i++ ] ) ) {\n\t\t\t\t\t\tnode = elem.getAttributeNode( \"id\" );\n\t\t\t\t\t\tif ( node && node.value === id ) {\n\t\t\t\t\t\t\treturn [ elem ];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn [];\n\t\t\t}\n\t\t};\n\t}\n\n\t// Tag\n\tExpr.find[ \"TAG\" ] = support.getElementsByTagName ?\n\t\tfunction( tag, context ) {\n\t\t\tif ( typeof context.getElementsByTagName !== \"undefined\" ) {\n\t\t\t\treturn context.getElementsByTagName( tag );\n\n\t\t\t// DocumentFragment nodes don't have gEBTN\n\t\t\t} else if ( support.qsa ) {\n\t\t\t\treturn context.querySelectorAll( tag );\n\t\t\t}\n\t\t} :\n\n\t\tfunction( tag, context ) {\n\t\t\tvar elem,\n\t\t\t\ttmp = [],\n\t\t\t\ti = 0,\n\n\t\t\t\t// By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too\n\t\t\t\tresults = context.getElementsByTagName( tag );\n\n\t\t\t// Filter out possible comments\n\t\t\tif ( tag === \"*\" ) {\n\t\t\t\twhile ( ( elem = results[ i++ ] ) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\ttmp.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn tmp;\n\t\t\t}\n\t\t\treturn results;\n\t\t};\n\n\t// Class\n\tExpr.find[ \"CLASS\" ] = support.getElementsByClassName && function( className, context ) {\n\t\tif ( typeof context.getElementsByClassName !== \"undefined\" && documentIsHTML ) {\n\t\t\treturn context.getElementsByClassName( className );\n\t\t}\n\t};\n\n\t/* QSA/matchesSelector\n\t---------------------------------------------------------------------- */\n\n\t// QSA and matchesSelector support\n\n\t// matchesSelector(:active) reports false when true (IE9/Opera 11.5)\n\trbuggyMatches = [];\n\n\t// qSa(:focus) reports false when true (Chrome 21)\n\t// We allow this because of a bug in IE8/9 that throws an error\n\t// whenever `document.activeElement` is accessed on an iframe\n\t// So, we allow :focus to pass through QSA all the time to avoid the IE error\n\t// See https://bugs.jquery.com/ticket/13378\n\trbuggyQSA = [];\n\n\tif ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) {\n\n\t\t// Build QSA regex\n\t\t// Regex strategy adopted from Diego Perini\n\t\tassert( function( el ) {\n\n\t\t\tvar input;\n\n\t\t\t// Select is set to empty string on purpose\n\t\t\t// This is to test IE's treatment of not explicitly\n\t\t\t// setting a boolean content attribute,\n\t\t\t// since its presence should be enough\n\t\t\t// https://bugs.jquery.com/ticket/12359\n\t\t\tdocElem.appendChild( el ).innerHTML = \"<a id='\" + expando + \"'></a>\" +\n\t\t\t\t\"<select id='\" + expando + \"-\\r\\\\' msallowcapture=''>\" +\n\t\t\t\t\"<option selected=''></option></select>\";\n\n\t\t\t// Support: IE8, Opera 11-12.16\n\t\t\t// Nothing should be selected when empty strings follow ^= or $= or *=\n\t\t\t// The test attribute must be unknown in Opera but \"safe\" for WinRT\n\t\t\t// https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section\n\t\t\tif ( el.querySelectorAll( \"[msallowcapture^='']\" ).length ) {\n\t\t\t\trbuggyQSA.push( \"[*^$]=\" + whitespace + \"*(?:''|\\\"\\\")\" );\n\t\t\t}\n\n\t\t\t// Support: IE8\n\t\t\t// Boolean attributes and \"value\" are not treated correctly\n\t\t\tif ( !el.querySelectorAll( \"[selected]\" ).length ) {\n\t\t\t\trbuggyQSA.push( \"\\\\[\" + whitespace + \"*(?:value|\" + booleans + \")\" );\n\t\t\t}\n\n\t\t\t// Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+\n\t\t\tif ( !el.querySelectorAll( \"[id~=\" + expando + \"-]\" ).length ) {\n\t\t\t\trbuggyQSA.push( \"~=\" );\n\t\t\t}\n\n\t\t\t// Support: IE 11+, Edge 15 - 18+\n\t\t\t// IE 11/Edge don't find elements on a `[name='']` query in some cases.\n\t\t\t// Adding a temporary attribute to the document before the selection works\n\t\t\t// around the issue.\n\t\t\t// Interestingly, IE 10 & older don't seem to have the issue.\n\t\t\tinput = document.createElement( \"input\" );\n\t\t\tinput.setAttribute( \"name\", \"\" );\n\t\t\tel.appendChild( input );\n\t\t\tif ( !el.querySelectorAll( \"[name='']\" ).length ) {\n\t\t\t\trbuggyQSA.push( \"\\\\[\" + whitespace + \"*name\" + whitespace + \"*=\" +\n\t\t\t\t\twhitespace + \"*(?:''|\\\"\\\")\" );\n\t\t\t}\n\n\t\t\t// Webkit/Opera - :checked should return selected option elements\n\t\t\t// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\t// IE8 throws error here and will not see later tests\n\t\t\tif ( !el.querySelectorAll( \":checked\" ).length ) {\n\t\t\t\trbuggyQSA.push( \":checked\" );\n\t\t\t}\n\n\t\t\t// Support: Safari 8+, iOS 8+\n\t\t\t// https://bugs.webkit.org/show_bug.cgi?id=136851\n\t\t\t// In-page `selector#id sibling-combinator selector` fails\n\t\t\tif ( !el.querySelectorAll( \"a#\" + expando + \"+*\" ).length ) {\n\t\t\t\trbuggyQSA.push( \".#.+[+~]\" );\n\t\t\t}\n\n\t\t\t// Support: Firefox <=3.6 - 5 only\n\t\t\t// Old Firefox doesn't throw on a badly-escaped identifier.\n\t\t\tel.querySelectorAll( \"\\\\\\f\" );\n\t\t\trbuggyQSA.push( \"[\\\\r\\\\n\\\\f]\" );\n\t\t} );\n\n\t\tassert( function( el ) {\n\t\t\tel.innerHTML = \"<a href='' disabled='disabled'></a>\" +\n\t\t\t\t\"<select disabled='disabled'><option/></select>\";\n\n\t\t\t// Support: Windows 8 Native Apps\n\t\t\t// The type and name attributes are restricted during .innerHTML assignment\n\t\t\tvar input = document.createElement( \"input\" );\n\t\t\tinput.setAttribute( \"type\", \"hidden\" );\n\t\t\tel.appendChild( input ).setAttribute( \"name\", \"D\" );\n\n\t\t\t// Support: IE8\n\t\t\t// Enforce case-sensitivity of name attribute\n\t\t\tif ( el.querySelectorAll( \"[name=d]\" ).length ) {\n\t\t\t\trbuggyQSA.push( \"name\" + whitespace + \"*[*^$|!~]?=\" );\n\t\t\t}\n\n\t\t\t// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)\n\t\t\t// IE8 throws error here and will not see later tests\n\t\t\tif ( el.querySelectorAll( \":enabled\" ).length !== 2 ) {\n\t\t\t\trbuggyQSA.push( \":enabled\", \":disabled\" );\n\t\t\t}\n\n\t\t\t// Support: IE9-11+\n\t\t\t// IE's :disabled selector does not pick up the children of disabled fieldsets\n\t\t\tdocElem.appendChild( el ).disabled = true;\n\t\t\tif ( el.querySelectorAll( \":disabled\" ).length !== 2 ) {\n\t\t\t\trbuggyQSA.push( \":enabled\", \":disabled\" );\n\t\t\t}\n\n\t\t\t// Support: Opera 10 - 11 only\n\t\t\t// Opera 10-11 does not throw on post-comma invalid pseudos\n\t\t\tel.querySelectorAll( \"*,:x\" );\n\t\t\trbuggyQSA.push( \",.*:\" );\n\t\t} );\n\t}\n\n\tif ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches ||\n\t\tdocElem.webkitMatchesSelector ||\n\t\tdocElem.mozMatchesSelector ||\n\t\tdocElem.oMatchesSelector ||\n\t\tdocElem.msMatchesSelector ) ) ) ) {\n\n\t\tassert( function( el ) {\n\n\t\t\t// Check to see if it's possible to do matchesSelector\n\t\t\t// on a disconnected node (IE 9)\n\t\t\tsupport.disconnectedMatch = matches.call( el, \"*\" );\n\n\t\t\t// This should fail with an exception\n\t\t\t// Gecko does not error, returns false instead\n\t\t\tmatches.call( el, \"[s!='']:x\" );\n\t\t\trbuggyMatches.push( \"!=\", pseudos );\n\t\t} );\n\t}\n\n\trbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( \"|\" ) );\n\trbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( \"|\" ) );\n\n\t/* Contains\n\t---------------------------------------------------------------------- */\n\thasCompare = rnative.test( docElem.compareDocumentPosition );\n\n\t// Element contains another\n\t// Purposefully self-exclusive\n\t// As in, an element does not contain itself\n\tcontains = hasCompare || rnative.test( docElem.contains ) ?\n\t\tfunction( a, b ) {\n\t\t\tvar adown = a.nodeType === 9 ? a.documentElement : a,\n\t\t\t\tbup = b && b.parentNode;\n\t\t\treturn a === bup || !!( bup && bup.nodeType === 1 && (\n\t\t\t\tadown.contains ?\n\t\t\t\t\tadown.contains( bup ) :\n\t\t\t\t\ta.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16\n\t\t\t) );\n\t\t} :\n\t\tfunction( a, b ) {\n\t\t\tif ( b ) {\n\t\t\t\twhile ( ( b = b.parentNode ) ) {\n\t\t\t\t\tif ( b === a ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n\n\t/* Sorting\n\t---------------------------------------------------------------------- */\n\n\t// Document order sorting\n\tsortOrder = hasCompare ?\n\tfunction( a, b ) {\n\n\t\t// Flag for duplicate removal\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\t\t}\n\n\t\t// Sort on method existence if only one input has compareDocumentPosition\n\t\tvar compare = !a.compareDocumentPosition - !b.compareDocumentPosition;\n\t\tif ( compare ) {\n\t\t\treturn compare;\n\t\t}\n\n\t\t// Calculate position if both inputs belong to the same document\n\t\t// Support: IE 11+, Edge 17 - 18+\n\t\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t\t// two documents; shallow comparisons work.\n\t\t// eslint-disable-next-line eqeqeq\n\t\tcompare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ?\n\t\t\ta.compareDocumentPosition( b ) :\n\n\t\t\t// Otherwise we know they are disconnected\n\t\t\t1;\n\n\t\t// Disconnected nodes\n\t\tif ( compare & 1 ||\n\t\t\t( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) {\n\n\t\t\t// Choose the first element that is related to our preferred document\n\t\t\t// Support: IE 11+, Edge 17 - 18+\n\t\t\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t\t\t// two documents; shallow comparisons work.\n\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\tif ( a == document || a.ownerDocument == preferredDoc &&\n\t\t\t\tcontains( preferredDoc, a ) ) {\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\t// Support: IE 11+, Edge 17 - 18+\n\t\t\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t\t\t// two documents; shallow comparisons work.\n\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\tif ( b == document || b.ownerDocument == preferredDoc &&\n\t\t\t\tcontains( preferredDoc, b ) ) {\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\t// Maintain original order\n\t\t\treturn sortInput ?\n\t\t\t\t( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :\n\t\t\t\t0;\n\t\t}\n\n\t\treturn compare & 4 ? -1 : 1;\n\t} :\n\tfunction( a, b ) {\n\n\t\t// Exit early if the nodes are identical\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\t\t}\n\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\taup = a.parentNode,\n\t\t\tbup = b.parentNode,\n\t\t\tap = [ a ],\n\t\t\tbp = [ b ];\n\n\t\t// Parentless nodes are either documents or disconnected\n\t\tif ( !aup || !bup ) {\n\n\t\t\t// Support: IE 11+, Edge 17 - 18+\n\t\t\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t\t\t// two documents; shallow comparisons work.\n\t\t\t/* eslint-disable eqeqeq */\n\t\t\treturn a == document ? -1 :\n\t\t\t\tb == document ? 1 :\n\t\t\t\t/* eslint-enable eqeqeq */\n\t\t\t\taup ? -1 :\n\t\t\t\tbup ? 1 :\n\t\t\t\tsortInput ?\n\t\t\t\t( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :\n\t\t\t\t0;\n\n\t\t// If the nodes are siblings, we can do a quick check\n\t\t} else if ( aup === bup ) {\n\t\t\treturn siblingCheck( a, b );\n\t\t}\n\n\t\t// Otherwise we need full lists of their ancestors for comparison\n\t\tcur = a;\n\t\twhile ( ( cur = cur.parentNode ) ) {\n\t\t\tap.unshift( cur );\n\t\t}\n\t\tcur = b;\n\t\twhile ( ( cur = cur.parentNode ) ) {\n\t\t\tbp.unshift( cur );\n\t\t}\n\n\t\t// Walk down the tree looking for a discrepancy\n\t\twhile ( ap[ i ] === bp[ i ] ) {\n\t\t\ti++;\n\t\t}\n\n\t\treturn i ?\n\n\t\t\t// Do a sibling check if the nodes have a common ancestor\n\t\t\tsiblingCheck( ap[ i ], bp[ i ] ) :\n\n\t\t\t// Otherwise nodes in our document sort first\n\t\t\t// Support: IE 11+, Edge 17 - 18+\n\t\t\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t\t\t// two documents; shallow comparisons work.\n\t\t\t/* eslint-disable eqeqeq */\n\t\t\tap[ i ] == preferredDoc ? -1 :\n\t\t\tbp[ i ] == preferredDoc ? 1 :\n\t\t\t/* eslint-enable eqeqeq */\n\t\t\t0;\n\t};\n\n\treturn document;\n};\n\nSizzle.matches = function( expr, elements ) {\n\treturn Sizzle( expr, null, null, elements );\n};\n\nSizzle.matchesSelector = function( elem, expr ) {\n\tsetDocument( elem );\n\n\tif ( support.matchesSelector && documentIsHTML &&\n\t\t!nonnativeSelectorCache[ expr + \" \" ] &&\n\t\t( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&\n\t\t( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {\n\n\t\ttry {\n\t\t\tvar ret = matches.call( elem, expr );\n\n\t\t\t// IE 9's matchesSelector returns false on disconnected nodes\n\t\t\tif ( ret || support.disconnectedMatch ||\n\n\t\t\t\t// As well, disconnected nodes are said to be in a document\n\t\t\t\t// fragment in IE 9\n\t\t\t\telem.document && elem.document.nodeType !== 11 ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\t\t} catch ( e ) {\n\t\t\tnonnativeSelectorCache( expr, true );\n\t\t}\n\t}\n\n\treturn Sizzle( expr, document, null, [ elem ] ).length > 0;\n};\n\nSizzle.contains = function( context, elem ) {\n\n\t// Set document vars if needed\n\t// Support: IE 11+, Edge 17 - 18+\n\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t// two documents; shallow comparisons work.\n\t// eslint-disable-next-line eqeqeq\n\tif ( ( context.ownerDocument || context ) != document ) {\n\t\tsetDocument( context );\n\t}\n\treturn contains( context, elem );\n};\n\nSizzle.attr = function( elem, name ) {\n\n\t// Set document vars if needed\n\t// Support: IE 11+, Edge 17 - 18+\n\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t// two documents; shallow comparisons work.\n\t// eslint-disable-next-line eqeqeq\n\tif ( ( elem.ownerDocument || elem ) != document ) {\n\t\tsetDocument( elem );\n\t}\n\n\tvar fn = Expr.attrHandle[ name.toLowerCase() ],\n\n\t\t// Don't get fooled by Object.prototype properties (jQuery #13807)\n\t\tval = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?\n\t\t\tfn( elem, name, !documentIsHTML ) :\n\t\t\tundefined;\n\n\treturn val !== undefined ?\n\t\tval :\n\t\tsupport.attributes || !documentIsHTML ?\n\t\t\telem.getAttribute( name ) :\n\t\t\t( val = elem.getAttributeNode( name ) ) && val.specified ?\n\t\t\t\tval.value :\n\t\t\t\tnull;\n};\n\nSizzle.escape = function( sel ) {\n\treturn ( sel + \"\" ).replace( rcssescape, fcssescape );\n};\n\nSizzle.error = function( msg ) {\n\tthrow new Error( \"Syntax error, unrecognized expression: \" + msg );\n};\n\n/**\n * Document sorting and removing duplicates\n * @param {ArrayLike} results\n */\nSizzle.uniqueSort = function( results ) {\n\tvar elem,\n\t\tduplicates = [],\n\t\tj = 0,\n\t\ti = 0;\n\n\t// Unless we *know* we can detect duplicates, assume their presence\n\thasDuplicate = !support.detectDuplicates;\n\tsortInput = !support.sortStable && results.slice( 0 );\n\tresults.sort( sortOrder );\n\n\tif ( hasDuplicate ) {\n\t\twhile ( ( elem = results[ i++ ] ) ) {\n\t\t\tif ( elem === results[ i ] ) {\n\t\t\t\tj = duplicates.push( i );\n\t\t\t}\n\t\t}\n\t\twhile ( j-- ) {\n\t\t\tresults.splice( duplicates[ j ], 1 );\n\t\t}\n\t}\n\n\t// Clear input after sorting to release objects\n\t// See https://github.com/jquery/sizzle/pull/225\n\tsortInput = null;\n\n\treturn results;\n};\n\n/**\n * Utility function for retrieving the text value of an array of DOM nodes\n * @param {Array|Element} elem\n */\ngetText = Sizzle.getText = function( elem ) {\n\tvar node,\n\t\tret = \"\",\n\t\ti = 0,\n\t\tnodeType = elem.nodeType;\n\n\tif ( !nodeType ) {\n\n\t\t// If no nodeType, this is expected to be an array\n\t\twhile ( ( node = elem[ i++ ] ) ) {\n\n\t\t\t// Do not traverse comment nodes\n\t\t\tret += getText( node );\n\t\t}\n\t} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {\n\n\t\t// Use textContent for elements\n\t\t// innerText usage removed for consistency of new lines (jQuery #11153)\n\t\tif ( typeof elem.textContent === \"string\" ) {\n\t\t\treturn elem.textContent;\n\t\t} else {\n\n\t\t\t// Traverse its children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tret += getText( elem );\n\t\t\t}\n\t\t}\n\t} else if ( nodeType === 3 || nodeType === 4 ) {\n\t\treturn elem.nodeValue;\n\t}\n\n\t// Do not include comment or processing instruction nodes\n\n\treturn ret;\n};\n\nExpr = Sizzle.selectors = {\n\n\t// Can be adjusted by the user\n\tcacheLength: 50,\n\n\tcreatePseudo: markFunction,\n\n\tmatch: matchExpr,\n\n\tattrHandle: {},\n\n\tfind: {},\n\n\trelative: {\n\t\t\">\": { dir: \"parentNode\", first: true },\n\t\t\" \": { dir: \"parentNode\" },\n\t\t\"+\": { dir: \"previousSibling\", first: true },\n\t\t\"~\": { dir: \"previousSibling\" }\n\t},\n\n\tpreFilter: {\n\t\t\"ATTR\": function( match ) {\n\t\t\tmatch[ 1 ] = match[ 1 ].replace( runescape, funescape );\n\n\t\t\t// Move the given value to match[3] whether quoted or unquoted\n\t\t\tmatch[ 3 ] = ( match[ 3 ] || match[ 4 ] ||\n\t\t\t\tmatch[ 5 ] || \"\" ).replace( runescape, funescape );\n\n\t\t\tif ( match[ 2 ] === \"~=\" ) {\n\t\t\t\tmatch[ 3 ] = \" \" + match[ 3 ] + \" \";\n\t\t\t}\n\n\t\t\treturn match.slice( 0, 4 );\n\t\t},\n\n\t\t\"CHILD\": function( match ) {\n\n\t\t\t/* matches from matchExpr[\"CHILD\"]\n\t\t\t\t1 type (only|nth|...)\n\t\t\t\t2 what (child|of-type)\n\t\t\t\t3 argument (even|odd|\\d*|\\d*n([+-]\\d+)?|...)\n\t\t\t\t4 xn-component of xn+y argument ([+-]?\\d*n|)\n\t\t\t\t5 sign of xn-component\n\t\t\t\t6 x of xn-component\n\t\t\t\t7 sign of y-component\n\t\t\t\t8 y of y-component\n\t\t\t*/\n\t\t\tmatch[ 1 ] = match[ 1 ].toLowerCase();\n\n\t\t\tif ( match[ 1 ].slice( 0, 3 ) === \"nth\" ) {\n\n\t\t\t\t// nth-* requires argument\n\t\t\t\tif ( !match[ 3 ] ) {\n\t\t\t\t\tSizzle.error( match[ 0 ] );\n\t\t\t\t}\n\n\t\t\t\t// numeric x and y parameters for Expr.filter.CHILD\n\t\t\t\t// remember that false/true cast respectively to 0/1\n\t\t\t\tmatch[ 4 ] = +( match[ 4 ] ?\n\t\t\t\t\tmatch[ 5 ] + ( match[ 6 ] || 1 ) :\n\t\t\t\t\t2 * ( match[ 3 ] === \"even\" || match[ 3 ] === \"odd\" ) );\n\t\t\t\tmatch[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === \"odd\" );\n\n\t\t\t\t// other types prohibit arguments\n\t\t\t} else if ( match[ 3 ] ) {\n\t\t\t\tSizzle.error( match[ 0 ] );\n\t\t\t}\n\n\t\t\treturn match;\n\t\t},\n\n\t\t\"PSEUDO\": function( match ) {\n\t\t\tvar excess,\n\t\t\t\tunquoted = !match[ 6 ] && match[ 2 ];\n\n\t\t\tif ( matchExpr[ \"CHILD\" ].test( match[ 0 ] ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// Accept quoted arguments as-is\n\t\t\tif ( match[ 3 ] ) {\n\t\t\t\tmatch[ 2 ] = match[ 4 ] || match[ 5 ] || \"\";\n\n\t\t\t// Strip excess characters from unquoted arguments\n\t\t\t} else if ( unquoted && rpseudo.test( unquoted ) &&\n\n\t\t\t\t// Get excess from tokenize (recursively)\n\t\t\t\t( excess = tokenize( unquoted, true ) ) &&\n\n\t\t\t\t// advance to the next closing parenthesis\n\t\t\t\t( excess = unquoted.indexOf( \")\", unquoted.length - excess ) - unquoted.length ) ) {\n\n\t\t\t\t// excess is a negative index\n\t\t\t\tmatch[ 0 ] = match[ 0 ].slice( 0, excess );\n\t\t\t\tmatch[ 2 ] = unquoted.slice( 0, excess );\n\t\t\t}\n\n\t\t\t// Return only captures needed by the pseudo filter method (type and argument)\n\t\t\treturn match.slice( 0, 3 );\n\t\t}\n\t},\n\n\tfilter: {\n\n\t\t\"TAG\": function( nodeNameSelector ) {\n\t\t\tvar nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();\n\t\t\treturn nodeNameSelector === \"*\" ?\n\t\t\t\tfunction() {\n\t\t\t\t\treturn true;\n\t\t\t\t} :\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn elem.nodeName && elem.nodeName.toLowerCase() === nodeName;\n\t\t\t\t};\n\t\t},\n\n\t\t\"CLASS\": function( className ) {\n\t\t\tvar pattern = classCache[ className + \" \" ];\n\n\t\t\treturn pattern ||\n\t\t\t\t( pattern = new RegExp( \"(^|\" + whitespace +\n\t\t\t\t\t\")\" + className + \"(\" + whitespace + \"|$)\" ) ) && classCache(\n\t\t\t\t\t\tclassName, function( elem ) {\n\t\t\t\t\t\t\treturn pattern.test(\n\t\t\t\t\t\t\t\ttypeof elem.className === \"string\" && elem.className ||\n\t\t\t\t\t\t\t\ttypeof elem.getAttribute !== \"undefined\" &&\n\t\t\t\t\t\t\t\t\telem.getAttribute( \"class\" ) ||\n\t\t\t\t\t\t\t\t\"\"\n\t\t\t\t\t\t\t);\n\t\t\t\t} );\n\t\t},\n\n\t\t\"ATTR\": function( name, operator, check ) {\n\t\t\treturn function( elem ) {\n\t\t\t\tvar result = Sizzle.attr( elem, name );\n\n\t\t\t\tif ( result == null ) {\n\t\t\t\t\treturn operator === \"!=\";\n\t\t\t\t}\n\t\t\t\tif ( !operator ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tresult += \"\";\n\n\t\t\t\t/* eslint-disable max-len */\n\n\t\t\t\treturn operator === \"=\" ? result === check :\n\t\t\t\t\toperator === \"!=\" ? result !== check :\n\t\t\t\t\toperator === \"^=\" ? check && result.indexOf( check ) === 0 :\n\t\t\t\t\toperator === \"*=\" ? check && result.indexOf( check ) > -1 :\n\t\t\t\t\toperator === \"$=\" ? check && result.slice( -check.length ) === check :\n\t\t\t\t\toperator === \"~=\" ? ( \" \" + result.replace( rwhitespace, \" \" ) + \" \" ).indexOf( check ) > -1 :\n\t\t\t\t\toperator === \"|=\" ? result === check || result.slice( 0, check.length + 1 ) === check + \"-\" :\n\t\t\t\t\tfalse;\n\t\t\t\t/* eslint-enable max-len */\n\n\t\t\t};\n\t\t},\n\n\t\t\"CHILD\": function( type, what, _argument, first, last ) {\n\t\t\tvar simple = type.slice( 0, 3 ) !== \"nth\",\n\t\t\t\tforward = type.slice( -4 ) !== \"last\",\n\t\t\t\tofType = what === \"of-type\";\n\n\t\t\treturn first === 1 && last === 0 ?\n\n\t\t\t\t// Shortcut for :nth-*(n)\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn !!elem.parentNode;\n\t\t\t\t} :\n\n\t\t\t\tfunction( elem, _context, xml ) {\n\t\t\t\t\tvar cache, uniqueCache, outerCache, node, nodeIndex, start,\n\t\t\t\t\t\tdir = simple !== forward ? \"nextSibling\" : \"previousSibling\",\n\t\t\t\t\t\tparent = elem.parentNode,\n\t\t\t\t\t\tname = ofType && elem.nodeName.toLowerCase(),\n\t\t\t\t\t\tuseCache = !xml && !ofType,\n\t\t\t\t\t\tdiff = false;\n\n\t\t\t\t\tif ( parent ) {\n\n\t\t\t\t\t\t// :(first|last|only)-(child|of-type)\n\t\t\t\t\t\tif ( simple ) {\n\t\t\t\t\t\t\twhile ( dir ) {\n\t\t\t\t\t\t\t\tnode = elem;\n\t\t\t\t\t\t\t\twhile ( ( node = node[ dir ] ) ) {\n\t\t\t\t\t\t\t\t\tif ( ofType ?\n\t\t\t\t\t\t\t\t\t\tnode.nodeName.toLowerCase() === name :\n\t\t\t\t\t\t\t\t\t\tnode.nodeType === 1 ) {\n\n\t\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Reverse direction for :only-* (if we haven't yet done so)\n\t\t\t\t\t\t\t\tstart = dir = type === \"only\" && !start && \"nextSibling\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tstart = [ forward ? parent.firstChild : parent.lastChild ];\n\n\t\t\t\t\t\t// non-xml :nth-child(...) stores cache data on `parent`\n\t\t\t\t\t\tif ( forward && useCache ) {\n\n\t\t\t\t\t\t\t// Seek `elem` from a previously-cached index\n\n\t\t\t\t\t\t\t// ...in a gzip-friendly way\n\t\t\t\t\t\t\tnode = parent;\n\t\t\t\t\t\t\touterCache = node[ expando ] || ( node[ expando ] = {} );\n\n\t\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\t\tuniqueCache = outerCache[ node.uniqueID ] ||\n\t\t\t\t\t\t\t\t( outerCache[ node.uniqueID ] = {} );\n\n\t\t\t\t\t\t\tcache = uniqueCache[ type ] || [];\n\t\t\t\t\t\t\tnodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];\n\t\t\t\t\t\t\tdiff = nodeIndex && cache[ 2 ];\n\t\t\t\t\t\t\tnode = nodeIndex && parent.childNodes[ nodeIndex ];\n\n\t\t\t\t\t\t\twhile ( ( node = ++nodeIndex && node && node[ dir ] ||\n\n\t\t\t\t\t\t\t\t// Fallback to seeking `elem` from the start\n\t\t\t\t\t\t\t\t( diff = nodeIndex = 0 ) || start.pop() ) ) {\n\n\t\t\t\t\t\t\t\t// When found, cache indexes on `parent` and break\n\t\t\t\t\t\t\t\tif ( node.nodeType === 1 && ++diff && node === elem ) {\n\t\t\t\t\t\t\t\t\tuniqueCache[ type ] = [ dirruns, nodeIndex, diff ];\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// Use previously-cached element index if available\n\t\t\t\t\t\t\tif ( useCache ) {\n\n\t\t\t\t\t\t\t\t// ...in a gzip-friendly way\n\t\t\t\t\t\t\t\tnode = elem;\n\t\t\t\t\t\t\t\touterCache = node[ expando ] || ( node[ expando ] = {} );\n\n\t\t\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\t\t\tuniqueCache = outerCache[ node.uniqueID ] ||\n\t\t\t\t\t\t\t\t\t( outerCache[ node.uniqueID ] = {} );\n\n\t\t\t\t\t\t\t\tcache = uniqueCache[ type ] || [];\n\t\t\t\t\t\t\t\tnodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];\n\t\t\t\t\t\t\t\tdiff = nodeIndex;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// xml :nth-child(...)\n\t\t\t\t\t\t\t// or :nth-last-child(...) or :nth(-last)?-of-type(...)\n\t\t\t\t\t\t\tif ( diff === false ) {\n\n\t\t\t\t\t\t\t\t// Use the same loop as above to seek `elem` from the start\n\t\t\t\t\t\t\t\twhile ( ( node = ++nodeIndex && node && node[ dir ] ||\n\t\t\t\t\t\t\t\t\t( diff = nodeIndex = 0 ) || start.pop() ) ) {\n\n\t\t\t\t\t\t\t\t\tif ( ( ofType ?\n\t\t\t\t\t\t\t\t\t\tnode.nodeName.toLowerCase() === name :\n\t\t\t\t\t\t\t\t\t\tnode.nodeType === 1 ) &&\n\t\t\t\t\t\t\t\t\t\t++diff ) {\n\n\t\t\t\t\t\t\t\t\t\t// Cache the index of each encountered element\n\t\t\t\t\t\t\t\t\t\tif ( useCache ) {\n\t\t\t\t\t\t\t\t\t\t\touterCache = node[ expando ] ||\n\t\t\t\t\t\t\t\t\t\t\t\t( node[ expando ] = {} );\n\n\t\t\t\t\t\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\t\t\t\t\t\tuniqueCache = outerCache[ node.uniqueID ] ||\n\t\t\t\t\t\t\t\t\t\t\t\t( outerCache[ node.uniqueID ] = {} );\n\n\t\t\t\t\t\t\t\t\t\t\tuniqueCache[ type ] = [ dirruns, diff ];\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tif ( node === elem ) {\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Incorporate the offset, then check against cycle size\n\t\t\t\t\t\tdiff -= last;\n\t\t\t\t\t\treturn diff === first || ( diff % first === 0 && diff / first >= 0 );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t},\n\n\t\t\"PSEUDO\": function( pseudo, argument ) {\n\n\t\t\t// pseudo-class names are case-insensitive\n\t\t\t// http://www.w3.org/TR/selectors/#pseudo-classes\n\t\t\t// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters\n\t\t\t// Remember that setFilters inherits from pseudos\n\t\t\tvar args,\n\t\t\t\tfn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||\n\t\t\t\t\tSizzle.error( \"unsupported pseudo: \" + pseudo );\n\n\t\t\t// The user may use createPseudo to indicate that\n\t\t\t// arguments are needed to create the filter function\n\t\t\t// just as Sizzle does\n\t\t\tif ( fn[ expando ] ) {\n\t\t\t\treturn fn( argument );\n\t\t\t}\n\n\t\t\t// But maintain support for old signatures\n\t\t\tif ( fn.length > 1 ) {\n\t\t\t\targs = [ pseudo, pseudo, \"\", argument ];\n\t\t\t\treturn Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?\n\t\t\t\t\tmarkFunction( function( seed, matches ) {\n\t\t\t\t\t\tvar idx,\n\t\t\t\t\t\t\tmatched = fn( seed, argument ),\n\t\t\t\t\t\t\ti = matched.length;\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tidx = indexOf( seed, matched[ i ] );\n\t\t\t\t\t\t\tseed[ idx ] = !( matches[ idx ] = matched[ i ] );\n\t\t\t\t\t\t}\n\t\t\t\t\t} ) :\n\t\t\t\t\tfunction( elem ) {\n\t\t\t\t\t\treturn fn( elem, 0, args );\n\t\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn fn;\n\t\t}\n\t},\n\n\tpseudos: {\n\n\t\t// Potentially complex pseudos\n\t\t\"not\": markFunction( function( selector ) {\n\n\t\t\t// Trim the selector passed to compile\n\t\t\t// to avoid treating leading and trailing\n\t\t\t// spaces as combinators\n\t\t\tvar input = [],\n\t\t\t\tresults = [],\n\t\t\t\tmatcher = compile( selector.replace( rtrim, \"$1\" ) );\n\n\t\t\treturn matcher[ expando ] ?\n\t\t\t\tmarkFunction( function( seed, matches, _context, xml ) {\n\t\t\t\t\tvar elem,\n\t\t\t\t\t\tunmatched = matcher( seed, null, xml, [] ),\n\t\t\t\t\t\ti = seed.length;\n\n\t\t\t\t\t// Match elements unmatched by `matcher`\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( ( elem = unmatched[ i ] ) ) {\n\t\t\t\t\t\t\tseed[ i ] = !( matches[ i ] = elem );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} ) :\n\t\t\t\tfunction( elem, _context, xml ) {\n\t\t\t\t\tinput[ 0 ] = elem;\n\t\t\t\t\tmatcher( input, null, xml, results );\n\n\t\t\t\t\t// Don't keep the element (issue #299)\n\t\t\t\t\tinput[ 0 ] = null;\n\t\t\t\t\treturn !results.pop();\n\t\t\t\t};\n\t\t} ),\n\n\t\t\"has\": markFunction( function( selector ) {\n\t\t\treturn function( elem ) {\n\t\t\t\treturn Sizzle( selector, elem ).length > 0;\n\t\t\t};\n\t\t} ),\n\n\t\t\"contains\": markFunction( function( text ) {\n\t\t\ttext = text.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn ( elem.textContent || getText( elem ) ).indexOf( text ) > -1;\n\t\t\t};\n\t\t} ),\n\n\t\t// \"Whether an element is represented by a :lang() selector\n\t\t// is based solely on the element's language value\n\t\t// being equal to the identifier C,\n\t\t// or beginning with the identifier C immediately followed by \"-\".\n\t\t// The matching of C against the element's language value is performed case-insensitively.\n\t\t// The identifier C does not have to be a valid language name.\"\n\t\t// http://www.w3.org/TR/selectors/#lang-pseudo\n\t\t\"lang\": markFunction( function( lang ) {\n\n\t\t\t// lang value must be a valid identifier\n\t\t\tif ( !ridentifier.test( lang || \"\" ) ) {\n\t\t\t\tSizzle.error( \"unsupported lang: \" + lang );\n\t\t\t}\n\t\t\tlang = lang.replace( runescape, funescape ).toLowerCase();\n\t\t\treturn function( elem ) {\n\t\t\t\tvar elemLang;\n\t\t\t\tdo {\n\t\t\t\t\tif ( ( elemLang = documentIsHTML ?\n\t\t\t\t\t\telem.lang :\n\t\t\t\t\t\telem.getAttribute( \"xml:lang\" ) || elem.getAttribute( \"lang\" ) ) ) {\n\n\t\t\t\t\t\telemLang = elemLang.toLowerCase();\n\t\t\t\t\t\treturn elemLang === lang || elemLang.indexOf( lang + \"-\" ) === 0;\n\t\t\t\t\t}\n\t\t\t\t} while ( ( elem = elem.parentNode ) && elem.nodeType === 1 );\n\t\t\t\treturn false;\n\t\t\t};\n\t\t} ),\n\n\t\t// Miscellaneous\n\t\t\"target\": function( elem ) {\n\t\t\tvar hash = window.location && window.location.hash;\n\t\t\treturn hash && hash.slice( 1 ) === elem.id;\n\t\t},\n\n\t\t\"root\": function( elem ) {\n\t\t\treturn elem === docElem;\n\t\t},\n\n\t\t\"focus\": function( elem ) {\n\t\t\treturn elem === document.activeElement &&\n\t\t\t\t( !document.hasFocus || document.hasFocus() ) &&\n\t\t\t\t!!( elem.type || elem.href || ~elem.tabIndex );\n\t\t},\n\n\t\t// Boolean properties\n\t\t\"enabled\": createDisabledPseudo( false ),\n\t\t\"disabled\": createDisabledPseudo( true ),\n\n\t\t\"checked\": function( elem ) {\n\n\t\t\t// In CSS3, :checked should return both checked and selected elements\n\t\t\t// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\tvar nodeName = elem.nodeName.toLowerCase();\n\t\t\treturn ( nodeName === \"input\" && !!elem.checked ) ||\n\t\t\t\t( nodeName === \"option\" && !!elem.selected );\n\t\t},\n\n\t\t\"selected\": function( elem ) {\n\n\t\t\t// Accessing this property makes selected-by-default\n\t\t\t// options in Safari work properly\n\t\t\tif ( elem.parentNode ) {\n\t\t\t\t// eslint-disable-next-line no-unused-expressions\n\t\t\t\telem.parentNode.selectedIndex;\n\t\t\t}\n\n\t\t\treturn elem.selected === true;\n\t\t},\n\n\t\t// Contents\n\t\t\"empty\": function( elem ) {\n\n\t\t\t// http://www.w3.org/TR/selectors/#empty-pseudo\n\t\t\t// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),\n\t\t\t//   but not by others (comment: 8; processing instruction: 7; etc.)\n\t\t\t// nodeType < 6 works because attributes (2) do not appear as children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tif ( elem.nodeType < 6 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\n\t\t\"parent\": function( elem ) {\n\t\t\treturn !Expr.pseudos[ \"empty\" ]( elem );\n\t\t},\n\n\t\t// Element/input types\n\t\t\"header\": function( elem ) {\n\t\t\treturn rheader.test( elem.nodeName );\n\t\t},\n\n\t\t\"input\": function( elem ) {\n\t\t\treturn rinputs.test( elem.nodeName );\n\t\t},\n\n\t\t\"button\": function( elem ) {\n\t\t\tvar name = elem.nodeName.toLowerCase();\n\t\t\treturn name === \"input\" && elem.type === \"button\" || name === \"button\";\n\t\t},\n\n\t\t\"text\": function( elem ) {\n\t\t\tvar attr;\n\t\t\treturn elem.nodeName.toLowerCase() === \"input\" &&\n\t\t\t\telem.type === \"text\" &&\n\n\t\t\t\t// Support: IE<8\n\t\t\t\t// New HTML5 attribute values (e.g., \"search\") appear with elem.type === \"text\"\n\t\t\t\t( ( attr = elem.getAttribute( \"type\" ) ) == null ||\n\t\t\t\t\tattr.toLowerCase() === \"text\" );\n\t\t},\n\n\t\t// Position-in-collection\n\t\t\"first\": createPositionalPseudo( function() {\n\t\t\treturn [ 0 ];\n\t\t} ),\n\n\t\t\"last\": createPositionalPseudo( function( _matchIndexes, length ) {\n\t\t\treturn [ length - 1 ];\n\t\t} ),\n\n\t\t\"eq\": createPositionalPseudo( function( _matchIndexes, length, argument ) {\n\t\t\treturn [ argument < 0 ? argument + length : argument ];\n\t\t} ),\n\n\t\t\"even\": createPositionalPseudo( function( matchIndexes, length ) {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t} ),\n\n\t\t\"odd\": createPositionalPseudo( function( matchIndexes, length ) {\n\t\t\tvar i = 1;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t} ),\n\n\t\t\"lt\": createPositionalPseudo( function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ?\n\t\t\t\targument + length :\n\t\t\t\targument > length ?\n\t\t\t\t\tlength :\n\t\t\t\t\targument;\n\t\t\tfor ( ; --i >= 0; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t} ),\n\n\t\t\"gt\": createPositionalPseudo( function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ? argument + length : argument;\n\t\t\tfor ( ; ++i < length; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t} )\n\t}\n};\n\nExpr.pseudos[ \"nth\" ] = Expr.pseudos[ \"eq\" ];\n\n// Add button/input type pseudos\nfor ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {\n\tExpr.pseudos[ i ] = createInputPseudo( i );\n}\nfor ( i in { submit: true, reset: true } ) {\n\tExpr.pseudos[ i ] = createButtonPseudo( i );\n}\n\n// Easy API for creating new setFilters\nfunction setFilters() {}\nsetFilters.prototype = Expr.filters = Expr.pseudos;\nExpr.setFilters = new setFilters();\n\ntokenize = Sizzle.tokenize = function( selector, parseOnly ) {\n\tvar matched, match, tokens, type,\n\t\tsoFar, groups, preFilters,\n\t\tcached = tokenCache[ selector + \" \" ];\n\n\tif ( cached ) {\n\t\treturn parseOnly ? 0 : cached.slice( 0 );\n\t}\n\n\tsoFar = selector;\n\tgroups = [];\n\tpreFilters = Expr.preFilter;\n\n\twhile ( soFar ) {\n\n\t\t// Comma and first run\n\t\tif ( !matched || ( match = rcomma.exec( soFar ) ) ) {\n\t\t\tif ( match ) {\n\n\t\t\t\t// Don't consume trailing commas as valid\n\t\t\t\tsoFar = soFar.slice( match[ 0 ].length ) || soFar;\n\t\t\t}\n\t\t\tgroups.push( ( tokens = [] ) );\n\t\t}\n\n\t\tmatched = false;\n\n\t\t// Combinators\n\t\tif ( ( match = rcombinators.exec( soFar ) ) ) {\n\t\t\tmatched = match.shift();\n\t\t\ttokens.push( {\n\t\t\t\tvalue: matched,\n\n\t\t\t\t// Cast descendant combinators to space\n\t\t\t\ttype: match[ 0 ].replace( rtrim, \" \" )\n\t\t\t} );\n\t\t\tsoFar = soFar.slice( matched.length );\n\t\t}\n\n\t\t// Filters\n\t\tfor ( type in Expr.filter ) {\n\t\t\tif ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] ||\n\t\t\t\t( match = preFilters[ type ]( match ) ) ) ) {\n\t\t\t\tmatched = match.shift();\n\t\t\t\ttokens.push( {\n\t\t\t\t\tvalue: matched,\n\t\t\t\t\ttype: type,\n\t\t\t\t\tmatches: match\n\t\t\t\t} );\n\t\t\t\tsoFar = soFar.slice( matched.length );\n\t\t\t}\n\t\t}\n\n\t\tif ( !matched ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Return the length of the invalid excess\n\t// if we're just parsing\n\t// Otherwise, throw an error or return tokens\n\treturn parseOnly ?\n\t\tsoFar.length :\n\t\tsoFar ?\n\t\t\tSizzle.error( selector ) :\n\n\t\t\t// Cache the tokens\n\t\t\ttokenCache( selector, groups ).slice( 0 );\n};\n\nfunction toSelector( tokens ) {\n\tvar i = 0,\n\t\tlen = tokens.length,\n\t\tselector = \"\";\n\tfor ( ; i < len; i++ ) {\n\t\tselector += tokens[ i ].value;\n\t}\n\treturn selector;\n}\n\nfunction addCombinator( matcher, combinator, base ) {\n\tvar dir = combinator.dir,\n\t\tskip = combinator.next,\n\t\tkey = skip || dir,\n\t\tcheckNonElements = base && key === \"parentNode\",\n\t\tdoneName = done++;\n\n\treturn combinator.first ?\n\n\t\t// Check against closest ancestor/preceding element\n\t\tfunction( elem, context, xml ) {\n\t\t\twhile ( ( elem = elem[ dir ] ) ) {\n\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\treturn matcher( elem, context, xml );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t} :\n\n\t\t// Check against all ancestor/preceding elements\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar oldCache, uniqueCache, outerCache,\n\t\t\t\tnewCache = [ dirruns, doneName ];\n\n\t\t\t// We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching\n\t\t\tif ( xml ) {\n\t\t\t\twhile ( ( elem = elem[ dir ] ) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\tif ( matcher( elem, context, xml ) ) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twhile ( ( elem = elem[ dir ] ) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\touterCache = elem[ expando ] || ( elem[ expando ] = {} );\n\n\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\tuniqueCache = outerCache[ elem.uniqueID ] ||\n\t\t\t\t\t\t\t( outerCache[ elem.uniqueID ] = {} );\n\n\t\t\t\t\t\tif ( skip && skip === elem.nodeName.toLowerCase() ) {\n\t\t\t\t\t\t\telem = elem[ dir ] || elem;\n\t\t\t\t\t\t} else if ( ( oldCache = uniqueCache[ key ] ) &&\n\t\t\t\t\t\t\toldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {\n\n\t\t\t\t\t\t\t// Assign to newCache so results back-propagate to previous elements\n\t\t\t\t\t\t\treturn ( newCache[ 2 ] = oldCache[ 2 ] );\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// Reuse newcache so results back-propagate to previous elements\n\t\t\t\t\t\t\tuniqueCache[ key ] = newCache;\n\n\t\t\t\t\t\t\t// A match means we're done; a fail means we have to keep checking\n\t\t\t\t\t\t\tif ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) {\n\t\t\t\t\t\t\t\treturn true;\n\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\treturn false;\n\t\t};\n}\n\nfunction elementMatcher( matchers ) {\n\treturn matchers.length > 1 ?\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar i = matchers.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( !matchers[ i ]( elem, context, xml ) ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t} :\n\t\tmatchers[ 0 ];\n}\n\nfunction multipleContexts( selector, contexts, results ) {\n\tvar i = 0,\n\t\tlen = contexts.length;\n\tfor ( ; i < len; i++ ) {\n\t\tSizzle( selector, contexts[ i ], results );\n\t}\n\treturn results;\n}\n\nfunction condense( unmatched, map, filter, context, xml ) {\n\tvar elem,\n\t\tnewUnmatched = [],\n\t\ti = 0,\n\t\tlen = unmatched.length,\n\t\tmapped = map != null;\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( ( elem = unmatched[ i ] ) ) {\n\t\t\tif ( !filter || filter( elem, context, xml ) ) {\n\t\t\t\tnewUnmatched.push( elem );\n\t\t\t\tif ( mapped ) {\n\t\t\t\t\tmap.push( i );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn newUnmatched;\n}\n\nfunction setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {\n\tif ( postFilter && !postFilter[ expando ] ) {\n\t\tpostFilter = setMatcher( postFilter );\n\t}\n\tif ( postFinder && !postFinder[ expando ] ) {\n\t\tpostFinder = setMatcher( postFinder, postSelector );\n\t}\n\treturn markFunction( function( seed, results, context, xml ) {\n\t\tvar temp, i, elem,\n\t\t\tpreMap = [],\n\t\t\tpostMap = [],\n\t\t\tpreexisting = results.length,\n\n\t\t\t// Get initial elements from seed or context\n\t\t\telems = seed || multipleContexts(\n\t\t\t\tselector || \"*\",\n\t\t\t\tcontext.nodeType ? [ context ] : context,\n\t\t\t\t[]\n\t\t\t),\n\n\t\t\t// Prefilter to get matcher input, preserving a map for seed-results synchronization\n\t\t\tmatcherIn = preFilter && ( seed || !selector ) ?\n\t\t\t\tcondense( elems, preMap, preFilter, context, xml ) :\n\t\t\t\telems,\n\n\t\t\tmatcherOut = matcher ?\n\n\t\t\t\t// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,\n\t\t\t\tpostFinder || ( seed ? preFilter : preexisting || postFilter ) ?\n\n\t\t\t\t\t// ...intermediate processing is necessary\n\t\t\t\t\t[] :\n\n\t\t\t\t\t// ...otherwise use results directly\n\t\t\t\t\tresults :\n\t\t\t\tmatcherIn;\n\n\t\t// Find primary matches\n\t\tif ( matcher ) {\n\t\t\tmatcher( matcherIn, matcherOut, context, xml );\n\t\t}\n\n\t\t// Apply postFilter\n\t\tif ( postFilter ) {\n\t\t\ttemp = condense( matcherOut, postMap );\n\t\t\tpostFilter( temp, [], context, xml );\n\n\t\t\t// Un-match failing elements by moving them back to matcherIn\n\t\t\ti = temp.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( ( elem = temp[ i ] ) ) {\n\t\t\t\t\tmatcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif ( seed ) {\n\t\t\tif ( postFinder || preFilter ) {\n\t\t\t\tif ( postFinder ) {\n\n\t\t\t\t\t// Get the final matcherOut by condensing this intermediate into postFinder contexts\n\t\t\t\t\ttemp = [];\n\t\t\t\t\ti = matcherOut.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( ( elem = matcherOut[ i ] ) ) {\n\n\t\t\t\t\t\t\t// Restore matcherIn since elem is not yet a final match\n\t\t\t\t\t\t\ttemp.push( ( matcherIn[ i ] = elem ) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tpostFinder( null, ( matcherOut = [] ), temp, xml );\n\t\t\t\t}\n\n\t\t\t\t// Move matched elements from seed to results to keep them synchronized\n\t\t\t\ti = matcherOut.length;\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\tif ( ( elem = matcherOut[ i ] ) &&\n\t\t\t\t\t\t( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) {\n\n\t\t\t\t\t\tseed[ temp ] = !( results[ temp ] = elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Add elements to results, through postFinder if defined\n\t\t} else {\n\t\t\tmatcherOut = condense(\n\t\t\t\tmatcherOut === results ?\n\t\t\t\t\tmatcherOut.splice( preexisting, matcherOut.length ) :\n\t\t\t\t\tmatcherOut\n\t\t\t);\n\t\t\tif ( postFinder ) {\n\t\t\t\tpostFinder( null, results, matcherOut, xml );\n\t\t\t} else {\n\t\t\t\tpush.apply( results, matcherOut );\n\t\t\t}\n\t\t}\n\t} );\n}\n\nfunction matcherFromTokens( tokens ) {\n\tvar checkContext, matcher, j,\n\t\tlen = tokens.length,\n\t\tleadingRelative = Expr.relative[ tokens[ 0 ].type ],\n\t\timplicitRelative = leadingRelative || Expr.relative[ \" \" ],\n\t\ti = leadingRelative ? 1 : 0,\n\n\t\t// The foundational matcher ensures that elements are reachable from top-level context(s)\n\t\tmatchContext = addCombinator( function( elem ) {\n\t\t\treturn elem === checkContext;\n\t\t}, implicitRelative, true ),\n\t\tmatchAnyContext = addCombinator( function( elem ) {\n\t\t\treturn indexOf( checkContext, elem ) > -1;\n\t\t}, implicitRelative, true ),\n\t\tmatchers = [ function( elem, context, xml ) {\n\t\t\tvar ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (\n\t\t\t\t( checkContext = context ).nodeType ?\n\t\t\t\t\tmatchContext( elem, context, xml ) :\n\t\t\t\t\tmatchAnyContext( elem, context, xml ) );\n\n\t\t\t// Avoid hanging onto element (issue #299)\n\t\t\tcheckContext = null;\n\t\t\treturn ret;\n\t\t} ];\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) {\n\t\t\tmatchers = [ addCombinator( elementMatcher( matchers ), matcher ) ];\n\t\t} else {\n\t\t\tmatcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches );\n\n\t\t\t// Return special upon seeing a positional matcher\n\t\t\tif ( matcher[ expando ] ) {\n\n\t\t\t\t// Find the next relative operator (if any) for proper handling\n\t\t\t\tj = ++i;\n\t\t\t\tfor ( ; j < len; j++ ) {\n\t\t\t\t\tif ( Expr.relative[ tokens[ j ].type ] ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn setMatcher(\n\t\t\t\t\ti > 1 && elementMatcher( matchers ),\n\t\t\t\t\ti > 1 && toSelector(\n\n\t\t\t\t\t// If the preceding token was a descendant combinator, insert an implicit any-element `*`\n\t\t\t\t\ttokens\n\t\t\t\t\t\t.slice( 0, i - 1 )\n\t\t\t\t\t\t.concat( { value: tokens[ i - 2 ].type === \" \" ? \"*\" : \"\" } )\n\t\t\t\t\t).replace( rtrim, \"$1\" ),\n\t\t\t\t\tmatcher,\n\t\t\t\t\ti < j && matcherFromTokens( tokens.slice( i, j ) ),\n\t\t\t\t\tj < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ),\n\t\t\t\t\tj < len && toSelector( tokens )\n\t\t\t\t);\n\t\t\t}\n\t\t\tmatchers.push( matcher );\n\t\t}\n\t}\n\n\treturn elementMatcher( matchers );\n}\n\nfunction matcherFromGroupMatchers( elementMatchers, setMatchers ) {\n\tvar bySet = setMatchers.length > 0,\n\t\tbyElement = elementMatchers.length > 0,\n\t\tsuperMatcher = function( seed, context, xml, results, outermost ) {\n\t\t\tvar elem, j, matcher,\n\t\t\t\tmatchedCount = 0,\n\t\t\t\ti = \"0\",\n\t\t\t\tunmatched = seed && [],\n\t\t\t\tsetMatched = [],\n\t\t\t\tcontextBackup = outermostContext,\n\n\t\t\t\t// We must always have either seed elements or outermost context\n\t\t\t\telems = seed || byElement && Expr.find[ \"TAG\" ]( \"*\", outermost ),\n\n\t\t\t\t// Use integer dirruns iff this is the outermost matcher\n\t\t\t\tdirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ),\n\t\t\t\tlen = elems.length;\n\n\t\t\tif ( outermost ) {\n\n\t\t\t\t// Support: IE 11+, Edge 17 - 18+\n\t\t\t\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t\t\t\t// two documents; shallow comparisons work.\n\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\toutermostContext = context == document || context || outermost;\n\t\t\t}\n\n\t\t\t// Add elements passing elementMatchers directly to results\n\t\t\t// Support: IE<9, Safari\n\t\t\t// Tolerate NodeList properties (IE: \"length\"; Safari: <number>) matching elements by id\n\t\t\tfor ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) {\n\t\t\t\tif ( byElement && elem ) {\n\t\t\t\t\tj = 0;\n\n\t\t\t\t\t// Support: IE 11+, Edge 17 - 18+\n\t\t\t\t\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t\t\t\t\t// two documents; shallow comparisons work.\n\t\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\t\tif ( !context && elem.ownerDocument != document ) {\n\t\t\t\t\t\tsetDocument( elem );\n\t\t\t\t\t\txml = !documentIsHTML;\n\t\t\t\t\t}\n\t\t\t\t\twhile ( ( matcher = elementMatchers[ j++ ] ) ) {\n\t\t\t\t\t\tif ( matcher( elem, context || document, xml ) ) {\n\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( outermost ) {\n\t\t\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Track unmatched elements for set filters\n\t\t\t\tif ( bySet ) {\n\n\t\t\t\t\t// They will have gone through all possible matchers\n\t\t\t\t\tif ( ( elem = !matcher && elem ) ) {\n\t\t\t\t\t\tmatchedCount--;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Lengthen the array for every element, matched or not\n\t\t\t\t\tif ( seed ) {\n\t\t\t\t\t\tunmatched.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// `i` is now the count of elements visited above, and adding it to `matchedCount`\n\t\t\t// makes the latter nonnegative.\n\t\t\tmatchedCount += i;\n\n\t\t\t// Apply set filters to unmatched elements\n\t\t\t// NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`\n\t\t\t// equals `i`), unless we didn't visit _any_ elements in the above loop because we have\n\t\t\t// no element matchers and no seed.\n\t\t\t// Incrementing an initially-string \"0\" `i` allows `i` to remain a string only in that\n\t\t\t// case, which will result in a \"00\" `matchedCount` that differs from `i` but is also\n\t\t\t// numerically zero.\n\t\t\tif ( bySet && i !== matchedCount ) {\n\t\t\t\tj = 0;\n\t\t\t\twhile ( ( matcher = setMatchers[ j++ ] ) ) {\n\t\t\t\t\tmatcher( unmatched, setMatched, context, xml );\n\t\t\t\t}\n\n\t\t\t\tif ( seed ) {\n\n\t\t\t\t\t// Reintegrate element matches to eliminate the need for sorting\n\t\t\t\t\tif ( matchedCount > 0 ) {\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tif ( !( unmatched[ i ] || setMatched[ i ] ) ) {\n\t\t\t\t\t\t\t\tsetMatched[ i ] = pop.call( results );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Discard index placeholder values to get only actual matches\n\t\t\t\t\tsetMatched = condense( setMatched );\n\t\t\t\t}\n\n\t\t\t\t// Add matches to results\n\t\t\t\tpush.apply( results, setMatched );\n\n\t\t\t\t// Seedless set matches succeeding multiple successful matchers stipulate sorting\n\t\t\t\tif ( outermost && !seed && setMatched.length > 0 &&\n\t\t\t\t\t( matchedCount + setMatchers.length ) > 1 ) {\n\n\t\t\t\t\tSizzle.uniqueSort( results );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Override manipulation of globals by nested matchers\n\t\t\tif ( outermost ) {\n\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\toutermostContext = contextBackup;\n\t\t\t}\n\n\t\t\treturn unmatched;\n\t\t};\n\n\treturn bySet ?\n\t\tmarkFunction( superMatcher ) :\n\t\tsuperMatcher;\n}\n\ncompile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {\n\tvar i,\n\t\tsetMatchers = [],\n\t\telementMatchers = [],\n\t\tcached = compilerCache[ selector + \" \" ];\n\n\tif ( !cached ) {\n\n\t\t// Generate a function of recursive functions that can be used to check each element\n\t\tif ( !match ) {\n\t\t\tmatch = tokenize( selector );\n\t\t}\n\t\ti = match.length;\n\t\twhile ( i-- ) {\n\t\t\tcached = matcherFromTokens( match[ i ] );\n\t\t\tif ( cached[ expando ] ) {\n\t\t\t\tsetMatchers.push( cached );\n\t\t\t} else {\n\t\t\t\telementMatchers.push( cached );\n\t\t\t}\n\t\t}\n\n\t\t// Cache the compiled function\n\t\tcached = compilerCache(\n\t\t\tselector,\n\t\t\tmatcherFromGroupMatchers( elementMatchers, setMatchers )\n\t\t);\n\n\t\t// Save selector and tokenization\n\t\tcached.selector = selector;\n\t}\n\treturn cached;\n};\n\n/**\n * A low-level selection function that works with Sizzle's compiled\n *  selector functions\n * @param {String|Function} selector A selector or a pre-compiled\n *  selector function built with Sizzle.compile\n * @param {Element} context\n * @param {Array} [results]\n * @param {Array} [seed] A set of elements to match against\n */\nselect = Sizzle.select = function( selector, context, results, seed ) {\n\tvar i, tokens, token, type, find,\n\t\tcompiled = typeof selector === \"function\" && selector,\n\t\tmatch = !seed && tokenize( ( selector = compiled.selector || selector ) );\n\n\tresults = results || [];\n\n\t// Try to minimize operations if there is only one selector in the list and no seed\n\t// (the latter of which guarantees us context)\n\tif ( match.length === 1 ) {\n\n\t\t// Reduce context if the leading compound selector is an ID\n\t\ttokens = match[ 0 ] = match[ 0 ].slice( 0 );\n\t\tif ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === \"ID\" &&\n\t\t\tcontext.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) {\n\n\t\t\tcontext = ( Expr.find[ \"ID\" ]( token.matches[ 0 ]\n\t\t\t\t.replace( runescape, funescape ), context ) || [] )[ 0 ];\n\t\t\tif ( !context ) {\n\t\t\t\treturn results;\n\n\t\t\t// Precompiled matchers will still verify ancestry, so step up a level\n\t\t\t} else if ( compiled ) {\n\t\t\t\tcontext = context.parentNode;\n\t\t\t}\n\n\t\t\tselector = selector.slice( tokens.shift().value.length );\n\t\t}\n\n\t\t// Fetch a seed set for right-to-left matching\n\t\ti = matchExpr[ \"needsContext\" ].test( selector ) ? 0 : tokens.length;\n\t\twhile ( i-- ) {\n\t\t\ttoken = tokens[ i ];\n\n\t\t\t// Abort if we hit a combinator\n\t\t\tif ( Expr.relative[ ( type = token.type ) ] ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( ( find = Expr.find[ type ] ) ) {\n\n\t\t\t\t// Search, expanding context for leading sibling combinators\n\t\t\t\tif ( ( seed = find(\n\t\t\t\t\ttoken.matches[ 0 ].replace( runescape, funescape ),\n\t\t\t\t\trsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) ||\n\t\t\t\t\t\tcontext\n\t\t\t\t) ) ) {\n\n\t\t\t\t\t// If seed is empty or no tokens remain, we can return early\n\t\t\t\t\ttokens.splice( i, 1 );\n\t\t\t\t\tselector = seed.length && toSelector( tokens );\n\t\t\t\t\tif ( !selector ) {\n\t\t\t\t\t\tpush.apply( results, seed );\n\t\t\t\t\t\treturn results;\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Compile and execute a filtering function if one is not provided\n\t// Provide `match` to avoid retokenization if we modified the selector above\n\t( compiled || compile( selector, match ) )(\n\t\tseed,\n\t\tcontext,\n\t\t!documentIsHTML,\n\t\tresults,\n\t\t!context || rsibling.test( selector ) && testContext( context.parentNode ) || context\n\t);\n\treturn results;\n};\n\n// One-time assignments\n\n// Sort stability\nsupport.sortStable = expando.split( \"\" ).sort( sortOrder ).join( \"\" ) === expando;\n\n// Support: Chrome 14-35+\n// Always assume duplicates if they aren't passed to the comparison function\nsupport.detectDuplicates = !!hasDuplicate;\n\n// Initialize against the default document\nsetDocument();\n\n// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)\n// Detached nodes confoundingly follow *each other*\nsupport.sortDetached = assert( function( el ) {\n\n\t// Should return 1, but returns 4 (following)\n\treturn el.compareDocumentPosition( document.createElement( \"fieldset\" ) ) & 1;\n} );\n\n// Support: IE<8\n// Prevent attribute/property \"interpolation\"\n// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx\nif ( !assert( function( el ) {\n\tel.innerHTML = \"<a href='#'></a>\";\n\treturn el.firstChild.getAttribute( \"href\" ) === \"#\";\n} ) ) {\n\taddHandle( \"type|href|height|width\", function( elem, name, isXML ) {\n\t\tif ( !isXML ) {\n\t\t\treturn elem.getAttribute( name, name.toLowerCase() === \"type\" ? 1 : 2 );\n\t\t}\n\t} );\n}\n\n// Support: IE<9\n// Use defaultValue in place of getAttribute(\"value\")\nif ( !support.attributes || !assert( function( el ) {\n\tel.innerHTML = \"<input/>\";\n\tel.firstChild.setAttribute( \"value\", \"\" );\n\treturn el.firstChild.getAttribute( \"value\" ) === \"\";\n} ) ) {\n\taddHandle( \"value\", function( elem, _name, isXML ) {\n\t\tif ( !isXML && elem.nodeName.toLowerCase() === \"input\" ) {\n\t\t\treturn elem.defaultValue;\n\t\t}\n\t} );\n}\n\n// Support: IE<9\n// Use getAttributeNode to fetch booleans when getAttribute lies\nif ( !assert( function( el ) {\n\treturn el.getAttribute( \"disabled\" ) == null;\n} ) ) {\n\taddHandle( booleans, function( elem, name, isXML ) {\n\t\tvar val;\n\t\tif ( !isXML ) {\n\t\t\treturn elem[ name ] === true ? name.toLowerCase() :\n\t\t\t\t( val = elem.getAttributeNode( name ) ) && val.specified ?\n\t\t\t\t\tval.value :\n\t\t\t\t\tnull;\n\t\t}\n\t} );\n}\n\nreturn Sizzle;\n\n} )( window );\n\n\n\njQuery.find = Sizzle;\njQuery.expr = Sizzle.selectors;\n\n// Deprecated\njQuery.expr[ \":\" ] = jQuery.expr.pseudos;\njQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort;\njQuery.text = Sizzle.getText;\njQuery.isXMLDoc = Sizzle.isXML;\njQuery.contains = Sizzle.contains;\njQuery.escapeSelector = Sizzle.escape;\n\n\n\n\nvar dir = function( elem, dir, until ) {\n\tvar matched = [],\n\t\ttruncate = until !== undefined;\n\n\twhile ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {\n\t\tif ( elem.nodeType === 1 ) {\n\t\t\tif ( truncate && jQuery( elem ).is( until ) ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tmatched.push( elem );\n\t\t}\n\t}\n\treturn matched;\n};\n\n\nvar siblings = function( n, elem ) {\n\tvar matched = [];\n\n\tfor ( ; n; n = n.nextSibling ) {\n\t\tif ( n.nodeType === 1 && n !== elem ) {\n\t\t\tmatched.push( n );\n\t\t}\n\t}\n\n\treturn matched;\n};\n\n\nvar rneedsContext = jQuery.expr.match.needsContext;\n\n\n\nfunction nodeName( elem, name ) {\n\n\treturn elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();\n\n}\nvar rsingleTag = ( /^<([a-z][^\\/\\0>:\\x20\\t\\r\\n\\f]*)[\\x20\\t\\r\\n\\f]*\\/?>(?:<\\/\\1>|)$/i );\n\n\n\n// Implement the identical functionality for filter and not\nfunction winnow( elements, qualifier, not ) {\n\tif ( isFunction( qualifier ) ) {\n\t\treturn jQuery.grep( elements, function( elem, i ) {\n\t\t\treturn !!qualifier.call( elem, i, elem ) !== not;\n\t\t} );\n\t}\n\n\t// Single element\n\tif ( qualifier.nodeType ) {\n\t\treturn jQuery.grep( elements, function( elem ) {\n\t\t\treturn ( elem === qualifier ) !== not;\n\t\t} );\n\t}\n\n\t// Arraylike of elements (jQuery, arguments, Array)\n\tif ( typeof qualifier !== \"string\" ) {\n\t\treturn jQuery.grep( elements, function( elem ) {\n\t\t\treturn ( indexOf.call( qualifier, elem ) > -1 ) !== not;\n\t\t} );\n\t}\n\n\t// Filtered directly for both simple and complex selectors\n\treturn jQuery.filter( qualifier, elements, not );\n}\n\njQuery.filter = function( expr, elems, not ) {\n\tvar elem = elems[ 0 ];\n\n\tif ( not ) {\n\t\texpr = \":not(\" + expr + \")\";\n\t}\n\n\tif ( elems.length === 1 && elem.nodeType === 1 ) {\n\t\treturn jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [];\n\t}\n\n\treturn jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {\n\t\treturn elem.nodeType === 1;\n\t} ) );\n};\n\njQuery.fn.extend( {\n\tfind: function( selector ) {\n\t\tvar i, ret,\n\t\t\tlen = this.length,\n\t\t\tself = this;\n\n\t\tif ( typeof selector !== \"string\" ) {\n\t\t\treturn this.pushStack( jQuery( selector ).filter( function() {\n\t\t\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\t\t\tif ( jQuery.contains( self[ i ], this ) ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} ) );\n\t\t}\n\n\t\tret = this.pushStack( [] );\n\n\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\tjQuery.find( selector, self[ i ], ret );\n\t\t}\n\n\t\treturn len > 1 ? jQuery.uniqueSort( ret ) : ret;\n\t},\n\tfilter: function( selector ) {\n\t\treturn this.pushStack( winnow( this, selector || [], false ) );\n\t},\n\tnot: function( selector ) {\n\t\treturn this.pushStack( winnow( this, selector || [], true ) );\n\t},\n\tis: function( selector ) {\n\t\treturn !!winnow(\n\t\t\tthis,\n\n\t\t\t// If this is a positional/relative selector, check membership in the returned set\n\t\t\t// so $(\"p:first\").is(\"p:last\") won't return true for a doc with two \"p\".\n\t\t\ttypeof selector === \"string\" && rneedsContext.test( selector ) ?\n\t\t\t\tjQuery( selector ) :\n\t\t\t\tselector || [],\n\t\t\tfalse\n\t\t).length;\n\t}\n} );\n\n\n// Initialize a jQuery object\n\n\n// A central reference to the root jQuery(document)\nvar rootjQuery,\n\n\t// A simple way to check for HTML strings\n\t// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)\n\t// Strict HTML recognition (#11290: must start with <)\n\t// Shortcut simple #id case for speed\n\trquickExpr = /^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]+))$/,\n\n\tinit = jQuery.fn.init = function( selector, context, root ) {\n\t\tvar match, elem;\n\n\t\t// HANDLE: $(\"\"), $(null), $(undefined), $(false)\n\t\tif ( !selector ) {\n\t\t\treturn this;\n\t\t}\n\n\t\t// Method init() accepts an alternate rootjQuery\n\t\t// so migrate can support jQuery.sub (gh-2101)\n\t\troot = root || rootjQuery;\n\n\t\t// Handle HTML strings\n\t\tif ( typeof selector === \"string\" ) {\n\t\t\tif ( selector[ 0 ] === \"<\" &&\n\t\t\t\tselector[ selector.length - 1 ] === \">\" &&\n\t\t\t\tselector.length >= 3 ) {\n\n\t\t\t\t// Assume that strings that start and end with <> are HTML and skip the regex check\n\t\t\t\tmatch = [ null, selector, null ];\n\n\t\t\t} else {\n\t\t\t\tmatch = rquickExpr.exec( selector );\n\t\t\t}\n\n\t\t\t// Match html or make sure no context is specified for #id\n\t\t\tif ( match && ( match[ 1 ] || !context ) ) {\n\n\t\t\t\t// HANDLE: $(html) -> $(array)\n\t\t\t\tif ( match[ 1 ] ) {\n\t\t\t\t\tcontext = context instanceof jQuery ? context[ 0 ] : context;\n\n\t\t\t\t\t// Option to run scripts is true for back-compat\n\t\t\t\t\t// Intentionally let the error be thrown if parseHTML is not present\n\t\t\t\t\tjQuery.merge( this, jQuery.parseHTML(\n\t\t\t\t\t\tmatch[ 1 ],\n\t\t\t\t\t\tcontext && context.nodeType ? context.ownerDocument || context : document,\n\t\t\t\t\t\ttrue\n\t\t\t\t\t) );\n\n\t\t\t\t\t// HANDLE: $(html, props)\n\t\t\t\t\tif ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) {\n\t\t\t\t\t\tfor ( match in context ) {\n\n\t\t\t\t\t\t\t// Properties of context are called as methods if possible\n\t\t\t\t\t\t\tif ( isFunction( this[ match ] ) ) {\n\t\t\t\t\t\t\t\tthis[ match ]( context[ match ] );\n\n\t\t\t\t\t\t\t// ...and otherwise set as attributes\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthis.attr( match, context[ match ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn this;\n\n\t\t\t\t// HANDLE: $(#id)\n\t\t\t\t} else {\n\t\t\t\t\telem = document.getElementById( match[ 2 ] );\n\n\t\t\t\t\tif ( elem ) {\n\n\t\t\t\t\t\t// Inject the element directly into the jQuery object\n\t\t\t\t\t\tthis[ 0 ] = elem;\n\t\t\t\t\t\tthis.length = 1;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\n\t\t\t// HANDLE: $(expr, $(...))\n\t\t\t} else if ( !context || context.jquery ) {\n\t\t\t\treturn ( context || root ).find( selector );\n\n\t\t\t// HANDLE: $(expr, context)\n\t\t\t// (which is just equivalent to: $(context).find(expr)\n\t\t\t} else {\n\t\t\t\treturn this.constructor( context ).find( selector );\n\t\t\t}\n\n\t\t// HANDLE: $(DOMElement)\n\t\t} else if ( selector.nodeType ) {\n\t\t\tthis[ 0 ] = selector;\n\t\t\tthis.length = 1;\n\t\t\treturn this;\n\n\t\t// HANDLE: $(function)\n\t\t// Shortcut for document ready\n\t\t} else if ( isFunction( selector ) ) {\n\t\t\treturn root.ready !== undefined ?\n\t\t\t\troot.ready( selector ) :\n\n\t\t\t\t// Execute immediately if ready is not present\n\t\t\t\tselector( jQuery );\n\t\t}\n\n\t\treturn jQuery.makeArray( selector, this );\n\t};\n\n// Give the init function the jQuery prototype for later instantiation\ninit.prototype = jQuery.fn;\n\n// Initialize central reference\nrootjQuery = jQuery( document );\n\n\nvar rparentsprev = /^(?:parents|prev(?:Until|All))/,\n\n\t// Methods guaranteed to produce a unique set when starting from a unique set\n\tguaranteedUnique = {\n\t\tchildren: true,\n\t\tcontents: true,\n\t\tnext: true,\n\t\tprev: true\n\t};\n\njQuery.fn.extend( {\n\thas: function( target ) {\n\t\tvar targets = jQuery( target, this ),\n\t\t\tl = targets.length;\n\n\t\treturn this.filter( function() {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tif ( jQuery.contains( this, targets[ i ] ) ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t},\n\n\tclosest: function( selectors, context ) {\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\tl = this.length,\n\t\t\tmatched = [],\n\t\t\ttargets = typeof selectors !== \"string\" && jQuery( selectors );\n\n\t\t// Positional selectors never match, since there's no _selection_ context\n\t\tif ( !rneedsContext.test( selectors ) ) {\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tfor ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) {\n\n\t\t\t\t\t// Always skip document fragments\n\t\t\t\t\tif ( cur.nodeType < 11 && ( targets ?\n\t\t\t\t\t\ttargets.index( cur ) > -1 :\n\n\t\t\t\t\t\t// Don't pass non-elements to Sizzle\n\t\t\t\t\t\tcur.nodeType === 1 &&\n\t\t\t\t\t\t\tjQuery.find.matchesSelector( cur, selectors ) ) ) {\n\n\t\t\t\t\t\tmatched.push( cur );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched );\n\t},\n\n\t// Determine the position of an element within the set\n\tindex: function( elem ) {\n\n\t\t// No argument, return index in parent\n\t\tif ( !elem ) {\n\t\t\treturn ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;\n\t\t}\n\n\t\t// Index in selector\n\t\tif ( typeof elem === \"string\" ) {\n\t\t\treturn indexOf.call( jQuery( elem ), this[ 0 ] );\n\t\t}\n\n\t\t// Locate the position of the desired element\n\t\treturn indexOf.call( this,\n\n\t\t\t// If it receives a jQuery object, the first element is used\n\t\t\telem.jquery ? elem[ 0 ] : elem\n\t\t);\n\t},\n\n\tadd: function( selector, context ) {\n\t\treturn this.pushStack(\n\t\t\tjQuery.uniqueSort(\n\t\t\t\tjQuery.merge( this.get(), jQuery( selector, context ) )\n\t\t\t)\n\t\t);\n\t},\n\n\taddBack: function( selector ) {\n\t\treturn this.add( selector == null ?\n\t\t\tthis.prevObject : this.prevObject.filter( selector )\n\t\t);\n\t}\n} );\n\nfunction sibling( cur, dir ) {\n\twhile ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {}\n\treturn cur;\n}\n\njQuery.each( {\n\tparent: function( elem ) {\n\t\tvar parent = elem.parentNode;\n\t\treturn parent && parent.nodeType !== 11 ? parent : null;\n\t},\n\tparents: function( elem ) {\n\t\treturn dir( elem, \"parentNode\" );\n\t},\n\tparentsUntil: function( elem, _i, until ) {\n\t\treturn dir( elem, \"parentNode\", until );\n\t},\n\tnext: function( elem ) {\n\t\treturn sibling( elem, \"nextSibling\" );\n\t},\n\tprev: function( elem ) {\n\t\treturn sibling( elem, \"previousSibling\" );\n\t},\n\tnextAll: function( elem ) {\n\t\treturn dir( elem, \"nextSibling\" );\n\t},\n\tprevAll: function( elem ) {\n\t\treturn dir( elem, \"previousSibling\" );\n\t},\n\tnextUntil: function( elem, _i, until ) {\n\t\treturn dir( elem, \"nextSibling\", until );\n\t},\n\tprevUntil: function( elem, _i, until ) {\n\t\treturn dir( elem, \"previousSibling\", until );\n\t},\n\tsiblings: function( elem ) {\n\t\treturn siblings( ( elem.parentNode || {} ).firstChild, elem );\n\t},\n\tchildren: function( elem ) {\n\t\treturn siblings( elem.firstChild );\n\t},\n\tcontents: function( elem ) {\n\t\tif ( elem.contentDocument != null &&\n\n\t\t\t// Support: IE 11+\n\t\t\t// <object> elements with no `data` attribute has an object\n\t\t\t// `contentDocument` with a `null` prototype.\n\t\t\tgetProto( elem.contentDocument ) ) {\n\n\t\t\treturn elem.contentDocument;\n\t\t}\n\n\t\t// Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only\n\t\t// Treat the template element as a regular one in browsers that\n\t\t// don't support it.\n\t\tif ( nodeName( elem, \"template\" ) ) {\n\t\t\telem = elem.content || elem;\n\t\t}\n\n\t\treturn jQuery.merge( [], elem.childNodes );\n\t}\n}, function( name, fn ) {\n\tjQuery.fn[ name ] = function( until, selector ) {\n\t\tvar matched = jQuery.map( this, fn, until );\n\n\t\tif ( name.slice( -5 ) !== \"Until\" ) {\n\t\t\tselector = until;\n\t\t}\n\n\t\tif ( selector && typeof selector === \"string\" ) {\n\t\t\tmatched = jQuery.filter( selector, matched );\n\t\t}\n\n\t\tif ( this.length > 1 ) {\n\n\t\t\t// Remove duplicates\n\t\t\tif ( !guaranteedUnique[ name ] ) {\n\t\t\t\tjQuery.uniqueSort( matched );\n\t\t\t}\n\n\t\t\t// Reverse order for parents* and prev-derivatives\n\t\t\tif ( rparentsprev.test( name ) ) {\n\t\t\t\tmatched.reverse();\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( matched );\n\t};\n} );\nvar rnothtmlwhite = ( /[^\\x20\\t\\r\\n\\f]+/g );\n\n\n\n// Convert String-formatted options into Object-formatted ones\nfunction createOptions( options ) {\n\tvar object = {};\n\tjQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) {\n\t\tobject[ flag ] = true;\n\t} );\n\treturn object;\n}\n\n/*\n * Create a callback list using the following parameters:\n *\n *\toptions: an optional list of space-separated options that will change how\n *\t\t\tthe callback list behaves or a more traditional option object\n *\n * By default a callback list will act like an event callback list and can be\n * \"fired\" multiple times.\n *\n * Possible options:\n *\n *\tonce:\t\t\twill ensure the callback list can only be fired once (like a Deferred)\n *\n *\tmemory:\t\t\twill keep track of previous values and will call any callback added\n *\t\t\t\t\tafter the list has been fired right away with the latest \"memorized\"\n *\t\t\t\t\tvalues (like a Deferred)\n *\n *\tunique:\t\t\twill ensure a callback can only be added once (no duplicate in the list)\n *\n *\tstopOnFalse:\tinterrupt callings when a callback returns false\n *\n */\njQuery.Callbacks = function( options ) {\n\n\t// Convert options from String-formatted to Object-formatted if needed\n\t// (we check in cache first)\n\toptions = typeof options === \"string\" ?\n\t\tcreateOptions( options ) :\n\t\tjQuery.extend( {}, options );\n\n\tvar // Flag to know if list is currently firing\n\t\tfiring,\n\n\t\t// Last fire value for non-forgettable lists\n\t\tmemory,\n\n\t\t// Flag to know if list was already fired\n\t\tfired,\n\n\t\t// Flag to prevent firing\n\t\tlocked,\n\n\t\t// Actual callback list\n\t\tlist = [],\n\n\t\t// Queue of execution data for repeatable lists\n\t\tqueue = [],\n\n\t\t// Index of currently firing callback (modified by add/remove as needed)\n\t\tfiringIndex = -1,\n\n\t\t// Fire callbacks\n\t\tfire = function() {\n\n\t\t\t// Enforce single-firing\n\t\t\tlocked = locked || options.once;\n\n\t\t\t// Execute callbacks for all pending executions,\n\t\t\t// respecting firingIndex overrides and runtime changes\n\t\t\tfired = firing = true;\n\t\t\tfor ( ; queue.length; firingIndex = -1 ) {\n\t\t\t\tmemory = queue.shift();\n\t\t\t\twhile ( ++firingIndex < list.length ) {\n\n\t\t\t\t\t// Run callback and check for early termination\n\t\t\t\t\tif ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&\n\t\t\t\t\t\toptions.stopOnFalse ) {\n\n\t\t\t\t\t\t// Jump to end and forget the data so .add doesn't re-fire\n\t\t\t\t\t\tfiringIndex = list.length;\n\t\t\t\t\t\tmemory = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Forget the data if we're done with it\n\t\t\tif ( !options.memory ) {\n\t\t\t\tmemory = false;\n\t\t\t}\n\n\t\t\tfiring = false;\n\n\t\t\t// Clean up if we're done firing for good\n\t\t\tif ( locked ) {\n\n\t\t\t\t// Keep an empty list if we have data for future add calls\n\t\t\t\tif ( memory ) {\n\t\t\t\t\tlist = [];\n\n\t\t\t\t// Otherwise, this object is spent\n\t\t\t\t} else {\n\t\t\t\t\tlist = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t// Actual Callbacks object\n\t\tself = {\n\n\t\t\t// Add a callback or a collection of callbacks to the list\n\t\t\tadd: function() {\n\t\t\t\tif ( list ) {\n\n\t\t\t\t\t// If we have memory from a past run, we should fire after adding\n\t\t\t\t\tif ( memory && !firing ) {\n\t\t\t\t\t\tfiringIndex = list.length - 1;\n\t\t\t\t\t\tqueue.push( memory );\n\t\t\t\t\t}\n\n\t\t\t\t\t( function add( args ) {\n\t\t\t\t\t\tjQuery.each( args, function( _, arg ) {\n\t\t\t\t\t\t\tif ( isFunction( arg ) ) {\n\t\t\t\t\t\t\t\tif ( !options.unique || !self.has( arg ) ) {\n\t\t\t\t\t\t\t\t\tlist.push( arg );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if ( arg && arg.length && toType( arg ) !== \"string\" ) {\n\n\t\t\t\t\t\t\t\t// Inspect recursively\n\t\t\t\t\t\t\t\tadd( arg );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} );\n\t\t\t\t\t} )( arguments );\n\n\t\t\t\t\tif ( memory && !firing ) {\n\t\t\t\t\t\tfire();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Remove a callback from the list\n\t\t\tremove: function() {\n\t\t\t\tjQuery.each( arguments, function( _, arg ) {\n\t\t\t\t\tvar index;\n\t\t\t\t\twhile ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {\n\t\t\t\t\t\tlist.splice( index, 1 );\n\n\t\t\t\t\t\t// Handle firing indexes\n\t\t\t\t\t\tif ( index <= firingIndex ) {\n\t\t\t\t\t\t\tfiringIndex--;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Check if a given callback is in the list.\n\t\t\t// If no argument is given, return whether or not list has callbacks attached.\n\t\t\thas: function( fn ) {\n\t\t\t\treturn fn ?\n\t\t\t\t\tjQuery.inArray( fn, list ) > -1 :\n\t\t\t\t\tlist.length > 0;\n\t\t\t},\n\n\t\t\t// Remove all callbacks from the list\n\t\t\tempty: function() {\n\t\t\t\tif ( list ) {\n\t\t\t\t\tlist = [];\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Disable .fire and .add\n\t\t\t// Abort any current/pending executions\n\t\t\t// Clear all callbacks and values\n\t\t\tdisable: function() {\n\t\t\t\tlocked = queue = [];\n\t\t\t\tlist = memory = \"\";\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\tdisabled: function() {\n\t\t\t\treturn !list;\n\t\t\t},\n\n\t\t\t// Disable .fire\n\t\t\t// Also disable .add unless we have memory (since it would have no effect)\n\t\t\t// Abort any pending executions\n\t\t\tlock: function() {\n\t\t\t\tlocked = queue = [];\n\t\t\t\tif ( !memory && !firing ) {\n\t\t\t\t\tlist = memory = \"\";\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\tlocked: function() {\n\t\t\t\treturn !!locked;\n\t\t\t},\n\n\t\t\t// Call all callbacks with the given context and arguments\n\t\t\tfireWith: function( context, args ) {\n\t\t\t\tif ( !locked ) {\n\t\t\t\t\targs = args || [];\n\t\t\t\t\targs = [ context, args.slice ? args.slice() : args ];\n\t\t\t\t\tqueue.push( args );\n\t\t\t\t\tif ( !firing ) {\n\t\t\t\t\t\tfire();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Call all the callbacks with the given arguments\n\t\t\tfire: function() {\n\t\t\t\tself.fireWith( this, arguments );\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// To know if the callbacks have already been called at least once\n\t\t\tfired: function() {\n\t\t\t\treturn !!fired;\n\t\t\t}\n\t\t};\n\n\treturn self;\n};\n\n\nfunction Identity( v ) {\n\treturn v;\n}\nfunction Thrower( ex ) {\n\tthrow ex;\n}\n\nfunction adoptValue( value, resolve, reject, noValue ) {\n\tvar method;\n\n\ttry {\n\n\t\t// Check for promise aspect first to privilege synchronous behavior\n\t\tif ( value && isFunction( ( method = value.promise ) ) ) {\n\t\t\tmethod.call( value ).done( resolve ).fail( reject );\n\n\t\t// Other thenables\n\t\t} else if ( value && isFunction( ( method = value.then ) ) ) {\n\t\t\tmethod.call( value, resolve, reject );\n\n\t\t// Other non-thenables\n\t\t} else {\n\n\t\t\t// Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer:\n\t\t\t// * false: [ value ].slice( 0 ) => resolve( value )\n\t\t\t// * true: [ value ].slice( 1 ) => resolve()\n\t\t\tresolve.apply( undefined, [ value ].slice( noValue ) );\n\t\t}\n\n\t// For Promises/A+, convert exceptions into rejections\n\t// Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in\n\t// Deferred#then to conditionally suppress rejection.\n\t} catch ( value ) {\n\n\t\t// Support: Android 4.0 only\n\t\t// Strict mode functions invoked without .call/.apply get global-object context\n\t\treject.apply( undefined, [ value ] );\n\t}\n}\n\njQuery.extend( {\n\n\tDeferred: function( func ) {\n\t\tvar tuples = [\n\n\t\t\t\t// action, add listener, callbacks,\n\t\t\t\t// ... .then handlers, argument index, [final state]\n\t\t\t\t[ \"notify\", \"progress\", jQuery.Callbacks( \"memory\" ),\n\t\t\t\t\tjQuery.Callbacks( \"memory\" ), 2 ],\n\t\t\t\t[ \"resolve\", \"done\", jQuery.Callbacks( \"once memory\" ),\n\t\t\t\t\tjQuery.Callbacks( \"once memory\" ), 0, \"resolved\" ],\n\t\t\t\t[ \"reject\", \"fail\", jQuery.Callbacks( \"once memory\" ),\n\t\t\t\t\tjQuery.Callbacks( \"once memory\" ), 1, \"rejected\" ]\n\t\t\t],\n\t\t\tstate = \"pending\",\n\t\t\tpromise = {\n\t\t\t\tstate: function() {\n\t\t\t\t\treturn state;\n\t\t\t\t},\n\t\t\t\talways: function() {\n\t\t\t\t\tdeferred.done( arguments ).fail( arguments );\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\t\t\t\t\"catch\": function( fn ) {\n\t\t\t\t\treturn promise.then( null, fn );\n\t\t\t\t},\n\n\t\t\t\t// Keep pipe for back-compat\n\t\t\t\tpipe: function( /* fnDone, fnFail, fnProgress */ ) {\n\t\t\t\t\tvar fns = arguments;\n\n\t\t\t\t\treturn jQuery.Deferred( function( newDefer ) {\n\t\t\t\t\t\tjQuery.each( tuples, function( _i, tuple ) {\n\n\t\t\t\t\t\t\t// Map tuples (progress, done, fail) to arguments (done, fail, progress)\n\t\t\t\t\t\t\tvar fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ];\n\n\t\t\t\t\t\t\t// deferred.progress(function() { bind to newDefer or newDefer.notify })\n\t\t\t\t\t\t\t// deferred.done(function() { bind to newDefer or newDefer.resolve })\n\t\t\t\t\t\t\t// deferred.fail(function() { bind to newDefer or newDefer.reject })\n\t\t\t\t\t\t\tdeferred[ tuple[ 1 ] ]( function() {\n\t\t\t\t\t\t\t\tvar returned = fn && fn.apply( this, arguments );\n\t\t\t\t\t\t\t\tif ( returned && isFunction( returned.promise ) ) {\n\t\t\t\t\t\t\t\t\treturned.promise()\n\t\t\t\t\t\t\t\t\t\t.progress( newDefer.notify )\n\t\t\t\t\t\t\t\t\t\t.done( newDefer.resolve )\n\t\t\t\t\t\t\t\t\t\t.fail( newDefer.reject );\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tnewDefer[ tuple[ 0 ] + \"With\" ](\n\t\t\t\t\t\t\t\t\t\tthis,\n\t\t\t\t\t\t\t\t\t\tfn ? [ returned ] : arguments\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t} );\n\t\t\t\t\t\tfns = null;\n\t\t\t\t\t} ).promise();\n\t\t\t\t},\n\t\t\t\tthen: function( onFulfilled, onRejected, onProgress ) {\n\t\t\t\t\tvar maxDepth = 0;\n\t\t\t\t\tfunction resolve( depth, deferred, handler, special ) {\n\t\t\t\t\t\treturn function() {\n\t\t\t\t\t\t\tvar that = this,\n\t\t\t\t\t\t\t\targs = arguments,\n\t\t\t\t\t\t\t\tmightThrow = function() {\n\t\t\t\t\t\t\t\t\tvar returned, then;\n\n\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.3.3.3\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-59\n\t\t\t\t\t\t\t\t\t// Ignore double-resolution attempts\n\t\t\t\t\t\t\t\t\tif ( depth < maxDepth ) {\n\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\treturned = handler.apply( that, args );\n\n\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.1\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-48\n\t\t\t\t\t\t\t\t\tif ( returned === deferred.promise() ) {\n\t\t\t\t\t\t\t\t\t\tthrow new TypeError( \"Thenable self-resolution\" );\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// Support: Promises/A+ sections 2.3.3.1, 3.5\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-54\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-75\n\t\t\t\t\t\t\t\t\t// Retrieve `then` only once\n\t\t\t\t\t\t\t\t\tthen = returned &&\n\n\t\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.4\n\t\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-64\n\t\t\t\t\t\t\t\t\t\t// Only check objects and functions for thenability\n\t\t\t\t\t\t\t\t\t\t( typeof returned === \"object\" ||\n\t\t\t\t\t\t\t\t\t\t\ttypeof returned === \"function\" ) &&\n\t\t\t\t\t\t\t\t\t\treturned.then;\n\n\t\t\t\t\t\t\t\t\t// Handle a returned thenable\n\t\t\t\t\t\t\t\t\tif ( isFunction( then ) ) {\n\n\t\t\t\t\t\t\t\t\t\t// Special processors (notify) just wait for resolution\n\t\t\t\t\t\t\t\t\t\tif ( special ) {\n\t\t\t\t\t\t\t\t\t\t\tthen.call(\n\t\t\t\t\t\t\t\t\t\t\t\treturned,\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Identity, special ),\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Thrower, special )\n\t\t\t\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\t\t\t// Normal processors (resolve) also hook into progress\n\t\t\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\t\t\t// ...and disregard older resolution values\n\t\t\t\t\t\t\t\t\t\t\tmaxDepth++;\n\n\t\t\t\t\t\t\t\t\t\t\tthen.call(\n\t\t\t\t\t\t\t\t\t\t\t\treturned,\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Identity, special ),\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Thrower, special ),\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Identity,\n\t\t\t\t\t\t\t\t\t\t\t\t\tdeferred.notifyWith )\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// Handle all other returned values\n\t\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\t\t// Only substitute handlers pass on context\n\t\t\t\t\t\t\t\t\t\t// and multiple values (non-spec behavior)\n\t\t\t\t\t\t\t\t\t\tif ( handler !== Identity ) {\n\t\t\t\t\t\t\t\t\t\t\tthat = undefined;\n\t\t\t\t\t\t\t\t\t\t\targs = [ returned ];\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t// Process the value(s)\n\t\t\t\t\t\t\t\t\t\t// Default process is resolve\n\t\t\t\t\t\t\t\t\t\t( special || deferred.resolveWith )( that, args );\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\n\t\t\t\t\t\t\t\t// Only normal processors (resolve) catch and reject exceptions\n\t\t\t\t\t\t\t\tprocess = special ?\n\t\t\t\t\t\t\t\t\tmightThrow :\n\t\t\t\t\t\t\t\t\tfunction() {\n\t\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\t\tmightThrow();\n\t\t\t\t\t\t\t\t\t\t} catch ( e ) {\n\n\t\t\t\t\t\t\t\t\t\t\tif ( jQuery.Deferred.exceptionHook ) {\n\t\t\t\t\t\t\t\t\t\t\t\tjQuery.Deferred.exceptionHook( e,\n\t\t\t\t\t\t\t\t\t\t\t\t\tprocess.stackTrace );\n\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.3.3.4.1\n\t\t\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-61\n\t\t\t\t\t\t\t\t\t\t\t// Ignore post-resolution exceptions\n\t\t\t\t\t\t\t\t\t\t\tif ( depth + 1 >= maxDepth ) {\n\n\t\t\t\t\t\t\t\t\t\t\t\t// Only substitute handlers pass on context\n\t\t\t\t\t\t\t\t\t\t\t\t// and multiple values (non-spec behavior)\n\t\t\t\t\t\t\t\t\t\t\t\tif ( handler !== Thrower ) {\n\t\t\t\t\t\t\t\t\t\t\t\t\tthat = undefined;\n\t\t\t\t\t\t\t\t\t\t\t\t\targs = [ e ];\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\t\tdeferred.rejectWith( that, args );\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.3.3.1\n\t\t\t\t\t\t\t// https://promisesaplus.com/#point-57\n\t\t\t\t\t\t\t// Re-resolve promises immediately to dodge false rejection from\n\t\t\t\t\t\t\t// subsequent errors\n\t\t\t\t\t\t\tif ( depth ) {\n\t\t\t\t\t\t\t\tprocess();\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t// Call an optional hook to record the stack, in case of exception\n\t\t\t\t\t\t\t\t// since it's otherwise lost when execution goes async\n\t\t\t\t\t\t\t\tif ( jQuery.Deferred.getStackHook ) {\n\t\t\t\t\t\t\t\t\tprocess.stackTrace = jQuery.Deferred.getStackHook();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\twindow.setTimeout( process );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\treturn jQuery.Deferred( function( newDefer ) {\n\n\t\t\t\t\t\t// progress_handlers.add( ... )\n\t\t\t\t\t\ttuples[ 0 ][ 3 ].add(\n\t\t\t\t\t\t\tresolve(\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\tnewDefer,\n\t\t\t\t\t\t\t\tisFunction( onProgress ) ?\n\t\t\t\t\t\t\t\t\tonProgress :\n\t\t\t\t\t\t\t\t\tIdentity,\n\t\t\t\t\t\t\t\tnewDefer.notifyWith\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t// fulfilled_handlers.add( ... )\n\t\t\t\t\t\ttuples[ 1 ][ 3 ].add(\n\t\t\t\t\t\t\tresolve(\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\tnewDefer,\n\t\t\t\t\t\t\t\tisFunction( onFulfilled ) ?\n\t\t\t\t\t\t\t\t\tonFulfilled :\n\t\t\t\t\t\t\t\t\tIdentity\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t// rejected_handlers.add( ... )\n\t\t\t\t\t\ttuples[ 2 ][ 3 ].add(\n\t\t\t\t\t\t\tresolve(\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\tnewDefer,\n\t\t\t\t\t\t\t\tisFunction( onRejected ) ?\n\t\t\t\t\t\t\t\t\tonRejected :\n\t\t\t\t\t\t\t\t\tThrower\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\t\t\t\t\t} ).promise();\n\t\t\t\t},\n\n\t\t\t\t// Get a promise for this deferred\n\t\t\t\t// If obj is provided, the promise aspect is added to the object\n\t\t\t\tpromise: function( obj ) {\n\t\t\t\t\treturn obj != null ? jQuery.extend( obj, promise ) : promise;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdeferred = {};\n\n\t\t// Add list-specific methods\n\t\tjQuery.each( tuples, function( i, tuple ) {\n\t\t\tvar list = tuple[ 2 ],\n\t\t\t\tstateString = tuple[ 5 ];\n\n\t\t\t// promise.progress = list.add\n\t\t\t// promise.done = list.add\n\t\t\t// promise.fail = list.add\n\t\t\tpromise[ tuple[ 1 ] ] = list.add;\n\n\t\t\t// Handle state\n\t\t\tif ( stateString ) {\n\t\t\t\tlist.add(\n\t\t\t\t\tfunction() {\n\n\t\t\t\t\t\t// state = \"resolved\" (i.e., fulfilled)\n\t\t\t\t\t\t// state = \"rejected\"\n\t\t\t\t\t\tstate = stateString;\n\t\t\t\t\t},\n\n\t\t\t\t\t// rejected_callbacks.disable\n\t\t\t\t\t// fulfilled_callbacks.disable\n\t\t\t\t\ttuples[ 3 - i ][ 2 ].disable,\n\n\t\t\t\t\t// rejected_handlers.disable\n\t\t\t\t\t// fulfilled_handlers.disable\n\t\t\t\t\ttuples[ 3 - i ][ 3 ].disable,\n\n\t\t\t\t\t// progress_callbacks.lock\n\t\t\t\t\ttuples[ 0 ][ 2 ].lock,\n\n\t\t\t\t\t// progress_handlers.lock\n\t\t\t\t\ttuples[ 0 ][ 3 ].lock\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// progress_handlers.fire\n\t\t\t// fulfilled_handlers.fire\n\t\t\t// rejected_handlers.fire\n\t\t\tlist.add( tuple[ 3 ].fire );\n\n\t\t\t// deferred.notify = function() { deferred.notifyWith(...) }\n\t\t\t// deferred.resolve = function() { deferred.resolveWith(...) }\n\t\t\t// deferred.reject = function() { deferred.rejectWith(...) }\n\t\t\tdeferred[ tuple[ 0 ] ] = function() {\n\t\t\t\tdeferred[ tuple[ 0 ] + \"With\" ]( this === deferred ? undefined : this, arguments );\n\t\t\t\treturn this;\n\t\t\t};\n\n\t\t\t// deferred.notifyWith = list.fireWith\n\t\t\t// deferred.resolveWith = list.fireWith\n\t\t\t// deferred.rejectWith = list.fireWith\n\t\t\tdeferred[ tuple[ 0 ] + \"With\" ] = list.fireWith;\n\t\t} );\n\n\t\t// Make the deferred a promise\n\t\tpromise.promise( deferred );\n\n\t\t// Call given func if any\n\t\tif ( func ) {\n\t\t\tfunc.call( deferred, deferred );\n\t\t}\n\n\t\t// All done!\n\t\treturn deferred;\n\t},\n\n\t// Deferred helper\n\twhen: function( singleValue ) {\n\t\tvar\n\n\t\t\t// count of uncompleted subordinates\n\t\t\tremaining = arguments.length,\n\n\t\t\t// count of unprocessed arguments\n\t\t\ti = remaining,\n\n\t\t\t// subordinate fulfillment data\n\t\t\tresolveContexts = Array( i ),\n\t\t\tresolveValues = slice.call( arguments ),\n\n\t\t\t// the primary Deferred\n\t\t\tprimary = jQuery.Deferred(),\n\n\t\t\t// subordinate callback factory\n\t\t\tupdateFunc = function( i ) {\n\t\t\t\treturn function( value ) {\n\t\t\t\t\tresolveContexts[ i ] = this;\n\t\t\t\t\tresolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;\n\t\t\t\t\tif ( !( --remaining ) ) {\n\t\t\t\t\t\tprimary.resolveWith( resolveContexts, resolveValues );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t};\n\n\t\t// Single- and empty arguments are adopted like Promise.resolve\n\t\tif ( remaining <= 1 ) {\n\t\t\tadoptValue( singleValue, primary.done( updateFunc( i ) ).resolve, primary.reject,\n\t\t\t\t!remaining );\n\n\t\t\t// Use .then() to unwrap secondary thenables (cf. gh-3000)\n\t\t\tif ( primary.state() === \"pending\" ||\n\t\t\t\tisFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) {\n\n\t\t\t\treturn primary.then();\n\t\t\t}\n\t\t}\n\n\t\t// Multiple arguments are aggregated like Promise.all array elements\n\t\twhile ( i-- ) {\n\t\t\tadoptValue( resolveValues[ i ], updateFunc( i ), primary.reject );\n\t\t}\n\n\t\treturn primary.promise();\n\t}\n} );\n\n\n// These usually indicate a programmer mistake during development,\n// warn about them ASAP rather than swallowing them by default.\nvar rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;\n\njQuery.Deferred.exceptionHook = function( error, stack ) {\n\n\t// Support: IE 8 - 9 only\n\t// Console exists when dev tools are open, which can happen at any time\n\tif ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) {\n\t\twindow.console.warn( \"jQuery.Deferred exception: \" + error.message, error.stack, stack );\n\t}\n};\n\n\n\n\njQuery.readyException = function( error ) {\n\twindow.setTimeout( function() {\n\t\tthrow error;\n\t} );\n};\n\n\n\n\n// The deferred used on DOM ready\nvar readyList = jQuery.Deferred();\n\njQuery.fn.ready = function( fn ) {\n\n\treadyList\n\t\t.then( fn )\n\n\t\t// Wrap jQuery.readyException in a function so that the lookup\n\t\t// happens at the time of error handling instead of callback\n\t\t// registration.\n\t\t.catch( function( error ) {\n\t\t\tjQuery.readyException( error );\n\t\t} );\n\n\treturn this;\n};\n\njQuery.extend( {\n\n\t// Is the DOM ready to be used? Set to true once it occurs.\n\tisReady: false,\n\n\t// A counter to track how many items to wait for before\n\t// the ready event fires. See #6781\n\treadyWait: 1,\n\n\t// Handle when the DOM is ready\n\tready: function( wait ) {\n\n\t\t// Abort if there are pending holds or we're already ready\n\t\tif ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Remember that the DOM is ready\n\t\tjQuery.isReady = true;\n\n\t\t// If a normal DOM Ready event fired, decrement, and wait if need be\n\t\tif ( wait !== true && --jQuery.readyWait > 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If there are functions bound, to execute\n\t\treadyList.resolveWith( document, [ jQuery ] );\n\t}\n} );\n\njQuery.ready.then = readyList.then;\n\n// The ready event handler and self cleanup method\nfunction completed() {\n\tdocument.removeEventListener( \"DOMContentLoaded\", completed );\n\twindow.removeEventListener( \"load\", completed );\n\tjQuery.ready();\n}\n\n// Catch cases where $(document).ready() is called\n// after the browser event has already occurred.\n// Support: IE <=9 - 10 only\n// Older IE sometimes signals \"interactive\" too soon\nif ( document.readyState === \"complete\" ||\n\t( document.readyState !== \"loading\" && !document.documentElement.doScroll ) ) {\n\n\t// Handle it asynchronously to allow scripts the opportunity to delay ready\n\twindow.setTimeout( jQuery.ready );\n\n} else {\n\n\t// Use the handy event callback\n\tdocument.addEventListener( \"DOMContentLoaded\", completed );\n\n\t// A fallback to window.onload, that will always work\n\twindow.addEventListener( \"load\", completed );\n}\n\n\n\n\n// Multifunctional method to get and set values of a collection\n// The value/s can optionally be executed if it's a function\nvar access = function( elems, fn, key, value, chainable, emptyGet, raw ) {\n\tvar i = 0,\n\t\tlen = elems.length,\n\t\tbulk = key == null;\n\n\t// Sets many values\n\tif ( toType( key ) === \"object\" ) {\n\t\tchainable = true;\n\t\tfor ( i in key ) {\n\t\t\taccess( elems, fn, i, key[ i ], true, emptyGet, raw );\n\t\t}\n\n\t// Sets one value\n\t} else if ( value !== undefined ) {\n\t\tchainable = true;\n\n\t\tif ( !isFunction( value ) ) {\n\t\t\traw = true;\n\t\t}\n\n\t\tif ( bulk ) {\n\n\t\t\t// Bulk operations run against the entire set\n\t\t\tif ( raw ) {\n\t\t\t\tfn.call( elems, value );\n\t\t\t\tfn = null;\n\n\t\t\t// ...except when executing function values\n\t\t\t} else {\n\t\t\t\tbulk = fn;\n\t\t\t\tfn = function( elem, _key, value ) {\n\t\t\t\t\treturn bulk.call( jQuery( elem ), value );\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tif ( fn ) {\n\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\tfn(\n\t\t\t\t\telems[ i ], key, raw ?\n\t\t\t\t\t\tvalue :\n\t\t\t\t\t\tvalue.call( elems[ i ], i, fn( elems[ i ], key ) )\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( chainable ) {\n\t\treturn elems;\n\t}\n\n\t// Gets\n\tif ( bulk ) {\n\t\treturn fn.call( elems );\n\t}\n\n\treturn len ? fn( elems[ 0 ], key ) : emptyGet;\n};\n\n\n// Matches dashed string for camelizing\nvar rmsPrefix = /^-ms-/,\n\trdashAlpha = /-([a-z])/g;\n\n// Used by camelCase as callback to replace()\nfunction fcamelCase( _all, letter ) {\n\treturn letter.toUpperCase();\n}\n\n// Convert dashed to camelCase; used by the css and data modules\n// Support: IE <=9 - 11, Edge 12 - 15\n// Microsoft forgot to hump their vendor prefix (#9572)\nfunction camelCase( string ) {\n\treturn string.replace( rmsPrefix, \"ms-\" ).replace( rdashAlpha, fcamelCase );\n}\nvar acceptData = function( owner ) {\n\n\t// Accepts only:\n\t//  - Node\n\t//    - Node.ELEMENT_NODE\n\t//    - Node.DOCUMENT_NODE\n\t//  - Object\n\t//    - Any\n\treturn owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );\n};\n\n\n\n\nfunction Data() {\n\tthis.expando = jQuery.expando + Data.uid++;\n}\n\nData.uid = 1;\n\nData.prototype = {\n\n\tcache: function( owner ) {\n\n\t\t// Check if the owner object already has a cache\n\t\tvar value = owner[ this.expando ];\n\n\t\t// If not, create one\n\t\tif ( !value ) {\n\t\t\tvalue = {};\n\n\t\t\t// We can accept data for non-element nodes in modern browsers,\n\t\t\t// but we should not, see #8335.\n\t\t\t// Always return an empty object.\n\t\t\tif ( acceptData( owner ) ) {\n\n\t\t\t\t// If it is a node unlikely to be stringify-ed or looped over\n\t\t\t\t// use plain assignment\n\t\t\t\tif ( owner.nodeType ) {\n\t\t\t\t\towner[ this.expando ] = value;\n\n\t\t\t\t// Otherwise secure it in a non-enumerable property\n\t\t\t\t// configurable must be true to allow the property to be\n\t\t\t\t// deleted when data is removed\n\t\t\t\t} else {\n\t\t\t\t\tObject.defineProperty( owner, this.expando, {\n\t\t\t\t\t\tvalue: value,\n\t\t\t\t\t\tconfigurable: true\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn value;\n\t},\n\tset: function( owner, data, value ) {\n\t\tvar prop,\n\t\t\tcache = this.cache( owner );\n\n\t\t// Handle: [ owner, key, value ] args\n\t\t// Always use camelCase key (gh-2257)\n\t\tif ( typeof data === \"string\" ) {\n\t\t\tcache[ camelCase( data ) ] = value;\n\n\t\t// Handle: [ owner, { properties } ] args\n\t\t} else {\n\n\t\t\t// Copy the properties one-by-one to the cache object\n\t\t\tfor ( prop in data ) {\n\t\t\t\tcache[ camelCase( prop ) ] = data[ prop ];\n\t\t\t}\n\t\t}\n\t\treturn cache;\n\t},\n\tget: function( owner, key ) {\n\t\treturn key === undefined ?\n\t\t\tthis.cache( owner ) :\n\n\t\t\t// Always use camelCase key (gh-2257)\n\t\t\towner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ];\n\t},\n\taccess: function( owner, key, value ) {\n\n\t\t// In cases where either:\n\t\t//\n\t\t//   1. No key was specified\n\t\t//   2. A string key was specified, but no value provided\n\t\t//\n\t\t// Take the \"read\" path and allow the get method to determine\n\t\t// which value to return, respectively either:\n\t\t//\n\t\t//   1. The entire cache object\n\t\t//   2. The data stored at the key\n\t\t//\n\t\tif ( key === undefined ||\n\t\t\t\t( ( key && typeof key === \"string\" ) && value === undefined ) ) {\n\n\t\t\treturn this.get( owner, key );\n\t\t}\n\n\t\t// When the key is not a string, or both a key and value\n\t\t// are specified, set or extend (existing objects) with either:\n\t\t//\n\t\t//   1. An object of properties\n\t\t//   2. A key and value\n\t\t//\n\t\tthis.set( owner, key, value );\n\n\t\t// Since the \"set\" path can have two possible entry points\n\t\t// return the expected data based on which path was taken[*]\n\t\treturn value !== undefined ? value : key;\n\t},\n\tremove: function( owner, key ) {\n\t\tvar i,\n\t\t\tcache = owner[ this.expando ];\n\n\t\tif ( cache === undefined ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( key !== undefined ) {\n\n\t\t\t// Support array or space separated string of keys\n\t\t\tif ( Array.isArray( key ) ) {\n\n\t\t\t\t// If key is an array of keys...\n\t\t\t\t// We always set camelCase keys, so remove that.\n\t\t\t\tkey = key.map( camelCase );\n\t\t\t} else {\n\t\t\t\tkey = camelCase( key );\n\n\t\t\t\t// If a key with the spaces exists, use it.\n\t\t\t\t// Otherwise, create an array by matching non-whitespace\n\t\t\t\tkey = key in cache ?\n\t\t\t\t\t[ key ] :\n\t\t\t\t\t( key.match( rnothtmlwhite ) || [] );\n\t\t\t}\n\n\t\t\ti = key.length;\n\n\t\t\twhile ( i-- ) {\n\t\t\t\tdelete cache[ key[ i ] ];\n\t\t\t}\n\t\t}\n\n\t\t// Remove the expando if there's no more data\n\t\tif ( key === undefined || jQuery.isEmptyObject( cache ) ) {\n\n\t\t\t// Support: Chrome <=35 - 45\n\t\t\t// Webkit & Blink performance suffers when deleting properties\n\t\t\t// from DOM nodes, so set to undefined instead\n\t\t\t// https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted)\n\t\t\tif ( owner.nodeType ) {\n\t\t\t\towner[ this.expando ] = undefined;\n\t\t\t} else {\n\t\t\t\tdelete owner[ this.expando ];\n\t\t\t}\n\t\t}\n\t},\n\thasData: function( owner ) {\n\t\tvar cache = owner[ this.expando ];\n\t\treturn cache !== undefined && !jQuery.isEmptyObject( cache );\n\t}\n};\nvar dataPriv = new Data();\n\nvar dataUser = new Data();\n\n\n\n//\tImplementation Summary\n//\n//\t1. Enforce API surface and semantic compatibility with 1.9.x branch\n//\t2. Improve the module's maintainability by reducing the storage\n//\t\tpaths to a single mechanism.\n//\t3. Use the same single mechanism to support \"private\" and \"user\" data.\n//\t4. _Never_ expose \"private\" data to user code (TODO: Drop _data, _removeData)\n//\t5. Avoid exposing implementation details on user objects (eg. expando properties)\n//\t6. Provide a clear path for implementation upgrade to WeakMap in 2014\n\nvar rbrace = /^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,\n\trmultiDash = /[A-Z]/g;\n\nfunction getData( data ) {\n\tif ( data === \"true\" ) {\n\t\treturn true;\n\t}\n\n\tif ( data === \"false\" ) {\n\t\treturn false;\n\t}\n\n\tif ( data === \"null\" ) {\n\t\treturn null;\n\t}\n\n\t// Only convert to a number if it doesn't change the string\n\tif ( data === +data + \"\" ) {\n\t\treturn +data;\n\t}\n\n\tif ( rbrace.test( data ) ) {\n\t\treturn JSON.parse( data );\n\t}\n\n\treturn data;\n}\n\nfunction dataAttr( elem, key, data ) {\n\tvar name;\n\n\t// If nothing was found internally, try to fetch any\n\t// data from the HTML5 data-* attribute\n\tif ( data === undefined && elem.nodeType === 1 ) {\n\t\tname = \"data-\" + key.replace( rmultiDash, \"-$&\" ).toLowerCase();\n\t\tdata = elem.getAttribute( name );\n\n\t\tif ( typeof data === \"string\" ) {\n\t\t\ttry {\n\t\t\t\tdata = getData( data );\n\t\t\t} catch ( e ) {}\n\n\t\t\t// Make sure we set the data so it isn't changed later\n\t\t\tdataUser.set( elem, key, data );\n\t\t} else {\n\t\t\tdata = undefined;\n\t\t}\n\t}\n\treturn data;\n}\n\njQuery.extend( {\n\thasData: function( elem ) {\n\t\treturn dataUser.hasData( elem ) || dataPriv.hasData( elem );\n\t},\n\n\tdata: function( elem, name, data ) {\n\t\treturn dataUser.access( elem, name, data );\n\t},\n\n\tremoveData: function( elem, name ) {\n\t\tdataUser.remove( elem, name );\n\t},\n\n\t// TODO: Now that all calls to _data and _removeData have been replaced\n\t// with direct calls to dataPriv methods, these can be deprecated.\n\t_data: function( elem, name, data ) {\n\t\treturn dataPriv.access( elem, name, data );\n\t},\n\n\t_removeData: function( elem, name ) {\n\t\tdataPriv.remove( elem, name );\n\t}\n} );\n\njQuery.fn.extend( {\n\tdata: function( key, value ) {\n\t\tvar i, name, data,\n\t\t\telem = this[ 0 ],\n\t\t\tattrs = elem && elem.attributes;\n\n\t\t// Gets all values\n\t\tif ( key === undefined ) {\n\t\t\tif ( this.length ) {\n\t\t\t\tdata = dataUser.get( elem );\n\n\t\t\t\tif ( elem.nodeType === 1 && !dataPriv.get( elem, \"hasDataAttrs\" ) ) {\n\t\t\t\t\ti = attrs.length;\n\t\t\t\t\twhile ( i-- ) {\n\n\t\t\t\t\t\t// Support: IE 11 only\n\t\t\t\t\t\t// The attrs elements can be null (#14894)\n\t\t\t\t\t\tif ( attrs[ i ] ) {\n\t\t\t\t\t\t\tname = attrs[ i ].name;\n\t\t\t\t\t\t\tif ( name.indexOf( \"data-\" ) === 0 ) {\n\t\t\t\t\t\t\t\tname = camelCase( name.slice( 5 ) );\n\t\t\t\t\t\t\t\tdataAttr( elem, name, data[ name ] );\n\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\tdataPriv.set( elem, \"hasDataAttrs\", true );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn data;\n\t\t}\n\n\t\t// Sets multiple values\n\t\tif ( typeof key === \"object\" ) {\n\t\t\treturn this.each( function() {\n\t\t\t\tdataUser.set( this, key );\n\t\t\t} );\n\t\t}\n\n\t\treturn access( this, function( value ) {\n\t\t\tvar data;\n\n\t\t\t// The calling jQuery object (element matches) is not empty\n\t\t\t// (and therefore has an element appears at this[ 0 ]) and the\n\t\t\t// `value` parameter was not undefined. An empty jQuery object\n\t\t\t// will result in `undefined` for elem = this[ 0 ] which will\n\t\t\t// throw an exception if an attempt to read a data cache is made.\n\t\t\tif ( elem && value === undefined ) {\n\n\t\t\t\t// Attempt to get data from the cache\n\t\t\t\t// The key will always be camelCased in Data\n\t\t\t\tdata = dataUser.get( elem, key );\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// Attempt to \"discover\" the data in\n\t\t\t\t// HTML5 custom data-* attrs\n\t\t\t\tdata = dataAttr( elem, key );\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// We tried really hard, but the data doesn't exist.\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Set the data...\n\t\t\tthis.each( function() {\n\n\t\t\t\t// We always store the camelCased key\n\t\t\t\tdataUser.set( this, key, value );\n\t\t\t} );\n\t\t}, null, value, arguments.length > 1, null, true );\n\t},\n\n\tremoveData: function( key ) {\n\t\treturn this.each( function() {\n\t\t\tdataUser.remove( this, key );\n\t\t} );\n\t}\n} );\n\n\njQuery.extend( {\n\tqueue: function( elem, type, data ) {\n\t\tvar queue;\n\n\t\tif ( elem ) {\n\t\t\ttype = ( type || \"fx\" ) + \"queue\";\n\t\t\tqueue = dataPriv.get( elem, type );\n\n\t\t\t// Speed up dequeue by getting out quickly if this is just a lookup\n\t\t\tif ( data ) {\n\t\t\t\tif ( !queue || Array.isArray( data ) ) {\n\t\t\t\t\tqueue = dataPriv.access( elem, type, jQuery.makeArray( data ) );\n\t\t\t\t} else {\n\t\t\t\t\tqueue.push( data );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn queue || [];\n\t\t}\n\t},\n\n\tdequeue: function( elem, type ) {\n\t\ttype = type || \"fx\";\n\n\t\tvar queue = jQuery.queue( elem, type ),\n\t\t\tstartLength = queue.length,\n\t\t\tfn = queue.shift(),\n\t\t\thooks = jQuery._queueHooks( elem, type ),\n\t\t\tnext = function() {\n\t\t\t\tjQuery.dequeue( elem, type );\n\t\t\t};\n\n\t\t// If the fx queue is dequeued, always remove the progress sentinel\n\t\tif ( fn === \"inprogress\" ) {\n\t\t\tfn = queue.shift();\n\t\t\tstartLength--;\n\t\t}\n\n\t\tif ( fn ) {\n\n\t\t\t// Add a progress sentinel to prevent the fx queue from being\n\t\t\t// automatically dequeued\n\t\t\tif ( type === \"fx\" ) {\n\t\t\t\tqueue.unshift( \"inprogress\" );\n\t\t\t}\n\n\t\t\t// Clear up the last queue stop function\n\t\t\tdelete hooks.stop;\n\t\t\tfn.call( elem, next, hooks );\n\t\t}\n\n\t\tif ( !startLength && hooks ) {\n\t\t\thooks.empty.fire();\n\t\t}\n\t},\n\n\t// Not public - generate a queueHooks object, or return the current one\n\t_queueHooks: function( elem, type ) {\n\t\tvar key = type + \"queueHooks\";\n\t\treturn dataPriv.get( elem, key ) || dataPriv.access( elem, key, {\n\t\t\tempty: jQuery.Callbacks( \"once memory\" ).add( function() {\n\t\t\t\tdataPriv.remove( elem, [ type + \"queue\", key ] );\n\t\t\t} )\n\t\t} );\n\t}\n} );\n\njQuery.fn.extend( {\n\tqueue: function( type, data ) {\n\t\tvar setter = 2;\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tdata = type;\n\t\t\ttype = \"fx\";\n\t\t\tsetter--;\n\t\t}\n\n\t\tif ( arguments.length < setter ) {\n\t\t\treturn jQuery.queue( this[ 0 ], type );\n\t\t}\n\n\t\treturn data === undefined ?\n\t\t\tthis :\n\t\t\tthis.each( function() {\n\t\t\t\tvar queue = jQuery.queue( this, type, data );\n\n\t\t\t\t// Ensure a hooks for this queue\n\t\t\t\tjQuery._queueHooks( this, type );\n\n\t\t\t\tif ( type === \"fx\" && queue[ 0 ] !== \"inprogress\" ) {\n\t\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t\t}\n\t\t\t} );\n\t},\n\tdequeue: function( type ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.dequeue( this, type );\n\t\t} );\n\t},\n\tclearQueue: function( type ) {\n\t\treturn this.queue( type || \"fx\", [] );\n\t},\n\n\t// Get a promise resolved when queues of a certain type\n\t// are emptied (fx is the type by default)\n\tpromise: function( type, obj ) {\n\t\tvar tmp,\n\t\t\tcount = 1,\n\t\t\tdefer = jQuery.Deferred(),\n\t\t\telements = this,\n\t\t\ti = this.length,\n\t\t\tresolve = function() {\n\t\t\t\tif ( !( --count ) ) {\n\t\t\t\t\tdefer.resolveWith( elements, [ elements ] );\n\t\t\t\t}\n\t\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tobj = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\ttype = type || \"fx\";\n\n\t\twhile ( i-- ) {\n\t\t\ttmp = dataPriv.get( elements[ i ], type + \"queueHooks\" );\n\t\t\tif ( tmp && tmp.empty ) {\n\t\t\t\tcount++;\n\t\t\t\ttmp.empty.add( resolve );\n\t\t\t}\n\t\t}\n\t\tresolve();\n\t\treturn defer.promise( obj );\n\t}\n} );\nvar pnum = ( /[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/ ).source;\n\nvar rcssNum = new RegExp( \"^(?:([+-])=|)(\" + pnum + \")([a-z%]*)$\", \"i\" );\n\n\nvar cssExpand = [ \"Top\", \"Right\", \"Bottom\", \"Left\" ];\n\nvar documentElement = document.documentElement;\n\n\n\n\tvar isAttached = function( elem ) {\n\t\t\treturn jQuery.contains( elem.ownerDocument, elem );\n\t\t},\n\t\tcomposed = { composed: true };\n\n\t// Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only\n\t// Check attachment across shadow DOM boundaries when possible (gh-3504)\n\t// Support: iOS 10.0-10.2 only\n\t// Early iOS 10 versions support `attachShadow` but not `getRootNode`,\n\t// leading to errors. We need to check for `getRootNode`.\n\tif ( documentElement.getRootNode ) {\n\t\tisAttached = function( elem ) {\n\t\t\treturn jQuery.contains( elem.ownerDocument, elem ) ||\n\t\t\t\telem.getRootNode( composed ) === elem.ownerDocument;\n\t\t};\n\t}\nvar isHiddenWithinTree = function( elem, el ) {\n\n\t\t// isHiddenWithinTree might be called from jQuery#filter function;\n\t\t// in that case, element will be second argument\n\t\telem = el || elem;\n\n\t\t// Inline style trumps all\n\t\treturn elem.style.display === \"none\" ||\n\t\t\telem.style.display === \"\" &&\n\n\t\t\t// Otherwise, check computed style\n\t\t\t// Support: Firefox <=43 - 45\n\t\t\t// Disconnected elements can have computed display: none, so first confirm that elem is\n\t\t\t// in the document.\n\t\t\tisAttached( elem ) &&\n\n\t\t\tjQuery.css( elem, \"display\" ) === \"none\";\n\t};\n\n\n\nfunction adjustCSS( elem, prop, valueParts, tween ) {\n\tvar adjusted, scale,\n\t\tmaxIterations = 20,\n\t\tcurrentValue = tween ?\n\t\t\tfunction() {\n\t\t\t\treturn tween.cur();\n\t\t\t} :\n\t\t\tfunction() {\n\t\t\t\treturn jQuery.css( elem, prop, \"\" );\n\t\t\t},\n\t\tinitial = currentValue(),\n\t\tunit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" ),\n\n\t\t// Starting value computation is required for potential unit mismatches\n\t\tinitialInUnit = elem.nodeType &&\n\t\t\t( jQuery.cssNumber[ prop ] || unit !== \"px\" && +initial ) &&\n\t\t\trcssNum.exec( jQuery.css( elem, prop ) );\n\n\tif ( initialInUnit && initialInUnit[ 3 ] !== unit ) {\n\n\t\t// Support: Firefox <=54\n\t\t// Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144)\n\t\tinitial = initial / 2;\n\n\t\t// Trust units reported by jQuery.css\n\t\tunit = unit || initialInUnit[ 3 ];\n\n\t\t// Iteratively approximate from a nonzero starting point\n\t\tinitialInUnit = +initial || 1;\n\n\t\twhile ( maxIterations-- ) {\n\n\t\t\t// Evaluate and update our best guess (doubling guesses that zero out).\n\t\t\t// Finish if the scale equals or crosses 1 (making the old*new product non-positive).\n\t\t\tjQuery.style( elem, prop, initialInUnit + unit );\n\t\t\tif ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) {\n\t\t\t\tmaxIterations = 0;\n\t\t\t}\n\t\t\tinitialInUnit = initialInUnit / scale;\n\n\t\t}\n\n\t\tinitialInUnit = initialInUnit * 2;\n\t\tjQuery.style( elem, prop, initialInUnit + unit );\n\n\t\t// Make sure we update the tween properties later on\n\t\tvalueParts = valueParts || [];\n\t}\n\n\tif ( valueParts ) {\n\t\tinitialInUnit = +initialInUnit || +initial || 0;\n\n\t\t// Apply relative offset (+=/-=) if specified\n\t\tadjusted = valueParts[ 1 ] ?\n\t\t\tinitialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] :\n\t\t\t+valueParts[ 2 ];\n\t\tif ( tween ) {\n\t\t\ttween.unit = unit;\n\t\t\ttween.start = initialInUnit;\n\t\t\ttween.end = adjusted;\n\t\t}\n\t}\n\treturn adjusted;\n}\n\n\nvar defaultDisplayMap = {};\n\nfunction getDefaultDisplay( elem ) {\n\tvar temp,\n\t\tdoc = elem.ownerDocument,\n\t\tnodeName = elem.nodeName,\n\t\tdisplay = defaultDisplayMap[ nodeName ];\n\n\tif ( display ) {\n\t\treturn display;\n\t}\n\n\ttemp = doc.body.appendChild( doc.createElement( nodeName ) );\n\tdisplay = jQuery.css( temp, \"display\" );\n\n\ttemp.parentNode.removeChild( temp );\n\n\tif ( display === \"none\" ) {\n\t\tdisplay = \"block\";\n\t}\n\tdefaultDisplayMap[ nodeName ] = display;\n\n\treturn display;\n}\n\nfunction showHide( elements, show ) {\n\tvar display, elem,\n\t\tvalues = [],\n\t\tindex = 0,\n\t\tlength = elements.length;\n\n\t// Determine new display value for elements that need to change\n\tfor ( ; index < length; index++ ) {\n\t\telem = elements[ index ];\n\t\tif ( !elem.style ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tdisplay = elem.style.display;\n\t\tif ( show ) {\n\n\t\t\t// Since we force visibility upon cascade-hidden elements, an immediate (and slow)\n\t\t\t// check is required in this first loop unless we have a nonempty display value (either\n\t\t\t// inline or about-to-be-restored)\n\t\t\tif ( display === \"none\" ) {\n\t\t\t\tvalues[ index ] = dataPriv.get( elem, \"display\" ) || null;\n\t\t\t\tif ( !values[ index ] ) {\n\t\t\t\t\telem.style.display = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ( elem.style.display === \"\" && isHiddenWithinTree( elem ) ) {\n\t\t\t\tvalues[ index ] = getDefaultDisplay( elem );\n\t\t\t}\n\t\t} else {\n\t\t\tif ( display !== \"none\" ) {\n\t\t\t\tvalues[ index ] = \"none\";\n\n\t\t\t\t// Remember what we're overwriting\n\t\t\t\tdataPriv.set( elem, \"display\", display );\n\t\t\t}\n\t\t}\n\t}\n\n\t// Set the display of the elements in a second loop to avoid constant reflow\n\tfor ( index = 0; index < length; index++ ) {\n\t\tif ( values[ index ] != null ) {\n\t\t\telements[ index ].style.display = values[ index ];\n\t\t}\n\t}\n\n\treturn elements;\n}\n\njQuery.fn.extend( {\n\tshow: function() {\n\t\treturn showHide( this, true );\n\t},\n\thide: function() {\n\t\treturn showHide( this );\n\t},\n\ttoggle: function( state ) {\n\t\tif ( typeof state === \"boolean\" ) {\n\t\t\treturn state ? this.show() : this.hide();\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tif ( isHiddenWithinTree( this ) ) {\n\t\t\t\tjQuery( this ).show();\n\t\t\t} else {\n\t\t\t\tjQuery( this ).hide();\n\t\t\t}\n\t\t} );\n\t}\n} );\nvar rcheckableType = ( /^(?:checkbox|radio)$/i );\n\nvar rtagName = ( /<([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]*)/i );\n\nvar rscriptType = ( /^$|^module$|\\/(?:java|ecma)script/i );\n\n\n\n( function() {\n\tvar fragment = document.createDocumentFragment(),\n\t\tdiv = fragment.appendChild( document.createElement( \"div\" ) ),\n\t\tinput = document.createElement( \"input\" );\n\n\t// Support: Android 4.0 - 4.3 only\n\t// Check state lost if the name is set (#11217)\n\t// Support: Windows Web Apps (WWA)\n\t// `name` and `type` must use .setAttribute for WWA (#14901)\n\tinput.setAttribute( \"type\", \"radio\" );\n\tinput.setAttribute( \"checked\", \"checked\" );\n\tinput.setAttribute( \"name\", \"t\" );\n\n\tdiv.appendChild( input );\n\n\t// Support: Android <=4.1 only\n\t// Older WebKit doesn't clone checked state correctly in fragments\n\tsupport.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;\n\n\t// Support: IE <=11 only\n\t// Make sure textarea (and checkbox) defaultValue is properly cloned\n\tdiv.innerHTML = \"<textarea>x</textarea>\";\n\tsupport.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;\n\n\t// Support: IE <=9 only\n\t// IE <=9 replaces <option> tags with their contents when inserted outside of\n\t// the select element.\n\tdiv.innerHTML = \"<option></option>\";\n\tsupport.option = !!div.lastChild;\n} )();\n\n\n// We have to close these tags to support XHTML (#13200)\nvar wrapMap = {\n\n\t// XHTML parsers do not magically insert elements in the\n\t// same way that tag soup parsers do. So we cannot shorten\n\t// this by omitting <tbody> or other required elements.\n\tthead: [ 1, \"<table>\", \"</table>\" ],\n\tcol: [ 2, \"<table><colgroup>\", \"</colgroup></table>\" ],\n\ttr: [ 2, \"<table><tbody>\", \"</tbody></table>\" ],\n\ttd: [ 3, \"<table><tbody><tr>\", \"</tr></tbody></table>\" ],\n\n\t_default: [ 0, \"\", \"\" ]\n};\n\nwrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;\nwrapMap.th = wrapMap.td;\n\n// Support: IE <=9 only\nif ( !support.option ) {\n\twrapMap.optgroup = wrapMap.option = [ 1, \"<select multiple='multiple'>\", \"</select>\" ];\n}\n\n\nfunction getAll( context, tag ) {\n\n\t// Support: IE <=9 - 11 only\n\t// Use typeof to avoid zero-argument method invocation on host objects (#15151)\n\tvar ret;\n\n\tif ( typeof context.getElementsByTagName !== \"undefined\" ) {\n\t\tret = context.getElementsByTagName( tag || \"*\" );\n\n\t} else if ( typeof context.querySelectorAll !== \"undefined\" ) {\n\t\tret = context.querySelectorAll( tag || \"*\" );\n\n\t} else {\n\t\tret = [];\n\t}\n\n\tif ( tag === undefined || tag && nodeName( context, tag ) ) {\n\t\treturn jQuery.merge( [ context ], ret );\n\t}\n\n\treturn ret;\n}\n\n\n// Mark scripts as having already been evaluated\nfunction setGlobalEval( elems, refElements ) {\n\tvar i = 0,\n\t\tl = elems.length;\n\n\tfor ( ; i < l; i++ ) {\n\t\tdataPriv.set(\n\t\t\telems[ i ],\n\t\t\t\"globalEval\",\n\t\t\t!refElements || dataPriv.get( refElements[ i ], \"globalEval\" )\n\t\t);\n\t}\n}\n\n\nvar rhtml = /<|&#?\\w+;/;\n\nfunction buildFragment( elems, context, scripts, selection, ignored ) {\n\tvar elem, tmp, tag, wrap, attached, j,\n\t\tfragment = context.createDocumentFragment(),\n\t\tnodes = [],\n\t\ti = 0,\n\t\tl = elems.length;\n\n\tfor ( ; i < l; i++ ) {\n\t\telem = elems[ i ];\n\n\t\tif ( elem || elem === 0 ) {\n\n\t\t\t// Add nodes directly\n\t\t\tif ( toType( elem ) === \"object\" ) {\n\n\t\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\tjQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );\n\n\t\t\t// Convert non-html into a text node\n\t\t\t} else if ( !rhtml.test( elem ) ) {\n\t\t\t\tnodes.push( context.createTextNode( elem ) );\n\n\t\t\t// Convert html into DOM nodes\n\t\t\t} else {\n\t\t\t\ttmp = tmp || fragment.appendChild( context.createElement( \"div\" ) );\n\n\t\t\t\t// Deserialize a standard representation\n\t\t\t\ttag = ( rtagName.exec( elem ) || [ \"\", \"\" ] )[ 1 ].toLowerCase();\n\t\t\t\twrap = wrapMap[ tag ] || wrapMap._default;\n\t\t\t\ttmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];\n\n\t\t\t\t// Descend through wrappers to the right content\n\t\t\t\tj = wrap[ 0 ];\n\t\t\t\twhile ( j-- ) {\n\t\t\t\t\ttmp = tmp.lastChild;\n\t\t\t\t}\n\n\t\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\tjQuery.merge( nodes, tmp.childNodes );\n\n\t\t\t\t// Remember the top-level container\n\t\t\t\ttmp = fragment.firstChild;\n\n\t\t\t\t// Ensure the created nodes are orphaned (#12392)\n\t\t\t\ttmp.textContent = \"\";\n\t\t\t}\n\t\t}\n\t}\n\n\t// Remove wrapper from fragment\n\tfragment.textContent = \"\";\n\n\ti = 0;\n\twhile ( ( elem = nodes[ i++ ] ) ) {\n\n\t\t// Skip elements already in the context collection (trac-4087)\n\t\tif ( selection && jQuery.inArray( elem, selection ) > -1 ) {\n\t\t\tif ( ignored ) {\n\t\t\t\tignored.push( elem );\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tattached = isAttached( elem );\n\n\t\t// Append to fragment\n\t\ttmp = getAll( fragment.appendChild( elem ), \"script\" );\n\n\t\t// Preserve script evaluation history\n\t\tif ( attached ) {\n\t\t\tsetGlobalEval( tmp );\n\t\t}\n\n\t\t// Capture executables\n\t\tif ( scripts ) {\n\t\t\tj = 0;\n\t\t\twhile ( ( elem = tmp[ j++ ] ) ) {\n\t\t\t\tif ( rscriptType.test( elem.type || \"\" ) ) {\n\t\t\t\t\tscripts.push( elem );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn fragment;\n}\n\n\nvar rtypenamespace = /^([^.]*)(?:\\.(.+)|)/;\n\nfunction returnTrue() {\n\treturn true;\n}\n\nfunction returnFalse() {\n\treturn false;\n}\n\n// Support: IE <=9 - 11+\n// focus() and blur() are asynchronous, except when they are no-op.\n// So expect focus to be synchronous when the element is already active,\n// and blur to be synchronous when the element is not already active.\n// (focus and blur are always synchronous in other supported browsers,\n// this just defines when we can count on it).\nfunction expectSync( elem, type ) {\n\treturn ( elem === safeActiveElement() ) === ( type === \"focus\" );\n}\n\n// Support: IE <=9 only\n// Accessing document.activeElement can throw unexpectedly\n// https://bugs.jquery.com/ticket/13393\nfunction safeActiveElement() {\n\ttry {\n\t\treturn document.activeElement;\n\t} catch ( err ) { }\n}\n\nfunction on( elem, types, selector, data, fn, one ) {\n\tvar origFn, type;\n\n\t// Types can be a map of types/handlers\n\tif ( typeof types === \"object\" ) {\n\n\t\t// ( types-Object, selector, data )\n\t\tif ( typeof selector !== \"string\" ) {\n\n\t\t\t// ( types-Object, data )\n\t\t\tdata = data || selector;\n\t\t\tselector = undefined;\n\t\t}\n\t\tfor ( type in types ) {\n\t\t\ton( elem, type, selector, data, types[ type ], one );\n\t\t}\n\t\treturn elem;\n\t}\n\n\tif ( data == null && fn == null ) {\n\n\t\t// ( types, fn )\n\t\tfn = selector;\n\t\tdata = selector = undefined;\n\t} else if ( fn == null ) {\n\t\tif ( typeof selector === \"string\" ) {\n\n\t\t\t// ( types, selector, fn )\n\t\t\tfn = data;\n\t\t\tdata = undefined;\n\t\t} else {\n\n\t\t\t// ( types, data, fn )\n\t\t\tfn = data;\n\t\t\tdata = selector;\n\t\t\tselector = undefined;\n\t\t}\n\t}\n\tif ( fn === false ) {\n\t\tfn = returnFalse;\n\t} else if ( !fn ) {\n\t\treturn elem;\n\t}\n\n\tif ( one === 1 ) {\n\t\torigFn = fn;\n\t\tfn = function( event ) {\n\n\t\t\t// Can use an empty set, since event contains the info\n\t\t\tjQuery().off( event );\n\t\t\treturn origFn.apply( this, arguments );\n\t\t};\n\n\t\t// Use same guid so caller can remove using origFn\n\t\tfn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );\n\t}\n\treturn elem.each( function() {\n\t\tjQuery.event.add( this, types, fn, data, selector );\n\t} );\n}\n\n/*\n * Helper functions for managing events -- not part of the public interface.\n * Props to Dean Edwards' addEvent library for many of the ideas.\n */\njQuery.event = {\n\n\tglobal: {},\n\n\tadd: function( elem, types, handler, data, selector ) {\n\n\t\tvar handleObjIn, eventHandle, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\telemData = dataPriv.get( elem );\n\n\t\t// Only attach events to objects that accept data\n\t\tif ( !acceptData( elem ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Caller can pass in an object of custom data in lieu of the handler\n\t\tif ( handler.handler ) {\n\t\t\thandleObjIn = handler;\n\t\t\thandler = handleObjIn.handler;\n\t\t\tselector = handleObjIn.selector;\n\t\t}\n\n\t\t// Ensure that invalid selectors throw exceptions at attach time\n\t\t// Evaluate against documentElement in case elem is a non-element node (e.g., document)\n\t\tif ( selector ) {\n\t\t\tjQuery.find.matchesSelector( documentElement, selector );\n\t\t}\n\n\t\t// Make sure that the handler has a unique ID, used to find/remove it later\n\t\tif ( !handler.guid ) {\n\t\t\thandler.guid = jQuery.guid++;\n\t\t}\n\n\t\t// Init the element's event structure and main handler, if this is the first\n\t\tif ( !( events = elemData.events ) ) {\n\t\t\tevents = elemData.events = Object.create( null );\n\t\t}\n\t\tif ( !( eventHandle = elemData.handle ) ) {\n\t\t\teventHandle = elemData.handle = function( e ) {\n\n\t\t\t\t// Discard the second event of a jQuery.event.trigger() and\n\t\t\t\t// when an event is called after a page has unloaded\n\t\t\t\treturn typeof jQuery !== \"undefined\" && jQuery.event.triggered !== e.type ?\n\t\t\t\t\tjQuery.event.dispatch.apply( elem, arguments ) : undefined;\n\t\t\t};\n\t\t}\n\n\t\t// Handle multiple events separated by a space\n\t\ttypes = ( types || \"\" ).match( rnothtmlwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[ t ] ) || [];\n\t\t\ttype = origType = tmp[ 1 ];\n\t\t\tnamespaces = ( tmp[ 2 ] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// There *must* be a type, no attaching namespace-only handlers\n\t\t\tif ( !type ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// If event changes its type, use the special event handlers for the changed type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// If selector defined, determine special event api type, otherwise given type\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\n\t\t\t// Update special based on newly reset type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// handleObj is passed to all event handlers\n\t\t\thandleObj = jQuery.extend( {\n\t\t\t\ttype: type,\n\t\t\t\torigType: origType,\n\t\t\t\tdata: data,\n\t\t\t\thandler: handler,\n\t\t\t\tguid: handler.guid,\n\t\t\t\tselector: selector,\n\t\t\t\tneedsContext: selector && jQuery.expr.match.needsContext.test( selector ),\n\t\t\t\tnamespace: namespaces.join( \".\" )\n\t\t\t}, handleObjIn );\n\n\t\t\t// Init the event handler queue if we're the first\n\t\t\tif ( !( handlers = events[ type ] ) ) {\n\t\t\t\thandlers = events[ type ] = [];\n\t\t\t\thandlers.delegateCount = 0;\n\n\t\t\t\t// Only use addEventListener if the special events handler returns false\n\t\t\t\tif ( !special.setup ||\n\t\t\t\t\tspecial.setup.call( elem, data, namespaces, eventHandle ) === false ) {\n\n\t\t\t\t\tif ( elem.addEventListener ) {\n\t\t\t\t\t\telem.addEventListener( type, eventHandle );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( special.add ) {\n\t\t\t\tspecial.add.call( elem, handleObj );\n\n\t\t\t\tif ( !handleObj.handler.guid ) {\n\t\t\t\t\thandleObj.handler.guid = handler.guid;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add to the element's handler list, delegates in front\n\t\t\tif ( selector ) {\n\t\t\t\thandlers.splice( handlers.delegateCount++, 0, handleObj );\n\t\t\t} else {\n\t\t\t\thandlers.push( handleObj );\n\t\t\t}\n\n\t\t\t// Keep track of which events have ever been used, for event optimization\n\t\t\tjQuery.event.global[ type ] = true;\n\t\t}\n\n\t},\n\n\t// Detach an event or set of events from an element\n\tremove: function( elem, types, handler, selector, mappedTypes ) {\n\n\t\tvar j, origCount, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\telemData = dataPriv.hasData( elem ) && dataPriv.get( elem );\n\n\t\tif ( !elemData || !( events = elemData.events ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Once for each type.namespace in types; type may be omitted\n\t\ttypes = ( types || \"\" ).match( rnothtmlwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[ t ] ) || [];\n\t\t\ttype = origType = tmp[ 1 ];\n\t\t\tnamespaces = ( tmp[ 2 ] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// Unbind all events (on this namespace, if provided) for the element\n\t\t\tif ( !type ) {\n\t\t\t\tfor ( type in events ) {\n\t\t\t\t\tjQuery.event.remove( elem, type + types[ t ], handler, selector, true );\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\t\t\thandlers = events[ type ] || [];\n\t\t\ttmp = tmp[ 2 ] &&\n\t\t\t\tnew RegExp( \"(^|\\\\.)\" + namespaces.join( \"\\\\.(?:.*\\\\.|)\" ) + \"(\\\\.|$)\" );\n\n\t\t\t// Remove matching events\n\t\t\torigCount = j = handlers.length;\n\t\t\twhile ( j-- ) {\n\t\t\t\thandleObj = handlers[ j ];\n\n\t\t\t\tif ( ( mappedTypes || origType === handleObj.origType ) &&\n\t\t\t\t\t( !handler || handler.guid === handleObj.guid ) &&\n\t\t\t\t\t( !tmp || tmp.test( handleObj.namespace ) ) &&\n\t\t\t\t\t( !selector || selector === handleObj.selector ||\n\t\t\t\t\t\tselector === \"**\" && handleObj.selector ) ) {\n\t\t\t\t\thandlers.splice( j, 1 );\n\n\t\t\t\t\tif ( handleObj.selector ) {\n\t\t\t\t\t\thandlers.delegateCount--;\n\t\t\t\t\t}\n\t\t\t\t\tif ( special.remove ) {\n\t\t\t\t\t\tspecial.remove.call( elem, handleObj );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Remove generic event handler if we removed something and no more handlers exist\n\t\t\t// (avoids potential for endless recursion during removal of special event handlers)\n\t\t\tif ( origCount && !handlers.length ) {\n\t\t\t\tif ( !special.teardown ||\n\t\t\t\t\tspecial.teardown.call( elem, namespaces, elemData.handle ) === false ) {\n\n\t\t\t\t\tjQuery.removeEvent( elem, type, elemData.handle );\n\t\t\t\t}\n\n\t\t\t\tdelete events[ type ];\n\t\t\t}\n\t\t}\n\n\t\t// Remove data and the expando if it's no longer used\n\t\tif ( jQuery.isEmptyObject( events ) ) {\n\t\t\tdataPriv.remove( elem, \"handle events\" );\n\t\t}\n\t},\n\n\tdispatch: function( nativeEvent ) {\n\n\t\tvar i, j, ret, matched, handleObj, handlerQueue,\n\t\t\targs = new Array( arguments.length ),\n\n\t\t\t// Make a writable jQuery.Event from the native event object\n\t\t\tevent = jQuery.event.fix( nativeEvent ),\n\n\t\t\thandlers = (\n\t\t\t\tdataPriv.get( this, \"events\" ) || Object.create( null )\n\t\t\t)[ event.type ] || [],\n\t\t\tspecial = jQuery.event.special[ event.type ] || {};\n\n\t\t// Use the fix-ed jQuery.Event rather than the (read-only) native event\n\t\targs[ 0 ] = event;\n\n\t\tfor ( i = 1; i < arguments.length; i++ ) {\n\t\t\targs[ i ] = arguments[ i ];\n\t\t}\n\n\t\tevent.delegateTarget = this;\n\n\t\t// Call the preDispatch hook for the mapped type, and let it bail if desired\n\t\tif ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine handlers\n\t\thandlerQueue = jQuery.event.handlers.call( this, event, handlers );\n\n\t\t// Run delegates first; they may want to stop propagation beneath us\n\t\ti = 0;\n\t\twhile ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {\n\t\t\tevent.currentTarget = matched.elem;\n\n\t\t\tj = 0;\n\t\t\twhile ( ( handleObj = matched.handlers[ j++ ] ) &&\n\t\t\t\t!event.isImmediatePropagationStopped() ) {\n\n\t\t\t\t// If the event is namespaced, then each handler is only invoked if it is\n\t\t\t\t// specially universal or its namespaces are a superset of the event's.\n\t\t\t\tif ( !event.rnamespace || handleObj.namespace === false ||\n\t\t\t\t\tevent.rnamespace.test( handleObj.namespace ) ) {\n\n\t\t\t\t\tevent.handleObj = handleObj;\n\t\t\t\t\tevent.data = handleObj.data;\n\n\t\t\t\t\tret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||\n\t\t\t\t\t\thandleObj.handler ).apply( matched.elem, args );\n\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\tif ( ( event.result = ret ) === false ) {\n\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\tevent.stopPropagation();\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}\n\n\t\t// Call the postDispatch hook for the mapped type\n\t\tif ( special.postDispatch ) {\n\t\t\tspecial.postDispatch.call( this, event );\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\thandlers: function( event, handlers ) {\n\t\tvar i, handleObj, sel, matchedHandlers, matchedSelectors,\n\t\t\thandlerQueue = [],\n\t\t\tdelegateCount = handlers.delegateCount,\n\t\t\tcur = event.target;\n\n\t\t// Find delegate handlers\n\t\tif ( delegateCount &&\n\n\t\t\t// Support: IE <=9\n\t\t\t// Black-hole SVG <use> instance trees (trac-13180)\n\t\t\tcur.nodeType &&\n\n\t\t\t// Support: Firefox <=42\n\t\t\t// Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861)\n\t\t\t// https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click\n\t\t\t// Support: IE 11 only\n\t\t\t// ...but not arrow key \"clicks\" of radio inputs, which can have `button` -1 (gh-2343)\n\t\t\t!( event.type === \"click\" && event.button >= 1 ) ) {\n\n\t\t\tfor ( ; cur !== this; cur = cur.parentNode || this ) {\n\n\t\t\t\t// Don't check non-elements (#13208)\n\t\t\t\t// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)\n\t\t\t\tif ( cur.nodeType === 1 && !( event.type === \"click\" && cur.disabled === true ) ) {\n\t\t\t\t\tmatchedHandlers = [];\n\t\t\t\t\tmatchedSelectors = {};\n\t\t\t\t\tfor ( i = 0; i < delegateCount; i++ ) {\n\t\t\t\t\t\thandleObj = handlers[ i ];\n\n\t\t\t\t\t\t// Don't conflict with Object.prototype properties (#13203)\n\t\t\t\t\t\tsel = handleObj.selector + \" \";\n\n\t\t\t\t\t\tif ( matchedSelectors[ sel ] === undefined ) {\n\t\t\t\t\t\t\tmatchedSelectors[ sel ] = handleObj.needsContext ?\n\t\t\t\t\t\t\t\tjQuery( sel, this ).index( cur ) > -1 :\n\t\t\t\t\t\t\t\tjQuery.find( sel, this, null, [ cur ] ).length;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( matchedSelectors[ sel ] ) {\n\t\t\t\t\t\t\tmatchedHandlers.push( handleObj );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( matchedHandlers.length ) {\n\t\t\t\t\t\thandlerQueue.push( { elem: cur, handlers: matchedHandlers } );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Add the remaining (directly-bound) handlers\n\t\tcur = this;\n\t\tif ( delegateCount < handlers.length ) {\n\t\t\thandlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } );\n\t\t}\n\n\t\treturn handlerQueue;\n\t},\n\n\taddProp: function( name, hook ) {\n\t\tObject.defineProperty( jQuery.Event.prototype, name, {\n\t\t\tenumerable: true,\n\t\t\tconfigurable: true,\n\n\t\t\tget: isFunction( hook ) ?\n\t\t\t\tfunction() {\n\t\t\t\t\tif ( this.originalEvent ) {\n\t\t\t\t\t\treturn hook( this.originalEvent );\n\t\t\t\t\t}\n\t\t\t\t} :\n\t\t\t\tfunction() {\n\t\t\t\t\tif ( this.originalEvent ) {\n\t\t\t\t\t\treturn this.originalEvent[ name ];\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\tset: function( value ) {\n\t\t\t\tObject.defineProperty( this, name, {\n\t\t\t\t\tenumerable: true,\n\t\t\t\t\tconfigurable: true,\n\t\t\t\t\twritable: true,\n\t\t\t\t\tvalue: value\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\t},\n\n\tfix: function( originalEvent ) {\n\t\treturn originalEvent[ jQuery.expando ] ?\n\t\t\toriginalEvent :\n\t\t\tnew jQuery.Event( originalEvent );\n\t},\n\n\tspecial: {\n\t\tload: {\n\n\t\t\t// Prevent triggered image.load events from bubbling to window.load\n\t\t\tnoBubble: true\n\t\t},\n\t\tclick: {\n\n\t\t\t// Utilize native event to ensure correct state for checkable inputs\n\t\t\tsetup: function( data ) {\n\n\t\t\t\t// For mutual compressibility with _default, replace `this` access with a local var.\n\t\t\t\t// `|| data` is dead code meant only to preserve the variable through minification.\n\t\t\t\tvar el = this || data;\n\n\t\t\t\t// Claim the first handler\n\t\t\t\tif ( rcheckableType.test( el.type ) &&\n\t\t\t\t\tel.click && nodeName( el, \"input\" ) ) {\n\n\t\t\t\t\t// dataPriv.set( el, \"click\", ... )\n\t\t\t\t\tleverageNative( el, \"click\", returnTrue );\n\t\t\t\t}\n\n\t\t\t\t// Return false to allow normal processing in the caller\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\ttrigger: function( data ) {\n\n\t\t\t\t// For mutual compressibility with _default, replace `this` access with a local var.\n\t\t\t\t// `|| data` is dead code meant only to preserve the variable through minification.\n\t\t\t\tvar el = this || data;\n\n\t\t\t\t// Force setup before triggering a click\n\t\t\t\tif ( rcheckableType.test( el.type ) &&\n\t\t\t\t\tel.click && nodeName( el, \"input\" ) ) {\n\n\t\t\t\t\tleverageNative( el, \"click\" );\n\t\t\t\t}\n\n\t\t\t\t// Return non-false to allow normal event-path propagation\n\t\t\t\treturn true;\n\t\t\t},\n\n\t\t\t// For cross-browser consistency, suppress native .click() on links\n\t\t\t// Also prevent it if we're currently inside a leveraged native-event stack\n\t\t\t_default: function( event ) {\n\t\t\t\tvar target = event.target;\n\t\t\t\treturn rcheckableType.test( target.type ) &&\n\t\t\t\t\ttarget.click && nodeName( target, \"input\" ) &&\n\t\t\t\t\tdataPriv.get( target, \"click\" ) ||\n\t\t\t\t\tnodeName( target, \"a\" );\n\t\t\t}\n\t\t},\n\n\t\tbeforeunload: {\n\t\t\tpostDispatch: function( event ) {\n\n\t\t\t\t// Support: Firefox 20+\n\t\t\t\t// Firefox doesn't alert if the returnValue field is not set.\n\t\t\t\tif ( event.result !== undefined && event.originalEvent ) {\n\t\t\t\t\tevent.originalEvent.returnValue = event.result;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n};\n\n// Ensure the presence of an event listener that handles manually-triggered\n// synthetic events by interrupting progress until reinvoked in response to\n// *native* events that it fires directly, ensuring that state changes have\n// already occurred before other listeners are invoked.\nfunction leverageNative( el, type, expectSync ) {\n\n\t// Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add\n\tif ( !expectSync ) {\n\t\tif ( dataPriv.get( el, type ) === undefined ) {\n\t\t\tjQuery.event.add( el, type, returnTrue );\n\t\t}\n\t\treturn;\n\t}\n\n\t// Register the controller as a special universal handler for all event namespaces\n\tdataPriv.set( el, type, false );\n\tjQuery.event.add( el, type, {\n\t\tnamespace: false,\n\t\thandler: function( event ) {\n\t\t\tvar notAsync, result,\n\t\t\t\tsaved = dataPriv.get( this, type );\n\n\t\t\tif ( ( event.isTrigger & 1 ) && this[ type ] ) {\n\n\t\t\t\t// Interrupt processing of the outer synthetic .trigger()ed event\n\t\t\t\t// Saved data should be false in such cases, but might be a leftover capture object\n\t\t\t\t// from an async native handler (gh-4350)\n\t\t\t\tif ( !saved.length ) {\n\n\t\t\t\t\t// Store arguments for use when handling the inner native event\n\t\t\t\t\t// There will always be at least one argument (an event object), so this array\n\t\t\t\t\t// will not be confused with a leftover capture object.\n\t\t\t\t\tsaved = slice.call( arguments );\n\t\t\t\t\tdataPriv.set( this, type, saved );\n\n\t\t\t\t\t// Trigger the native event and capture its result\n\t\t\t\t\t// Support: IE <=9 - 11+\n\t\t\t\t\t// focus() and blur() are asynchronous\n\t\t\t\t\tnotAsync = expectSync( this, type );\n\t\t\t\t\tthis[ type ]();\n\t\t\t\t\tresult = dataPriv.get( this, type );\n\t\t\t\t\tif ( saved !== result || notAsync ) {\n\t\t\t\t\t\tdataPriv.set( this, type, false );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult = {};\n\t\t\t\t\t}\n\t\t\t\t\tif ( saved !== result ) {\n\n\t\t\t\t\t\t// Cancel the outer synthetic event\n\t\t\t\t\t\tevent.stopImmediatePropagation();\n\t\t\t\t\t\tevent.preventDefault();\n\n\t\t\t\t\t\t// Support: Chrome 86+\n\t\t\t\t\t\t// In Chrome, if an element having a focusout handler is blurred by\n\t\t\t\t\t\t// clicking outside of it, it invokes the handler synchronously. If\n\t\t\t\t\t\t// that handler calls `.remove()` on the element, the data is cleared,\n\t\t\t\t\t\t// leaving `result` undefined. We need to guard against this.\n\t\t\t\t\t\treturn result && result.value;\n\t\t\t\t\t}\n\n\t\t\t\t// If this is an inner synthetic event for an event with a bubbling surrogate\n\t\t\t\t// (focus or blur), assume that the surrogate already propagated from triggering the\n\t\t\t\t// native event and prevent that from happening again here.\n\t\t\t\t// This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the\n\t\t\t\t// bubbling surrogate propagates *after* the non-bubbling base), but that seems\n\t\t\t\t// less bad than duplication.\n\t\t\t\t} else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) {\n\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t}\n\n\t\t\t// If this is a native event triggered above, everything is now in order\n\t\t\t// Fire an inner synthetic event with the original arguments\n\t\t\t} else if ( saved.length ) {\n\n\t\t\t\t// ...and capture the result\n\t\t\t\tdataPriv.set( this, type, {\n\t\t\t\t\tvalue: jQuery.event.trigger(\n\n\t\t\t\t\t\t// Support: IE <=9 - 11+\n\t\t\t\t\t\t// Extend with the prototype to reset the above stopImmediatePropagation()\n\t\t\t\t\t\tjQuery.extend( saved[ 0 ], jQuery.Event.prototype ),\n\t\t\t\t\t\tsaved.slice( 1 ),\n\t\t\t\t\t\tthis\n\t\t\t\t\t)\n\t\t\t\t} );\n\n\t\t\t\t// Abort handling of the native event\n\t\t\t\tevent.stopImmediatePropagation();\n\t\t\t}\n\t\t}\n\t} );\n}\n\njQuery.removeEvent = function( elem, type, handle ) {\n\n\t// This \"if\" is needed for plain objects\n\tif ( elem.removeEventListener ) {\n\t\telem.removeEventListener( type, handle );\n\t}\n};\n\njQuery.Event = function( src, props ) {\n\n\t// Allow instantiation without the 'new' keyword\n\tif ( !( this instanceof jQuery.Event ) ) {\n\t\treturn new jQuery.Event( src, props );\n\t}\n\n\t// Event object\n\tif ( src && src.type ) {\n\t\tthis.originalEvent = src;\n\t\tthis.type = src.type;\n\n\t\t// Events bubbling up the document may have been marked as prevented\n\t\t// by a handler lower down the tree; reflect the correct value.\n\t\tthis.isDefaultPrevented = src.defaultPrevented ||\n\t\t\t\tsrc.defaultPrevented === undefined &&\n\n\t\t\t\t// Support: Android <=2.3 only\n\t\t\t\tsrc.returnValue === false ?\n\t\t\treturnTrue :\n\t\t\treturnFalse;\n\n\t\t// Create target properties\n\t\t// Support: Safari <=6 - 7 only\n\t\t// Target should not be a text node (#504, #13143)\n\t\tthis.target = ( src.target && src.target.nodeType === 3 ) ?\n\t\t\tsrc.target.parentNode :\n\t\t\tsrc.target;\n\n\t\tthis.currentTarget = src.currentTarget;\n\t\tthis.relatedTarget = src.relatedTarget;\n\n\t// Event type\n\t} else {\n\t\tthis.type = src;\n\t}\n\n\t// Put explicitly provided properties onto the event object\n\tif ( props ) {\n\t\tjQuery.extend( this, props );\n\t}\n\n\t// Create a timestamp if incoming event doesn't have one\n\tthis.timeStamp = src && src.timeStamp || Date.now();\n\n\t// Mark it as fixed\n\tthis[ jQuery.expando ] = true;\n};\n\n// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding\n// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html\njQuery.Event.prototype = {\n\tconstructor: jQuery.Event,\n\tisDefaultPrevented: returnFalse,\n\tisPropagationStopped: returnFalse,\n\tisImmediatePropagationStopped: returnFalse,\n\tisSimulated: false,\n\n\tpreventDefault: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isDefaultPrevented = returnTrue;\n\n\t\tif ( e && !this.isSimulated ) {\n\t\t\te.preventDefault();\n\t\t}\n\t},\n\tstopPropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isPropagationStopped = returnTrue;\n\n\t\tif ( e && !this.isSimulated ) {\n\t\t\te.stopPropagation();\n\t\t}\n\t},\n\tstopImmediatePropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isImmediatePropagationStopped = returnTrue;\n\n\t\tif ( e && !this.isSimulated ) {\n\t\t\te.stopImmediatePropagation();\n\t\t}\n\n\t\tthis.stopPropagation();\n\t}\n};\n\n// Includes all common event props including KeyEvent and MouseEvent specific props\njQuery.each( {\n\taltKey: true,\n\tbubbles: true,\n\tcancelable: true,\n\tchangedTouches: true,\n\tctrlKey: true,\n\tdetail: true,\n\teventPhase: true,\n\tmetaKey: true,\n\tpageX: true,\n\tpageY: true,\n\tshiftKey: true,\n\tview: true,\n\t\"char\": true,\n\tcode: true,\n\tcharCode: true,\n\tkey: true,\n\tkeyCode: true,\n\tbutton: true,\n\tbuttons: true,\n\tclientX: true,\n\tclientY: true,\n\toffsetX: true,\n\toffsetY: true,\n\tpointerId: true,\n\tpointerType: true,\n\tscreenX: true,\n\tscreenY: true,\n\ttargetTouches: true,\n\ttoElement: true,\n\ttouches: true,\n\twhich: true\n}, jQuery.event.addProp );\n\njQuery.each( { focus: \"focusin\", blur: \"focusout\" }, function( type, delegateType ) {\n\tjQuery.event.special[ type ] = {\n\n\t\t// Utilize native event if possible so blur/focus sequence is correct\n\t\tsetup: function() {\n\n\t\t\t// Claim the first handler\n\t\t\t// dataPriv.set( this, \"focus\", ... )\n\t\t\t// dataPriv.set( this, \"blur\", ... )\n\t\t\tleverageNative( this, type, expectSync );\n\n\t\t\t// Return false to allow normal processing in the caller\n\t\t\treturn false;\n\t\t},\n\t\ttrigger: function() {\n\n\t\t\t// Force setup before trigger\n\t\t\tleverageNative( this, type );\n\n\t\t\t// Return non-false to allow normal event-path propagation\n\t\t\treturn true;\n\t\t},\n\n\t\t// Suppress native focus or blur as it's already being fired\n\t\t// in leverageNative.\n\t\t_default: function() {\n\t\t\treturn true;\n\t\t},\n\n\t\tdelegateType: delegateType\n\t};\n} );\n\n// Create mouseenter/leave events using mouseover/out and event-time checks\n// so that event delegation works in jQuery.\n// Do the same for pointerenter/pointerleave and pointerover/pointerout\n//\n// Support: Safari 7 only\n// Safari sends mouseenter too often; see:\n// https://bugs.chromium.org/p/chromium/issues/detail?id=470258\n// for the description of the bug (it existed in older Chrome versions as well).\njQuery.each( {\n\tmouseenter: \"mouseover\",\n\tmouseleave: \"mouseout\",\n\tpointerenter: \"pointerover\",\n\tpointerleave: \"pointerout\"\n}, function( orig, fix ) {\n\tjQuery.event.special[ orig ] = {\n\t\tdelegateType: fix,\n\t\tbindType: fix,\n\n\t\thandle: function( event ) {\n\t\t\tvar ret,\n\t\t\t\ttarget = this,\n\t\t\t\trelated = event.relatedTarget,\n\t\t\t\thandleObj = event.handleObj;\n\n\t\t\t// For mouseenter/leave call the handler if related is outside the target.\n\t\t\t// NB: No relatedTarget if the mouse left/entered the browser window\n\t\t\tif ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) {\n\t\t\t\tevent.type = handleObj.origType;\n\t\t\t\tret = handleObj.handler.apply( this, arguments );\n\t\t\t\tevent.type = fix;\n\t\t\t}\n\t\t\treturn ret;\n\t\t}\n\t};\n} );\n\njQuery.fn.extend( {\n\n\ton: function( types, selector, data, fn ) {\n\t\treturn on( this, types, selector, data, fn );\n\t},\n\tone: function( types, selector, data, fn ) {\n\t\treturn on( this, types, selector, data, fn, 1 );\n\t},\n\toff: function( types, selector, fn ) {\n\t\tvar handleObj, type;\n\t\tif ( types && types.preventDefault && types.handleObj ) {\n\n\t\t\t// ( event )  dispatched jQuery.Event\n\t\t\thandleObj = types.handleObj;\n\t\t\tjQuery( types.delegateTarget ).off(\n\t\t\t\thandleObj.namespace ?\n\t\t\t\t\thandleObj.origType + \".\" + handleObj.namespace :\n\t\t\t\t\thandleObj.origType,\n\t\t\t\thandleObj.selector,\n\t\t\t\thandleObj.handler\n\t\t\t);\n\t\t\treturn this;\n\t\t}\n\t\tif ( typeof types === \"object\" ) {\n\n\t\t\t// ( types-object [, selector] )\n\t\t\tfor ( type in types ) {\n\t\t\t\tthis.off( type, selector, types[ type ] );\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\t\tif ( selector === false || typeof selector === \"function\" ) {\n\n\t\t\t// ( types [, fn] )\n\t\t\tfn = selector;\n\t\t\tselector = undefined;\n\t\t}\n\t\tif ( fn === false ) {\n\t\t\tfn = returnFalse;\n\t\t}\n\t\treturn this.each( function() {\n\t\t\tjQuery.event.remove( this, types, fn, selector );\n\t\t} );\n\t}\n} );\n\n\nvar\n\n\t// Support: IE <=10 - 11, Edge 12 - 13 only\n\t// In IE/Edge using regex groups here causes severe slowdowns.\n\t// See https://connect.microsoft.com/IE/feedback/details/1736512/\n\trnoInnerhtml = /<script|<style|<link/i,\n\n\t// checked=\"checked\" or checked\n\trchecked = /checked\\s*(?:[^=]|=\\s*.checked.)/i,\n\trcleanScript = /^\\s*<!(?:\\[CDATA\\[|--)|(?:\\]\\]|--)>\\s*$/g;\n\n// Prefer a tbody over its parent table for containing new rows\nfunction manipulationTarget( elem, content ) {\n\tif ( nodeName( elem, \"table\" ) &&\n\t\tnodeName( content.nodeType !== 11 ? content : content.firstChild, \"tr\" ) ) {\n\n\t\treturn jQuery( elem ).children( \"tbody\" )[ 0 ] || elem;\n\t}\n\n\treturn elem;\n}\n\n// Replace/restore the type attribute of script elements for safe DOM manipulation\nfunction disableScript( elem ) {\n\telem.type = ( elem.getAttribute( \"type\" ) !== null ) + \"/\" + elem.type;\n\treturn elem;\n}\nfunction restoreScript( elem ) {\n\tif ( ( elem.type || \"\" ).slice( 0, 5 ) === \"true/\" ) {\n\t\telem.type = elem.type.slice( 5 );\n\t} else {\n\t\telem.removeAttribute( \"type\" );\n\t}\n\n\treturn elem;\n}\n\nfunction cloneCopyEvent( src, dest ) {\n\tvar i, l, type, pdataOld, udataOld, udataCur, events;\n\n\tif ( dest.nodeType !== 1 ) {\n\t\treturn;\n\t}\n\n\t// 1. Copy private data: events, handlers, etc.\n\tif ( dataPriv.hasData( src ) ) {\n\t\tpdataOld = dataPriv.get( src );\n\t\tevents = pdataOld.events;\n\n\t\tif ( events ) {\n\t\t\tdataPriv.remove( dest, \"handle events\" );\n\n\t\t\tfor ( type in events ) {\n\t\t\t\tfor ( i = 0, l = events[ type ].length; i < l; i++ ) {\n\t\t\t\t\tjQuery.event.add( dest, type, events[ type ][ i ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// 2. Copy user data\n\tif ( dataUser.hasData( src ) ) {\n\t\tudataOld = dataUser.access( src );\n\t\tudataCur = jQuery.extend( {}, udataOld );\n\n\t\tdataUser.set( dest, udataCur );\n\t}\n}\n\n// Fix IE bugs, see support tests\nfunction fixInput( src, dest ) {\n\tvar nodeName = dest.nodeName.toLowerCase();\n\n\t// Fails to persist the checked state of a cloned checkbox or radio button.\n\tif ( nodeName === \"input\" && rcheckableType.test( src.type ) ) {\n\t\tdest.checked = src.checked;\n\n\t// Fails to return the selected option to the default selected state when cloning options\n\t} else if ( nodeName === \"input\" || nodeName === \"textarea\" ) {\n\t\tdest.defaultValue = src.defaultValue;\n\t}\n}\n\nfunction domManip( collection, args, callback, ignored ) {\n\n\t// Flatten any nested arrays\n\targs = flat( args );\n\n\tvar fragment, first, scripts, hasScripts, node, doc,\n\t\ti = 0,\n\t\tl = collection.length,\n\t\tiNoClone = l - 1,\n\t\tvalue = args[ 0 ],\n\t\tvalueIsFunction = isFunction( value );\n\n\t// We can't cloneNode fragments that contain checked, in WebKit\n\tif ( valueIsFunction ||\n\t\t\t( l > 1 && typeof value === \"string\" &&\n\t\t\t\t!support.checkClone && rchecked.test( value ) ) ) {\n\t\treturn collection.each( function( index ) {\n\t\t\tvar self = collection.eq( index );\n\t\t\tif ( valueIsFunction ) {\n\t\t\t\targs[ 0 ] = value.call( this, index, self.html() );\n\t\t\t}\n\t\t\tdomManip( self, args, callback, ignored );\n\t\t} );\n\t}\n\n\tif ( l ) {\n\t\tfragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored );\n\t\tfirst = fragment.firstChild;\n\n\t\tif ( fragment.childNodes.length === 1 ) {\n\t\t\tfragment = first;\n\t\t}\n\n\t\t// Require either new content or an interest in ignored elements to invoke the callback\n\t\tif ( first || ignored ) {\n\t\t\tscripts = jQuery.map( getAll( fragment, \"script\" ), disableScript );\n\t\t\thasScripts = scripts.length;\n\n\t\t\t// Use the original fragment for the last item\n\t\t\t// instead of the first because it can end up\n\t\t\t// being emptied incorrectly in certain situations (#8070).\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tnode = fragment;\n\n\t\t\t\tif ( i !== iNoClone ) {\n\t\t\t\t\tnode = jQuery.clone( node, true, true );\n\n\t\t\t\t\t// Keep references to cloned scripts for later restoration\n\t\t\t\t\tif ( hasScripts ) {\n\n\t\t\t\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\t\t\tjQuery.merge( scripts, getAll( node, \"script\" ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcallback.call( collection[ i ], node, i );\n\t\t\t}\n\n\t\t\tif ( hasScripts ) {\n\t\t\t\tdoc = scripts[ scripts.length - 1 ].ownerDocument;\n\n\t\t\t\t// Reenable scripts\n\t\t\t\tjQuery.map( scripts, restoreScript );\n\n\t\t\t\t// Evaluate executable scripts on first document insertion\n\t\t\t\tfor ( i = 0; i < hasScripts; i++ ) {\n\t\t\t\t\tnode = scripts[ i ];\n\t\t\t\t\tif ( rscriptType.test( node.type || \"\" ) &&\n\t\t\t\t\t\t!dataPriv.access( node, \"globalEval\" ) &&\n\t\t\t\t\t\tjQuery.contains( doc, node ) ) {\n\n\t\t\t\t\t\tif ( node.src && ( node.type || \"\" ).toLowerCase()  !== \"module\" ) {\n\n\t\t\t\t\t\t\t// Optional AJAX dependency, but won't run scripts if not present\n\t\t\t\t\t\t\tif ( jQuery._evalUrl && !node.noModule ) {\n\t\t\t\t\t\t\t\tjQuery._evalUrl( node.src, {\n\t\t\t\t\t\t\t\t\tnonce: node.nonce || node.getAttribute( \"nonce\" )\n\t\t\t\t\t\t\t\t}, doc );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tDOMEval( node.textContent.replace( rcleanScript, \"\" ), node, doc );\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}\n\t}\n\n\treturn collection;\n}\n\nfunction remove( elem, selector, keepData ) {\n\tvar node,\n\t\tnodes = selector ? jQuery.filter( selector, elem ) : elem,\n\t\ti = 0;\n\n\tfor ( ; ( node = nodes[ i ] ) != null; i++ ) {\n\t\tif ( !keepData && node.nodeType === 1 ) {\n\t\t\tjQuery.cleanData( getAll( node ) );\n\t\t}\n\n\t\tif ( node.parentNode ) {\n\t\t\tif ( keepData && isAttached( node ) ) {\n\t\t\t\tsetGlobalEval( getAll( node, \"script\" ) );\n\t\t\t}\n\t\t\tnode.parentNode.removeChild( node );\n\t\t}\n\t}\n\n\treturn elem;\n}\n\njQuery.extend( {\n\thtmlPrefilter: function( html ) {\n\t\treturn html;\n\t},\n\n\tclone: function( elem, dataAndEvents, deepDataAndEvents ) {\n\t\tvar i, l, srcElements, destElements,\n\t\t\tclone = elem.cloneNode( true ),\n\t\t\tinPage = isAttached( elem );\n\n\t\t// Fix IE cloning issues\n\t\tif ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&\n\t\t\t\t!jQuery.isXMLDoc( elem ) ) {\n\n\t\t\t// We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2\n\t\t\tdestElements = getAll( clone );\n\t\t\tsrcElements = getAll( elem );\n\n\t\t\tfor ( i = 0, l = srcElements.length; i < l; i++ ) {\n\t\t\t\tfixInput( srcElements[ i ], destElements[ i ] );\n\t\t\t}\n\t\t}\n\n\t\t// Copy the events from the original to the clone\n\t\tif ( dataAndEvents ) {\n\t\t\tif ( deepDataAndEvents ) {\n\t\t\t\tsrcElements = srcElements || getAll( elem );\n\t\t\t\tdestElements = destElements || getAll( clone );\n\n\t\t\t\tfor ( i = 0, l = srcElements.length; i < l; i++ ) {\n\t\t\t\t\tcloneCopyEvent( srcElements[ i ], destElements[ i ] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcloneCopyEvent( elem, clone );\n\t\t\t}\n\t\t}\n\n\t\t// Preserve script evaluation history\n\t\tdestElements = getAll( clone, \"script\" );\n\t\tif ( destElements.length > 0 ) {\n\t\t\tsetGlobalEval( destElements, !inPage && getAll( elem, \"script\" ) );\n\t\t}\n\n\t\t// Return the cloned set\n\t\treturn clone;\n\t},\n\n\tcleanData: function( elems ) {\n\t\tvar data, elem, type,\n\t\t\tspecial = jQuery.event.special,\n\t\t\ti = 0;\n\n\t\tfor ( ; ( elem = elems[ i ] ) !== undefined; i++ ) {\n\t\t\tif ( acceptData( elem ) ) {\n\t\t\t\tif ( ( data = elem[ dataPriv.expando ] ) ) {\n\t\t\t\t\tif ( data.events ) {\n\t\t\t\t\t\tfor ( type in data.events ) {\n\t\t\t\t\t\t\tif ( special[ type ] ) {\n\t\t\t\t\t\t\t\tjQuery.event.remove( elem, type );\n\n\t\t\t\t\t\t\t// This is a shortcut to avoid jQuery.event.remove's overhead\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tjQuery.removeEvent( elem, type, data.handle );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Support: Chrome <=35 - 45+\n\t\t\t\t\t// Assign undefined instead of using delete, see Data#remove\n\t\t\t\t\telem[ dataPriv.expando ] = undefined;\n\t\t\t\t}\n\t\t\t\tif ( elem[ dataUser.expando ] ) {\n\n\t\t\t\t\t// Support: Chrome <=35 - 45+\n\t\t\t\t\t// Assign undefined instead of using delete, see Data#remove\n\t\t\t\t\telem[ dataUser.expando ] = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n} );\n\njQuery.fn.extend( {\n\tdetach: function( selector ) {\n\t\treturn remove( this, selector, true );\n\t},\n\n\tremove: function( selector ) {\n\t\treturn remove( this, selector );\n\t},\n\n\ttext: function( value ) {\n\t\treturn access( this, function( value ) {\n\t\t\treturn value === undefined ?\n\t\t\t\tjQuery.text( this ) :\n\t\t\t\tthis.empty().each( function() {\n\t\t\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\t\t\tthis.textContent = value;\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t}, null, value, arguments.length );\n\t},\n\n\tappend: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.appendChild( elem );\n\t\t\t}\n\t\t} );\n\t},\n\n\tprepend: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.insertBefore( elem, target.firstChild );\n\t\t\t}\n\t\t} );\n\t},\n\n\tbefore: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this );\n\t\t\t}\n\t\t} );\n\t},\n\n\tafter: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this.nextSibling );\n\t\t\t}\n\t\t} );\n\t},\n\n\tempty: function() {\n\t\tvar elem,\n\t\t\ti = 0;\n\n\t\tfor ( ; ( elem = this[ i ] ) != null; i++ ) {\n\t\t\tif ( elem.nodeType === 1 ) {\n\n\t\t\t\t// Prevent memory leaks\n\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\n\t\t\t\t// Remove any remaining nodes\n\t\t\t\telem.textContent = \"\";\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tclone: function( dataAndEvents, deepDataAndEvents ) {\n\t\tdataAndEvents = dataAndEvents == null ? false : dataAndEvents;\n\t\tdeepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;\n\n\t\treturn this.map( function() {\n\t\t\treturn jQuery.clone( this, dataAndEvents, deepDataAndEvents );\n\t\t} );\n\t},\n\n\thtml: function( value ) {\n\t\treturn access( this, function( value ) {\n\t\t\tvar elem = this[ 0 ] || {},\n\t\t\t\ti = 0,\n\t\t\t\tl = this.length;\n\n\t\t\tif ( value === undefined && elem.nodeType === 1 ) {\n\t\t\t\treturn elem.innerHTML;\n\t\t\t}\n\n\t\t\t// See if we can take a shortcut and just use innerHTML\n\t\t\tif ( typeof value === \"string\" && !rnoInnerhtml.test( value ) &&\n\t\t\t\t!wrapMap[ ( rtagName.exec( value ) || [ \"\", \"\" ] )[ 1 ].toLowerCase() ] ) {\n\n\t\t\t\tvalue = jQuery.htmlPrefilter( value );\n\n\t\t\t\ttry {\n\t\t\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\t\t\telem = this[ i ] || {};\n\n\t\t\t\t\t\t// Remove element nodes and prevent memory leaks\n\t\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\t\t\t\t\t\t\telem.innerHTML = value;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\telem = 0;\n\n\t\t\t\t// If using innerHTML throws an exception, use the fallback method\n\t\t\t\t} catch ( e ) {}\n\t\t\t}\n\n\t\t\tif ( elem ) {\n\t\t\t\tthis.empty().append( value );\n\t\t\t}\n\t\t}, null, value, arguments.length );\n\t},\n\n\treplaceWith: function() {\n\t\tvar ignored = [];\n\n\t\t// Make the changes, replacing each non-ignored context element with the new content\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tvar parent = this.parentNode;\n\n\t\t\tif ( jQuery.inArray( this, ignored ) < 0 ) {\n\t\t\t\tjQuery.cleanData( getAll( this ) );\n\t\t\t\tif ( parent ) {\n\t\t\t\t\tparent.replaceChild( elem, this );\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Force callback invocation\n\t\t}, ignored );\n\t}\n} );\n\njQuery.each( {\n\tappendTo: \"append\",\n\tprependTo: \"prepend\",\n\tinsertBefore: \"before\",\n\tinsertAfter: \"after\",\n\treplaceAll: \"replaceWith\"\n}, function( name, original ) {\n\tjQuery.fn[ name ] = function( selector ) {\n\t\tvar elems,\n\t\t\tret = [],\n\t\t\tinsert = jQuery( selector ),\n\t\t\tlast = insert.length - 1,\n\t\t\ti = 0;\n\n\t\tfor ( ; i <= last; i++ ) {\n\t\t\telems = i === last ? this : this.clone( true );\n\t\t\tjQuery( insert[ i ] )[ original ]( elems );\n\n\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t// .get() because push.apply(_, arraylike) throws on ancient WebKit\n\t\t\tpush.apply( ret, elems.get() );\n\t\t}\n\n\t\treturn this.pushStack( ret );\n\t};\n} );\nvar rnumnonpx = new RegExp( \"^(\" + pnum + \")(?!px)[a-z%]+$\", \"i\" );\n\nvar getStyles = function( elem ) {\n\n\t\t// Support: IE <=11 only, Firefox <=30 (#15098, #14150)\n\t\t// IE throws on elements created in popups\n\t\t// FF meanwhile throws on frame elements through \"defaultView.getComputedStyle\"\n\t\tvar view = elem.ownerDocument.defaultView;\n\n\t\tif ( !view || !view.opener ) {\n\t\t\tview = window;\n\t\t}\n\n\t\treturn view.getComputedStyle( elem );\n\t};\n\nvar swap = function( elem, options, callback ) {\n\tvar ret, name,\n\t\told = {};\n\n\t// Remember the old values, and insert the new ones\n\tfor ( name in options ) {\n\t\told[ name ] = elem.style[ name ];\n\t\telem.style[ name ] = options[ name ];\n\t}\n\n\tret = callback.call( elem );\n\n\t// Revert the old values\n\tfor ( name in options ) {\n\t\telem.style[ name ] = old[ name ];\n\t}\n\n\treturn ret;\n};\n\n\nvar rboxStyle = new RegExp( cssExpand.join( \"|\" ), \"i\" );\n\n\n\n( function() {\n\n\t// Executing both pixelPosition & boxSizingReliable tests require only one layout\n\t// so they're executed at the same time to save the second computation.\n\tfunction computeStyleTests() {\n\n\t\t// This is a singleton, we need to execute it only once\n\t\tif ( !div ) {\n\t\t\treturn;\n\t\t}\n\n\t\tcontainer.style.cssText = \"position:absolute;left:-11111px;width:60px;\" +\n\t\t\t\"margin-top:1px;padding:0;border:0\";\n\t\tdiv.style.cssText =\n\t\t\t\"position:relative;display:block;box-sizing:border-box;overflow:scroll;\" +\n\t\t\t\"margin:auto;border:1px;padding:1px;\" +\n\t\t\t\"width:60%;top:1%\";\n\t\tdocumentElement.appendChild( container ).appendChild( div );\n\n\t\tvar divStyle = window.getComputedStyle( div );\n\t\tpixelPositionVal = divStyle.top !== \"1%\";\n\n\t\t// Support: Android 4.0 - 4.3 only, Firefox <=3 - 44\n\t\treliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12;\n\n\t\t// Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3\n\t\t// Some styles come back with percentage values, even though they shouldn't\n\t\tdiv.style.right = \"60%\";\n\t\tpixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36;\n\n\t\t// Support: IE 9 - 11 only\n\t\t// Detect misreporting of content dimensions for box-sizing:border-box elements\n\t\tboxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36;\n\n\t\t// Support: IE 9 only\n\t\t// Detect overflow:scroll screwiness (gh-3699)\n\t\t// Support: Chrome <=64\n\t\t// Don't get tricked when zoom affects offsetWidth (gh-4029)\n\t\tdiv.style.position = \"absolute\";\n\t\tscrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12;\n\n\t\tdocumentElement.removeChild( container );\n\n\t\t// Nullify the div so it wouldn't be stored in the memory and\n\t\t// it will also be a sign that checks already performed\n\t\tdiv = null;\n\t}\n\n\tfunction roundPixelMeasures( measure ) {\n\t\treturn Math.round( parseFloat( measure ) );\n\t}\n\n\tvar pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal,\n\t\treliableTrDimensionsVal, reliableMarginLeftVal,\n\t\tcontainer = document.createElement( \"div\" ),\n\t\tdiv = document.createElement( \"div\" );\n\n\t// Finish early in limited (non-browser) environments\n\tif ( !div.style ) {\n\t\treturn;\n\t}\n\n\t// Support: IE <=9 - 11 only\n\t// Style of cloned element affects source element cloned (#8908)\n\tdiv.style.backgroundClip = \"content-box\";\n\tdiv.cloneNode( true ).style.backgroundClip = \"\";\n\tsupport.clearCloneStyle = div.style.backgroundClip === \"content-box\";\n\n\tjQuery.extend( support, {\n\t\tboxSizingReliable: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn boxSizingReliableVal;\n\t\t},\n\t\tpixelBoxStyles: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn pixelBoxStylesVal;\n\t\t},\n\t\tpixelPosition: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn pixelPositionVal;\n\t\t},\n\t\treliableMarginLeft: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn reliableMarginLeftVal;\n\t\t},\n\t\tscrollboxSize: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn scrollboxSizeVal;\n\t\t},\n\n\t\t// Support: IE 9 - 11+, Edge 15 - 18+\n\t\t// IE/Edge misreport `getComputedStyle` of table rows with width/height\n\t\t// set in CSS while `offset*` properties report correct values.\n\t\t// Behavior in IE 9 is more subtle than in newer versions & it passes\n\t\t// some versions of this test; make sure not to make it pass there!\n\t\t//\n\t\t// Support: Firefox 70+\n\t\t// Only Firefox includes border widths\n\t\t// in computed dimensions. (gh-4529)\n\t\treliableTrDimensions: function() {\n\t\t\tvar table, tr, trChild, trStyle;\n\t\t\tif ( reliableTrDimensionsVal == null ) {\n\t\t\t\ttable = document.createElement( \"table\" );\n\t\t\t\ttr = document.createElement( \"tr\" );\n\t\t\t\ttrChild = document.createElement( \"div\" );\n\n\t\t\t\ttable.style.cssText = \"position:absolute;left:-11111px;border-collapse:separate\";\n\t\t\t\ttr.style.cssText = \"border:1px solid\";\n\n\t\t\t\t// Support: Chrome 86+\n\t\t\t\t// Height set through cssText does not get applied.\n\t\t\t\t// Computed height then comes back as 0.\n\t\t\t\ttr.style.height = \"1px\";\n\t\t\t\ttrChild.style.height = \"9px\";\n\n\t\t\t\t// Support: Android 8 Chrome 86+\n\t\t\t\t// In our bodyBackground.html iframe,\n\t\t\t\t// display for all div elements is set to \"inline\",\n\t\t\t\t// which causes a problem only in Android 8 Chrome 86.\n\t\t\t\t// Ensuring the div is display: block\n\t\t\t\t// gets around this issue.\n\t\t\t\ttrChild.style.display = \"block\";\n\n\t\t\t\tdocumentElement\n\t\t\t\t\t.appendChild( table )\n\t\t\t\t\t.appendChild( tr )\n\t\t\t\t\t.appendChild( trChild );\n\n\t\t\t\ttrStyle = window.getComputedStyle( tr );\n\t\t\t\treliableTrDimensionsVal = ( parseInt( trStyle.height, 10 ) +\n\t\t\t\t\tparseInt( trStyle.borderTopWidth, 10 ) +\n\t\t\t\t\tparseInt( trStyle.borderBottomWidth, 10 ) ) === tr.offsetHeight;\n\n\t\t\t\tdocumentElement.removeChild( table );\n\t\t\t}\n\t\t\treturn reliableTrDimensionsVal;\n\t\t}\n\t} );\n} )();\n\n\nfunction curCSS( elem, name, computed ) {\n\tvar width, minWidth, maxWidth, ret,\n\n\t\t// Support: Firefox 51+\n\t\t// Retrieving style before computed somehow\n\t\t// fixes an issue with getting wrong values\n\t\t// on detached elements\n\t\tstyle = elem.style;\n\n\tcomputed = computed || getStyles( elem );\n\n\t// getPropertyValue is needed for:\n\t//   .css('filter') (IE 9 only, #12537)\n\t//   .css('--customProperty) (#3144)\n\tif ( computed ) {\n\t\tret = computed.getPropertyValue( name ) || computed[ name ];\n\n\t\tif ( ret === \"\" && !isAttached( elem ) ) {\n\t\t\tret = jQuery.style( elem, name );\n\t\t}\n\n\t\t// A tribute to the \"awesome hack by Dean Edwards\"\n\t\t// Android Browser returns percentage for some values,\n\t\t// but width seems to be reliably pixels.\n\t\t// This is against the CSSOM draft spec:\n\t\t// https://drafts.csswg.org/cssom/#resolved-values\n\t\tif ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) {\n\n\t\t\t// Remember the original values\n\t\t\twidth = style.width;\n\t\t\tminWidth = style.minWidth;\n\t\t\tmaxWidth = style.maxWidth;\n\n\t\t\t// Put in the new values to get a computed value out\n\t\t\tstyle.minWidth = style.maxWidth = style.width = ret;\n\t\t\tret = computed.width;\n\n\t\t\t// Revert the changed values\n\t\t\tstyle.width = width;\n\t\t\tstyle.minWidth = minWidth;\n\t\t\tstyle.maxWidth = maxWidth;\n\t\t}\n\t}\n\n\treturn ret !== undefined ?\n\n\t\t// Support: IE <=9 - 11 only\n\t\t// IE returns zIndex value as an integer.\n\t\tret + \"\" :\n\t\tret;\n}\n\n\nfunction addGetHookIf( conditionFn, hookFn ) {\n\n\t// Define the hook, we'll check on the first run if it's really needed.\n\treturn {\n\t\tget: function() {\n\t\t\tif ( conditionFn() ) {\n\n\t\t\t\t// Hook not needed (or it's not possible to use it due\n\t\t\t\t// to missing dependency), remove it.\n\t\t\t\tdelete this.get;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Hook needed; redefine it so that the support test is not executed again.\n\t\t\treturn ( this.get = hookFn ).apply( this, arguments );\n\t\t}\n\t};\n}\n\n\nvar cssPrefixes = [ \"Webkit\", \"Moz\", \"ms\" ],\n\temptyStyle = document.createElement( \"div\" ).style,\n\tvendorProps = {};\n\n// Return a vendor-prefixed property or undefined\nfunction vendorPropName( name ) {\n\n\t// Check for vendor prefixed names\n\tvar capName = name[ 0 ].toUpperCase() + name.slice( 1 ),\n\t\ti = cssPrefixes.length;\n\n\twhile ( i-- ) {\n\t\tname = cssPrefixes[ i ] + capName;\n\t\tif ( name in emptyStyle ) {\n\t\t\treturn name;\n\t\t}\n\t}\n}\n\n// Return a potentially-mapped jQuery.cssProps or vendor prefixed property\nfunction finalPropName( name ) {\n\tvar final = jQuery.cssProps[ name ] || vendorProps[ name ];\n\n\tif ( final ) {\n\t\treturn final;\n\t}\n\tif ( name in emptyStyle ) {\n\t\treturn name;\n\t}\n\treturn vendorProps[ name ] = vendorPropName( name ) || name;\n}\n\n\nvar\n\n\t// Swappable if display is none or starts with table\n\t// except \"table\", \"table-cell\", or \"table-caption\"\n\t// See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display\n\trdisplayswap = /^(none|table(?!-c[ea]).+)/,\n\trcustomProp = /^--/,\n\tcssShow = { position: \"absolute\", visibility: \"hidden\", display: \"block\" },\n\tcssNormalTransform = {\n\t\tletterSpacing: \"0\",\n\t\tfontWeight: \"400\"\n\t};\n\nfunction setPositiveNumber( _elem, value, subtract ) {\n\n\t// Any relative (+/-) values have already been\n\t// normalized at this point\n\tvar matches = rcssNum.exec( value );\n\treturn matches ?\n\n\t\t// Guard against undefined \"subtract\", e.g., when used as in cssHooks\n\t\tMath.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || \"px\" ) :\n\t\tvalue;\n}\n\nfunction boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) {\n\tvar i = dimension === \"width\" ? 1 : 0,\n\t\textra = 0,\n\t\tdelta = 0;\n\n\t// Adjustment may not be necessary\n\tif ( box === ( isBorderBox ? \"border\" : \"content\" ) ) {\n\t\treturn 0;\n\t}\n\n\tfor ( ; i < 4; i += 2 ) {\n\n\t\t// Both box models exclude margin\n\t\tif ( box === \"margin\" ) {\n\t\t\tdelta += jQuery.css( elem, box + cssExpand[ i ], true, styles );\n\t\t}\n\n\t\t// If we get here with a content-box, we're seeking \"padding\" or \"border\" or \"margin\"\n\t\tif ( !isBorderBox ) {\n\n\t\t\t// Add padding\n\t\t\tdelta += jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\n\t\t\t// For \"border\" or \"margin\", add border\n\t\t\tif ( box !== \"padding\" ) {\n\t\t\t\tdelta += jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\n\t\t\t// But still keep track of it otherwise\n\t\t\t} else {\n\t\t\t\textra += jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\n\t\t// If we get here with a border-box (content + padding + border), we're seeking \"content\" or\n\t\t// \"padding\" or \"margin\"\n\t\t} else {\n\n\t\t\t// For \"content\", subtract padding\n\t\t\tif ( box === \"content\" ) {\n\t\t\t\tdelta -= jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\t\t\t}\n\n\t\t\t// For \"content\" or \"padding\", subtract border\n\t\t\tif ( box !== \"margin\" ) {\n\t\t\t\tdelta -= jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\t\t}\n\t}\n\n\t// Account for positive content-box scroll gutter when requested by providing computedVal\n\tif ( !isBorderBox && computedVal >= 0 ) {\n\n\t\t// offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border\n\t\t// Assuming integer scroll gutter, subtract the rest and round down\n\t\tdelta += Math.max( 0, Math.ceil(\n\t\t\telem[ \"offset\" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -\n\t\t\tcomputedVal -\n\t\t\tdelta -\n\t\t\textra -\n\t\t\t0.5\n\n\t\t// If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter\n\t\t// Use an explicit zero to avoid NaN (gh-3964)\n\t\t) ) || 0;\n\t}\n\n\treturn delta;\n}\n\nfunction getWidthOrHeight( elem, dimension, extra ) {\n\n\t// Start with computed style\n\tvar styles = getStyles( elem ),\n\n\t\t// To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322).\n\t\t// Fake content-box until we know it's needed to know the true value.\n\t\tboxSizingNeeded = !support.boxSizingReliable() || extra,\n\t\tisBorderBox = boxSizingNeeded &&\n\t\t\tjQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\",\n\t\tvalueIsBorderBox = isBorderBox,\n\n\t\tval = curCSS( elem, dimension, styles ),\n\t\toffsetProp = \"offset\" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 );\n\n\t// Support: Firefox <=54\n\t// Return a confounding non-pixel value or feign ignorance, as appropriate.\n\tif ( rnumnonpx.test( val ) ) {\n\t\tif ( !extra ) {\n\t\t\treturn val;\n\t\t}\n\t\tval = \"auto\";\n\t}\n\n\n\t// Support: IE 9 - 11 only\n\t// Use offsetWidth/offsetHeight for when box sizing is unreliable.\n\t// In those cases, the computed value can be trusted to be border-box.\n\tif ( ( !support.boxSizingReliable() && isBorderBox ||\n\n\t\t// Support: IE 10 - 11+, Edge 15 - 18+\n\t\t// IE/Edge misreport `getComputedStyle` of table rows with width/height\n\t\t// set in CSS while `offset*` properties report correct values.\n\t\t// Interestingly, in some cases IE 9 doesn't suffer from this issue.\n\t\t!support.reliableTrDimensions() && nodeName( elem, \"tr\" ) ||\n\n\t\t// Fall back to offsetWidth/offsetHeight when value is \"auto\"\n\t\t// This happens for inline elements with no explicit setting (gh-3571)\n\t\tval === \"auto\" ||\n\n\t\t// Support: Android <=4.1 - 4.3 only\n\t\t// Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602)\n\t\t!parseFloat( val ) && jQuery.css( elem, \"display\", false, styles ) === \"inline\" ) &&\n\n\t\t// Make sure the element is visible & connected\n\t\telem.getClientRects().length ) {\n\n\t\tisBorderBox = jQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\";\n\n\t\t// Where available, offsetWidth/offsetHeight approximate border box dimensions.\n\t\t// Where not available (e.g., SVG), assume unreliable box-sizing and interpret the\n\t\t// retrieved value as a content box dimension.\n\t\tvalueIsBorderBox = offsetProp in elem;\n\t\tif ( valueIsBorderBox ) {\n\t\t\tval = elem[ offsetProp ];\n\t\t}\n\t}\n\n\t// Normalize \"\" and auto\n\tval = parseFloat( val ) || 0;\n\n\t// Adjust for the element's box model\n\treturn ( val +\n\t\tboxModelAdjustment(\n\t\t\telem,\n\t\t\tdimension,\n\t\t\textra || ( isBorderBox ? \"border\" : \"content\" ),\n\t\t\tvalueIsBorderBox,\n\t\t\tstyles,\n\n\t\t\t// Provide the current computed size to request scroll gutter calculation (gh-3589)\n\t\t\tval\n\t\t)\n\t) + \"px\";\n}\n\njQuery.extend( {\n\n\t// Add in style property hooks for overriding the default\n\t// behavior of getting and setting a style property\n\tcssHooks: {\n\t\topacity: {\n\t\t\tget: function( elem, computed ) {\n\t\t\t\tif ( computed ) {\n\n\t\t\t\t\t// We should always get a number back from opacity\n\t\t\t\t\tvar ret = curCSS( elem, \"opacity\" );\n\t\t\t\t\treturn ret === \"\" ? \"1\" : ret;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t// Don't automatically add \"px\" to these possibly-unitless properties\n\tcssNumber: {\n\t\t\"animationIterationCount\": true,\n\t\t\"columnCount\": true,\n\t\t\"fillOpacity\": true,\n\t\t\"flexGrow\": true,\n\t\t\"flexShrink\": true,\n\t\t\"fontWeight\": true,\n\t\t\"gridArea\": true,\n\t\t\"gridColumn\": true,\n\t\t\"gridColumnEnd\": true,\n\t\t\"gridColumnStart\": true,\n\t\t\"gridRow\": true,\n\t\t\"gridRowEnd\": true,\n\t\t\"gridRowStart\": true,\n\t\t\"lineHeight\": true,\n\t\t\"opacity\": true,\n\t\t\"order\": true,\n\t\t\"orphans\": true,\n\t\t\"widows\": true,\n\t\t\"zIndex\": true,\n\t\t\"zoom\": true\n\t},\n\n\t// Add in properties whose names you wish to fix before\n\t// setting or getting the value\n\tcssProps: {},\n\n\t// Get and set the style property on a DOM Node\n\tstyle: function( elem, name, value, extra ) {\n\n\t\t// Don't set styles on text and comment nodes\n\t\tif ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Make sure that we're working with the right name\n\t\tvar ret, type, hooks,\n\t\t\torigName = camelCase( name ),\n\t\t\tisCustomProp = rcustomProp.test( name ),\n\t\t\tstyle = elem.style;\n\n\t\t// Make sure that we're working with the right name. We don't\n\t\t// want to query the value if it is a CSS custom property\n\t\t// since they are user-defined.\n\t\tif ( !isCustomProp ) {\n\t\t\tname = finalPropName( origName );\n\t\t}\n\n\t\t// Gets hook for the prefixed version, then unprefixed version\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// Check if we're setting a value\n\t\tif ( value !== undefined ) {\n\t\t\ttype = typeof value;\n\n\t\t\t// Convert \"+=\" or \"-=\" to relative numbers (#7345)\n\t\t\tif ( type === \"string\" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {\n\t\t\t\tvalue = adjustCSS( elem, name, ret );\n\n\t\t\t\t// Fixes bug #9237\n\t\t\t\ttype = \"number\";\n\t\t\t}\n\n\t\t\t// Make sure that null and NaN values aren't set (#7116)\n\t\t\tif ( value == null || value !== value ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If a number was passed in, add the unit (except for certain CSS properties)\n\t\t\t// The isCustomProp check can be removed in jQuery 4.0 when we only auto-append\n\t\t\t// \"px\" to a few hardcoded values.\n\t\t\tif ( type === \"number\" && !isCustomProp ) {\n\t\t\t\tvalue += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? \"\" : \"px\" );\n\t\t\t}\n\n\t\t\t// background-* props affect original clone's values\n\t\t\tif ( !support.clearCloneStyle && value === \"\" && name.indexOf( \"background\" ) === 0 ) {\n\t\t\t\tstyle[ name ] = \"inherit\";\n\t\t\t}\n\n\t\t\t// If a hook was provided, use that value, otherwise just set the specified value\n\t\t\tif ( !hooks || !( \"set\" in hooks ) ||\n\t\t\t\t( value = hooks.set( elem, value, extra ) ) !== undefined ) {\n\n\t\t\t\tif ( isCustomProp ) {\n\t\t\t\t\tstyle.setProperty( name, value );\n\t\t\t\t} else {\n\t\t\t\t\tstyle[ name ] = value;\n\t\t\t\t}\n\t\t\t}\n\n\t\t} else {\n\n\t\t\t// If a hook was provided get the non-computed value from there\n\t\t\tif ( hooks && \"get\" in hooks &&\n\t\t\t\t( ret = hooks.get( elem, false, extra ) ) !== undefined ) {\n\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\t// Otherwise just get the value from the style object\n\t\t\treturn style[ name ];\n\t\t}\n\t},\n\n\tcss: function( elem, name, extra, styles ) {\n\t\tvar val, num, hooks,\n\t\t\torigName = camelCase( name ),\n\t\t\tisCustomProp = rcustomProp.test( name );\n\n\t\t// Make sure that we're working with the right name. We don't\n\t\t// want to modify the value if it is a CSS custom property\n\t\t// since they are user-defined.\n\t\tif ( !isCustomProp ) {\n\t\t\tname = finalPropName( origName );\n\t\t}\n\n\t\t// Try prefixed name followed by the unprefixed name\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// If a hook was provided get the computed value from there\n\t\tif ( hooks && \"get\" in hooks ) {\n\t\t\tval = hooks.get( elem, true, extra );\n\t\t}\n\n\t\t// Otherwise, if a way to get the computed value exists, use that\n\t\tif ( val === undefined ) {\n\t\t\tval = curCSS( elem, name, styles );\n\t\t}\n\n\t\t// Convert \"normal\" to computed value\n\t\tif ( val === \"normal\" && name in cssNormalTransform ) {\n\t\t\tval = cssNormalTransform[ name ];\n\t\t}\n\n\t\t// Make numeric if forced or a qualifier was provided and val looks numeric\n\t\tif ( extra === \"\" || extra ) {\n\t\t\tnum = parseFloat( val );\n\t\t\treturn extra === true || isFinite( num ) ? num || 0 : val;\n\t\t}\n\n\t\treturn val;\n\t}\n} );\n\njQuery.each( [ \"height\", \"width\" ], function( _i, dimension ) {\n\tjQuery.cssHooks[ dimension ] = {\n\t\tget: function( elem, computed, extra ) {\n\t\t\tif ( computed ) {\n\n\t\t\t\t// Certain elements can have dimension info if we invisibly show them\n\t\t\t\t// but it must have a current display style that would benefit\n\t\t\t\treturn rdisplayswap.test( jQuery.css( elem, \"display\" ) ) &&\n\n\t\t\t\t\t// Support: Safari 8+\n\t\t\t\t\t// Table columns in Safari have non-zero offsetWidth & zero\n\t\t\t\t\t// getBoundingClientRect().width unless display is changed.\n\t\t\t\t\t// Support: IE <=11 only\n\t\t\t\t\t// Running getBoundingClientRect on a disconnected node\n\t\t\t\t\t// in IE throws an error.\n\t\t\t\t\t( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ?\n\t\t\t\t\tswap( elem, cssShow, function() {\n\t\t\t\t\t\treturn getWidthOrHeight( elem, dimension, extra );\n\t\t\t\t\t} ) :\n\t\t\t\t\tgetWidthOrHeight( elem, dimension, extra );\n\t\t\t}\n\t\t},\n\n\t\tset: function( elem, value, extra ) {\n\t\t\tvar matches,\n\t\t\t\tstyles = getStyles( elem ),\n\n\t\t\t\t// Only read styles.position if the test has a chance to fail\n\t\t\t\t// to avoid forcing a reflow.\n\t\t\t\tscrollboxSizeBuggy = !support.scrollboxSize() &&\n\t\t\t\t\tstyles.position === \"absolute\",\n\n\t\t\t\t// To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991)\n\t\t\t\tboxSizingNeeded = scrollboxSizeBuggy || extra,\n\t\t\t\tisBorderBox = boxSizingNeeded &&\n\t\t\t\t\tjQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\",\n\t\t\t\tsubtract = extra ?\n\t\t\t\t\tboxModelAdjustment(\n\t\t\t\t\t\telem,\n\t\t\t\t\t\tdimension,\n\t\t\t\t\t\textra,\n\t\t\t\t\t\tisBorderBox,\n\t\t\t\t\t\tstyles\n\t\t\t\t\t) :\n\t\t\t\t\t0;\n\n\t\t\t// Account for unreliable border-box dimensions by comparing offset* to computed and\n\t\t\t// faking a content-box to get border and padding (gh-3699)\n\t\t\tif ( isBorderBox && scrollboxSizeBuggy ) {\n\t\t\t\tsubtract -= Math.ceil(\n\t\t\t\t\telem[ \"offset\" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -\n\t\t\t\t\tparseFloat( styles[ dimension ] ) -\n\t\t\t\t\tboxModelAdjustment( elem, dimension, \"border\", false, styles ) -\n\t\t\t\t\t0.5\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Convert to pixels if value adjustment is needed\n\t\t\tif ( subtract && ( matches = rcssNum.exec( value ) ) &&\n\t\t\t\t( matches[ 3 ] || \"px\" ) !== \"px\" ) {\n\n\t\t\t\telem.style[ dimension ] = value;\n\t\t\t\tvalue = jQuery.css( elem, dimension );\n\t\t\t}\n\n\t\t\treturn setPositiveNumber( elem, value, subtract );\n\t\t}\n\t};\n} );\n\njQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft,\n\tfunction( elem, computed ) {\n\t\tif ( computed ) {\n\t\t\treturn ( parseFloat( curCSS( elem, \"marginLeft\" ) ) ||\n\t\t\t\telem.getBoundingClientRect().left -\n\t\t\t\t\tswap( elem, { marginLeft: 0 }, function() {\n\t\t\t\t\t\treturn elem.getBoundingClientRect().left;\n\t\t\t\t\t} )\n\t\t\t) + \"px\";\n\t\t}\n\t}\n);\n\n// These hooks are used by animate to expand properties\njQuery.each( {\n\tmargin: \"\",\n\tpadding: \"\",\n\tborder: \"Width\"\n}, function( prefix, suffix ) {\n\tjQuery.cssHooks[ prefix + suffix ] = {\n\t\texpand: function( value ) {\n\t\t\tvar i = 0,\n\t\t\t\texpanded = {},\n\n\t\t\t\t// Assumes a single number if not a string\n\t\t\t\tparts = typeof value === \"string\" ? value.split( \" \" ) : [ value ];\n\n\t\t\tfor ( ; i < 4; i++ ) {\n\t\t\t\texpanded[ prefix + cssExpand[ i ] + suffix ] =\n\t\t\t\t\tparts[ i ] || parts[ i - 2 ] || parts[ 0 ];\n\t\t\t}\n\n\t\t\treturn expanded;\n\t\t}\n\t};\n\n\tif ( prefix !== \"margin\" ) {\n\t\tjQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;\n\t}\n} );\n\njQuery.fn.extend( {\n\tcss: function( name, value ) {\n\t\treturn access( this, function( elem, name, value ) {\n\t\t\tvar styles, len,\n\t\t\t\tmap = {},\n\t\t\t\ti = 0;\n\n\t\t\tif ( Array.isArray( name ) ) {\n\t\t\t\tstyles = getStyles( elem );\n\t\t\t\tlen = name.length;\n\n\t\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\t\tmap[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );\n\t\t\t\t}\n\n\t\t\t\treturn map;\n\t\t\t}\n\n\t\t\treturn value !== undefined ?\n\t\t\t\tjQuery.style( elem, name, value ) :\n\t\t\t\tjQuery.css( elem, name );\n\t\t}, name, value, arguments.length > 1 );\n\t}\n} );\n\n\n// Based off of the plugin by Clint Helfers, with permission.\n// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/\njQuery.fn.delay = function( time, type ) {\n\ttime = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;\n\ttype = type || \"fx\";\n\n\treturn this.queue( type, function( next, hooks ) {\n\t\tvar timeout = window.setTimeout( next, time );\n\t\thooks.stop = function() {\n\t\t\twindow.clearTimeout( timeout );\n\t\t};\n\t} );\n};\n\n\n( function() {\n\tvar input = document.createElement( \"input\" ),\n\t\tselect = document.createElement( \"select\" ),\n\t\topt = select.appendChild( document.createElement( \"option\" ) );\n\n\tinput.type = \"checkbox\";\n\n\t// Support: Android <=4.3 only\n\t// Default value for a checkbox should be \"on\"\n\tsupport.checkOn = input.value !== \"\";\n\n\t// Support: IE <=11 only\n\t// Must access selectedIndex to make default options select\n\tsupport.optSelected = opt.selected;\n\n\t// Support: IE <=11 only\n\t// An input loses its value after becoming a radio\n\tinput = document.createElement( \"input\" );\n\tinput.value = \"t\";\n\tinput.type = \"radio\";\n\tsupport.radioValue = input.value === \"t\";\n} )();\n\n\nvar boolHook,\n\tattrHandle = jQuery.expr.attrHandle;\n\njQuery.fn.extend( {\n\tattr: function( name, value ) {\n\t\treturn access( this, jQuery.attr, name, value, arguments.length > 1 );\n\t},\n\n\tremoveAttr: function( name ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.removeAttr( this, name );\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tattr: function( elem, name, value ) {\n\t\tvar ret, hooks,\n\t\t\tnType = elem.nodeType;\n\n\t\t// Don't get/set attributes on text, comment and attribute nodes\n\t\tif ( nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Fallback to prop when attributes are not supported\n\t\tif ( typeof elem.getAttribute === \"undefined\" ) {\n\t\t\treturn jQuery.prop( elem, name, value );\n\t\t}\n\n\t\t// Attribute hooks are determined by the lowercase version\n\t\t// Grab necessary hook if one is defined\n\t\tif ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {\n\t\t\thooks = jQuery.attrHooks[ name.toLowerCase() ] ||\n\t\t\t\t( jQuery.expr.match.bool.test( name ) ? boolHook : undefined );\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\tif ( value === null ) {\n\t\t\t\tjQuery.removeAttr( elem, name );\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( hooks && \"set\" in hooks &&\n\t\t\t\t( ret = hooks.set( elem, value, name ) ) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\telem.setAttribute( name, value + \"\" );\n\t\t\treturn value;\n\t\t}\n\n\t\tif ( hooks && \"get\" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {\n\t\t\treturn ret;\n\t\t}\n\n\t\tret = jQuery.find.attr( elem, name );\n\n\t\t// Non-existent attributes return null, we normalize to undefined\n\t\treturn ret == null ? undefined : ret;\n\t},\n\n\tattrHooks: {\n\t\ttype: {\n\t\t\tset: function( elem, value ) {\n\t\t\t\tif ( !support.radioValue && value === \"radio\" &&\n\t\t\t\t\tnodeName( elem, \"input\" ) ) {\n\t\t\t\t\tvar val = elem.value;\n\t\t\t\t\telem.setAttribute( \"type\", value );\n\t\t\t\t\tif ( val ) {\n\t\t\t\t\t\telem.value = val;\n\t\t\t\t\t}\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\tremoveAttr: function( elem, value ) {\n\t\tvar name,\n\t\t\ti = 0,\n\n\t\t\t// Attribute names can contain non-HTML whitespace characters\n\t\t\t// https://html.spec.whatwg.org/multipage/syntax.html#attributes-2\n\t\t\tattrNames = value && value.match( rnothtmlwhite );\n\n\t\tif ( attrNames && elem.nodeType === 1 ) {\n\t\t\twhile ( ( name = attrNames[ i++ ] ) ) {\n\t\t\t\telem.removeAttribute( name );\n\t\t\t}\n\t\t}\n\t}\n} );\n\n// Hooks for boolean attributes\nboolHook = {\n\tset: function( elem, value, name ) {\n\t\tif ( value === false ) {\n\n\t\t\t// Remove boolean attributes when set to false\n\t\t\tjQuery.removeAttr( elem, name );\n\t\t} else {\n\t\t\telem.setAttribute( name, name );\n\t\t}\n\t\treturn name;\n\t}\n};\n\njQuery.each( jQuery.expr.match.bool.source.match( /\\w+/g ), function( _i, name ) {\n\tvar getter = attrHandle[ name ] || jQuery.find.attr;\n\n\tattrHandle[ name ] = function( elem, name, isXML ) {\n\t\tvar ret, handle,\n\t\t\tlowercaseName = name.toLowerCase();\n\n\t\tif ( !isXML ) {\n\n\t\t\t// Avoid an infinite loop by temporarily removing this function from the getter\n\t\t\thandle = attrHandle[ lowercaseName ];\n\t\t\tattrHandle[ lowercaseName ] = ret;\n\t\t\tret = getter( elem, name, isXML ) != null ?\n\t\t\t\tlowercaseName :\n\t\t\t\tnull;\n\t\t\tattrHandle[ lowercaseName ] = handle;\n\t\t}\n\t\treturn ret;\n\t};\n} );\n\n\n\n\nvar rfocusable = /^(?:input|select|textarea|button)$/i,\n\trclickable = /^(?:a|area)$/i;\n\njQuery.fn.extend( {\n\tprop: function( name, value ) {\n\t\treturn access( this, jQuery.prop, name, value, arguments.length > 1 );\n\t},\n\n\tremoveProp: function( name ) {\n\t\treturn this.each( function() {\n\t\t\tdelete this[ jQuery.propFix[ name ] || name ];\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tprop: function( elem, name, value ) {\n\t\tvar ret, hooks,\n\t\t\tnType = elem.nodeType;\n\n\t\t// Don't get/set properties on text, comment and attribute nodes\n\t\tif ( nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {\n\n\t\t\t// Fix name and attach hooks\n\t\t\tname = jQuery.propFix[ name ] || name;\n\t\t\thooks = jQuery.propHooks[ name ];\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\tif ( hooks && \"set\" in hooks &&\n\t\t\t\t( ret = hooks.set( elem, value, name ) ) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\treturn ( elem[ name ] = value );\n\t\t}\n\n\t\tif ( hooks && \"get\" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {\n\t\t\treturn ret;\n\t\t}\n\n\t\treturn elem[ name ];\n\t},\n\n\tpropHooks: {\n\t\ttabIndex: {\n\t\t\tget: function( elem ) {\n\n\t\t\t\t// Support: IE <=9 - 11 only\n\t\t\t\t// elem.tabIndex doesn't always return the\n\t\t\t\t// correct value when it hasn't been explicitly set\n\t\t\t\t// https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/\n\t\t\t\t// Use proper attribute retrieval(#12072)\n\t\t\t\tvar tabindex = jQuery.find.attr( elem, \"tabindex\" );\n\n\t\t\t\tif ( tabindex ) {\n\t\t\t\t\treturn parseInt( tabindex, 10 );\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\trfocusable.test( elem.nodeName ) ||\n\t\t\t\t\trclickable.test( elem.nodeName ) &&\n\t\t\t\t\telem.href\n\t\t\t\t) {\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t},\n\n\tpropFix: {\n\t\t\"for\": \"htmlFor\",\n\t\t\"class\": \"className\"\n\t}\n} );\n\n// Support: IE <=11 only\n// Accessing the selectedIndex property\n// forces the browser to respect setting selected\n// on the option\n// The getter ensures a default option is selected\n// when in an optgroup\n// eslint rule \"no-unused-expressions\" is disabled for this code\n// since it considers such accessions noop\nif ( !support.optSelected ) {\n\tjQuery.propHooks.selected = {\n\t\tget: function( elem ) {\n\n\t\t\t/* eslint no-unused-expressions: \"off\" */\n\n\t\t\tvar parent = elem.parentNode;\n\t\t\tif ( parent && parent.parentNode ) {\n\t\t\t\tparent.parentNode.selectedIndex;\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t\tset: function( elem ) {\n\n\t\t\t/* eslint no-unused-expressions: \"off\" */\n\n\t\t\tvar parent = elem.parentNode;\n\t\t\tif ( parent ) {\n\t\t\t\tparent.selectedIndex;\n\n\t\t\t\tif ( parent.parentNode ) {\n\t\t\t\t\tparent.parentNode.selectedIndex;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\njQuery.each( [\n\t\"tabIndex\",\n\t\"readOnly\",\n\t\"maxLength\",\n\t\"cellSpacing\",\n\t\"cellPadding\",\n\t\"rowSpan\",\n\t\"colSpan\",\n\t\"useMap\",\n\t\"frameBorder\",\n\t\"contentEditable\"\n], function() {\n\tjQuery.propFix[ this.toLowerCase() ] = this;\n} );\n\n\n\n\n\t// Strip and collapse whitespace according to HTML spec\n\t// https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace\n\tfunction stripAndCollapse( value ) {\n\t\tvar tokens = value.match( rnothtmlwhite ) || [];\n\t\treturn tokens.join( \" \" );\n\t}\n\n\nfunction getClass( elem ) {\n\treturn elem.getAttribute && elem.getAttribute( \"class\" ) || \"\";\n}\n\nfunction classesToArray( value ) {\n\tif ( Array.isArray( value ) ) {\n\t\treturn value;\n\t}\n\tif ( typeof value === \"string\" ) {\n\t\treturn value.match( rnothtmlwhite ) || [];\n\t}\n\treturn [];\n}\n\njQuery.fn.extend( {\n\taddClass: function( value ) {\n\t\tvar classes, elem, cur, curValue, clazz, j, finalValue,\n\t\t\ti = 0;\n\n\t\tif ( isFunction( value ) ) {\n\t\t\treturn this.each( function( j ) {\n\t\t\t\tjQuery( this ).addClass( value.call( this, j, getClass( this ) ) );\n\t\t\t} );\n\t\t}\n\n\t\tclasses = classesToArray( value );\n\n\t\tif ( classes.length ) {\n\t\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\t\tcurValue = getClass( elem );\n\t\t\t\tcur = elem.nodeType === 1 && ( \" \" + stripAndCollapse( curValue ) + \" \" );\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( ( clazz = classes[ j++ ] ) ) {\n\t\t\t\t\t\tif ( cur.indexOf( \" \" + clazz + \" \" ) < 0 ) {\n\t\t\t\t\t\t\tcur += clazz + \" \";\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = stripAndCollapse( cur );\n\t\t\t\t\tif ( curValue !== finalValue ) {\n\t\t\t\t\t\telem.setAttribute( \"class\", finalValue );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tremoveClass: function( value ) {\n\t\tvar classes, elem, cur, curValue, clazz, j, finalValue,\n\t\t\ti = 0;\n\n\t\tif ( isFunction( value ) ) {\n\t\t\treturn this.each( function( j ) {\n\t\t\t\tjQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );\n\t\t\t} );\n\t\t}\n\n\t\tif ( !arguments.length ) {\n\t\t\treturn this.attr( \"class\", \"\" );\n\t\t}\n\n\t\tclasses = classesToArray( value );\n\n\t\tif ( classes.length ) {\n\t\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\t\tcurValue = getClass( elem );\n\n\t\t\t\t// This expression is here for better compressibility (see addClass)\n\t\t\t\tcur = elem.nodeType === 1 && ( \" \" + stripAndCollapse( curValue ) + \" \" );\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( ( clazz = classes[ j++ ] ) ) {\n\n\t\t\t\t\t\t// Remove *all* instances\n\t\t\t\t\t\twhile ( cur.indexOf( \" \" + clazz + \" \" ) > -1 ) {\n\t\t\t\t\t\t\tcur = cur.replace( \" \" + clazz + \" \", \" \" );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = stripAndCollapse( cur );\n\t\t\t\t\tif ( curValue !== finalValue ) {\n\t\t\t\t\t\telem.setAttribute( \"class\", finalValue );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\ttoggleClass: function( value, stateVal ) {\n\t\tvar type = typeof value,\n\t\t\tisValidValue = type === \"string\" || Array.isArray( value );\n\n\t\tif ( typeof stateVal === \"boolean\" && isValidValue ) {\n\t\t\treturn stateVal ? this.addClass( value ) : this.removeClass( value );\n\t\t}\n\n\t\tif ( isFunction( value ) ) {\n\t\t\treturn this.each( function( i ) {\n\t\t\t\tjQuery( this ).toggleClass(\n\t\t\t\t\tvalue.call( this, i, getClass( this ), stateVal ),\n\t\t\t\t\tstateVal\n\t\t\t\t);\n\t\t\t} );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar className, i, self, classNames;\n\n\t\t\tif ( isValidValue ) {\n\n\t\t\t\t// Toggle individual class names\n\t\t\t\ti = 0;\n\t\t\t\tself = jQuery( this );\n\t\t\t\tclassNames = classesToArray( value );\n\n\t\t\t\twhile ( ( className = classNames[ i++ ] ) ) {\n\n\t\t\t\t\t// Check each className given, space separated list\n\t\t\t\t\tif ( self.hasClass( className ) ) {\n\t\t\t\t\t\tself.removeClass( className );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tself.addClass( className );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t// Toggle whole class name\n\t\t\t} else if ( value === undefined || type === \"boolean\" ) {\n\t\t\t\tclassName = getClass( this );\n\t\t\t\tif ( className ) {\n\n\t\t\t\t\t// Store className if set\n\t\t\t\t\tdataPriv.set( this, \"__className__\", className );\n\t\t\t\t}\n\n\t\t\t\t// If the element has a class name or if we're passed `false`,\n\t\t\t\t// then remove the whole classname (if there was one, the above saved it).\n\t\t\t\t// Otherwise bring back whatever was previously saved (if anything),\n\t\t\t\t// falling back to the empty string if nothing was stored.\n\t\t\t\tif ( this.setAttribute ) {\n\t\t\t\t\tthis.setAttribute( \"class\",\n\t\t\t\t\t\tclassName || value === false ?\n\t\t\t\t\t\t\t\"\" :\n\t\t\t\t\t\t\tdataPriv.get( this, \"__className__\" ) || \"\"\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t},\n\n\thasClass: function( selector ) {\n\t\tvar className, elem,\n\t\t\ti = 0;\n\n\t\tclassName = \" \" + selector + \" \";\n\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\tif ( elem.nodeType === 1 &&\n\t\t\t\t( \" \" + stripAndCollapse( getClass( elem ) ) + \" \" ).indexOf( className ) > -1 ) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n} );\n\n\n\n\nvar rreturn = /\\r/g;\n\njQuery.fn.extend( {\n\tval: function( value ) {\n\t\tvar hooks, ret, valueIsFunction,\n\t\t\telem = this[ 0 ];\n\n\t\tif ( !arguments.length ) {\n\t\t\tif ( elem ) {\n\t\t\t\thooks = jQuery.valHooks[ elem.type ] ||\n\t\t\t\t\tjQuery.valHooks[ elem.nodeName.toLowerCase() ];\n\n\t\t\t\tif ( hooks &&\n\t\t\t\t\t\"get\" in hooks &&\n\t\t\t\t\t( ret = hooks.get( elem, \"value\" ) ) !== undefined\n\t\t\t\t) {\n\t\t\t\t\treturn ret;\n\t\t\t\t}\n\n\t\t\t\tret = elem.value;\n\n\t\t\t\t// Handle most common string cases\n\t\t\t\tif ( typeof ret === \"string\" ) {\n\t\t\t\t\treturn ret.replace( rreturn, \"\" );\n\t\t\t\t}\n\n\t\t\t\t// Handle cases where value is null/undef or number\n\t\t\t\treturn ret == null ? \"\" : ret;\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tvalueIsFunction = isFunction( value );\n\n\t\treturn this.each( function( i ) {\n\t\t\tvar val;\n\n\t\t\tif ( this.nodeType !== 1 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( valueIsFunction ) {\n\t\t\t\tval = value.call( this, i, jQuery( this ).val() );\n\t\t\t} else {\n\t\t\t\tval = value;\n\t\t\t}\n\n\t\t\t// Treat null/undefined as \"\"; convert numbers to string\n\t\t\tif ( val == null ) {\n\t\t\t\tval = \"\";\n\n\t\t\t} else if ( typeof val === \"number\" ) {\n\t\t\t\tval += \"\";\n\n\t\t\t} else if ( Array.isArray( val ) ) {\n\t\t\t\tval = jQuery.map( val, function( value ) {\n\t\t\t\t\treturn value == null ? \"\" : value + \"\";\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\thooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];\n\n\t\t\t// If set returns undefined, fall back to normal setting\n\t\t\tif ( !hooks || !( \"set\" in hooks ) || hooks.set( this, val, \"value\" ) === undefined ) {\n\t\t\t\tthis.value = val;\n\t\t\t}\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tvalHooks: {\n\t\toption: {\n\t\t\tget: function( elem ) {\n\n\t\t\t\tvar val = jQuery.find.attr( elem, \"value\" );\n\t\t\t\treturn val != null ?\n\t\t\t\t\tval :\n\n\t\t\t\t\t// Support: IE <=10 - 11 only\n\t\t\t\t\t// option.text throws exceptions (#14686, #14858)\n\t\t\t\t\t// Strip and collapse whitespace\n\t\t\t\t\t// https://html.spec.whatwg.org/#strip-and-collapse-whitespace\n\t\t\t\t\tstripAndCollapse( jQuery.text( elem ) );\n\t\t\t}\n\t\t},\n\t\tselect: {\n\t\t\tget: function( elem ) {\n\t\t\t\tvar value, option, i,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tindex = elem.selectedIndex,\n\t\t\t\t\tone = elem.type === \"select-one\",\n\t\t\t\t\tvalues = one ? null : [],\n\t\t\t\t\tmax = one ? index + 1 : options.length;\n\n\t\t\t\tif ( index < 0 ) {\n\t\t\t\t\ti = max;\n\n\t\t\t\t} else {\n\t\t\t\t\ti = one ? index : 0;\n\t\t\t\t}\n\n\t\t\t\t// Loop through all the selected options\n\t\t\t\tfor ( ; i < max; i++ ) {\n\t\t\t\t\toption = options[ i ];\n\n\t\t\t\t\t// Support: IE <=9 only\n\t\t\t\t\t// IE8-9 doesn't update selected after form reset (#2551)\n\t\t\t\t\tif ( ( option.selected || i === index ) &&\n\n\t\t\t\t\t\t\t// Don't return options that are disabled or in a disabled optgroup\n\t\t\t\t\t\t\t!option.disabled &&\n\t\t\t\t\t\t\t( !option.parentNode.disabled ||\n\t\t\t\t\t\t\t\t!nodeName( option.parentNode, \"optgroup\" ) ) ) {\n\n\t\t\t\t\t\t// Get the specific value for the option\n\t\t\t\t\t\tvalue = jQuery( option ).val();\n\n\t\t\t\t\t\t// We don't need an array for one selects\n\t\t\t\t\t\tif ( one ) {\n\t\t\t\t\t\t\treturn value;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Multi-Selects return an array\n\t\t\t\t\t\tvalues.push( value );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn values;\n\t\t\t},\n\n\t\t\tset: function( elem, value ) {\n\t\t\t\tvar optionSet, option,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tvalues = jQuery.makeArray( value ),\n\t\t\t\t\ti = options.length;\n\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\toption = options[ i ];\n\n\t\t\t\t\t/* eslint-disable no-cond-assign */\n\n\t\t\t\t\tif ( option.selected =\n\t\t\t\t\t\tjQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1\n\t\t\t\t\t) {\n\t\t\t\t\t\toptionSet = true;\n\t\t\t\t\t}\n\n\t\t\t\t\t/* eslint-enable no-cond-assign */\n\t\t\t\t}\n\n\t\t\t\t// Force browsers to behave consistently when non-matching value is set\n\t\t\t\tif ( !optionSet ) {\n\t\t\t\t\telem.selectedIndex = -1;\n\t\t\t\t}\n\t\t\t\treturn values;\n\t\t\t}\n\t\t}\n\t}\n} );\n\n// Radios and checkboxes getter/setter\njQuery.each( [ \"radio\", \"checkbox\" ], function() {\n\tjQuery.valHooks[ this ] = {\n\t\tset: function( elem, value ) {\n\t\t\tif ( Array.isArray( value ) ) {\n\t\t\t\treturn ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 );\n\t\t\t}\n\t\t}\n\t};\n\tif ( !support.checkOn ) {\n\t\tjQuery.valHooks[ this ].get = function( elem ) {\n\t\t\treturn elem.getAttribute( \"value\" ) === null ? \"on\" : elem.value;\n\t\t};\n\t}\n} );\n\n\n\n\n// Return jQuery for attributes-only inclusion\n\n\nsupport.focusin = \"onfocusin\" in window;\n\n\nvar rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,\n\tstopPropagationCallback = function( e ) {\n\t\te.stopPropagation();\n\t};\n\njQuery.extend( jQuery.event, {\n\n\ttrigger: function( event, data, elem, onlyHandlers ) {\n\n\t\tvar i, cur, tmp, bubbleType, ontype, handle, special, lastElement,\n\t\t\teventPath = [ elem || document ],\n\t\t\ttype = hasOwn.call( event, \"type\" ) ? event.type : event,\n\t\t\tnamespaces = hasOwn.call( event, \"namespace\" ) ? event.namespace.split( \".\" ) : [];\n\n\t\tcur = lastElement = tmp = elem = elem || document;\n\n\t\t// Don't do events on text and comment nodes\n\t\tif ( elem.nodeType === 3 || elem.nodeType === 8 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// focus/blur morphs to focusin/out; ensure we're not firing them right now\n\t\tif ( rfocusMorph.test( type + jQuery.event.triggered ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( type.indexOf( \".\" ) > -1 ) {\n\n\t\t\t// Namespaced trigger; create a regexp to match event type in handle()\n\t\t\tnamespaces = type.split( \".\" );\n\t\t\ttype = namespaces.shift();\n\t\t\tnamespaces.sort();\n\t\t}\n\t\tontype = type.indexOf( \":\" ) < 0 && \"on\" + type;\n\n\t\t// Caller can pass in a jQuery.Event object, Object, or just an event type string\n\t\tevent = event[ jQuery.expando ] ?\n\t\t\tevent :\n\t\t\tnew jQuery.Event( type, typeof event === \"object\" && event );\n\n\t\t// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)\n\t\tevent.isTrigger = onlyHandlers ? 2 : 3;\n\t\tevent.namespace = namespaces.join( \".\" );\n\t\tevent.rnamespace = event.namespace ?\n\t\t\tnew RegExp( \"(^|\\\\.)\" + namespaces.join( \"\\\\.(?:.*\\\\.|)\" ) + \"(\\\\.|$)\" ) :\n\t\t\tnull;\n\n\t\t// Clean up the event in case it is being reused\n\t\tevent.result = undefined;\n\t\tif ( !event.target ) {\n\t\t\tevent.target = elem;\n\t\t}\n\n\t\t// Clone any incoming data and prepend the event, creating the handler arg list\n\t\tdata = data == null ?\n\t\t\t[ event ] :\n\t\t\tjQuery.makeArray( data, [ event ] );\n\n\t\t// Allow special events to draw outside the lines\n\t\tspecial = jQuery.event.special[ type ] || {};\n\t\tif ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine event propagation path in advance, per W3C events spec (#9951)\n\t\t// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)\n\t\tif ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) {\n\n\t\t\tbubbleType = special.delegateType || type;\n\t\t\tif ( !rfocusMorph.test( bubbleType + type ) ) {\n\t\t\t\tcur = cur.parentNode;\n\t\t\t}\n\t\t\tfor ( ; cur; cur = cur.parentNode ) {\n\t\t\t\teventPath.push( cur );\n\t\t\t\ttmp = cur;\n\t\t\t}\n\n\t\t\t// Only add window if we got to document (e.g., not plain obj or detached DOM)\n\t\t\tif ( tmp === ( elem.ownerDocument || document ) ) {\n\t\t\t\teventPath.push( tmp.defaultView || tmp.parentWindow || window );\n\t\t\t}\n\t\t}\n\n\t\t// Fire handlers on the event path\n\t\ti = 0;\n\t\twhile ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {\n\t\t\tlastElement = cur;\n\t\t\tevent.type = i > 1 ?\n\t\t\t\tbubbleType :\n\t\t\t\tspecial.bindType || type;\n\n\t\t\t// jQuery handler\n\t\t\thandle = ( dataPriv.get( cur, \"events\" ) || Object.create( null ) )[ event.type ] &&\n\t\t\t\tdataPriv.get( cur, \"handle\" );\n\t\t\tif ( handle ) {\n\t\t\t\thandle.apply( cur, data );\n\t\t\t}\n\n\t\t\t// Native handler\n\t\t\thandle = ontype && cur[ ontype ];\n\t\t\tif ( handle && handle.apply && acceptData( cur ) ) {\n\t\t\t\tevent.result = handle.apply( cur, data );\n\t\t\t\tif ( event.result === false ) {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tevent.type = type;\n\n\t\t// If nobody prevented the default action, do it now\n\t\tif ( !onlyHandlers && !event.isDefaultPrevented() ) {\n\n\t\t\tif ( ( !special._default ||\n\t\t\t\tspecial._default.apply( eventPath.pop(), data ) === false ) &&\n\t\t\t\tacceptData( elem ) ) {\n\n\t\t\t\t// Call a native DOM method on the target with the same name as the event.\n\t\t\t\t// Don't do default actions on window, that's where global variables be (#6170)\n\t\t\t\tif ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) {\n\n\t\t\t\t\t// Don't re-trigger an onFOO event when we call its FOO() method\n\t\t\t\t\ttmp = elem[ ontype ];\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = null;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prevent re-triggering of the same event, since we already bubbled it above\n\t\t\t\t\tjQuery.event.triggered = type;\n\n\t\t\t\t\tif ( event.isPropagationStopped() ) {\n\t\t\t\t\t\tlastElement.addEventListener( type, stopPropagationCallback );\n\t\t\t\t\t}\n\n\t\t\t\t\telem[ type ]();\n\n\t\t\t\t\tif ( event.isPropagationStopped() ) {\n\t\t\t\t\t\tlastElement.removeEventListener( type, stopPropagationCallback );\n\t\t\t\t\t}\n\n\t\t\t\t\tjQuery.event.triggered = undefined;\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = tmp;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\t// Piggyback on a donor event to simulate a different one\n\t// Used only for `focus(in | out)` events\n\tsimulate: function( type, elem, event ) {\n\t\tvar e = jQuery.extend(\n\t\t\tnew jQuery.Event(),\n\t\t\tevent,\n\t\t\t{\n\t\t\t\ttype: type,\n\t\t\t\tisSimulated: true\n\t\t\t}\n\t\t);\n\n\t\tjQuery.event.trigger( e, null, elem );\n\t}\n\n} );\n\njQuery.fn.extend( {\n\n\ttrigger: function( type, data ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.event.trigger( type, data, this );\n\t\t} );\n\t},\n\ttriggerHandler: function( type, data ) {\n\t\tvar elem = this[ 0 ];\n\t\tif ( elem ) {\n\t\t\treturn jQuery.event.trigger( type, data, elem, true );\n\t\t}\n\t}\n} );\n\n\n// Support: Firefox <=44\n// Firefox doesn't have focus(in | out) events\n// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787\n//\n// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1\n// focus(in | out) events fire after focus & blur events,\n// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order\n// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857\nif ( !support.focusin ) {\n\tjQuery.each( { focus: \"focusin\", blur: \"focusout\" }, function( orig, fix ) {\n\n\t\t// Attach a single capturing handler on the document while someone wants focusin/focusout\n\t\tvar handler = function( event ) {\n\t\t\tjQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );\n\t\t};\n\n\t\tjQuery.event.special[ fix ] = {\n\t\t\tsetup: function() {\n\n\t\t\t\t// Handle: regular nodes (via `this.ownerDocument`), window\n\t\t\t\t// (via `this.document`) & document (via `this`).\n\t\t\t\tvar doc = this.ownerDocument || this.document || this,\n\t\t\t\t\tattaches = dataPriv.access( doc, fix );\n\n\t\t\t\tif ( !attaches ) {\n\t\t\t\t\tdoc.addEventListener( orig, handler, true );\n\t\t\t\t}\n\t\t\t\tdataPriv.access( doc, fix, ( attaches || 0 ) + 1 );\n\t\t\t},\n\t\t\tteardown: function() {\n\t\t\t\tvar doc = this.ownerDocument || this.document || this,\n\t\t\t\t\tattaches = dataPriv.access( doc, fix ) - 1;\n\n\t\t\t\tif ( !attaches ) {\n\t\t\t\t\tdoc.removeEventListener( orig, handler, true );\n\t\t\t\t\tdataPriv.remove( doc, fix );\n\n\t\t\t\t} else {\n\t\t\t\t\tdataPriv.access( doc, fix, attaches );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t} );\n}\n\n\n// Cross-browser xml parsing\njQuery.parseXML = function( data ) {\n\tvar xml, parserErrorElem;\n\tif ( !data || typeof data !== \"string\" ) {\n\t\treturn null;\n\t}\n\n\t// Support: IE 9 - 11 only\n\t// IE throws on parseFromString with invalid input.\n\ttry {\n\t\txml = ( new window.DOMParser() ).parseFromString( data, \"text/xml\" );\n\t} catch ( e ) {}\n\n\tparserErrorElem = xml && xml.getElementsByTagName( \"parsererror\" )[ 0 ];\n\tif ( !xml || parserErrorElem ) {\n\t\tjQuery.error( \"Invalid XML: \" + (\n\t\t\tparserErrorElem ?\n\t\t\t\tjQuery.map( parserErrorElem.childNodes, function( el ) {\n\t\t\t\t\treturn el.textContent;\n\t\t\t\t} ).join( \"\\n\" ) :\n\t\t\t\tdata\n\t\t) );\n\t}\n\treturn xml;\n};\n\n\nvar\n\trbracket = /\\[\\]$/,\n\trCRLF = /\\r?\\n/g,\n\trsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,\n\trsubmittable = /^(?:input|select|textarea|keygen)/i;\n\nfunction buildParams( prefix, obj, traditional, add ) {\n\tvar name;\n\n\tif ( Array.isArray( obj ) ) {\n\n\t\t// Serialize array item.\n\t\tjQuery.each( obj, function( i, v ) {\n\t\t\tif ( traditional || rbracket.test( prefix ) ) {\n\n\t\t\t\t// Treat each array item as a scalar.\n\t\t\t\tadd( prefix, v );\n\n\t\t\t} else {\n\n\t\t\t\t// Item is non-scalar (array or object), encode its numeric index.\n\t\t\t\tbuildParams(\n\t\t\t\t\tprefix + \"[\" + ( typeof v === \"object\" && v != null ? i : \"\" ) + \"]\",\n\t\t\t\t\tv,\n\t\t\t\t\ttraditional,\n\t\t\t\t\tadd\n\t\t\t\t);\n\t\t\t}\n\t\t} );\n\n\t} else if ( !traditional && toType( obj ) === \"object\" ) {\n\n\t\t// Serialize object item.\n\t\tfor ( name in obj ) {\n\t\t\tbuildParams( prefix + \"[\" + name + \"]\", obj[ name ], traditional, add );\n\t\t}\n\n\t} else {\n\n\t\t// Serialize scalar item.\n\t\tadd( prefix, obj );\n\t}\n}\n\n// Serialize an array of form elements or a set of\n// key/values into a query string\njQuery.param = function( a, traditional ) {\n\tvar prefix,\n\t\ts = [],\n\t\tadd = function( key, valueOrFunction ) {\n\n\t\t\t// If value is a function, invoke it and use its return value\n\t\t\tvar value = isFunction( valueOrFunction ) ?\n\t\t\t\tvalueOrFunction() :\n\t\t\t\tvalueOrFunction;\n\n\t\t\ts[ s.length ] = encodeURIComponent( key ) + \"=\" +\n\t\t\t\tencodeURIComponent( value == null ? \"\" : value );\n\t\t};\n\n\tif ( a == null ) {\n\t\treturn \"\";\n\t}\n\n\t// If an array was passed in, assume that it is an array of form elements.\n\tif ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {\n\n\t\t// Serialize the form elements\n\t\tjQuery.each( a, function() {\n\t\t\tadd( this.name, this.value );\n\t\t} );\n\n\t} else {\n\n\t\t// If traditional, encode the \"old\" way (the way 1.3.2 or older\n\t\t// did it), otherwise encode params recursively.\n\t\tfor ( prefix in a ) {\n\t\t\tbuildParams( prefix, a[ prefix ], traditional, add );\n\t\t}\n\t}\n\n\t// Return the resulting serialization\n\treturn s.join( \"&\" );\n};\n\njQuery.fn.extend( {\n\tserialize: function() {\n\t\treturn jQuery.param( this.serializeArray() );\n\t},\n\tserializeArray: function() {\n\t\treturn this.map( function() {\n\n\t\t\t// Can add propHook for \"elements\" to filter or add form elements\n\t\t\tvar elements = jQuery.prop( this, \"elements\" );\n\t\t\treturn elements ? jQuery.makeArray( elements ) : this;\n\t\t} ).filter( function() {\n\t\t\tvar type = this.type;\n\n\t\t\t// Use .is( \":disabled\" ) so that fieldset[disabled] works\n\t\t\treturn this.name && !jQuery( this ).is( \":disabled\" ) &&\n\t\t\t\trsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&\n\t\t\t\t( this.checked || !rcheckableType.test( type ) );\n\t\t} ).map( function( _i, elem ) {\n\t\t\tvar val = jQuery( this ).val();\n\n\t\t\tif ( val == null ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tif ( Array.isArray( val ) ) {\n\t\t\t\treturn jQuery.map( val, function( val ) {\n\t\t\t\t\treturn { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\treturn { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t} ).get();\n\t}\n} );\n\n\njQuery.fn.extend( {\n\twrapAll: function( html ) {\n\t\tvar wrap;\n\n\t\tif ( this[ 0 ] ) {\n\t\t\tif ( isFunction( html ) ) {\n\t\t\t\thtml = html.call( this[ 0 ] );\n\t\t\t}\n\n\t\t\t// The elements to wrap the target around\n\t\t\twrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );\n\n\t\t\tif ( this[ 0 ].parentNode ) {\n\t\t\t\twrap.insertBefore( this[ 0 ] );\n\t\t\t}\n\n\t\t\twrap.map( function() {\n\t\t\t\tvar elem = this;\n\n\t\t\t\twhile ( elem.firstElementChild ) {\n\t\t\t\t\telem = elem.firstElementChild;\n\t\t\t\t}\n\n\t\t\t\treturn elem;\n\t\t\t} ).append( this );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\twrapInner: function( html ) {\n\t\tif ( isFunction( html ) ) {\n\t\t\treturn this.each( function( i ) {\n\t\t\t\tjQuery( this ).wrapInner( html.call( this, i ) );\n\t\t\t} );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar self = jQuery( this ),\n\t\t\t\tcontents = self.contents();\n\n\t\t\tif ( contents.length ) {\n\t\t\t\tcontents.wrapAll( html );\n\n\t\t\t} else {\n\t\t\t\tself.append( html );\n\t\t\t}\n\t\t} );\n\t},\n\n\twrap: function( html ) {\n\t\tvar htmlIsFunction = isFunction( html );\n\n\t\treturn this.each( function( i ) {\n\t\t\tjQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html );\n\t\t} );\n\t},\n\n\tunwrap: function( selector ) {\n\t\tthis.parent( selector ).not( \"body\" ).each( function() {\n\t\t\tjQuery( this ).replaceWith( this.childNodes );\n\t\t} );\n\t\treturn this;\n\t}\n} );\n\n\njQuery.expr.pseudos.hidden = function( elem ) {\n\treturn !jQuery.expr.pseudos.visible( elem );\n};\njQuery.expr.pseudos.visible = function( elem ) {\n\treturn !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );\n};\n\n\n\n\n// Support: Safari 8 only\n// In Safari 8 documents created via document.implementation.createHTMLDocument\n// collapse sibling forms: the second one becomes a child of the first one.\n// Because of that, this security measure has to be disabled in Safari 8.\n// https://bugs.webkit.org/show_bug.cgi?id=137337\nsupport.createHTMLDocument = ( function() {\n\tvar body = document.implementation.createHTMLDocument( \"\" ).body;\n\tbody.innerHTML = \"<form></form><form></form>\";\n\treturn body.childNodes.length === 2;\n} )();\n\n\n// Argument \"data\" should be string of html\n// context (optional): If specified, the fragment will be created in this context,\n// defaults to document\n// keepScripts (optional): If true, will include scripts passed in the html string\njQuery.parseHTML = function( data, context, keepScripts ) {\n\tif ( typeof data !== \"string\" ) {\n\t\treturn [];\n\t}\n\tif ( typeof context === \"boolean\" ) {\n\t\tkeepScripts = context;\n\t\tcontext = false;\n\t}\n\n\tvar base, parsed, scripts;\n\n\tif ( !context ) {\n\n\t\t// Stop scripts or inline event handlers from being executed immediately\n\t\t// by using document.implementation\n\t\tif ( support.createHTMLDocument ) {\n\t\t\tcontext = document.implementation.createHTMLDocument( \"\" );\n\n\t\t\t// Set the base href for the created document\n\t\t\t// so any parsed elements with URLs\n\t\t\t// are based on the document's URL (gh-2965)\n\t\t\tbase = context.createElement( \"base\" );\n\t\t\tbase.href = document.location.href;\n\t\t\tcontext.head.appendChild( base );\n\t\t} else {\n\t\t\tcontext = document;\n\t\t}\n\t}\n\n\tparsed = rsingleTag.exec( data );\n\tscripts = !keepScripts && [];\n\n\t// Single tag\n\tif ( parsed ) {\n\t\treturn [ context.createElement( parsed[ 1 ] ) ];\n\t}\n\n\tparsed = buildFragment( [ data ], context, scripts );\n\n\tif ( scripts && scripts.length ) {\n\t\tjQuery( scripts ).remove();\n\t}\n\n\treturn jQuery.merge( [], parsed.childNodes );\n};\n\n\njQuery.offset = {\n\tsetOffset: function( elem, options, i ) {\n\t\tvar curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,\n\t\t\tposition = jQuery.css( elem, \"position\" ),\n\t\t\tcurElem = jQuery( elem ),\n\t\t\tprops = {};\n\n\t\t// Set position first, in-case top/left are set even on static elem\n\t\tif ( position === \"static\" ) {\n\t\t\telem.style.position = \"relative\";\n\t\t}\n\n\t\tcurOffset = curElem.offset();\n\t\tcurCSSTop = jQuery.css( elem, \"top\" );\n\t\tcurCSSLeft = jQuery.css( elem, \"left\" );\n\t\tcalculatePosition = ( position === \"absolute\" || position === \"fixed\" ) &&\n\t\t\t( curCSSTop + curCSSLeft ).indexOf( \"auto\" ) > -1;\n\n\t\t// Need to be able to calculate position if either\n\t\t// top or left is auto and position is either absolute or fixed\n\t\tif ( calculatePosition ) {\n\t\t\tcurPosition = curElem.position();\n\t\t\tcurTop = curPosition.top;\n\t\t\tcurLeft = curPosition.left;\n\n\t\t} else {\n\t\t\tcurTop = parseFloat( curCSSTop ) || 0;\n\t\t\tcurLeft = parseFloat( curCSSLeft ) || 0;\n\t\t}\n\n\t\tif ( isFunction( options ) ) {\n\n\t\t\t// Use jQuery.extend here to allow modification of coordinates argument (gh-1848)\n\t\t\toptions = options.call( elem, i, jQuery.extend( {}, curOffset ) );\n\t\t}\n\n\t\tif ( options.top != null ) {\n\t\t\tprops.top = ( options.top - curOffset.top ) + curTop;\n\t\t}\n\t\tif ( options.left != null ) {\n\t\t\tprops.left = ( options.left - curOffset.left ) + curLeft;\n\t\t}\n\n\t\tif ( \"using\" in options ) {\n\t\t\toptions.using.call( elem, props );\n\n\t\t} else {\n\t\t\tcurElem.css( props );\n\t\t}\n\t}\n};\n\njQuery.fn.extend( {\n\n\t// offset() relates an element's border box to the document origin\n\toffset: function( options ) {\n\n\t\t// Preserve chaining for setter\n\t\tif ( arguments.length ) {\n\t\t\treturn options === undefined ?\n\t\t\t\tthis :\n\t\t\t\tthis.each( function( i ) {\n\t\t\t\t\tjQuery.offset.setOffset( this, options, i );\n\t\t\t\t} );\n\t\t}\n\n\t\tvar rect, win,\n\t\t\telem = this[ 0 ];\n\n\t\tif ( !elem ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Return zeros for disconnected and hidden (display: none) elements (gh-2310)\n\t\t// Support: IE <=11 only\n\t\t// Running getBoundingClientRect on a\n\t\t// disconnected node in IE throws an error\n\t\tif ( !elem.getClientRects().length ) {\n\t\t\treturn { top: 0, left: 0 };\n\t\t}\n\n\t\t// Get document-relative position by adding viewport scroll to viewport-relative gBCR\n\t\trect = elem.getBoundingClientRect();\n\t\twin = elem.ownerDocument.defaultView;\n\t\treturn {\n\t\t\ttop: rect.top + win.pageYOffset,\n\t\t\tleft: rect.left + win.pageXOffset\n\t\t};\n\t},\n\n\t// position() relates an element's margin box to its offset parent's padding box\n\t// This corresponds to the behavior of CSS absolute positioning\n\tposition: function() {\n\t\tif ( !this[ 0 ] ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar offsetParent, offset, doc,\n\t\t\telem = this[ 0 ],\n\t\t\tparentOffset = { top: 0, left: 0 };\n\n\t\t// position:fixed elements are offset from the viewport, which itself always has zero offset\n\t\tif ( jQuery.css( elem, \"position\" ) === \"fixed\" ) {\n\n\t\t\t// Assume position:fixed implies availability of getBoundingClientRect\n\t\t\toffset = elem.getBoundingClientRect();\n\n\t\t} else {\n\t\t\toffset = this.offset();\n\n\t\t\t// Account for the *real* offset parent, which can be the document or its root element\n\t\t\t// when a statically positioned element is identified\n\t\t\tdoc = elem.ownerDocument;\n\t\t\toffsetParent = elem.offsetParent || doc.documentElement;\n\t\t\twhile ( offsetParent &&\n\t\t\t\t( offsetParent === doc.body || offsetParent === doc.documentElement ) &&\n\t\t\t\tjQuery.css( offsetParent, \"position\" ) === \"static\" ) {\n\n\t\t\t\toffsetParent = offsetParent.parentNode;\n\t\t\t}\n\t\t\tif ( offsetParent && offsetParent !== elem && offsetParent.nodeType === 1 ) {\n\n\t\t\t\t// Incorporate borders into its offset, since they are outside its content origin\n\t\t\t\tparentOffset = jQuery( offsetParent ).offset();\n\t\t\t\tparentOffset.top += jQuery.css( offsetParent, \"borderTopWidth\", true );\n\t\t\t\tparentOffset.left += jQuery.css( offsetParent, \"borderLeftWidth\", true );\n\t\t\t}\n\t\t}\n\n\t\t// Subtract parent offsets and element margins\n\t\treturn {\n\t\t\ttop: offset.top - parentOffset.top - jQuery.css( elem, \"marginTop\", true ),\n\t\t\tleft: offset.left - parentOffset.left - jQuery.css( elem, \"marginLeft\", true )\n\t\t};\n\t},\n\n\t// This method will return documentElement in the following cases:\n\t// 1) For the element inside the iframe without offsetParent, this method will return\n\t//    documentElement of the parent window\n\t// 2) For the hidden or detached element\n\t// 3) For body or html element, i.e. in case of the html node - it will return itself\n\t//\n\t// but those exceptions were never presented as a real life use-cases\n\t// and might be considered as more preferable results.\n\t//\n\t// This logic, however, is not guaranteed and can change at any point in the future\n\toffsetParent: function() {\n\t\treturn this.map( function() {\n\t\t\tvar offsetParent = this.offsetParent;\n\n\t\t\twhile ( offsetParent && jQuery.css( offsetParent, \"position\" ) === \"static\" ) {\n\t\t\t\toffsetParent = offsetParent.offsetParent;\n\t\t\t}\n\n\t\t\treturn offsetParent || documentElement;\n\t\t} );\n\t}\n} );\n\n// Create scrollLeft and scrollTop methods\njQuery.each( { scrollLeft: \"pageXOffset\", scrollTop: \"pageYOffset\" }, function( method, prop ) {\n\tvar top = \"pageYOffset\" === prop;\n\n\tjQuery.fn[ method ] = function( val ) {\n\t\treturn access( this, function( elem, method, val ) {\n\n\t\t\t// Coalesce documents and windows\n\t\t\tvar win;\n\t\t\tif ( isWindow( elem ) ) {\n\t\t\t\twin = elem;\n\t\t\t} else if ( elem.nodeType === 9 ) {\n\t\t\t\twin = elem.defaultView;\n\t\t\t}\n\n\t\t\tif ( val === undefined ) {\n\t\t\t\treturn win ? win[ prop ] : elem[ method ];\n\t\t\t}\n\n\t\t\tif ( win ) {\n\t\t\t\twin.scrollTo(\n\t\t\t\t\t!top ? val : win.pageXOffset,\n\t\t\t\t\ttop ? val : win.pageYOffset\n\t\t\t\t);\n\n\t\t\t} else {\n\t\t\t\telem[ method ] = val;\n\t\t\t}\n\t\t}, method, val, arguments.length );\n\t};\n} );\n\n// Support: Safari <=7 - 9.1, Chrome <=37 - 49\n// Add the top/left cssHooks using jQuery.fn.position\n// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084\n// Blink bug: https://bugs.chromium.org/p/chromium/issues/detail?id=589347\n// getComputedStyle returns percent when specified for top/left/bottom/right;\n// rather than make the css module depend on the offset module, just check for it here\njQuery.each( [ \"top\", \"left\" ], function( _i, prop ) {\n\tjQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,\n\t\tfunction( elem, computed ) {\n\t\t\tif ( computed ) {\n\t\t\t\tcomputed = curCSS( elem, prop );\n\n\t\t\t\t// If curCSS returns percentage, fallback to offset\n\t\t\t\treturn rnumnonpx.test( computed ) ?\n\t\t\t\t\tjQuery( elem ).position()[ prop ] + \"px\" :\n\t\t\t\t\tcomputed;\n\t\t\t}\n\t\t}\n\t);\n} );\n\n\n// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods\njQuery.each( { Height: \"height\", Width: \"width\" }, function( name, type ) {\n\tjQuery.each( {\n\t\tpadding: \"inner\" + name,\n\t\tcontent: type,\n\t\t\"\": \"outer\" + name\n\t}, function( defaultExtra, funcName ) {\n\n\t\t// Margin is only for outerHeight, outerWidth\n\t\tjQuery.fn[ funcName ] = function( margin, value ) {\n\t\t\tvar chainable = arguments.length && ( defaultExtra || typeof margin !== \"boolean\" ),\n\t\t\t\textra = defaultExtra || ( margin === true || value === true ? \"margin\" : \"border\" );\n\n\t\t\treturn access( this, function( elem, type, value ) {\n\t\t\t\tvar doc;\n\n\t\t\t\tif ( isWindow( elem ) ) {\n\n\t\t\t\t\t// $( window ).outerWidth/Height return w/h including scrollbars (gh-1729)\n\t\t\t\t\treturn funcName.indexOf( \"outer\" ) === 0 ?\n\t\t\t\t\t\telem[ \"inner\" + name ] :\n\t\t\t\t\t\telem.document.documentElement[ \"client\" + name ];\n\t\t\t\t}\n\n\t\t\t\t// Get document width or height\n\t\t\t\tif ( elem.nodeType === 9 ) {\n\t\t\t\t\tdoc = elem.documentElement;\n\n\t\t\t\t\t// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],\n\t\t\t\t\t// whichever is greatest\n\t\t\t\t\treturn Math.max(\n\t\t\t\t\t\telem.body[ \"scroll\" + name ], doc[ \"scroll\" + name ],\n\t\t\t\t\t\telem.body[ \"offset\" + name ], doc[ \"offset\" + name ],\n\t\t\t\t\t\tdoc[ \"client\" + name ]\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn value === undefined ?\n\n\t\t\t\t\t// Get width or height on the element, requesting but not forcing parseFloat\n\t\t\t\t\tjQuery.css( elem, type, extra ) :\n\n\t\t\t\t\t// Set width or height on the element\n\t\t\t\t\tjQuery.style( elem, type, value, extra );\n\t\t\t}, type, chainable ? margin : undefined, chainable );\n\t\t};\n\t} );\n} );\n\n\njQuery.fn.extend( {\n\n\tbind: function( types, data, fn ) {\n\t\treturn this.on( types, null, data, fn );\n\t},\n\tunbind: function( types, fn ) {\n\t\treturn this.off( types, null, fn );\n\t},\n\n\tdelegate: function( selector, types, data, fn ) {\n\t\treturn this.on( types, selector, data, fn );\n\t},\n\tundelegate: function( selector, types, fn ) {\n\n\t\t// ( namespace ) or ( selector, types [, fn] )\n\t\treturn arguments.length === 1 ?\n\t\t\tthis.off( selector, \"**\" ) :\n\t\t\tthis.off( types, selector || \"**\", fn );\n\t},\n\n\thover: function( fnOver, fnOut ) {\n\t\treturn this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );\n\t}\n} );\n\njQuery.each(\n\t( \"blur focus focusin focusout resize scroll click dblclick \" +\n\t\"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave \" +\n\t\"change select submit keydown keypress keyup contextmenu\" ).split( \" \" ),\n\tfunction( _i, name ) {\n\n\t\t// Handle event binding\n\t\tjQuery.fn[ name ] = function( data, fn ) {\n\t\t\treturn arguments.length > 0 ?\n\t\t\t\tthis.on( name, null, data, fn ) :\n\t\t\t\tthis.trigger( name );\n\t\t};\n\t}\n);\n\n\n\n\n// Support: Android <=4.0 only\n// Make sure we trim BOM and NBSP\nvar rtrim = /^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g;\n\n// Bind a function to a context, optionally partially applying any\n// arguments.\n// jQuery.proxy is deprecated to promote standards (specifically Function#bind)\n// However, it is not slated for removal any time soon\njQuery.proxy = function( fn, context ) {\n\tvar tmp, args, proxy;\n\n\tif ( typeof context === \"string\" ) {\n\t\ttmp = fn[ context ];\n\t\tcontext = fn;\n\t\tfn = tmp;\n\t}\n\n\t// Quick check to determine if target is callable, in the spec\n\t// this throws a TypeError, but we will just return undefined.\n\tif ( !isFunction( fn ) ) {\n\t\treturn undefined;\n\t}\n\n\t// Simulated bind\n\targs = slice.call( arguments, 2 );\n\tproxy = function() {\n\t\treturn fn.apply( context || this, args.concat( slice.call( arguments ) ) );\n\t};\n\n\t// Set the guid of unique handler to the same of original handler, so it can be removed\n\tproxy.guid = fn.guid = fn.guid || jQuery.guid++;\n\n\treturn proxy;\n};\n\njQuery.holdReady = function( hold ) {\n\tif ( hold ) {\n\t\tjQuery.readyWait++;\n\t} else {\n\t\tjQuery.ready( true );\n\t}\n};\njQuery.isArray = Array.isArray;\njQuery.parseJSON = JSON.parse;\njQuery.nodeName = nodeName;\njQuery.isFunction = isFunction;\njQuery.isWindow = isWindow;\njQuery.camelCase = camelCase;\njQuery.type = toType;\n\njQuery.now = Date.now;\n\njQuery.isNumeric = function( obj ) {\n\n\t// As of jQuery 3.0, isNumeric is limited to\n\t// strings and numbers (primitives or objects)\n\t// that can be coerced to finite numbers (gh-2662)\n\tvar type = jQuery.type( obj );\n\treturn ( type === \"number\" || type === \"string\" ) &&\n\n\t\t// parseFloat NaNs numeric-cast false positives (\"\")\n\t\t// ...but misinterprets leading-number strings, particularly hex literals (\"0x...\")\n\t\t// subtraction forces infinities to NaN\n\t\t!isNaN( obj - parseFloat( obj ) );\n};\n\njQuery.trim = function( text ) {\n\treturn text == null ?\n\t\t\"\" :\n\t\t( text + \"\" ).replace( rtrim, \"\" );\n};\n\n\n\n// Register as a named AMD module, since jQuery can be concatenated with other\n// files that may use define, but not via a proper concatenation script that\n// understands anonymous AMD modules. A named AMD is safest and most robust\n// way to register. Lowercase jquery is used because AMD module names are\n// derived from file names, and jQuery is normally delivered in a lowercase\n// file name. Do this after creating the global so that if an AMD module wants\n// to call noConflict to hide this version of jQuery, it will work.\n\n// Note that for maximum portability, libraries that are not jQuery should\n// declare themselves as anonymous modules, and avoid setting a global if an\n// AMD loader is present. jQuery is a special case. For more information, see\n// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon\n\nif ( typeof define === \"function\" && define.amd ) {\n\tdefine( \"jquery\", [], function() {\n\t\treturn jQuery;\n\t} );\n}\n\n\n\n\nvar\n\n\t// Map over jQuery in case of overwrite\n\t_jQuery = window.jQuery,\n\n\t// Map over the $ in case of overwrite\n\t_$ = window.$;\n\njQuery.noConflict = function( deep ) {\n\tif ( window.$ === jQuery ) {\n\t\twindow.$ = _$;\n\t}\n\n\tif ( deep && window.jQuery === jQuery ) {\n\t\twindow.jQuery = _jQuery;\n\t}\n\n\treturn jQuery;\n};\n\n// Expose jQuery and $ identifiers, even in AMD\n// (#7102#comment:10, https://github.com/jquery/jquery/pull/557)\n// and CommonJS for browser emulators (#13566)\nif ( typeof noGlobal === \"undefined\" ) {\n\twindow.jQuery = window.$ = jQuery;\n}\n\n\n\n\nreturn jQuery;\n} );\n","/**\n * [js-md5]{@link https://github.com/emn178/js-md5}\n *\n * @namespace md5\n * @version 0.7.3\n * @author Chen, Yi-Cyuan [emn178@gmail.com]\n * @copyright Chen, Yi-Cyuan 2014-2017\n * @license MIT\n */\n(function () {\n  'use strict';\n\n  var ERROR = 'input is invalid type';\n  var WINDOW = typeof window === 'object';\n  var root = WINDOW ? window : {};\n  if (root.JS_MD5_NO_WINDOW) {\n    WINDOW = false;\n  }\n  var WEB_WORKER = !WINDOW && typeof self === 'object';\n  var NODE_JS = !root.JS_MD5_NO_NODE_JS && typeof process === 'object' && process.versions && process.versions.node;\n  if (NODE_JS) {\n    root = global;\n  } else if (WEB_WORKER) {\n    root = self;\n  }\n  var COMMON_JS = !root.JS_MD5_NO_COMMON_JS && typeof module === 'object' && module.exports;\n  var AMD = typeof define === 'function' && define.amd;\n  var ARRAY_BUFFER = !root.JS_MD5_NO_ARRAY_BUFFER && typeof ArrayBuffer !== 'undefined';\n  var HEX_CHARS = '0123456789abcdef'.split('');\n  var EXTRA = [128, 32768, 8388608, -2147483648];\n  var SHIFT = [0, 8, 16, 24];\n  var OUTPUT_TYPES = ['hex', 'array', 'digest', 'buffer', 'arrayBuffer', 'base64'];\n  var BASE64_ENCODE_CHAR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split('');\n\n  var blocks = [], buffer8;\n  if (ARRAY_BUFFER) {\n    var buffer = new ArrayBuffer(68);\n    buffer8 = new Uint8Array(buffer);\n    blocks = new Uint32Array(buffer);\n  }\n\n  if (root.JS_MD5_NO_NODE_JS || !Array.isArray) {\n    Array.isArray = function (obj) {\n      return Object.prototype.toString.call(obj) === '[object Array]';\n    };\n  }\n\n  if (ARRAY_BUFFER && (root.JS_MD5_NO_ARRAY_BUFFER_IS_VIEW || !ArrayBuffer.isView)) {\n    ArrayBuffer.isView = function (obj) {\n      return typeof obj === 'object' && obj.buffer && obj.buffer.constructor === ArrayBuffer;\n    };\n  }\n\n  /**\n   * @method hex\n   * @memberof md5\n   * @description Output hash as hex string\n   * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash\n   * @returns {String} Hex string\n   * @example\n   * md5.hex('The quick brown fox jumps over the lazy dog');\n   * // equal to\n   * md5('The quick brown fox jumps over the lazy dog');\n   */\n  /**\n   * @method digest\n   * @memberof md5\n   * @description Output hash as bytes array\n   * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash\n   * @returns {Array} Bytes array\n   * @example\n   * md5.digest('The quick brown fox jumps over the lazy dog');\n   */\n  /**\n   * @method array\n   * @memberof md5\n   * @description Output hash as bytes array\n   * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash\n   * @returns {Array} Bytes array\n   * @example\n   * md5.array('The quick brown fox jumps over the lazy dog');\n   */\n  /**\n   * @method arrayBuffer\n   * @memberof md5\n   * @description Output hash as ArrayBuffer\n   * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash\n   * @returns {ArrayBuffer} ArrayBuffer\n   * @example\n   * md5.arrayBuffer('The quick brown fox jumps over the lazy dog');\n   */\n  /**\n   * @method buffer\n   * @deprecated This maybe confuse with Buffer in node.js. Please use arrayBuffer instead.\n   * @memberof md5\n   * @description Output hash as ArrayBuffer\n   * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash\n   * @returns {ArrayBuffer} ArrayBuffer\n   * @example\n   * md5.buffer('The quick brown fox jumps over the lazy dog');\n   */\n  /**\n   * @method base64\n   * @memberof md5\n   * @description Output hash as base64 string\n   * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash\n   * @returns {String} base64 string\n   * @example\n   * md5.base64('The quick brown fox jumps over the lazy dog');\n   */\n  var createOutputMethod = function (outputType) {\n    return function (message) {\n      return new Md5(true).update(message)[outputType]();\n    };\n  };\n\n  /**\n   * @method create\n   * @memberof md5\n   * @description Create Md5 object\n   * @returns {Md5} Md5 object.\n   * @example\n   * var hash = md5.create();\n   */\n  /**\n   * @method update\n   * @memberof md5\n   * @description Create and update Md5 object\n   * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash\n   * @returns {Md5} Md5 object.\n   * @example\n   * var hash = md5.update('The quick brown fox jumps over the lazy dog');\n   * // equal to\n   * var hash = md5.create();\n   * hash.update('The quick brown fox jumps over the lazy dog');\n   */\n  var createMethod = function () {\n    var method = createOutputMethod('hex');\n    if (NODE_JS) {\n      method = nodeWrap(method);\n    }\n    method.create = function () {\n      return new Md5();\n    };\n    method.update = function (message) {\n      return method.create().update(message);\n    };\n    for (var i = 0; i < OUTPUT_TYPES.length; ++i) {\n      var type = OUTPUT_TYPES[i];\n      method[type] = createOutputMethod(type);\n    }\n    return method;\n  };\n\n  var nodeWrap = function (method) {\n    var crypto = eval(\"require('crypto')\");\n    var Buffer = eval(\"require('buffer').Buffer\");\n    var nodeMethod = function (message) {\n      if (typeof message === 'string') {\n        return crypto.createHash('md5').update(message, 'utf8').digest('hex');\n      } else {\n        if (message === null || message === undefined) {\n          throw ERROR;\n        } else if (message.constructor === ArrayBuffer) {\n          message = new Uint8Array(message);\n        }\n      }\n      if (Array.isArray(message) || ArrayBuffer.isView(message) ||\n        message.constructor === Buffer) {\n        return crypto.createHash('md5').update(new Buffer(message)).digest('hex');\n      } else {\n        return method(message);\n      }\n    };\n    return nodeMethod;\n  };\n\n  /**\n   * Md5 class\n   * @class Md5\n   * @description This is internal class.\n   * @see {@link md5.create}\n   */\n  function Md5(sharedMemory) {\n    if (sharedMemory) {\n      blocks[0] = blocks[16] = blocks[1] = blocks[2] = blocks[3] =\n      blocks[4] = blocks[5] = blocks[6] = blocks[7] =\n      blocks[8] = blocks[9] = blocks[10] = blocks[11] =\n      blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;\n      this.blocks = blocks;\n      this.buffer8 = buffer8;\n    } else {\n      if (ARRAY_BUFFER) {\n        var buffer = new ArrayBuffer(68);\n        this.buffer8 = new Uint8Array(buffer);\n        this.blocks = new Uint32Array(buffer);\n      } else {\n        this.blocks = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];\n      }\n    }\n    this.h0 = this.h1 = this.h2 = this.h3 = this.start = this.bytes = this.hBytes = 0;\n    this.finalized = this.hashed = false;\n    this.first = true;\n  }\n\n  /**\n   * @method update\n   * @memberof Md5\n   * @instance\n   * @description Update hash\n   * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash\n   * @returns {Md5} Md5 object.\n   * @see {@link md5.update}\n   */\n  Md5.prototype.update = function (message) {\n    if (this.finalized) {\n      return;\n    }\n\n    var notString, type = typeof message;\n    if (type !== 'string') {\n      if (type === 'object') {\n        if (message === null) {\n          throw ERROR;\n        } else if (ARRAY_BUFFER && message.constructor === ArrayBuffer) {\n          message = new Uint8Array(message);\n        } else if (!Array.isArray(message)) {\n          if (!ARRAY_BUFFER || !ArrayBuffer.isView(message)) {\n            throw ERROR;\n          }\n        }\n      } else {\n        throw ERROR;\n      }\n      notString = true;\n    }\n    var code, index = 0, i, length = message.length, blocks = this.blocks;\n    var buffer8 = this.buffer8;\n\n    while (index < length) {\n      if (this.hashed) {\n        this.hashed = false;\n        blocks[0] = blocks[16];\n        blocks[16] = blocks[1] = blocks[2] = blocks[3] =\n        blocks[4] = blocks[5] = blocks[6] = blocks[7] =\n        blocks[8] = blocks[9] = blocks[10] = blocks[11] =\n        blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;\n      }\n\n      if (notString) {\n        if (ARRAY_BUFFER) {\n          for (i = this.start; index < length && i < 64; ++index) {\n            buffer8[i++] = message[index];\n          }\n        } else {\n          for (i = this.start; index < length && i < 64; ++index) {\n            blocks[i >> 2] |= message[index] << SHIFT[i++ & 3];\n          }\n        }\n      } else {\n        if (ARRAY_BUFFER) {\n          for (i = this.start; index < length && i < 64; ++index) {\n            code = message.charCodeAt(index);\n            if (code < 0x80) {\n              buffer8[i++] = code;\n            } else if (code < 0x800) {\n              buffer8[i++] = 0xc0 | (code >> 6);\n              buffer8[i++] = 0x80 | (code & 0x3f);\n            } else if (code < 0xd800 || code >= 0xe000) {\n              buffer8[i++] = 0xe0 | (code >> 12);\n              buffer8[i++] = 0x80 | ((code >> 6) & 0x3f);\n              buffer8[i++] = 0x80 | (code & 0x3f);\n            } else {\n              code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff));\n              buffer8[i++] = 0xf0 | (code >> 18);\n              buffer8[i++] = 0x80 | ((code >> 12) & 0x3f);\n              buffer8[i++] = 0x80 | ((code >> 6) & 0x3f);\n              buffer8[i++] = 0x80 | (code & 0x3f);\n            }\n          }\n        } else {\n          for (i = this.start; index < length && i < 64; ++index) {\n            code = message.charCodeAt(index);\n            if (code < 0x80) {\n              blocks[i >> 2] |= code << SHIFT[i++ & 3];\n            } else if (code < 0x800) {\n              blocks[i >> 2] |= (0xc0 | (code >> 6)) << SHIFT[i++ & 3];\n              blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];\n            } else if (code < 0xd800 || code >= 0xe000) {\n              blocks[i >> 2] |= (0xe0 | (code >> 12)) << SHIFT[i++ & 3];\n              blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];\n              blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];\n            } else {\n              code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff));\n              blocks[i >> 2] |= (0xf0 | (code >> 18)) << SHIFT[i++ & 3];\n              blocks[i >> 2] |= (0x80 | ((code >> 12) & 0x3f)) << SHIFT[i++ & 3];\n              blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];\n              blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];\n            }\n          }\n        }\n      }\n      this.lastByteIndex = i;\n      this.bytes += i - this.start;\n      if (i >= 64) {\n        this.start = i - 64;\n        this.hash();\n        this.hashed = true;\n      } else {\n        this.start = i;\n      }\n    }\n    if (this.bytes > 4294967295) {\n      this.hBytes += this.bytes / 4294967296 << 0;\n      this.bytes = this.bytes % 4294967296;\n    }\n    return this;\n  };\n\n  Md5.prototype.finalize = function () {\n    if (this.finalized) {\n      return;\n    }\n    this.finalized = true;\n    var blocks = this.blocks, i = this.lastByteIndex;\n    blocks[i >> 2] |= EXTRA[i & 3];\n    if (i >= 56) {\n      if (!this.hashed) {\n        this.hash();\n      }\n      blocks[0] = blocks[16];\n      blocks[16] = blocks[1] = blocks[2] = blocks[3] =\n      blocks[4] = blocks[5] = blocks[6] = blocks[7] =\n      blocks[8] = blocks[9] = blocks[10] = blocks[11] =\n      blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;\n    }\n    blocks[14] = this.bytes << 3;\n    blocks[15] = this.hBytes << 3 | this.bytes >>> 29;\n    this.hash();\n  };\n\n  Md5.prototype.hash = function () {\n    var a, b, c, d, bc, da, blocks = this.blocks;\n\n    if (this.first) {\n      a = blocks[0] - 680876937;\n      a = (a << 7 | a >>> 25) - 271733879 << 0;\n      d = (-1732584194 ^ a & 2004318071) + blocks[1] - 117830708;\n      d = (d << 12 | d >>> 20) + a << 0;\n      c = (-271733879 ^ (d & (a ^ -271733879))) + blocks[2] - 1126478375;\n      c = (c << 17 | c >>> 15) + d << 0;\n      b = (a ^ (c & (d ^ a))) + blocks[3] - 1316259209;\n      b = (b << 22 | b >>> 10) + c << 0;\n    } else {\n      a = this.h0;\n      b = this.h1;\n      c = this.h2;\n      d = this.h3;\n      a += (d ^ (b & (c ^ d))) + blocks[0] - 680876936;\n      a = (a << 7 | a >>> 25) + b << 0;\n      d += (c ^ (a & (b ^ c))) + blocks[1] - 389564586;\n      d = (d << 12 | d >>> 20) + a << 0;\n      c += (b ^ (d & (a ^ b))) + blocks[2] + 606105819;\n      c = (c << 17 | c >>> 15) + d << 0;\n      b += (a ^ (c & (d ^ a))) + blocks[3] - 1044525330;\n      b = (b << 22 | b >>> 10) + c << 0;\n    }\n\n    a += (d ^ (b & (c ^ d))) + blocks[4] - 176418897;\n    a = (a << 7 | a >>> 25) + b << 0;\n    d += (c ^ (a & (b ^ c))) + blocks[5] + 1200080426;\n    d = (d << 12 | d >>> 20) + a << 0;\n    c += (b ^ (d & (a ^ b))) + blocks[6] - 1473231341;\n    c = (c << 17 | c >>> 15) + d << 0;\n    b += (a ^ (c & (d ^ a))) + blocks[7] - 45705983;\n    b = (b << 22 | b >>> 10) + c << 0;\n    a += (d ^ (b & (c ^ d))) + blocks[8] + 1770035416;\n    a = (a << 7 | a >>> 25) + b << 0;\n    d += (c ^ (a & (b ^ c))) + blocks[9] - 1958414417;\n    d = (d << 12 | d >>> 20) + a << 0;\n    c += (b ^ (d & (a ^ b))) + blocks[10] - 42063;\n    c = (c << 17 | c >>> 15) + d << 0;\n    b += (a ^ (c & (d ^ a))) + blocks[11] - 1990404162;\n    b = (b << 22 | b >>> 10) + c << 0;\n    a += (d ^ (b & (c ^ d))) + blocks[12] + 1804603682;\n    a = (a << 7 | a >>> 25) + b << 0;\n    d += (c ^ (a & (b ^ c))) + blocks[13] - 40341101;\n    d = (d << 12 | d >>> 20) + a << 0;\n    c += (b ^ (d & (a ^ b))) + blocks[14] - 1502002290;\n    c = (c << 17 | c >>> 15) + d << 0;\n    b += (a ^ (c & (d ^ a))) + blocks[15] + 1236535329;\n    b = (b << 22 | b >>> 10) + c << 0;\n    a += (c ^ (d & (b ^ c))) + blocks[1] - 165796510;\n    a = (a << 5 | a >>> 27) + b << 0;\n    d += (b ^ (c & (a ^ b))) + blocks[6] - 1069501632;\n    d = (d << 9 | d >>> 23) + a << 0;\n    c += (a ^ (b & (d ^ a))) + blocks[11] + 643717713;\n    c = (c << 14 | c >>> 18) + d << 0;\n    b += (d ^ (a & (c ^ d))) + blocks[0] - 373897302;\n    b = (b << 20 | b >>> 12) + c << 0;\n    a += (c ^ (d & (b ^ c))) + blocks[5] - 701558691;\n    a = (a << 5 | a >>> 27) + b << 0;\n    d += (b ^ (c & (a ^ b))) + blocks[10] + 38016083;\n    d = (d << 9 | d >>> 23) + a << 0;\n    c += (a ^ (b & (d ^ a))) + blocks[15] - 660478335;\n    c = (c << 14 | c >>> 18) + d << 0;\n    b += (d ^ (a & (c ^ d))) + blocks[4] - 405537848;\n    b = (b << 20 | b >>> 12) + c << 0;\n    a += (c ^ (d & (b ^ c))) + blocks[9] + 568446438;\n    a = (a << 5 | a >>> 27) + b << 0;\n    d += (b ^ (c & (a ^ b))) + blocks[14] - 1019803690;\n    d = (d << 9 | d >>> 23) + a << 0;\n    c += (a ^ (b & (d ^ a))) + blocks[3] - 187363961;\n    c = (c << 14 | c >>> 18) + d << 0;\n    b += (d ^ (a & (c ^ d))) + blocks[8] + 1163531501;\n    b = (b << 20 | b >>> 12) + c << 0;\n    a += (c ^ (d & (b ^ c))) + blocks[13] - 1444681467;\n    a = (a << 5 | a >>> 27) + b << 0;\n    d += (b ^ (c & (a ^ b))) + blocks[2] - 51403784;\n    d = (d << 9 | d >>> 23) + a << 0;\n    c += (a ^ (b & (d ^ a))) + blocks[7] + 1735328473;\n    c = (c << 14 | c >>> 18) + d << 0;\n    b += (d ^ (a & (c ^ d))) + blocks[12] - 1926607734;\n    b = (b << 20 | b >>> 12) + c << 0;\n    bc = b ^ c;\n    a += (bc ^ d) + blocks[5] - 378558;\n    a = (a << 4 | a >>> 28) + b << 0;\n    d += (bc ^ a) + blocks[8] - 2022574463;\n    d = (d << 11 | d >>> 21) + a << 0;\n    da = d ^ a;\n    c += (da ^ b) + blocks[11] + 1839030562;\n    c = (c << 16 | c >>> 16) + d << 0;\n    b += (da ^ c) + blocks[14] - 35309556;\n    b = (b << 23 | b >>> 9) + c << 0;\n    bc = b ^ c;\n    a += (bc ^ d) + blocks[1] - 1530992060;\n    a = (a << 4 | a >>> 28) + b << 0;\n    d += (bc ^ a) + blocks[4] + 1272893353;\n    d = (d << 11 | d >>> 21) + a << 0;\n    da = d ^ a;\n    c += (da ^ b) + blocks[7] - 155497632;\n    c = (c << 16 | c >>> 16) + d << 0;\n    b += (da ^ c) + blocks[10] - 1094730640;\n    b = (b << 23 | b >>> 9) + c << 0;\n    bc = b ^ c;\n    a += (bc ^ d) + blocks[13] + 681279174;\n    a = (a << 4 | a >>> 28) + b << 0;\n    d += (bc ^ a) + blocks[0] - 358537222;\n    d = (d << 11 | d >>> 21) + a << 0;\n    da = d ^ a;\n    c += (da ^ b) + blocks[3] - 722521979;\n    c = (c << 16 | c >>> 16) + d << 0;\n    b += (da ^ c) + blocks[6] + 76029189;\n    b = (b << 23 | b >>> 9) + c << 0;\n    bc = b ^ c;\n    a += (bc ^ d) + blocks[9] - 640364487;\n    a = (a << 4 | a >>> 28) + b << 0;\n    d += (bc ^ a) + blocks[12] - 421815835;\n    d = (d << 11 | d >>> 21) + a << 0;\n    da = d ^ a;\n    c += (da ^ b) + blocks[15] + 530742520;\n    c = (c << 16 | c >>> 16) + d << 0;\n    b += (da ^ c) + blocks[2] - 995338651;\n    b = (b << 23 | b >>> 9) + c << 0;\n    a += (c ^ (b | ~d)) + blocks[0] - 198630844;\n    a = (a << 6 | a >>> 26) + b << 0;\n    d += (b ^ (a | ~c)) + blocks[7] + 1126891415;\n    d = (d << 10 | d >>> 22) + a << 0;\n    c += (a ^ (d | ~b)) + blocks[14] - 1416354905;\n    c = (c << 15 | c >>> 17) + d << 0;\n    b += (d ^ (c | ~a)) + blocks[5] - 57434055;\n    b = (b << 21 | b >>> 11) + c << 0;\n    a += (c ^ (b | ~d)) + blocks[12] + 1700485571;\n    a = (a << 6 | a >>> 26) + b << 0;\n    d += (b ^ (a | ~c)) + blocks[3] - 1894986606;\n    d = (d << 10 | d >>> 22) + a << 0;\n    c += (a ^ (d | ~b)) + blocks[10] - 1051523;\n    c = (c << 15 | c >>> 17) + d << 0;\n    b += (d ^ (c | ~a)) + blocks[1] - 2054922799;\n    b = (b << 21 | b >>> 11) + c << 0;\n    a += (c ^ (b | ~d)) + blocks[8] + 1873313359;\n    a = (a << 6 | a >>> 26) + b << 0;\n    d += (b ^ (a | ~c)) + blocks[15] - 30611744;\n    d = (d << 10 | d >>> 22) + a << 0;\n    c += (a ^ (d | ~b)) + blocks[6] - 1560198380;\n    c = (c << 15 | c >>> 17) + d << 0;\n    b += (d ^ (c | ~a)) + blocks[13] + 1309151649;\n    b = (b << 21 | b >>> 11) + c << 0;\n    a += (c ^ (b | ~d)) + blocks[4] - 145523070;\n    a = (a << 6 | a >>> 26) + b << 0;\n    d += (b ^ (a | ~c)) + blocks[11] - 1120210379;\n    d = (d << 10 | d >>> 22) + a << 0;\n    c += (a ^ (d | ~b)) + blocks[2] + 718787259;\n    c = (c << 15 | c >>> 17) + d << 0;\n    b += (d ^ (c | ~a)) + blocks[9] - 343485551;\n    b = (b << 21 | b >>> 11) + c << 0;\n\n    if (this.first) {\n      this.h0 = a + 1732584193 << 0;\n      this.h1 = b - 271733879 << 0;\n      this.h2 = c - 1732584194 << 0;\n      this.h3 = d + 271733878 << 0;\n      this.first = false;\n    } else {\n      this.h0 = this.h0 + a << 0;\n      this.h1 = this.h1 + b << 0;\n      this.h2 = this.h2 + c << 0;\n      this.h3 = this.h3 + d << 0;\n    }\n  };\n\n  /**\n   * @method hex\n   * @memberof Md5\n   * @instance\n   * @description Output hash as hex string\n   * @returns {String} Hex string\n   * @see {@link md5.hex}\n   * @example\n   * hash.hex();\n   */\n  Md5.prototype.hex = function () {\n    this.finalize();\n\n    var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3;\n\n    return HEX_CHARS[(h0 >> 4) & 0x0F] + HEX_CHARS[h0 & 0x0F] +\n      HEX_CHARS[(h0 >> 12) & 0x0F] + HEX_CHARS[(h0 >> 8) & 0x0F] +\n      HEX_CHARS[(h0 >> 20) & 0x0F] + HEX_CHARS[(h0 >> 16) & 0x0F] +\n      HEX_CHARS[(h0 >> 28) & 0x0F] + HEX_CHARS[(h0 >> 24) & 0x0F] +\n      HEX_CHARS[(h1 >> 4) & 0x0F] + HEX_CHARS[h1 & 0x0F] +\n      HEX_CHARS[(h1 >> 12) & 0x0F] + HEX_CHARS[(h1 >> 8) & 0x0F] +\n      HEX_CHARS[(h1 >> 20) & 0x0F] + HEX_CHARS[(h1 >> 16) & 0x0F] +\n      HEX_CHARS[(h1 >> 28) & 0x0F] + HEX_CHARS[(h1 >> 24) & 0x0F] +\n      HEX_CHARS[(h2 >> 4) & 0x0F] + HEX_CHARS[h2 & 0x0F] +\n      HEX_CHARS[(h2 >> 12) & 0x0F] + HEX_CHARS[(h2 >> 8) & 0x0F] +\n      HEX_CHARS[(h2 >> 20) & 0x0F] + HEX_CHARS[(h2 >> 16) & 0x0F] +\n      HEX_CHARS[(h2 >> 28) & 0x0F] + HEX_CHARS[(h2 >> 24) & 0x0F] +\n      HEX_CHARS[(h3 >> 4) & 0x0F] + HEX_CHARS[h3 & 0x0F] +\n      HEX_CHARS[(h3 >> 12) & 0x0F] + HEX_CHARS[(h3 >> 8) & 0x0F] +\n      HEX_CHARS[(h3 >> 20) & 0x0F] + HEX_CHARS[(h3 >> 16) & 0x0F] +\n      HEX_CHARS[(h3 >> 28) & 0x0F] + HEX_CHARS[(h3 >> 24) & 0x0F];\n  };\n\n  /**\n   * @method toString\n   * @memberof Md5\n   * @instance\n   * @description Output hash as hex string\n   * @returns {String} Hex string\n   * @see {@link md5.hex}\n   * @example\n   * hash.toString();\n   */\n  Md5.prototype.toString = Md5.prototype.hex;\n\n  /**\n   * @method digest\n   * @memberof Md5\n   * @instance\n   * @description Output hash as bytes array\n   * @returns {Array} Bytes array\n   * @see {@link md5.digest}\n   * @example\n   * hash.digest();\n   */\n  Md5.prototype.digest = function () {\n    this.finalize();\n\n    var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3;\n    return [\n      h0 & 0xFF, (h0 >> 8) & 0xFF, (h0 >> 16) & 0xFF, (h0 >> 24) & 0xFF,\n      h1 & 0xFF, (h1 >> 8) & 0xFF, (h1 >> 16) & 0xFF, (h1 >> 24) & 0xFF,\n      h2 & 0xFF, (h2 >> 8) & 0xFF, (h2 >> 16) & 0xFF, (h2 >> 24) & 0xFF,\n      h3 & 0xFF, (h3 >> 8) & 0xFF, (h3 >> 16) & 0xFF, (h3 >> 24) & 0xFF\n    ];\n  };\n\n  /**\n   * @method array\n   * @memberof Md5\n   * @instance\n   * @description Output hash as bytes array\n   * @returns {Array} Bytes array\n   * @see {@link md5.array}\n   * @example\n   * hash.array();\n   */\n  Md5.prototype.array = Md5.prototype.digest;\n\n  /**\n   * @method arrayBuffer\n   * @memberof Md5\n   * @instance\n   * @description Output hash as ArrayBuffer\n   * @returns {ArrayBuffer} ArrayBuffer\n   * @see {@link md5.arrayBuffer}\n   * @example\n   * hash.arrayBuffer();\n   */\n  Md5.prototype.arrayBuffer = function () {\n    this.finalize();\n\n    var buffer = new ArrayBuffer(16);\n    var blocks = new Uint32Array(buffer);\n    blocks[0] = this.h0;\n    blocks[1] = this.h1;\n    blocks[2] = this.h2;\n    blocks[3] = this.h3;\n    return buffer;\n  };\n\n  /**\n   * @method buffer\n   * @deprecated This maybe confuse with Buffer in node.js. Please use arrayBuffer instead.\n   * @memberof Md5\n   * @instance\n   * @description Output hash as ArrayBuffer\n   * @returns {ArrayBuffer} ArrayBuffer\n   * @see {@link md5.buffer}\n   * @example\n   * hash.buffer();\n   */\n  Md5.prototype.buffer = Md5.prototype.arrayBuffer;\n\n  /**\n   * @method base64\n   * @memberof Md5\n   * @instance\n   * @description Output hash as base64 string\n   * @returns {String} base64 string\n   * @see {@link md5.base64}\n   * @example\n   * hash.base64();\n   */\n  Md5.prototype.base64 = function () {\n    var v1, v2, v3, base64Str = '', bytes = this.array();\n    for (var i = 0; i < 15;) {\n      v1 = bytes[i++];\n      v2 = bytes[i++];\n      v3 = bytes[i++];\n      base64Str += BASE64_ENCODE_CHAR[v1 >>> 2] +\n        BASE64_ENCODE_CHAR[(v1 << 4 | v2 >>> 4) & 63] +\n        BASE64_ENCODE_CHAR[(v2 << 2 | v3 >>> 6) & 63] +\n        BASE64_ENCODE_CHAR[v3 & 63];\n    }\n    v1 = bytes[i];\n    base64Str += BASE64_ENCODE_CHAR[v1 >>> 2] +\n      BASE64_ENCODE_CHAR[(v1 << 4) & 63] +\n      '==';\n    return base64Str;\n  };\n\n  var exports = createMethod();\n\n  if (COMMON_JS) {\n    module.exports = exports;\n  } else {\n    /**\n     * @method md5\b\n     * @description Md5 hash function, export to global in browsers.\n     * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash\n     * @returns {String} md5 hashes\n     * @example\n     * md5(''); // d41d8cd98f00b204e9800998ecf8427e\n     * md5('The quick brown fox jumps over the lazy dog'); // 9e107d9d372bb6826bd81d3542a419d6\n     * md5('The quick brown fox jumps over the lazy dog.'); // e4d909c290d0fb1ca068ffaddf22cbd0\n     *\n     * // It also supports UTF-8 encoding\n     * md5('中文'); // a7bac2239fcdcb3a067903d8077c4a07\n     *\n     * // It also supports byte `Array`, `Uint8Array`, `ArrayBuffer`\n     * md5([]); // d41d8cd98f00b204e9800998ecf8427e\n     * md5(new Uint8Array([])); // d41d8cd98f00b204e9800998ecf8427e\n     */\n    root.md5 = exports;\n    if (AMD) {\n      define(function () {\n        return exports;\n      });\n    }\n  }\n})();\n","/**\n * lodash (Custom Build) <https://lodash.com/>\n * Build: `lodash modularize exports=\"npm\" -o ./`\n * Copyright jQuery Foundation and other contributors <https://jquery.org/>\n * Released under MIT license <https://lodash.com/license>\n * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>\n * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n */\n\n/** Used as the size to enable large array optimizations. */\nvar LARGE_ARRAY_SIZE = 200;\n\n/** Used to stand-in for `undefined` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/** `Object#toString` result references. */\nvar argsTag = '[object Arguments]',\n    arrayTag = '[object Array]',\n    boolTag = '[object Boolean]',\n    dateTag = '[object Date]',\n    errorTag = '[object Error]',\n    funcTag = '[object Function]',\n    genTag = '[object GeneratorFunction]',\n    mapTag = '[object Map]',\n    numberTag = '[object Number]',\n    objectTag = '[object Object]',\n    promiseTag = '[object Promise]',\n    regexpTag = '[object RegExp]',\n    setTag = '[object Set]',\n    stringTag = '[object String]',\n    symbolTag = '[object Symbol]',\n    weakMapTag = '[object WeakMap]';\n\nvar arrayBufferTag = '[object ArrayBuffer]',\n    dataViewTag = '[object DataView]',\n    float32Tag = '[object Float32Array]',\n    float64Tag = '[object Float64Array]',\n    int8Tag = '[object Int8Array]',\n    int16Tag = '[object Int16Array]',\n    int32Tag = '[object Int32Array]',\n    uint8Tag = '[object Uint8Array]',\n    uint8ClampedTag = '[object Uint8ClampedArray]',\n    uint16Tag = '[object Uint16Array]',\n    uint32Tag = '[object Uint32Array]';\n\n/**\n * Used to match `RegExp`\n * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).\n */\nvar reRegExpChar = /[\\\\^$.*+?()[\\]{}|]/g;\n\n/** Used to match `RegExp` flags from their coerced string values. */\nvar reFlags = /\\w*$/;\n\n/** Used to detect host constructors (Safari). */\nvar reIsHostCtor = /^\\[object .+?Constructor\\]$/;\n\n/** Used to detect unsigned integer values. */\nvar reIsUint = /^(?:0|[1-9]\\d*)$/;\n\n/** Used to identify `toStringTag` values supported by `_.clone`. */\nvar cloneableTags = {};\ncloneableTags[argsTag] = cloneableTags[arrayTag] =\ncloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] =\ncloneableTags[boolTag] = cloneableTags[dateTag] =\ncloneableTags[float32Tag] = cloneableTags[float64Tag] =\ncloneableTags[int8Tag] = cloneableTags[int16Tag] =\ncloneableTags[int32Tag] = cloneableTags[mapTag] =\ncloneableTags[numberTag] = cloneableTags[objectTag] =\ncloneableTags[regexpTag] = cloneableTags[setTag] =\ncloneableTags[stringTag] = cloneableTags[symbolTag] =\ncloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =\ncloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;\ncloneableTags[errorTag] = cloneableTags[funcTag] =\ncloneableTags[weakMapTag] = false;\n\n/** Detect free variable `global` from Node.js. */\nvar freeGlobal = typeof global == 'object' && global && global.Object === Object && global;\n\n/** Detect free variable `self`. */\nvar freeSelf = typeof self == 'object' && self && self.Object === Object && self;\n\n/** Used as a reference to the global object. */\nvar root = freeGlobal || freeSelf || Function('return this')();\n\n/** Detect free variable `exports`. */\nvar freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;\n\n/** Detect free variable `module`. */\nvar freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;\n\n/** Detect the popular CommonJS extension `module.exports`. */\nvar moduleExports = freeModule && freeModule.exports === freeExports;\n\n/**\n * Adds the key-value `pair` to `map`.\n *\n * @private\n * @param {Object} map The map to modify.\n * @param {Array} pair The key-value pair to add.\n * @returns {Object} Returns `map`.\n */\nfunction addMapEntry(map, pair) {\n  // Don't return `map.set` because it's not chainable in IE 11.\n  map.set(pair[0], pair[1]);\n  return map;\n}\n\n/**\n * Adds `value` to `set`.\n *\n * @private\n * @param {Object} set The set to modify.\n * @param {*} value The value to add.\n * @returns {Object} Returns `set`.\n */\nfunction addSetEntry(set, value) {\n  // Don't return `set.add` because it's not chainable in IE 11.\n  set.add(value);\n  return set;\n}\n\n/**\n * A specialized version of `_.forEach` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns `array`.\n */\nfunction arrayEach(array, iteratee) {\n  var index = -1,\n      length = array ? array.length : 0;\n\n  while (++index < length) {\n    if (iteratee(array[index], index, array) === false) {\n      break;\n    }\n  }\n  return array;\n}\n\n/**\n * Appends the elements of `values` to `array`.\n *\n * @private\n * @param {Array} array The array to modify.\n * @param {Array} values The values to append.\n * @returns {Array} Returns `array`.\n */\nfunction arrayPush(array, values) {\n  var index = -1,\n      length = values.length,\n      offset = array.length;\n\n  while (++index < length) {\n    array[offset + index] = values[index];\n  }\n  return array;\n}\n\n/**\n * A specialized version of `_.reduce` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @param {*} [accumulator] The initial value.\n * @param {boolean} [initAccum] Specify using the first element of `array` as\n *  the initial value.\n * @returns {*} Returns the accumulated value.\n */\nfunction arrayReduce(array, iteratee, accumulator, initAccum) {\n  var index = -1,\n      length = array ? array.length : 0;\n\n  if (initAccum && length) {\n    accumulator = array[++index];\n  }\n  while (++index < length) {\n    accumulator = iteratee(accumulator, array[index], index, array);\n  }\n  return accumulator;\n}\n\n/**\n * The base implementation of `_.times` without support for iteratee shorthands\n * or max array length checks.\n *\n * @private\n * @param {number} n The number of times to invoke `iteratee`.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the array of results.\n */\nfunction baseTimes(n, iteratee) {\n  var index = -1,\n      result = Array(n);\n\n  while (++index < n) {\n    result[index] = iteratee(index);\n  }\n  return result;\n}\n\n/**\n * Gets the value at `key` of `object`.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction getValue(object, key) {\n  return object == null ? undefined : object[key];\n}\n\n/**\n * Checks if `value` is a host object in IE < 9.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a host object, else `false`.\n */\nfunction isHostObject(value) {\n  // Many host objects are `Object` objects that can coerce to strings\n  // despite having improperly defined `toString` methods.\n  var result = false;\n  if (value != null && typeof value.toString != 'function') {\n    try {\n      result = !!(value + '');\n    } catch (e) {}\n  }\n  return result;\n}\n\n/**\n * Converts `map` to its key-value pairs.\n *\n * @private\n * @param {Object} map The map to convert.\n * @returns {Array} Returns the key-value pairs.\n */\nfunction mapToArray(map) {\n  var index = -1,\n      result = Array(map.size);\n\n  map.forEach(function(value, key) {\n    result[++index] = [key, value];\n  });\n  return result;\n}\n\n/**\n * Creates a unary function that invokes `func` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n  return function(arg) {\n    return func(transform(arg));\n  };\n}\n\n/**\n * Converts `set` to an array of its values.\n *\n * @private\n * @param {Object} set The set to convert.\n * @returns {Array} Returns the values.\n */\nfunction setToArray(set) {\n  var index = -1,\n      result = Array(set.size);\n\n  set.forEach(function(value) {\n    result[++index] = value;\n  });\n  return result;\n}\n\n/** Used for built-in method references. */\nvar arrayProto = Array.prototype,\n    funcProto = Function.prototype,\n    objectProto = Object.prototype;\n\n/** Used to detect overreaching core-js shims. */\nvar coreJsData = root['__core-js_shared__'];\n\n/** Used to detect methods masquerading as native. */\nvar maskSrcKey = (function() {\n  var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');\n  return uid ? ('Symbol(src)_1.' + uid) : '';\n}());\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar objectToString = objectProto.toString;\n\n/** Used to detect if a method is native. */\nvar reIsNative = RegExp('^' +\n  funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\\\$&')\n  .replace(/hasOwnProperty|(function).*?(?=\\\\\\()| for .+?(?=\\\\\\])/g, '$1.*?') + '$'\n);\n\n/** Built-in value references. */\nvar Buffer = moduleExports ? root.Buffer : undefined,\n    Symbol = root.Symbol,\n    Uint8Array = root.Uint8Array,\n    getPrototype = overArg(Object.getPrototypeOf, Object),\n    objectCreate = Object.create,\n    propertyIsEnumerable = objectProto.propertyIsEnumerable,\n    splice = arrayProto.splice;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeGetSymbols = Object.getOwnPropertySymbols,\n    nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined,\n    nativeKeys = overArg(Object.keys, Object);\n\n/* Built-in method references that are verified to be native. */\nvar DataView = getNative(root, 'DataView'),\n    Map = getNative(root, 'Map'),\n    Promise = getNative(root, 'Promise'),\n    Set = getNative(root, 'Set'),\n    WeakMap = getNative(root, 'WeakMap'),\n    nativeCreate = getNative(Object, 'create');\n\n/** Used to detect maps, sets, and weakmaps. */\nvar dataViewCtorString = toSource(DataView),\n    mapCtorString = toSource(Map),\n    promiseCtorString = toSource(Promise),\n    setCtorString = toSource(Set),\n    weakMapCtorString = toSource(WeakMap);\n\n/** Used to convert symbols to primitives and strings. */\nvar symbolProto = Symbol ? Symbol.prototype : undefined,\n    symbolValueOf = symbolProto ? symbolProto.valueOf : undefined;\n\n/**\n * Creates a hash object.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction Hash(entries) {\n  var index = -1,\n      length = entries ? entries.length : 0;\n\n  this.clear();\n  while (++index < length) {\n    var entry = entries[index];\n    this.set(entry[0], entry[1]);\n  }\n}\n\n/**\n * Removes all key-value entries from the hash.\n *\n * @private\n * @name clear\n * @memberOf Hash\n */\nfunction hashClear() {\n  this.__data__ = nativeCreate ? nativeCreate(null) : {};\n}\n\n/**\n * Removes `key` and its value from the hash.\n *\n * @private\n * @name delete\n * @memberOf Hash\n * @param {Object} hash The hash to modify.\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction hashDelete(key) {\n  return this.has(key) && delete this.__data__[key];\n}\n\n/**\n * Gets the hash value for `key`.\n *\n * @private\n * @name get\n * @memberOf Hash\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction hashGet(key) {\n  var data = this.__data__;\n  if (nativeCreate) {\n    var result = data[key];\n    return result === HASH_UNDEFINED ? undefined : result;\n  }\n  return hasOwnProperty.call(data, key) ? data[key] : undefined;\n}\n\n/**\n * Checks if a hash value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Hash\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction hashHas(key) {\n  var data = this.__data__;\n  return nativeCreate ? data[key] !== undefined : hasOwnProperty.call(data, key);\n}\n\n/**\n * Sets the hash `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf Hash\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the hash instance.\n */\nfunction hashSet(key, value) {\n  var data = this.__data__;\n  data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;\n  return this;\n}\n\n// Add methods to `Hash`.\nHash.prototype.clear = hashClear;\nHash.prototype['delete'] = hashDelete;\nHash.prototype.get = hashGet;\nHash.prototype.has = hashHas;\nHash.prototype.set = hashSet;\n\n/**\n * Creates an list cache object.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction ListCache(entries) {\n  var index = -1,\n      length = entries ? entries.length : 0;\n\n  this.clear();\n  while (++index < length) {\n    var entry = entries[index];\n    this.set(entry[0], entry[1]);\n  }\n}\n\n/**\n * Removes all key-value entries from the list cache.\n *\n * @private\n * @name clear\n * @memberOf ListCache\n */\nfunction listCacheClear() {\n  this.__data__ = [];\n}\n\n/**\n * Removes `key` and its value from the list cache.\n *\n * @private\n * @name delete\n * @memberOf ListCache\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction listCacheDelete(key) {\n  var data = this.__data__,\n      index = assocIndexOf(data, key);\n\n  if (index < 0) {\n    return false;\n  }\n  var lastIndex = data.length - 1;\n  if (index == lastIndex) {\n    data.pop();\n  } else {\n    splice.call(data, index, 1);\n  }\n  return true;\n}\n\n/**\n * Gets the list cache value for `key`.\n *\n * @private\n * @name get\n * @memberOf ListCache\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction listCacheGet(key) {\n  var data = this.__data__,\n      index = assocIndexOf(data, key);\n\n  return index < 0 ? undefined : data[index][1];\n}\n\n/**\n * Checks if a list cache value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf ListCache\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction listCacheHas(key) {\n  return assocIndexOf(this.__data__, key) > -1;\n}\n\n/**\n * Sets the list cache `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf ListCache\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the list cache instance.\n */\nfunction listCacheSet(key, value) {\n  var data = this.__data__,\n      index = assocIndexOf(data, key);\n\n  if (index < 0) {\n    data.push([key, value]);\n  } else {\n    data[index][1] = value;\n  }\n  return this;\n}\n\n// Add methods to `ListCache`.\nListCache.prototype.clear = listCacheClear;\nListCache.prototype['delete'] = listCacheDelete;\nListCache.prototype.get = listCacheGet;\nListCache.prototype.has = listCacheHas;\nListCache.prototype.set = listCacheSet;\n\n/**\n * Creates a map cache object to store key-value pairs.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction MapCache(entries) {\n  var index = -1,\n      length = entries ? entries.length : 0;\n\n  this.clear();\n  while (++index < length) {\n    var entry = entries[index];\n    this.set(entry[0], entry[1]);\n  }\n}\n\n/**\n * Removes all key-value entries from the map.\n *\n * @private\n * @name clear\n * @memberOf MapCache\n */\nfunction mapCacheClear() {\n  this.__data__ = {\n    'hash': new Hash,\n    'map': new (Map || ListCache),\n    'string': new Hash\n  };\n}\n\n/**\n * Removes `key` and its value from the map.\n *\n * @private\n * @name delete\n * @memberOf MapCache\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction mapCacheDelete(key) {\n  return getMapData(this, key)['delete'](key);\n}\n\n/**\n * Gets the map value for `key`.\n *\n * @private\n * @name get\n * @memberOf MapCache\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction mapCacheGet(key) {\n  return getMapData(this, key).get(key);\n}\n\n/**\n * Checks if a map value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf MapCache\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction mapCacheHas(key) {\n  return getMapData(this, key).has(key);\n}\n\n/**\n * Sets the map `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf MapCache\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the map cache instance.\n */\nfunction mapCacheSet(key, value) {\n  getMapData(this, key).set(key, value);\n  return this;\n}\n\n// Add methods to `MapCache`.\nMapCache.prototype.clear = mapCacheClear;\nMapCache.prototype['delete'] = mapCacheDelete;\nMapCache.prototype.get = mapCacheGet;\nMapCache.prototype.has = mapCacheHas;\nMapCache.prototype.set = mapCacheSet;\n\n/**\n * Creates a stack cache object to store key-value pairs.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction Stack(entries) {\n  this.__data__ = new ListCache(entries);\n}\n\n/**\n * Removes all key-value entries from the stack.\n *\n * @private\n * @name clear\n * @memberOf Stack\n */\nfunction stackClear() {\n  this.__data__ = new ListCache;\n}\n\n/**\n * Removes `key` and its value from the stack.\n *\n * @private\n * @name delete\n * @memberOf Stack\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction stackDelete(key) {\n  return this.__data__['delete'](key);\n}\n\n/**\n * Gets the stack value for `key`.\n *\n * @private\n * @name get\n * @memberOf Stack\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction stackGet(key) {\n  return this.__data__.get(key);\n}\n\n/**\n * Checks if a stack value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Stack\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction stackHas(key) {\n  return this.__data__.has(key);\n}\n\n/**\n * Sets the stack `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf Stack\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the stack cache instance.\n */\nfunction stackSet(key, value) {\n  var cache = this.__data__;\n  if (cache instanceof ListCache) {\n    var pairs = cache.__data__;\n    if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) {\n      pairs.push([key, value]);\n      return this;\n    }\n    cache = this.__data__ = new MapCache(pairs);\n  }\n  cache.set(key, value);\n  return this;\n}\n\n// Add methods to `Stack`.\nStack.prototype.clear = stackClear;\nStack.prototype['delete'] = stackDelete;\nStack.prototype.get = stackGet;\nStack.prototype.has = stackHas;\nStack.prototype.set = stackSet;\n\n/**\n * Creates an array of the enumerable property names of the array-like `value`.\n *\n * @private\n * @param {*} value The value to query.\n * @param {boolean} inherited Specify returning inherited property names.\n * @returns {Array} Returns the array of property names.\n */\nfunction arrayLikeKeys(value, inherited) {\n  // Safari 8.1 makes `arguments.callee` enumerable in strict mode.\n  // Safari 9 makes `arguments.length` enumerable in strict mode.\n  var result = (isArray(value) || isArguments(value))\n    ? baseTimes(value.length, String)\n    : [];\n\n  var length = result.length,\n      skipIndexes = !!length;\n\n  for (var key in value) {\n    if ((inherited || hasOwnProperty.call(value, key)) &&\n        !(skipIndexes && (key == 'length' || isIndex(key, length)))) {\n      result.push(key);\n    }\n  }\n  return result;\n}\n\n/**\n * Assigns `value` to `key` of `object` if the existing value is not equivalent\n * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * for equality comparisons.\n *\n * @private\n * @param {Object} object The object to modify.\n * @param {string} key The key of the property to assign.\n * @param {*} value The value to assign.\n */\nfunction assignValue(object, key, value) {\n  var objValue = object[key];\n  if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||\n      (value === undefined && !(key in object))) {\n    object[key] = value;\n  }\n}\n\n/**\n * Gets the index at which the `key` is found in `array` of key-value pairs.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {*} key The key to search for.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction assocIndexOf(array, key) {\n  var length = array.length;\n  while (length--) {\n    if (eq(array[length][0], key)) {\n      return length;\n    }\n  }\n  return -1;\n}\n\n/**\n * The base implementation of `_.assign` without support for multiple sources\n * or `customizer` functions.\n *\n * @private\n * @param {Object} object The destination object.\n * @param {Object} source The source object.\n * @returns {Object} Returns `object`.\n */\nfunction baseAssign(object, source) {\n  return object && copyObject(source, keys(source), object);\n}\n\n/**\n * The base implementation of `_.clone` and `_.cloneDeep` which tracks\n * traversed objects.\n *\n * @private\n * @param {*} value The value to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @param {boolean} [isFull] Specify a clone including symbols.\n * @param {Function} [customizer] The function to customize cloning.\n * @param {string} [key] The key of `value`.\n * @param {Object} [object] The parent object of `value`.\n * @param {Object} [stack] Tracks traversed objects and their clone counterparts.\n * @returns {*} Returns the cloned value.\n */\nfunction baseClone(value, isDeep, isFull, customizer, key, object, stack) {\n  var result;\n  if (customizer) {\n    result = object ? customizer(value, key, object, stack) : customizer(value);\n  }\n  if (result !== undefined) {\n    return result;\n  }\n  if (!isObject(value)) {\n    return value;\n  }\n  var isArr = isArray(value);\n  if (isArr) {\n    result = initCloneArray(value);\n    if (!isDeep) {\n      return copyArray(value, result);\n    }\n  } else {\n    var tag = getTag(value),\n        isFunc = tag == funcTag || tag == genTag;\n\n    if (isBuffer(value)) {\n      return cloneBuffer(value, isDeep);\n    }\n    if (tag == objectTag || tag == argsTag || (isFunc && !object)) {\n      if (isHostObject(value)) {\n        return object ? value : {};\n      }\n      result = initCloneObject(isFunc ? {} : value);\n      if (!isDeep) {\n        return copySymbols(value, baseAssign(result, value));\n      }\n    } else {\n      if (!cloneableTags[tag]) {\n        return object ? value : {};\n      }\n      result = initCloneByTag(value, tag, baseClone, isDeep);\n    }\n  }\n  // Check for circular references and return its corresponding clone.\n  stack || (stack = new Stack);\n  var stacked = stack.get(value);\n  if (stacked) {\n    return stacked;\n  }\n  stack.set(value, result);\n\n  if (!isArr) {\n    var props = isFull ? getAllKeys(value) : keys(value);\n  }\n  arrayEach(props || value, function(subValue, key) {\n    if (props) {\n      key = subValue;\n      subValue = value[key];\n    }\n    // Recursively populate clone (susceptible to call stack limits).\n    assignValue(result, key, baseClone(subValue, isDeep, isFull, customizer, key, value, stack));\n  });\n  return result;\n}\n\n/**\n * The base implementation of `_.create` without support for assigning\n * properties to the created object.\n *\n * @private\n * @param {Object} prototype The object to inherit from.\n * @returns {Object} Returns the new object.\n */\nfunction baseCreate(proto) {\n  return isObject(proto) ? objectCreate(proto) : {};\n}\n\n/**\n * The base implementation of `getAllKeys` and `getAllKeysIn` which uses\n * `keysFunc` and `symbolsFunc` to get the enumerable property names and\n * symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {Function} keysFunc The function to get the keys of `object`.\n * @param {Function} symbolsFunc The function to get the symbols of `object`.\n * @returns {Array} Returns the array of property names and symbols.\n */\nfunction baseGetAllKeys(object, keysFunc, symbolsFunc) {\n  var result = keysFunc(object);\n  return isArray(object) ? result : arrayPush(result, symbolsFunc(object));\n}\n\n/**\n * The base implementation of `getTag`.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\nfunction baseGetTag(value) {\n  return objectToString.call(value);\n}\n\n/**\n * The base implementation of `_.isNative` without bad shim checks.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a native function,\n *  else `false`.\n */\nfunction baseIsNative(value) {\n  if (!isObject(value) || isMasked(value)) {\n    return false;\n  }\n  var pattern = (isFunction(value) || isHostObject(value)) ? reIsNative : reIsHostCtor;\n  return pattern.test(toSource(value));\n}\n\n/**\n * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction baseKeys(object) {\n  if (!isPrototype(object)) {\n    return nativeKeys(object);\n  }\n  var result = [];\n  for (var key in Object(object)) {\n    if (hasOwnProperty.call(object, key) && key != 'constructor') {\n      result.push(key);\n    }\n  }\n  return result;\n}\n\n/**\n * Creates a clone of  `buffer`.\n *\n * @private\n * @param {Buffer} buffer The buffer to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Buffer} Returns the cloned buffer.\n */\nfunction cloneBuffer(buffer, isDeep) {\n  if (isDeep) {\n    return buffer.slice();\n  }\n  var result = new buffer.constructor(buffer.length);\n  buffer.copy(result);\n  return result;\n}\n\n/**\n * Creates a clone of `arrayBuffer`.\n *\n * @private\n * @param {ArrayBuffer} arrayBuffer The array buffer to clone.\n * @returns {ArrayBuffer} Returns the cloned array buffer.\n */\nfunction cloneArrayBuffer(arrayBuffer) {\n  var result = new arrayBuffer.constructor(arrayBuffer.byteLength);\n  new Uint8Array(result).set(new Uint8Array(arrayBuffer));\n  return result;\n}\n\n/**\n * Creates a clone of `dataView`.\n *\n * @private\n * @param {Object} dataView The data view to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Object} Returns the cloned data view.\n */\nfunction cloneDataView(dataView, isDeep) {\n  var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer;\n  return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength);\n}\n\n/**\n * Creates a clone of `map`.\n *\n * @private\n * @param {Object} map The map to clone.\n * @param {Function} cloneFunc The function to clone values.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Object} Returns the cloned map.\n */\nfunction cloneMap(map, isDeep, cloneFunc) {\n  var array = isDeep ? cloneFunc(mapToArray(map), true) : mapToArray(map);\n  return arrayReduce(array, addMapEntry, new map.constructor);\n}\n\n/**\n * Creates a clone of `regexp`.\n *\n * @private\n * @param {Object} regexp The regexp to clone.\n * @returns {Object} Returns the cloned regexp.\n */\nfunction cloneRegExp(regexp) {\n  var result = new regexp.constructor(regexp.source, reFlags.exec(regexp));\n  result.lastIndex = regexp.lastIndex;\n  return result;\n}\n\n/**\n * Creates a clone of `set`.\n *\n * @private\n * @param {Object} set The set to clone.\n * @param {Function} cloneFunc The function to clone values.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Object} Returns the cloned set.\n */\nfunction cloneSet(set, isDeep, cloneFunc) {\n  var array = isDeep ? cloneFunc(setToArray(set), true) : setToArray(set);\n  return arrayReduce(array, addSetEntry, new set.constructor);\n}\n\n/**\n * Creates a clone of the `symbol` object.\n *\n * @private\n * @param {Object} symbol The symbol object to clone.\n * @returns {Object} Returns the cloned symbol object.\n */\nfunction cloneSymbol(symbol) {\n  return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {};\n}\n\n/**\n * Creates a clone of `typedArray`.\n *\n * @private\n * @param {Object} typedArray The typed array to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Object} Returns the cloned typed array.\n */\nfunction cloneTypedArray(typedArray, isDeep) {\n  var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer;\n  return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length);\n}\n\n/**\n * Copies the values of `source` to `array`.\n *\n * @private\n * @param {Array} source The array to copy values from.\n * @param {Array} [array=[]] The array to copy values to.\n * @returns {Array} Returns `array`.\n */\nfunction copyArray(source, array) {\n  var index = -1,\n      length = source.length;\n\n  array || (array = Array(length));\n  while (++index < length) {\n    array[index] = source[index];\n  }\n  return array;\n}\n\n/**\n * Copies properties of `source` to `object`.\n *\n * @private\n * @param {Object} source The object to copy properties from.\n * @param {Array} props The property identifiers to copy.\n * @param {Object} [object={}] The object to copy properties to.\n * @param {Function} [customizer] The function to customize copied values.\n * @returns {Object} Returns `object`.\n */\nfunction copyObject(source, props, object, customizer) {\n  object || (object = {});\n\n  var index = -1,\n      length = props.length;\n\n  while (++index < length) {\n    var key = props[index];\n\n    var newValue = customizer\n      ? customizer(object[key], source[key], key, object, source)\n      : undefined;\n\n    assignValue(object, key, newValue === undefined ? source[key] : newValue);\n  }\n  return object;\n}\n\n/**\n * Copies own symbol properties of `source` to `object`.\n *\n * @private\n * @param {Object} source The object to copy symbols from.\n * @param {Object} [object={}] The object to copy symbols to.\n * @returns {Object} Returns `object`.\n */\nfunction copySymbols(source, object) {\n  return copyObject(source, getSymbols(source), object);\n}\n\n/**\n * Creates an array of own enumerable property names and symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names and symbols.\n */\nfunction getAllKeys(object) {\n  return baseGetAllKeys(object, keys, getSymbols);\n}\n\n/**\n * Gets the data for `map`.\n *\n * @private\n * @param {Object} map The map to query.\n * @param {string} key The reference key.\n * @returns {*} Returns the map data.\n */\nfunction getMapData(map, key) {\n  var data = map.__data__;\n  return isKeyable(key)\n    ? data[typeof key == 'string' ? 'string' : 'hash']\n    : data.map;\n}\n\n/**\n * Gets the native function at `key` of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the method to get.\n * @returns {*} Returns the function if it's native, else `undefined`.\n */\nfunction getNative(object, key) {\n  var value = getValue(object, key);\n  return baseIsNative(value) ? value : undefined;\n}\n\n/**\n * Creates an array of the own enumerable symbol properties of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of symbols.\n */\nvar getSymbols = nativeGetSymbols ? overArg(nativeGetSymbols, Object) : stubArray;\n\n/**\n * Gets the `toStringTag` of `value`.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\nvar getTag = baseGetTag;\n\n// Fallback for data views, maps, sets, and weak maps in IE 11,\n// for data views in Edge < 14, and promises in Node.js.\nif ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) ||\n    (Map && getTag(new Map) != mapTag) ||\n    (Promise && getTag(Promise.resolve()) != promiseTag) ||\n    (Set && getTag(new Set) != setTag) ||\n    (WeakMap && getTag(new WeakMap) != weakMapTag)) {\n  getTag = function(value) {\n    var result = objectToString.call(value),\n        Ctor = result == objectTag ? value.constructor : undefined,\n        ctorString = Ctor ? toSource(Ctor) : undefined;\n\n    if (ctorString) {\n      switch (ctorString) {\n        case dataViewCtorString: return dataViewTag;\n        case mapCtorString: return mapTag;\n        case promiseCtorString: return promiseTag;\n        case setCtorString: return setTag;\n        case weakMapCtorString: return weakMapTag;\n      }\n    }\n    return result;\n  };\n}\n\n/**\n * Initializes an array clone.\n *\n * @private\n * @param {Array} array The array to clone.\n * @returns {Array} Returns the initialized clone.\n */\nfunction initCloneArray(array) {\n  var length = array.length,\n      result = array.constructor(length);\n\n  // Add properties assigned by `RegExp#exec`.\n  if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {\n    result.index = array.index;\n    result.input = array.input;\n  }\n  return result;\n}\n\n/**\n * Initializes an object clone.\n *\n * @private\n * @param {Object} object The object to clone.\n * @returns {Object} Returns the initialized clone.\n */\nfunction initCloneObject(object) {\n  return (typeof object.constructor == 'function' && !isPrototype(object))\n    ? baseCreate(getPrototype(object))\n    : {};\n}\n\n/**\n * Initializes an object clone based on its `toStringTag`.\n *\n * **Note:** This function only supports cloning values with tags of\n * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.\n *\n * @private\n * @param {Object} object The object to clone.\n * @param {string} tag The `toStringTag` of the object to clone.\n * @param {Function} cloneFunc The function to clone values.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Object} Returns the initialized clone.\n */\nfunction initCloneByTag(object, tag, cloneFunc, isDeep) {\n  var Ctor = object.constructor;\n  switch (tag) {\n    case arrayBufferTag:\n      return cloneArrayBuffer(object);\n\n    case boolTag:\n    case dateTag:\n      return new Ctor(+object);\n\n    case dataViewTag:\n      return cloneDataView(object, isDeep);\n\n    case float32Tag: case float64Tag:\n    case int8Tag: case int16Tag: case int32Tag:\n    case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:\n      return cloneTypedArray(object, isDeep);\n\n    case mapTag:\n      return cloneMap(object, isDeep, cloneFunc);\n\n    case numberTag:\n    case stringTag:\n      return new Ctor(object);\n\n    case regexpTag:\n      return cloneRegExp(object);\n\n    case setTag:\n      return cloneSet(object, isDeep, cloneFunc);\n\n    case symbolTag:\n      return cloneSymbol(object);\n  }\n}\n\n/**\n * Checks if `value` is a valid array-like index.\n *\n * @private\n * @param {*} value The value to check.\n * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.\n */\nfunction isIndex(value, length) {\n  length = length == null ? MAX_SAFE_INTEGER : length;\n  return !!length &&\n    (typeof value == 'number' || reIsUint.test(value)) &&\n    (value > -1 && value % 1 == 0 && value < length);\n}\n\n/**\n * Checks if `value` is suitable for use as unique object key.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is suitable, else `false`.\n */\nfunction isKeyable(value) {\n  var type = typeof value;\n  return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')\n    ? (value !== '__proto__')\n    : (value === null);\n}\n\n/**\n * Checks if `func` has its source masked.\n *\n * @private\n * @param {Function} func The function to check.\n * @returns {boolean} Returns `true` if `func` is masked, else `false`.\n */\nfunction isMasked(func) {\n  return !!maskSrcKey && (maskSrcKey in func);\n}\n\n/**\n * Checks if `value` is likely a prototype object.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.\n */\nfunction isPrototype(value) {\n  var Ctor = value && value.constructor,\n      proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;\n\n  return value === proto;\n}\n\n/**\n * Converts `func` to its source code.\n *\n * @private\n * @param {Function} func The function to process.\n * @returns {string} Returns the source code.\n */\nfunction toSource(func) {\n  if (func != null) {\n    try {\n      return funcToString.call(func);\n    } catch (e) {}\n    try {\n      return (func + '');\n    } catch (e) {}\n  }\n  return '';\n}\n\n/**\n * This method is like `_.clone` except that it recursively clones `value`.\n *\n * @static\n * @memberOf _\n * @since 1.0.0\n * @category Lang\n * @param {*} value The value to recursively clone.\n * @returns {*} Returns the deep cloned value.\n * @see _.clone\n * @example\n *\n * var objects = [{ 'a': 1 }, { 'b': 2 }];\n *\n * var deep = _.cloneDeep(objects);\n * console.log(deep[0] === objects[0]);\n * // => false\n */\nfunction cloneDeep(value) {\n  return baseClone(value, true, true);\n}\n\n/**\n * Performs a\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\nfunction eq(value, other) {\n  return value === other || (value !== value && other !== other);\n}\n\n/**\n * Checks if `value` is likely an `arguments` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an `arguments` object,\n *  else `false`.\n * @example\n *\n * _.isArguments(function() { return arguments; }());\n * // => true\n *\n * _.isArguments([1, 2, 3]);\n * // => false\n */\nfunction isArguments(value) {\n  // Safari 8.1 makes `arguments.callee` enumerable in strict mode.\n  return isArrayLikeObject(value) && hasOwnProperty.call(value, 'callee') &&\n    (!propertyIsEnumerable.call(value, 'callee') || objectToString.call(value) == argsTag);\n}\n\n/**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\nvar isArray = Array.isArray;\n\n/**\n * Checks if `value` is array-like. A value is considered array-like if it's\n * not a function and has a `value.length` that's an integer greater than or\n * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is array-like, else `false`.\n * @example\n *\n * _.isArrayLike([1, 2, 3]);\n * // => true\n *\n * _.isArrayLike(document.body.children);\n * // => true\n *\n * _.isArrayLike('abc');\n * // => true\n *\n * _.isArrayLike(_.noop);\n * // => false\n */\nfunction isArrayLike(value) {\n  return value != null && isLength(value.length) && !isFunction(value);\n}\n\n/**\n * This method is like `_.isArrayLike` except that it also checks if `value`\n * is an object.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array-like object,\n *  else `false`.\n * @example\n *\n * _.isArrayLikeObject([1, 2, 3]);\n * // => true\n *\n * _.isArrayLikeObject(document.body.children);\n * // => true\n *\n * _.isArrayLikeObject('abc');\n * // => false\n *\n * _.isArrayLikeObject(_.noop);\n * // => false\n */\nfunction isArrayLikeObject(value) {\n  return isObjectLike(value) && isArrayLike(value);\n}\n\n/**\n * Checks if `value` is a buffer.\n *\n * @static\n * @memberOf _\n * @since 4.3.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a buffer, else `false`.\n * @example\n *\n * _.isBuffer(new Buffer(2));\n * // => true\n *\n * _.isBuffer(new Uint8Array(2));\n * // => false\n */\nvar isBuffer = nativeIsBuffer || stubFalse;\n\n/**\n * Checks if `value` is classified as a `Function` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a function, else `false`.\n * @example\n *\n * _.isFunction(_);\n * // => true\n *\n * _.isFunction(/abc/);\n * // => false\n */\nfunction isFunction(value) {\n  // The use of `Object#toString` avoids issues with the `typeof` operator\n  // in Safari 8-9 which returns 'object' for typed array and other constructors.\n  var tag = isObject(value) ? objectToString.call(value) : '';\n  return tag == funcTag || tag == genTag;\n}\n\n/**\n * Checks if `value` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\nfunction isLength(value) {\n  return typeof value == 'number' &&\n    value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n}\n\n/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n  var type = typeof value;\n  return !!value && (type == 'object' || type == 'function');\n}\n\n/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n  return !!value && typeof value == 'object';\n}\n\n/**\n * Creates an array of the own enumerable property names of `object`.\n *\n * **Note:** Non-object values are coerced to objects. See the\n * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * for more details.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Object\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n * @example\n *\n * function Foo() {\n *   this.a = 1;\n *   this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.keys(new Foo);\n * // => ['a', 'b'] (iteration order is not guaranteed)\n *\n * _.keys('hi');\n * // => ['0', '1']\n */\nfunction keys(object) {\n  return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);\n}\n\n/**\n * This method returns a new empty array.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {Array} Returns the new empty array.\n * @example\n *\n * var arrays = _.times(2, _.stubArray);\n *\n * console.log(arrays);\n * // => [[], []]\n *\n * console.log(arrays[0] === arrays[1]);\n * // => false\n */\nfunction stubArray() {\n  return [];\n}\n\n/**\n * This method returns `false`.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {boolean} Returns `false`.\n * @example\n *\n * _.times(2, _.stubFalse);\n * // => [false, false]\n */\nfunction stubFalse() {\n  return false;\n}\n\nmodule.exports = cloneDeep;\n","/**\n * lodash (Custom Build) <https://lodash.com/>\n * Build: `lodash modularize exports=\"npm\" -o ./`\n * Copyright jQuery Foundation and other contributors <https://jquery.org/>\n * Released under MIT license <https://lodash.com/license>\n * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>\n * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n */\n\n/** Used as the `TypeError` message for \"Functions\" methods. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/** Used as references for various `Number` constants. */\nvar NAN = 0 / 0;\n\n/** `Object#toString` result references. */\nvar symbolTag = '[object Symbol]';\n\n/** Used to match leading and trailing whitespace. */\nvar reTrim = /^\\s+|\\s+$/g;\n\n/** Used to detect bad signed hexadecimal string values. */\nvar reIsBadHex = /^[-+]0x[0-9a-f]+$/i;\n\n/** Used to detect binary string values. */\nvar reIsBinary = /^0b[01]+$/i;\n\n/** Used to detect octal string values. */\nvar reIsOctal = /^0o[0-7]+$/i;\n\n/** Built-in method references without a dependency on `root`. */\nvar freeParseInt = parseInt;\n\n/** Detect free variable `global` from Node.js. */\nvar freeGlobal = typeof global == 'object' && global && global.Object === Object && global;\n\n/** Detect free variable `self`. */\nvar freeSelf = typeof self == 'object' && self && self.Object === Object && self;\n\n/** Used as a reference to the global object. */\nvar root = freeGlobal || freeSelf || Function('return this')();\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar objectToString = objectProto.toString;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeMax = Math.max,\n    nativeMin = Math.min;\n\n/**\n * Gets the timestamp of the number of milliseconds that have elapsed since\n * the Unix epoch (1 January 1970 00:00:00 UTC).\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Date\n * @returns {number} Returns the timestamp.\n * @example\n *\n * _.defer(function(stamp) {\n *   console.log(_.now() - stamp);\n * }, _.now());\n * // => Logs the number of milliseconds it took for the deferred invocation.\n */\nvar now = function() {\n  return root.Date.now();\n};\n\n/**\n * Creates a debounced function that delays invoking `func` until after `wait`\n * milliseconds have elapsed since the last time the debounced function was\n * invoked. The debounced function comes with a `cancel` method to cancel\n * delayed `func` invocations and a `flush` method to immediately invoke them.\n * Provide `options` to indicate whether `func` should be invoked on the\n * leading and/or trailing edge of the `wait` timeout. The `func` is invoked\n * with the last arguments provided to the debounced function. Subsequent\n * calls to the debounced function return the result of the last `func`\n * invocation.\n *\n * **Note:** If `leading` and `trailing` options are `true`, `func` is\n * invoked on the trailing edge of the timeout only if the debounced function\n * is invoked more than once during the `wait` timeout.\n *\n * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred\n * until to the next tick, similar to `setTimeout` with a timeout of `0`.\n *\n * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)\n * for details over the differences between `_.debounce` and `_.throttle`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Function\n * @param {Function} func The function to debounce.\n * @param {number} [wait=0] The number of milliseconds to delay.\n * @param {Object} [options={}] The options object.\n * @param {boolean} [options.leading=false]\n *  Specify invoking on the leading edge of the timeout.\n * @param {number} [options.maxWait]\n *  The maximum time `func` is allowed to be delayed before it's invoked.\n * @param {boolean} [options.trailing=true]\n *  Specify invoking on the trailing edge of the timeout.\n * @returns {Function} Returns the new debounced function.\n * @example\n *\n * // Avoid costly calculations while the window size is in flux.\n * jQuery(window).on('resize', _.debounce(calculateLayout, 150));\n *\n * // Invoke `sendMail` when clicked, debouncing subsequent calls.\n * jQuery(element).on('click', _.debounce(sendMail, 300, {\n *   'leading': true,\n *   'trailing': false\n * }));\n *\n * // Ensure `batchLog` is invoked once after 1 second of debounced calls.\n * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });\n * var source = new EventSource('/stream');\n * jQuery(source).on('message', debounced);\n *\n * // Cancel the trailing debounced invocation.\n * jQuery(window).on('popstate', debounced.cancel);\n */\nfunction debounce(func, wait, options) {\n  var lastArgs,\n      lastThis,\n      maxWait,\n      result,\n      timerId,\n      lastCallTime,\n      lastInvokeTime = 0,\n      leading = false,\n      maxing = false,\n      trailing = true;\n\n  if (typeof func != 'function') {\n    throw new TypeError(FUNC_ERROR_TEXT);\n  }\n  wait = toNumber(wait) || 0;\n  if (isObject(options)) {\n    leading = !!options.leading;\n    maxing = 'maxWait' in options;\n    maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;\n    trailing = 'trailing' in options ? !!options.trailing : trailing;\n  }\n\n  function invokeFunc(time) {\n    var args = lastArgs,\n        thisArg = lastThis;\n\n    lastArgs = lastThis = undefined;\n    lastInvokeTime = time;\n    result = func.apply(thisArg, args);\n    return result;\n  }\n\n  function leadingEdge(time) {\n    // Reset any `maxWait` timer.\n    lastInvokeTime = time;\n    // Start the timer for the trailing edge.\n    timerId = setTimeout(timerExpired, wait);\n    // Invoke the leading edge.\n    return leading ? invokeFunc(time) : result;\n  }\n\n  function remainingWait(time) {\n    var timeSinceLastCall = time - lastCallTime,\n        timeSinceLastInvoke = time - lastInvokeTime,\n        result = wait - timeSinceLastCall;\n\n    return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result;\n  }\n\n  function shouldInvoke(time) {\n    var timeSinceLastCall = time - lastCallTime,\n        timeSinceLastInvoke = time - lastInvokeTime;\n\n    // Either this is the first call, activity has stopped and we're at the\n    // trailing edge, the system time has gone backwards and we're treating\n    // it as the trailing edge, or we've hit the `maxWait` limit.\n    return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||\n      (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));\n  }\n\n  function timerExpired() {\n    var time = now();\n    if (shouldInvoke(time)) {\n      return trailingEdge(time);\n    }\n    // Restart the timer.\n    timerId = setTimeout(timerExpired, remainingWait(time));\n  }\n\n  function trailingEdge(time) {\n    timerId = undefined;\n\n    // Only invoke if we have `lastArgs` which means `func` has been\n    // debounced at least once.\n    if (trailing && lastArgs) {\n      return invokeFunc(time);\n    }\n    lastArgs = lastThis = undefined;\n    return result;\n  }\n\n  function cancel() {\n    if (timerId !== undefined) {\n      clearTimeout(timerId);\n    }\n    lastInvokeTime = 0;\n    lastArgs = lastCallTime = lastThis = timerId = undefined;\n  }\n\n  function flush() {\n    return timerId === undefined ? result : trailingEdge(now());\n  }\n\n  function debounced() {\n    var time = now(),\n        isInvoking = shouldInvoke(time);\n\n    lastArgs = arguments;\n    lastThis = this;\n    lastCallTime = time;\n\n    if (isInvoking) {\n      if (timerId === undefined) {\n        return leadingEdge(lastCallTime);\n      }\n      if (maxing) {\n        // Handle invocations in a tight loop.\n        timerId = setTimeout(timerExpired, wait);\n        return invokeFunc(lastCallTime);\n      }\n    }\n    if (timerId === undefined) {\n      timerId = setTimeout(timerExpired, wait);\n    }\n    return result;\n  }\n  debounced.cancel = cancel;\n  debounced.flush = flush;\n  return debounced;\n}\n\n/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n  var type = typeof value;\n  return !!value && (type == 'object' || type == 'function');\n}\n\n/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n  return !!value && typeof value == 'object';\n}\n\n/**\n * Checks if `value` is classified as a `Symbol` primitive or object.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.\n * @example\n *\n * _.isSymbol(Symbol.iterator);\n * // => true\n *\n * _.isSymbol('abc');\n * // => false\n */\nfunction isSymbol(value) {\n  return typeof value == 'symbol' ||\n    (isObjectLike(value) && objectToString.call(value) == symbolTag);\n}\n\n/**\n * Converts `value` to a number.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to process.\n * @returns {number} Returns the number.\n * @example\n *\n * _.toNumber(3.2);\n * // => 3.2\n *\n * _.toNumber(Number.MIN_VALUE);\n * // => 5e-324\n *\n * _.toNumber(Infinity);\n * // => Infinity\n *\n * _.toNumber('3.2');\n * // => 3.2\n */\nfunction toNumber(value) {\n  if (typeof value == 'number') {\n    return value;\n  }\n  if (isSymbol(value)) {\n    return NAN;\n  }\n  if (isObject(value)) {\n    var other = typeof value.valueOf == 'function' ? value.valueOf() : value;\n    value = isObject(other) ? (other + '') : other;\n  }\n  if (typeof value != 'string') {\n    return value === 0 ? value : +value;\n  }\n  value = value.replace(reTrim, '');\n  var isBinary = reIsBinary.test(value);\n  return (isBinary || reIsOctal.test(value))\n    ? freeParseInt(value.slice(2), isBinary ? 2 : 8)\n    : (reIsBadHex.test(value) ? NAN : +value);\n}\n\nmodule.exports = debounce;\n","/**\n * Lodash (Custom Build) <https://lodash.com/>\n * Build: `lodash modularize exports=\"npm\" -o ./`\n * Copyright JS Foundation and other contributors <https://js.foundation/>\n * Released under MIT license <https://lodash.com/license>\n * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>\n * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n */\n\n/** Used as the size to enable large array optimizations. */\nvar LARGE_ARRAY_SIZE = 200;\n\n/** Used to stand-in for `undefined` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n/** Used to compose bitmasks for value comparisons. */\nvar COMPARE_PARTIAL_FLAG = 1,\n    COMPARE_UNORDERED_FLAG = 2;\n\n/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/** `Object#toString` result references. */\nvar argsTag = '[object Arguments]',\n    arrayTag = '[object Array]',\n    asyncTag = '[object AsyncFunction]',\n    boolTag = '[object Boolean]',\n    dateTag = '[object Date]',\n    errorTag = '[object Error]',\n    funcTag = '[object Function]',\n    genTag = '[object GeneratorFunction]',\n    mapTag = '[object Map]',\n    numberTag = '[object Number]',\n    nullTag = '[object Null]',\n    objectTag = '[object Object]',\n    promiseTag = '[object Promise]',\n    proxyTag = '[object Proxy]',\n    regexpTag = '[object RegExp]',\n    setTag = '[object Set]',\n    stringTag = '[object String]',\n    symbolTag = '[object Symbol]',\n    undefinedTag = '[object Undefined]',\n    weakMapTag = '[object WeakMap]';\n\nvar arrayBufferTag = '[object ArrayBuffer]',\n    dataViewTag = '[object DataView]',\n    float32Tag = '[object Float32Array]',\n    float64Tag = '[object Float64Array]',\n    int8Tag = '[object Int8Array]',\n    int16Tag = '[object Int16Array]',\n    int32Tag = '[object Int32Array]',\n    uint8Tag = '[object Uint8Array]',\n    uint8ClampedTag = '[object Uint8ClampedArray]',\n    uint16Tag = '[object Uint16Array]',\n    uint32Tag = '[object Uint32Array]';\n\n/**\n * Used to match `RegExp`\n * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).\n */\nvar reRegExpChar = /[\\\\^$.*+?()[\\]{}|]/g;\n\n/** Used to detect host constructors (Safari). */\nvar reIsHostCtor = /^\\[object .+?Constructor\\]$/;\n\n/** Used to detect unsigned integer values. */\nvar reIsUint = /^(?:0|[1-9]\\d*)$/;\n\n/** Used to identify `toStringTag` values of typed arrays. */\nvar typedArrayTags = {};\ntypedArrayTags[float32Tag] = typedArrayTags[float64Tag] =\ntypedArrayTags[int8Tag] = typedArrayTags[int16Tag] =\ntypedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =\ntypedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =\ntypedArrayTags[uint32Tag] = true;\ntypedArrayTags[argsTag] = typedArrayTags[arrayTag] =\ntypedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =\ntypedArrayTags[dataViewTag] = typedArrayTags[dateTag] =\ntypedArrayTags[errorTag] = typedArrayTags[funcTag] =\ntypedArrayTags[mapTag] = typedArrayTags[numberTag] =\ntypedArrayTags[objectTag] = typedArrayTags[regexpTag] =\ntypedArrayTags[setTag] = typedArrayTags[stringTag] =\ntypedArrayTags[weakMapTag] = false;\n\n/** Detect free variable `global` from Node.js. */\nvar freeGlobal = typeof global == 'object' && global && global.Object === Object && global;\n\n/** Detect free variable `self`. */\nvar freeSelf = typeof self == 'object' && self && self.Object === Object && self;\n\n/** Used as a reference to the global object. */\nvar root = freeGlobal || freeSelf || Function('return this')();\n\n/** Detect free variable `exports`. */\nvar freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;\n\n/** Detect free variable `module`. */\nvar freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;\n\n/** Detect the popular CommonJS extension `module.exports`. */\nvar moduleExports = freeModule && freeModule.exports === freeExports;\n\n/** Detect free variable `process` from Node.js. */\nvar freeProcess = moduleExports && freeGlobal.process;\n\n/** Used to access faster Node.js helpers. */\nvar nodeUtil = (function() {\n  try {\n    return freeProcess && freeProcess.binding && freeProcess.binding('util');\n  } catch (e) {}\n}());\n\n/* Node.js helper references. */\nvar nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray;\n\n/**\n * A specialized version of `_.filter` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {Array} Returns the new filtered array.\n */\nfunction arrayFilter(array, predicate) {\n  var index = -1,\n      length = array == null ? 0 : array.length,\n      resIndex = 0,\n      result = [];\n\n  while (++index < length) {\n    var value = array[index];\n    if (predicate(value, index, array)) {\n      result[resIndex++] = value;\n    }\n  }\n  return result;\n}\n\n/**\n * Appends the elements of `values` to `array`.\n *\n * @private\n * @param {Array} array The array to modify.\n * @param {Array} values The values to append.\n * @returns {Array} Returns `array`.\n */\nfunction arrayPush(array, values) {\n  var index = -1,\n      length = values.length,\n      offset = array.length;\n\n  while (++index < length) {\n    array[offset + index] = values[index];\n  }\n  return array;\n}\n\n/**\n * A specialized version of `_.some` for arrays without support for iteratee\n * shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {boolean} Returns `true` if any element passes the predicate check,\n *  else `false`.\n */\nfunction arraySome(array, predicate) {\n  var index = -1,\n      length = array == null ? 0 : array.length;\n\n  while (++index < length) {\n    if (predicate(array[index], index, array)) {\n      return true;\n    }\n  }\n  return false;\n}\n\n/**\n * The base implementation of `_.times` without support for iteratee shorthands\n * or max array length checks.\n *\n * @private\n * @param {number} n The number of times to invoke `iteratee`.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the array of results.\n */\nfunction baseTimes(n, iteratee) {\n  var index = -1,\n      result = Array(n);\n\n  while (++index < n) {\n    result[index] = iteratee(index);\n  }\n  return result;\n}\n\n/**\n * The base implementation of `_.unary` without support for storing metadata.\n *\n * @private\n * @param {Function} func The function to cap arguments for.\n * @returns {Function} Returns the new capped function.\n */\nfunction baseUnary(func) {\n  return function(value) {\n    return func(value);\n  };\n}\n\n/**\n * Checks if a `cache` value for `key` exists.\n *\n * @private\n * @param {Object} cache The cache to query.\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction cacheHas(cache, key) {\n  return cache.has(key);\n}\n\n/**\n * Gets the value at `key` of `object`.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction getValue(object, key) {\n  return object == null ? undefined : object[key];\n}\n\n/**\n * Converts `map` to its key-value pairs.\n *\n * @private\n * @param {Object} map The map to convert.\n * @returns {Array} Returns the key-value pairs.\n */\nfunction mapToArray(map) {\n  var index = -1,\n      result = Array(map.size);\n\n  map.forEach(function(value, key) {\n    result[++index] = [key, value];\n  });\n  return result;\n}\n\n/**\n * Creates a unary function that invokes `func` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n  return function(arg) {\n    return func(transform(arg));\n  };\n}\n\n/**\n * Converts `set` to an array of its values.\n *\n * @private\n * @param {Object} set The set to convert.\n * @returns {Array} Returns the values.\n */\nfunction setToArray(set) {\n  var index = -1,\n      result = Array(set.size);\n\n  set.forEach(function(value) {\n    result[++index] = value;\n  });\n  return result;\n}\n\n/** Used for built-in method references. */\nvar arrayProto = Array.prototype,\n    funcProto = Function.prototype,\n    objectProto = Object.prototype;\n\n/** Used to detect overreaching core-js shims. */\nvar coreJsData = root['__core-js_shared__'];\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/** Used to detect methods masquerading as native. */\nvar maskSrcKey = (function() {\n  var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');\n  return uid ? ('Symbol(src)_1.' + uid) : '';\n}());\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/** Used to detect if a method is native. */\nvar reIsNative = RegExp('^' +\n  funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\\\$&')\n  .replace(/hasOwnProperty|(function).*?(?=\\\\\\()| for .+?(?=\\\\\\])/g, '$1.*?') + '$'\n);\n\n/** Built-in value references. */\nvar Buffer = moduleExports ? root.Buffer : undefined,\n    Symbol = root.Symbol,\n    Uint8Array = root.Uint8Array,\n    propertyIsEnumerable = objectProto.propertyIsEnumerable,\n    splice = arrayProto.splice,\n    symToStringTag = Symbol ? Symbol.toStringTag : undefined;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeGetSymbols = Object.getOwnPropertySymbols,\n    nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined,\n    nativeKeys = overArg(Object.keys, Object);\n\n/* Built-in method references that are verified to be native. */\nvar DataView = getNative(root, 'DataView'),\n    Map = getNative(root, 'Map'),\n    Promise = getNative(root, 'Promise'),\n    Set = getNative(root, 'Set'),\n    WeakMap = getNative(root, 'WeakMap'),\n    nativeCreate = getNative(Object, 'create');\n\n/** Used to detect maps, sets, and weakmaps. */\nvar dataViewCtorString = toSource(DataView),\n    mapCtorString = toSource(Map),\n    promiseCtorString = toSource(Promise),\n    setCtorString = toSource(Set),\n    weakMapCtorString = toSource(WeakMap);\n\n/** Used to convert symbols to primitives and strings. */\nvar symbolProto = Symbol ? Symbol.prototype : undefined,\n    symbolValueOf = symbolProto ? symbolProto.valueOf : undefined;\n\n/**\n * Creates a hash object.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction Hash(entries) {\n  var index = -1,\n      length = entries == null ? 0 : entries.length;\n\n  this.clear();\n  while (++index < length) {\n    var entry = entries[index];\n    this.set(entry[0], entry[1]);\n  }\n}\n\n/**\n * Removes all key-value entries from the hash.\n *\n * @private\n * @name clear\n * @memberOf Hash\n */\nfunction hashClear() {\n  this.__data__ = nativeCreate ? nativeCreate(null) : {};\n  this.size = 0;\n}\n\n/**\n * Removes `key` and its value from the hash.\n *\n * @private\n * @name delete\n * @memberOf Hash\n * @param {Object} hash The hash to modify.\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction hashDelete(key) {\n  var result = this.has(key) && delete this.__data__[key];\n  this.size -= result ? 1 : 0;\n  return result;\n}\n\n/**\n * Gets the hash value for `key`.\n *\n * @private\n * @name get\n * @memberOf Hash\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction hashGet(key) {\n  var data = this.__data__;\n  if (nativeCreate) {\n    var result = data[key];\n    return result === HASH_UNDEFINED ? undefined : result;\n  }\n  return hasOwnProperty.call(data, key) ? data[key] : undefined;\n}\n\n/**\n * Checks if a hash value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Hash\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction hashHas(key) {\n  var data = this.__data__;\n  return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key);\n}\n\n/**\n * Sets the hash `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf Hash\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the hash instance.\n */\nfunction hashSet(key, value) {\n  var data = this.__data__;\n  this.size += this.has(key) ? 0 : 1;\n  data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;\n  return this;\n}\n\n// Add methods to `Hash`.\nHash.prototype.clear = hashClear;\nHash.prototype['delete'] = hashDelete;\nHash.prototype.get = hashGet;\nHash.prototype.has = hashHas;\nHash.prototype.set = hashSet;\n\n/**\n * Creates an list cache object.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction ListCache(entries) {\n  var index = -1,\n      length = entries == null ? 0 : entries.length;\n\n  this.clear();\n  while (++index < length) {\n    var entry = entries[index];\n    this.set(entry[0], entry[1]);\n  }\n}\n\n/**\n * Removes all key-value entries from the list cache.\n *\n * @private\n * @name clear\n * @memberOf ListCache\n */\nfunction listCacheClear() {\n  this.__data__ = [];\n  this.size = 0;\n}\n\n/**\n * Removes `key` and its value from the list cache.\n *\n * @private\n * @name delete\n * @memberOf ListCache\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction listCacheDelete(key) {\n  var data = this.__data__,\n      index = assocIndexOf(data, key);\n\n  if (index < 0) {\n    return false;\n  }\n  var lastIndex = data.length - 1;\n  if (index == lastIndex) {\n    data.pop();\n  } else {\n    splice.call(data, index, 1);\n  }\n  --this.size;\n  return true;\n}\n\n/**\n * Gets the list cache value for `key`.\n *\n * @private\n * @name get\n * @memberOf ListCache\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction listCacheGet(key) {\n  var data = this.__data__,\n      index = assocIndexOf(data, key);\n\n  return index < 0 ? undefined : data[index][1];\n}\n\n/**\n * Checks if a list cache value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf ListCache\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction listCacheHas(key) {\n  return assocIndexOf(this.__data__, key) > -1;\n}\n\n/**\n * Sets the list cache `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf ListCache\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the list cache instance.\n */\nfunction listCacheSet(key, value) {\n  var data = this.__data__,\n      index = assocIndexOf(data, key);\n\n  if (index < 0) {\n    ++this.size;\n    data.push([key, value]);\n  } else {\n    data[index][1] = value;\n  }\n  return this;\n}\n\n// Add methods to `ListCache`.\nListCache.prototype.clear = listCacheClear;\nListCache.prototype['delete'] = listCacheDelete;\nListCache.prototype.get = listCacheGet;\nListCache.prototype.has = listCacheHas;\nListCache.prototype.set = listCacheSet;\n\n/**\n * Creates a map cache object to store key-value pairs.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction MapCache(entries) {\n  var index = -1,\n      length = entries == null ? 0 : entries.length;\n\n  this.clear();\n  while (++index < length) {\n    var entry = entries[index];\n    this.set(entry[0], entry[1]);\n  }\n}\n\n/**\n * Removes all key-value entries from the map.\n *\n * @private\n * @name clear\n * @memberOf MapCache\n */\nfunction mapCacheClear() {\n  this.size = 0;\n  this.__data__ = {\n    'hash': new Hash,\n    'map': new (Map || ListCache),\n    'string': new Hash\n  };\n}\n\n/**\n * Removes `key` and its value from the map.\n *\n * @private\n * @name delete\n * @memberOf MapCache\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction mapCacheDelete(key) {\n  var result = getMapData(this, key)['delete'](key);\n  this.size -= result ? 1 : 0;\n  return result;\n}\n\n/**\n * Gets the map value for `key`.\n *\n * @private\n * @name get\n * @memberOf MapCache\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction mapCacheGet(key) {\n  return getMapData(this, key).get(key);\n}\n\n/**\n * Checks if a map value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf MapCache\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction mapCacheHas(key) {\n  return getMapData(this, key).has(key);\n}\n\n/**\n * Sets the map `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf MapCache\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the map cache instance.\n */\nfunction mapCacheSet(key, value) {\n  var data = getMapData(this, key),\n      size = data.size;\n\n  data.set(key, value);\n  this.size += data.size == size ? 0 : 1;\n  return this;\n}\n\n// Add methods to `MapCache`.\nMapCache.prototype.clear = mapCacheClear;\nMapCache.prototype['delete'] = mapCacheDelete;\nMapCache.prototype.get = mapCacheGet;\nMapCache.prototype.has = mapCacheHas;\nMapCache.prototype.set = mapCacheSet;\n\n/**\n *\n * Creates an array cache object to store unique values.\n *\n * @private\n * @constructor\n * @param {Array} [values] The values to cache.\n */\nfunction SetCache(values) {\n  var index = -1,\n      length = values == null ? 0 : values.length;\n\n  this.__data__ = new MapCache;\n  while (++index < length) {\n    this.add(values[index]);\n  }\n}\n\n/**\n * Adds `value` to the array cache.\n *\n * @private\n * @name add\n * @memberOf SetCache\n * @alias push\n * @param {*} value The value to cache.\n * @returns {Object} Returns the cache instance.\n */\nfunction setCacheAdd(value) {\n  this.__data__.set(value, HASH_UNDEFINED);\n  return this;\n}\n\n/**\n * Checks if `value` is in the array cache.\n *\n * @private\n * @name has\n * @memberOf SetCache\n * @param {*} value The value to search for.\n * @returns {number} Returns `true` if `value` is found, else `false`.\n */\nfunction setCacheHas(value) {\n  return this.__data__.has(value);\n}\n\n// Add methods to `SetCache`.\nSetCache.prototype.add = SetCache.prototype.push = setCacheAdd;\nSetCache.prototype.has = setCacheHas;\n\n/**\n * Creates a stack cache object to store key-value pairs.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction Stack(entries) {\n  var data = this.__data__ = new ListCache(entries);\n  this.size = data.size;\n}\n\n/**\n * Removes all key-value entries from the stack.\n *\n * @private\n * @name clear\n * @memberOf Stack\n */\nfunction stackClear() {\n  this.__data__ = new ListCache;\n  this.size = 0;\n}\n\n/**\n * Removes `key` and its value from the stack.\n *\n * @private\n * @name delete\n * @memberOf Stack\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction stackDelete(key) {\n  var data = this.__data__,\n      result = data['delete'](key);\n\n  this.size = data.size;\n  return result;\n}\n\n/**\n * Gets the stack value for `key`.\n *\n * @private\n * @name get\n * @memberOf Stack\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction stackGet(key) {\n  return this.__data__.get(key);\n}\n\n/**\n * Checks if a stack value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Stack\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction stackHas(key) {\n  return this.__data__.has(key);\n}\n\n/**\n * Sets the stack `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf Stack\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the stack cache instance.\n */\nfunction stackSet(key, value) {\n  var data = this.__data__;\n  if (data instanceof ListCache) {\n    var pairs = data.__data__;\n    if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) {\n      pairs.push([key, value]);\n      this.size = ++data.size;\n      return this;\n    }\n    data = this.__data__ = new MapCache(pairs);\n  }\n  data.set(key, value);\n  this.size = data.size;\n  return this;\n}\n\n// Add methods to `Stack`.\nStack.prototype.clear = stackClear;\nStack.prototype['delete'] = stackDelete;\nStack.prototype.get = stackGet;\nStack.prototype.has = stackHas;\nStack.prototype.set = stackSet;\n\n/**\n * Creates an array of the enumerable property names of the array-like `value`.\n *\n * @private\n * @param {*} value The value to query.\n * @param {boolean} inherited Specify returning inherited property names.\n * @returns {Array} Returns the array of property names.\n */\nfunction arrayLikeKeys(value, inherited) {\n  var isArr = isArray(value),\n      isArg = !isArr && isArguments(value),\n      isBuff = !isArr && !isArg && isBuffer(value),\n      isType = !isArr && !isArg && !isBuff && isTypedArray(value),\n      skipIndexes = isArr || isArg || isBuff || isType,\n      result = skipIndexes ? baseTimes(value.length, String) : [],\n      length = result.length;\n\n  for (var key in value) {\n    if ((inherited || hasOwnProperty.call(value, key)) &&\n        !(skipIndexes && (\n           // Safari 9 has enumerable `arguments.length` in strict mode.\n           key == 'length' ||\n           // Node.js 0.10 has enumerable non-index properties on buffers.\n           (isBuff && (key == 'offset' || key == 'parent')) ||\n           // PhantomJS 2 has enumerable non-index properties on typed arrays.\n           (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) ||\n           // Skip index properties.\n           isIndex(key, length)\n        ))) {\n      result.push(key);\n    }\n  }\n  return result;\n}\n\n/**\n * Gets the index at which the `key` is found in `array` of key-value pairs.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {*} key The key to search for.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction assocIndexOf(array, key) {\n  var length = array.length;\n  while (length--) {\n    if (eq(array[length][0], key)) {\n      return length;\n    }\n  }\n  return -1;\n}\n\n/**\n * The base implementation of `getAllKeys` and `getAllKeysIn` which uses\n * `keysFunc` and `symbolsFunc` to get the enumerable property names and\n * symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {Function} keysFunc The function to get the keys of `object`.\n * @param {Function} symbolsFunc The function to get the symbols of `object`.\n * @returns {Array} Returns the array of property names and symbols.\n */\nfunction baseGetAllKeys(object, keysFunc, symbolsFunc) {\n  var result = keysFunc(object);\n  return isArray(object) ? result : arrayPush(result, symbolsFunc(object));\n}\n\n/**\n * The base implementation of `getTag` without fallbacks for buggy environments.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\nfunction baseGetTag(value) {\n  if (value == null) {\n    return value === undefined ? undefinedTag : nullTag;\n  }\n  return (symToStringTag && symToStringTag in Object(value))\n    ? getRawTag(value)\n    : objectToString(value);\n}\n\n/**\n * The base implementation of `_.isArguments`.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an `arguments` object,\n */\nfunction baseIsArguments(value) {\n  return isObjectLike(value) && baseGetTag(value) == argsTag;\n}\n\n/**\n * The base implementation of `_.isEqual` which supports partial comparisons\n * and tracks traversed objects.\n *\n * @private\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @param {boolean} bitmask The bitmask flags.\n *  1 - Unordered comparison\n *  2 - Partial comparison\n * @param {Function} [customizer] The function to customize comparisons.\n * @param {Object} [stack] Tracks traversed `value` and `other` objects.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n */\nfunction baseIsEqual(value, other, bitmask, customizer, stack) {\n  if (value === other) {\n    return true;\n  }\n  if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) {\n    return value !== value && other !== other;\n  }\n  return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack);\n}\n\n/**\n * A specialized version of `baseIsEqual` for arrays and objects which performs\n * deep comparisons and tracks traversed objects enabling objects with circular\n * references to be compared.\n *\n * @private\n * @param {Object} object The object to compare.\n * @param {Object} other The other object to compare.\n * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.\n * @param {Function} customizer The function to customize comparisons.\n * @param {Function} equalFunc The function to determine equivalents of values.\n * @param {Object} [stack] Tracks traversed `object` and `other` objects.\n * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.\n */\nfunction baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) {\n  var objIsArr = isArray(object),\n      othIsArr = isArray(other),\n      objTag = objIsArr ? arrayTag : getTag(object),\n      othTag = othIsArr ? arrayTag : getTag(other);\n\n  objTag = objTag == argsTag ? objectTag : objTag;\n  othTag = othTag == argsTag ? objectTag : othTag;\n\n  var objIsObj = objTag == objectTag,\n      othIsObj = othTag == objectTag,\n      isSameTag = objTag == othTag;\n\n  if (isSameTag && isBuffer(object)) {\n    if (!isBuffer(other)) {\n      return false;\n    }\n    objIsArr = true;\n    objIsObj = false;\n  }\n  if (isSameTag && !objIsObj) {\n    stack || (stack = new Stack);\n    return (objIsArr || isTypedArray(object))\n      ? equalArrays(object, other, bitmask, customizer, equalFunc, stack)\n      : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack);\n  }\n  if (!(bitmask & COMPARE_PARTIAL_FLAG)) {\n    var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),\n        othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');\n\n    if (objIsWrapped || othIsWrapped) {\n      var objUnwrapped = objIsWrapped ? object.value() : object,\n          othUnwrapped = othIsWrapped ? other.value() : other;\n\n      stack || (stack = new Stack);\n      return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack);\n    }\n  }\n  if (!isSameTag) {\n    return false;\n  }\n  stack || (stack = new Stack);\n  return equalObjects(object, other, bitmask, customizer, equalFunc, stack);\n}\n\n/**\n * The base implementation of `_.isNative` without bad shim checks.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a native function,\n *  else `false`.\n */\nfunction baseIsNative(value) {\n  if (!isObject(value) || isMasked(value)) {\n    return false;\n  }\n  var pattern = isFunction(value) ? reIsNative : reIsHostCtor;\n  return pattern.test(toSource(value));\n}\n\n/**\n * The base implementation of `_.isTypedArray` without Node.js optimizations.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.\n */\nfunction baseIsTypedArray(value) {\n  return isObjectLike(value) &&\n    isLength(value.length) && !!typedArrayTags[baseGetTag(value)];\n}\n\n/**\n * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction baseKeys(object) {\n  if (!isPrototype(object)) {\n    return nativeKeys(object);\n  }\n  var result = [];\n  for (var key in Object(object)) {\n    if (hasOwnProperty.call(object, key) && key != 'constructor') {\n      result.push(key);\n    }\n  }\n  return result;\n}\n\n/**\n * A specialized version of `baseIsEqualDeep` for arrays with support for\n * partial deep comparisons.\n *\n * @private\n * @param {Array} array The array to compare.\n * @param {Array} other The other array to compare.\n * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.\n * @param {Function} customizer The function to customize comparisons.\n * @param {Function} equalFunc The function to determine equivalents of values.\n * @param {Object} stack Tracks traversed `array` and `other` objects.\n * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.\n */\nfunction equalArrays(array, other, bitmask, customizer, equalFunc, stack) {\n  var isPartial = bitmask & COMPARE_PARTIAL_FLAG,\n      arrLength = array.length,\n      othLength = other.length;\n\n  if (arrLength != othLength && !(isPartial && othLength > arrLength)) {\n    return false;\n  }\n  // Assume cyclic values are equal.\n  var stacked = stack.get(array);\n  if (stacked && stack.get(other)) {\n    return stacked == other;\n  }\n  var index = -1,\n      result = true,\n      seen = (bitmask & COMPARE_UNORDERED_FLAG) ? new SetCache : undefined;\n\n  stack.set(array, other);\n  stack.set(other, array);\n\n  // Ignore non-index properties.\n  while (++index < arrLength) {\n    var arrValue = array[index],\n        othValue = other[index];\n\n    if (customizer) {\n      var compared = isPartial\n        ? customizer(othValue, arrValue, index, other, array, stack)\n        : customizer(arrValue, othValue, index, array, other, stack);\n    }\n    if (compared !== undefined) {\n      if (compared) {\n        continue;\n      }\n      result = false;\n      break;\n    }\n    // Recursively compare arrays (susceptible to call stack limits).\n    if (seen) {\n      if (!arraySome(other, function(othValue, othIndex) {\n            if (!cacheHas(seen, othIndex) &&\n                (arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) {\n              return seen.push(othIndex);\n            }\n          })) {\n        result = false;\n        break;\n      }\n    } else if (!(\n          arrValue === othValue ||\n            equalFunc(arrValue, othValue, bitmask, customizer, stack)\n        )) {\n      result = false;\n      break;\n    }\n  }\n  stack['delete'](array);\n  stack['delete'](other);\n  return result;\n}\n\n/**\n * A specialized version of `baseIsEqualDeep` for comparing objects of\n * the same `toStringTag`.\n *\n * **Note:** This function only supports comparing values with tags of\n * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.\n *\n * @private\n * @param {Object} object The object to compare.\n * @param {Object} other The other object to compare.\n * @param {string} tag The `toStringTag` of the objects to compare.\n * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.\n * @param {Function} customizer The function to customize comparisons.\n * @param {Function} equalFunc The function to determine equivalents of values.\n * @param {Object} stack Tracks traversed `object` and `other` objects.\n * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.\n */\nfunction equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) {\n  switch (tag) {\n    case dataViewTag:\n      if ((object.byteLength != other.byteLength) ||\n          (object.byteOffset != other.byteOffset)) {\n        return false;\n      }\n      object = object.buffer;\n      other = other.buffer;\n\n    case arrayBufferTag:\n      if ((object.byteLength != other.byteLength) ||\n          !equalFunc(new Uint8Array(object), new Uint8Array(other))) {\n        return false;\n      }\n      return true;\n\n    case boolTag:\n    case dateTag:\n    case numberTag:\n      // Coerce booleans to `1` or `0` and dates to milliseconds.\n      // Invalid dates are coerced to `NaN`.\n      return eq(+object, +other);\n\n    case errorTag:\n      return object.name == other.name && object.message == other.message;\n\n    case regexpTag:\n    case stringTag:\n      // Coerce regexes to strings and treat strings, primitives and objects,\n      // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring\n      // for more details.\n      return object == (other + '');\n\n    case mapTag:\n      var convert = mapToArray;\n\n    case setTag:\n      var isPartial = bitmask & COMPARE_PARTIAL_FLAG;\n      convert || (convert = setToArray);\n\n      if (object.size != other.size && !isPartial) {\n        return false;\n      }\n      // Assume cyclic values are equal.\n      var stacked = stack.get(object);\n      if (stacked) {\n        return stacked == other;\n      }\n      bitmask |= COMPARE_UNORDERED_FLAG;\n\n      // Recursively compare objects (susceptible to call stack limits).\n      stack.set(object, other);\n      var result = equalArrays(convert(object), convert(other), bitmask, customizer, equalFunc, stack);\n      stack['delete'](object);\n      return result;\n\n    case symbolTag:\n      if (symbolValueOf) {\n        return symbolValueOf.call(object) == symbolValueOf.call(other);\n      }\n  }\n  return false;\n}\n\n/**\n * A specialized version of `baseIsEqualDeep` for objects with support for\n * partial deep comparisons.\n *\n * @private\n * @param {Object} object The object to compare.\n * @param {Object} other The other object to compare.\n * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.\n * @param {Function} customizer The function to customize comparisons.\n * @param {Function} equalFunc The function to determine equivalents of values.\n * @param {Object} stack Tracks traversed `object` and `other` objects.\n * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.\n */\nfunction equalObjects(object, other, bitmask, customizer, equalFunc, stack) {\n  var isPartial = bitmask & COMPARE_PARTIAL_FLAG,\n      objProps = getAllKeys(object),\n      objLength = objProps.length,\n      othProps = getAllKeys(other),\n      othLength = othProps.length;\n\n  if (objLength != othLength && !isPartial) {\n    return false;\n  }\n  var index = objLength;\n  while (index--) {\n    var key = objProps[index];\n    if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) {\n      return false;\n    }\n  }\n  // Assume cyclic values are equal.\n  var stacked = stack.get(object);\n  if (stacked && stack.get(other)) {\n    return stacked == other;\n  }\n  var result = true;\n  stack.set(object, other);\n  stack.set(other, object);\n\n  var skipCtor = isPartial;\n  while (++index < objLength) {\n    key = objProps[index];\n    var objValue = object[key],\n        othValue = other[key];\n\n    if (customizer) {\n      var compared = isPartial\n        ? customizer(othValue, objValue, key, other, object, stack)\n        : customizer(objValue, othValue, key, object, other, stack);\n    }\n    // Recursively compare objects (susceptible to call stack limits).\n    if (!(compared === undefined\n          ? (objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack))\n          : compared\n        )) {\n      result = false;\n      break;\n    }\n    skipCtor || (skipCtor = key == 'constructor');\n  }\n  if (result && !skipCtor) {\n    var objCtor = object.constructor,\n        othCtor = other.constructor;\n\n    // Non `Object` object instances with different constructors are not equal.\n    if (objCtor != othCtor &&\n        ('constructor' in object && 'constructor' in other) &&\n        !(typeof objCtor == 'function' && objCtor instanceof objCtor &&\n          typeof othCtor == 'function' && othCtor instanceof othCtor)) {\n      result = false;\n    }\n  }\n  stack['delete'](object);\n  stack['delete'](other);\n  return result;\n}\n\n/**\n * Creates an array of own enumerable property names and symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names and symbols.\n */\nfunction getAllKeys(object) {\n  return baseGetAllKeys(object, keys, getSymbols);\n}\n\n/**\n * Gets the data for `map`.\n *\n * @private\n * @param {Object} map The map to query.\n * @param {string} key The reference key.\n * @returns {*} Returns the map data.\n */\nfunction getMapData(map, key) {\n  var data = map.__data__;\n  return isKeyable(key)\n    ? data[typeof key == 'string' ? 'string' : 'hash']\n    : data.map;\n}\n\n/**\n * Gets the native function at `key` of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the method to get.\n * @returns {*} Returns the function if it's native, else `undefined`.\n */\nfunction getNative(object, key) {\n  var value = getValue(object, key);\n  return baseIsNative(value) ? value : undefined;\n}\n\n/**\n * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the raw `toStringTag`.\n */\nfunction getRawTag(value) {\n  var isOwn = hasOwnProperty.call(value, symToStringTag),\n      tag = value[symToStringTag];\n\n  try {\n    value[symToStringTag] = undefined;\n    var unmasked = true;\n  } catch (e) {}\n\n  var result = nativeObjectToString.call(value);\n  if (unmasked) {\n    if (isOwn) {\n      value[symToStringTag] = tag;\n    } else {\n      delete value[symToStringTag];\n    }\n  }\n  return result;\n}\n\n/**\n * Creates an array of the own enumerable symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of symbols.\n */\nvar getSymbols = !nativeGetSymbols ? stubArray : function(object) {\n  if (object == null) {\n    return [];\n  }\n  object = Object(object);\n  return arrayFilter(nativeGetSymbols(object), function(symbol) {\n    return propertyIsEnumerable.call(object, symbol);\n  });\n};\n\n/**\n * Gets the `toStringTag` of `value`.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\nvar getTag = baseGetTag;\n\n// Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6.\nif ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) ||\n    (Map && getTag(new Map) != mapTag) ||\n    (Promise && getTag(Promise.resolve()) != promiseTag) ||\n    (Set && getTag(new Set) != setTag) ||\n    (WeakMap && getTag(new WeakMap) != weakMapTag)) {\n  getTag = function(value) {\n    var result = baseGetTag(value),\n        Ctor = result == objectTag ? value.constructor : undefined,\n        ctorString = Ctor ? toSource(Ctor) : '';\n\n    if (ctorString) {\n      switch (ctorString) {\n        case dataViewCtorString: return dataViewTag;\n        case mapCtorString: return mapTag;\n        case promiseCtorString: return promiseTag;\n        case setCtorString: return setTag;\n        case weakMapCtorString: return weakMapTag;\n      }\n    }\n    return result;\n  };\n}\n\n/**\n * Checks if `value` is a valid array-like index.\n *\n * @private\n * @param {*} value The value to check.\n * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.\n */\nfunction isIndex(value, length) {\n  length = length == null ? MAX_SAFE_INTEGER : length;\n  return !!length &&\n    (typeof value == 'number' || reIsUint.test(value)) &&\n    (value > -1 && value % 1 == 0 && value < length);\n}\n\n/**\n * Checks if `value` is suitable for use as unique object key.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is suitable, else `false`.\n */\nfunction isKeyable(value) {\n  var type = typeof value;\n  return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')\n    ? (value !== '__proto__')\n    : (value === null);\n}\n\n/**\n * Checks if `func` has its source masked.\n *\n * @private\n * @param {Function} func The function to check.\n * @returns {boolean} Returns `true` if `func` is masked, else `false`.\n */\nfunction isMasked(func) {\n  return !!maskSrcKey && (maskSrcKey in func);\n}\n\n/**\n * Checks if `value` is likely a prototype object.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.\n */\nfunction isPrototype(value) {\n  var Ctor = value && value.constructor,\n      proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;\n\n  return value === proto;\n}\n\n/**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n  return nativeObjectToString.call(value);\n}\n\n/**\n * Converts `func` to its source code.\n *\n * @private\n * @param {Function} func The function to convert.\n * @returns {string} Returns the source code.\n */\nfunction toSource(func) {\n  if (func != null) {\n    try {\n      return funcToString.call(func);\n    } catch (e) {}\n    try {\n      return (func + '');\n    } catch (e) {}\n  }\n  return '';\n}\n\n/**\n * Performs a\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\nfunction eq(value, other) {\n  return value === other || (value !== value && other !== other);\n}\n\n/**\n * Checks if `value` is likely an `arguments` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an `arguments` object,\n *  else `false`.\n * @example\n *\n * _.isArguments(function() { return arguments; }());\n * // => true\n *\n * _.isArguments([1, 2, 3]);\n * // => false\n */\nvar isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) {\n  return isObjectLike(value) && hasOwnProperty.call(value, 'callee') &&\n    !propertyIsEnumerable.call(value, 'callee');\n};\n\n/**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\nvar isArray = Array.isArray;\n\n/**\n * Checks if `value` is array-like. A value is considered array-like if it's\n * not a function and has a `value.length` that's an integer greater than or\n * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is array-like, else `false`.\n * @example\n *\n * _.isArrayLike([1, 2, 3]);\n * // => true\n *\n * _.isArrayLike(document.body.children);\n * // => true\n *\n * _.isArrayLike('abc');\n * // => true\n *\n * _.isArrayLike(_.noop);\n * // => false\n */\nfunction isArrayLike(value) {\n  return value != null && isLength(value.length) && !isFunction(value);\n}\n\n/**\n * Checks if `value` is a buffer.\n *\n * @static\n * @memberOf _\n * @since 4.3.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a buffer, else `false`.\n * @example\n *\n * _.isBuffer(new Buffer(2));\n * // => true\n *\n * _.isBuffer(new Uint8Array(2));\n * // => false\n */\nvar isBuffer = nativeIsBuffer || stubFalse;\n\n/**\n * Performs a deep comparison between two values to determine if they are\n * equivalent.\n *\n * **Note:** This method supports comparing arrays, array buffers, booleans,\n * date objects, error objects, maps, numbers, `Object` objects, regexes,\n * sets, strings, symbols, and typed arrays. `Object` objects are compared\n * by their own, not inherited, enumerable properties. Functions and DOM\n * nodes are compared by strict equality, i.e. `===`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.isEqual(object, other);\n * // => true\n *\n * object === other;\n * // => false\n */\nfunction isEqual(value, other) {\n  return baseIsEqual(value, other);\n}\n\n/**\n * Checks if `value` is classified as a `Function` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a function, else `false`.\n * @example\n *\n * _.isFunction(_);\n * // => true\n *\n * _.isFunction(/abc/);\n * // => false\n */\nfunction isFunction(value) {\n  if (!isObject(value)) {\n    return false;\n  }\n  // The use of `Object#toString` avoids issues with the `typeof` operator\n  // in Safari 9 which returns 'object' for typed arrays and other constructors.\n  var tag = baseGetTag(value);\n  return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;\n}\n\n/**\n * Checks if `value` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\nfunction isLength(value) {\n  return typeof value == 'number' &&\n    value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n}\n\n/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n  var type = typeof value;\n  return value != null && (type == 'object' || type == 'function');\n}\n\n/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n  return value != null && typeof value == 'object';\n}\n\n/**\n * Checks if `value` is classified as a typed array.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.\n * @example\n *\n * _.isTypedArray(new Uint8Array);\n * // => true\n *\n * _.isTypedArray([]);\n * // => false\n */\nvar isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray;\n\n/**\n * Creates an array of the own enumerable property names of `object`.\n *\n * **Note:** Non-object values are coerced to objects. See the\n * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * for more details.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Object\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n * @example\n *\n * function Foo() {\n *   this.a = 1;\n *   this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.keys(new Foo);\n * // => ['a', 'b'] (iteration order is not guaranteed)\n *\n * _.keys('hi');\n * // => ['0', '1']\n */\nfunction keys(object) {\n  return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);\n}\n\n/**\n * This method returns a new empty array.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {Array} Returns the new empty array.\n * @example\n *\n * var arrays = _.times(2, _.stubArray);\n *\n * console.log(arrays);\n * // => [[], []]\n *\n * console.log(arrays[0] === arrays[1]);\n * // => false\n */\nfunction stubArray() {\n  return [];\n}\n\n/**\n * This method returns `false`.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {boolean} Returns `false`.\n * @example\n *\n * _.times(2, _.stubFalse);\n * // => [false, false]\n */\nfunction stubFalse() {\n  return false;\n}\n\nmodule.exports = isEqual;\n","var grammar = module.exports = {\n  v: [{\n    name: 'version',\n    reg: /^(\\d*)$/\n  }],\n  o: [{\n    // o=- 20518 0 IN IP4 203.0.113.1\n    // NB: sessionId will be a String in most cases because it is huge\n    name: 'origin',\n    reg: /^(\\S*) (\\d*) (\\d*) (\\S*) IP(\\d) (\\S*)/,\n    names: ['username', 'sessionId', 'sessionVersion', 'netType', 'ipVer', 'address'],\n    format: '%s %s %d %s IP%d %s'\n  }],\n  // default parsing of these only (though some of these feel outdated)\n  s: [{ name: 'name' }],\n  i: [{ name: 'description' }],\n  u: [{ name: 'uri' }],\n  e: [{ name: 'email' }],\n  p: [{ name: 'phone' }],\n  z: [{ name: 'timezones' }], // TODO: this one can actually be parsed properly...\n  r: [{ name: 'repeats' }],   // TODO: this one can also be parsed properly\n  // k: [{}], // outdated thing ignored\n  t: [{\n    // t=0 0\n    name: 'timing',\n    reg: /^(\\d*) (\\d*)/,\n    names: ['start', 'stop'],\n    format: '%d %d'\n  }],\n  c: [{\n    // c=IN IP4 10.47.197.26\n    name: 'connection',\n    reg: /^IN IP(\\d) (\\S*)/,\n    names: ['version', 'ip'],\n    format: 'IN IP%d %s'\n  }],\n  b: [{\n    // b=AS:4000\n    push: 'bandwidth',\n    reg: /^(TIAS|AS|CT|RR|RS):(\\d*)/,\n    names: ['type', 'limit'],\n    format: '%s:%s'\n  }],\n  m: [{\n    // m=video 51744 RTP/AVP 126 97 98 34 31\n    // NB: special - pushes to session\n    // TODO: rtp/fmtp should be filtered by the payloads found here?\n    reg: /^(\\w*) (\\d*) ([\\w/]*)(?: (.*))?/,\n    names: ['type', 'port', 'protocol', 'payloads'],\n    format: '%s %d %s %s'\n  }],\n  a: [\n    {\n      // a=rtpmap:110 opus/48000/2\n      push: 'rtp',\n      reg: /^rtpmap:(\\d*) ([\\w\\-.]*)(?:\\s*\\/(\\d*)(?:\\s*\\/(\\S*))?)?/,\n      names: ['payload', 'codec', 'rate', 'encoding'],\n      format: function (o) {\n        return (o.encoding)\n          ? 'rtpmap:%d %s/%s/%s'\n          : o.rate\n            ? 'rtpmap:%d %s/%s'\n            : 'rtpmap:%d %s';\n      }\n    },\n    {\n      // a=fmtp:108 profile-level-id=24;object=23;bitrate=64000\n      // a=fmtp:111 minptime=10; useinbandfec=1\n      push: 'fmtp',\n      reg: /^fmtp:(\\d*) ([\\S| ]*)/,\n      names: ['payload', 'config'],\n      format: 'fmtp:%d %s'\n    },\n    {\n      // a=control:streamid=0\n      name: 'control',\n      reg: /^control:(.*)/,\n      format: 'control:%s'\n    },\n    {\n      // a=rtcp:65179 IN IP4 193.84.77.194\n      name: 'rtcp',\n      reg: /^rtcp:(\\d*)(?: (\\S*) IP(\\d) (\\S*))?/,\n      names: ['port', 'netType', 'ipVer', 'address'],\n      format: function (o) {\n        return (o.address != null)\n          ? 'rtcp:%d %s IP%d %s'\n          : 'rtcp:%d';\n      }\n    },\n    {\n      // a=rtcp-fb:98 trr-int 100\n      push: 'rtcpFbTrrInt',\n      reg: /^rtcp-fb:(\\*|\\d*) trr-int (\\d*)/,\n      names: ['payload', 'value'],\n      format: 'rtcp-fb:%s trr-int %d'\n    },\n    {\n      // a=rtcp-fb:98 nack rpsi\n      push: 'rtcpFb',\n      reg: /^rtcp-fb:(\\*|\\d*) ([\\w-_]*)(?: ([\\w-_]*))?/,\n      names: ['payload', 'type', 'subtype'],\n      format: function (o) {\n        return (o.subtype != null)\n          ? 'rtcp-fb:%s %s %s'\n          : 'rtcp-fb:%s %s';\n      }\n    },\n    {\n      // a=extmap:2 urn:ietf:params:rtp-hdrext:toffset\n      // a=extmap:1/recvonly URI-gps-string\n      // a=extmap:3 urn:ietf:params:rtp-hdrext:encrypt urn:ietf:params:rtp-hdrext:smpte-tc 25@600/24\n      push: 'ext',\n      reg: /^extmap:(\\d+)(?:\\/(\\w+))?(?: (urn:ietf:params:rtp-hdrext:encrypt))? (\\S*)(?: (\\S*))?/,\n      names: ['value', 'direction', 'encrypt-uri', 'uri', 'config'],\n      format: function (o) {\n        return (\n          'extmap:%d' +\n          (o.direction ? '/%s' : '%v') +\n          (o['encrypt-uri'] ? ' %s' : '%v') +\n          ' %s' +\n          (o.config ? ' %s' : '')\n        );\n      }\n    },\n    {\n      // a=extmap-allow-mixed\n      name: 'extmapAllowMixed',\n      reg: /^(extmap-allow-mixed)/\n    },\n    {\n      // a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:PS1uQCVeeCFCanVmcjkpPywjNWhcYD0mXXtxaVBR|2^20|1:32\n      push: 'crypto',\n      reg: /^crypto:(\\d*) ([\\w_]*) (\\S*)(?: (\\S*))?/,\n      names: ['id', 'suite', 'config', 'sessionConfig'],\n      format: function (o) {\n        return (o.sessionConfig != null)\n          ? 'crypto:%d %s %s %s'\n          : 'crypto:%d %s %s';\n      }\n    },\n    {\n      // a=setup:actpass\n      name: 'setup',\n      reg: /^setup:(\\w*)/,\n      format: 'setup:%s'\n    },\n    {\n      // a=connection:new\n      name: 'connectionType',\n      reg: /^connection:(new|existing)/,\n      format: 'connection:%s'\n    },\n    {\n      // a=mid:1\n      name: 'mid',\n      reg: /^mid:([^\\s]*)/,\n      format: 'mid:%s'\n    },\n    {\n      // a=msid:0c8b064d-d807-43b4-b434-f92a889d8587 98178685-d409-46e0-8e16-7ef0db0db64a\n      name: 'msid',\n      reg: /^msid:(.*)/,\n      format: 'msid:%s'\n    },\n    {\n      // a=ptime:20\n      name: 'ptime',\n      reg: /^ptime:(\\d*(?:\\.\\d*)*)/,\n      format: 'ptime:%d'\n    },\n    {\n      // a=maxptime:60\n      name: 'maxptime',\n      reg: /^maxptime:(\\d*(?:\\.\\d*)*)/,\n      format: 'maxptime:%d'\n    },\n    {\n      // a=sendrecv\n      name: 'direction',\n      reg: /^(sendrecv|recvonly|sendonly|inactive)/\n    },\n    {\n      // a=ice-lite\n      name: 'icelite',\n      reg: /^(ice-lite)/\n    },\n    {\n      // a=ice-ufrag:F7gI\n      name: 'iceUfrag',\n      reg: /^ice-ufrag:(\\S*)/,\n      format: 'ice-ufrag:%s'\n    },\n    {\n      // a=ice-pwd:x9cml/YzichV2+XlhiMu8g\n      name: 'icePwd',\n      reg: /^ice-pwd:(\\S*)/,\n      format: 'ice-pwd:%s'\n    },\n    {\n      // a=fingerprint:SHA-1 00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33\n      name: 'fingerprint',\n      reg: /^fingerprint:(\\S*) (\\S*)/,\n      names: ['type', 'hash'],\n      format: 'fingerprint:%s %s'\n    },\n    {\n      // a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host\n      // a=candidate:1162875081 1 udp 2113937151 192.168.34.75 60017 typ host generation 0 network-id 3 network-cost 10\n      // a=candidate:3289912957 2 udp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 generation 0 network-id 3 network-cost 10\n      // a=candidate:229815620 1 tcp 1518280447 192.168.150.19 60017 typ host tcptype active generation 0 network-id 3 network-cost 10\n      // a=candidate:3289912957 2 tcp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 tcptype passive generation 0 network-id 3 network-cost 10\n      push:'candidates',\n      reg: /^candidate:(\\S*) (\\d*) (\\S*) (\\d*) (\\S*) (\\d*) typ (\\S*)(?: raddr (\\S*) rport (\\d*))?(?: tcptype (\\S*))?(?: generation (\\d*))?(?: network-id (\\d*))?(?: network-cost (\\d*))?/,\n      names: ['foundation', 'component', 'transport', 'priority', 'ip', 'port', 'type', 'raddr', 'rport', 'tcptype', 'generation', 'network-id', 'network-cost'],\n      format: function (o) {\n        var str = 'candidate:%s %d %s %d %s %d typ %s';\n\n        str += (o.raddr != null) ? ' raddr %s rport %d' : '%v%v';\n\n        // NB: candidate has three optional chunks, so %void middles one if it's missing\n        str += (o.tcptype != null) ? ' tcptype %s' : '%v';\n\n        if (o.generation != null) {\n          str += ' generation %d';\n        }\n\n        str += (o['network-id'] != null) ? ' network-id %d' : '%v';\n        str += (o['network-cost'] != null) ? ' network-cost %d' : '%v';\n        return str;\n      }\n    },\n    {\n      // a=end-of-candidates (keep after the candidates line for readability)\n      name: 'endOfCandidates',\n      reg: /^(end-of-candidates)/\n    },\n    {\n      // a=remote-candidates:1 203.0.113.1 54400 2 203.0.113.1 54401 ...\n      name: 'remoteCandidates',\n      reg: /^remote-candidates:(.*)/,\n      format: 'remote-candidates:%s'\n    },\n    {\n      // a=ice-options:google-ice\n      name: 'iceOptions',\n      reg: /^ice-options:(\\S*)/,\n      format: 'ice-options:%s'\n    },\n    {\n      // a=ssrc:2566107569 cname:t9YU8M1UxTF8Y1A1\n      push: 'ssrcs',\n      reg: /^ssrc:(\\d*) ([\\w_-]*)(?::(.*))?/,\n      names: ['id', 'attribute', 'value'],\n      format: function (o) {\n        var str = 'ssrc:%d';\n        if (o.attribute != null) {\n          str += ' %s';\n          if (o.value != null) {\n            str += ':%s';\n          }\n        }\n        return str;\n      }\n    },\n    {\n      // a=ssrc-group:FEC 1 2\n      // a=ssrc-group:FEC-FR 3004364195 1080772241\n      push: 'ssrcGroups',\n      // token-char = %x21 / %x23-27 / %x2A-2B / %x2D-2E / %x30-39 / %x41-5A / %x5E-7E\n      reg: /^ssrc-group:([\\x21\\x23\\x24\\x25\\x26\\x27\\x2A\\x2B\\x2D\\x2E\\w]*) (.*)/,\n      names: ['semantics', 'ssrcs'],\n      format: 'ssrc-group:%s %s'\n    },\n    {\n      // a=msid-semantic: WMS Jvlam5X3SX1OP6pn20zWogvaKJz5Hjf9OnlV\n      name: 'msidSemantic',\n      reg: /^msid-semantic:\\s?(\\w*) (\\S*)/,\n      names: ['semantic', 'token'],\n      format: 'msid-semantic: %s %s' // space after ':' is not accidental\n    },\n    {\n      // a=group:BUNDLE audio video\n      push: 'groups',\n      reg: /^group:(\\w*) (.*)/,\n      names: ['type', 'mids'],\n      format: 'group:%s %s'\n    },\n    {\n      // a=rtcp-mux\n      name: 'rtcpMux',\n      reg: /^(rtcp-mux)/\n    },\n    {\n      // a=rtcp-rsize\n      name: 'rtcpRsize',\n      reg: /^(rtcp-rsize)/\n    },\n    {\n      // a=sctpmap:5000 webrtc-datachannel 1024\n      name: 'sctpmap',\n      reg: /^sctpmap:([\\w_/]*) (\\S*)(?: (\\S*))?/,\n      names: ['sctpmapNumber', 'app', 'maxMessageSize'],\n      format: function (o) {\n        return (o.maxMessageSize != null)\n          ? 'sctpmap:%s %s %s'\n          : 'sctpmap:%s %s';\n      }\n    },\n    {\n      // a=x-google-flag:conference\n      name: 'xGoogleFlag',\n      reg: /^x-google-flag:([^\\s]*)/,\n      format: 'x-google-flag:%s'\n    },\n    {\n      // a=rid:1 send max-width=1280;max-height=720;max-fps=30;depend=0\n      push: 'rids',\n      reg: /^rid:([\\d\\w]+) (\\w+)(?: ([\\S| ]*))?/,\n      names: ['id', 'direction', 'params'],\n      format: function (o) {\n        return (o.params) ? 'rid:%s %s %s' : 'rid:%s %s';\n      }\n    },\n    {\n      // a=imageattr:97 send [x=800,y=640,sar=1.1,q=0.6] [x=480,y=320] recv [x=330,y=250]\n      // a=imageattr:* send [x=800,y=640] recv *\n      // a=imageattr:100 recv [x=320,y=240]\n      push: 'imageattrs',\n      reg: new RegExp(\n        // a=imageattr:97\n        '^imageattr:(\\\\d+|\\\\*)' +\n        // send [x=800,y=640,sar=1.1,q=0.6] [x=480,y=320]\n        '[\\\\s\\\\t]+(send|recv)[\\\\s\\\\t]+(\\\\*|\\\\[\\\\S+\\\\](?:[\\\\s\\\\t]+\\\\[\\\\S+\\\\])*)' +\n        // recv [x=330,y=250]\n        '(?:[\\\\s\\\\t]+(recv|send)[\\\\s\\\\t]+(\\\\*|\\\\[\\\\S+\\\\](?:[\\\\s\\\\t]+\\\\[\\\\S+\\\\])*))?'\n      ),\n      names: ['pt', 'dir1', 'attrs1', 'dir2', 'attrs2'],\n      format: function (o) {\n        return 'imageattr:%s %s %s' + (o.dir2 ? ' %s %s' : '');\n      }\n    },\n    {\n      // a=simulcast:send 1,2,3;~4,~5 recv 6;~7,~8\n      // a=simulcast:recv 1;4,5 send 6;7\n      name: 'simulcast',\n      reg: new RegExp(\n        // a=simulcast:\n        '^simulcast:' +\n        // send 1,2,3;~4,~5\n        '(send|recv) ([a-zA-Z0-9\\\\-_~;,]+)' +\n        // space + recv 6;~7,~8\n        '(?:\\\\s?(send|recv) ([a-zA-Z0-9\\\\-_~;,]+))?' +\n        // end\n        '$'\n      ),\n      names: ['dir1', 'list1', 'dir2', 'list2'],\n      format: function (o) {\n        return 'simulcast:%s %s' + (o.dir2 ? ' %s %s' : '');\n      }\n    },\n    {\n      // old simulcast draft 03 (implemented by Firefox)\n      //   https://tools.ietf.org/html/draft-ietf-mmusic-sdp-simulcast-03\n      // a=simulcast: recv pt=97;98 send pt=97\n      // a=simulcast: send rid=5;6;7 paused=6,7\n      name: 'simulcast_03',\n      reg: /^simulcast:[\\s\\t]+([\\S+\\s\\t]+)$/,\n      names: ['value'],\n      format: 'simulcast: %s'\n    },\n    {\n      // a=framerate:25\n      // a=framerate:29.97\n      name: 'framerate',\n      reg: /^framerate:(\\d+(?:$|\\.\\d+))/,\n      format: 'framerate:%s'\n    },\n    {\n      // RFC4570\n      // a=source-filter: incl IN IP4 239.5.2.31 10.1.15.5\n      name: 'sourceFilter',\n      reg: /^source-filter: *(excl|incl) (\\S*) (IP4|IP6|\\*) (\\S*) (.*)/,\n      names: ['filterMode', 'netType', 'addressTypes', 'destAddress', 'srcList'],\n      format: 'source-filter: %s %s %s %s %s'\n    },\n    {\n      // a=bundle-only\n      name: 'bundleOnly',\n      reg: /^(bundle-only)/\n    },\n    {\n      // a=label:1\n      name: 'label',\n      reg: /^label:(.+)/,\n      format: 'label:%s'\n    },\n    {\n      // RFC version 26 for SCTP over DTLS\n      // https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-26#section-5\n      name: 'sctpPort',\n      reg: /^sctp-port:(\\d+)$/,\n      format: 'sctp-port:%s'\n    },\n    {\n      // RFC version 26 for SCTP over DTLS\n      // https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-26#section-6\n      name: 'maxMessageSize',\n      reg: /^max-message-size:(\\d+)$/,\n      format: 'max-message-size:%s'\n    },\n    {\n      // RFC7273\n      // a=ts-refclk:ptp=IEEE1588-2008:39-A7-94-FF-FE-07-CB-D0:37\n      push:'tsRefClocks',\n      reg: /^ts-refclk:([^\\s=]*)(?:=(\\S*))?/,\n      names: ['clksrc', 'clksrcExt'],\n      format: function (o) {\n        return 'ts-refclk:%s' + (o.clksrcExt != null ? '=%s' : '');\n      }\n    },\n    {\n      // RFC7273\n      // a=mediaclk:direct=963214424\n      name:'mediaClk',\n      reg: /^mediaclk:(?:id=(\\S*))? *([^\\s=]*)(?:=(\\S*))?(?: *rate=(\\d+)\\/(\\d+))?/,\n      names: ['id', 'mediaClockName', 'mediaClockValue', 'rateNumerator', 'rateDenominator'],\n      format: function (o) {\n        var str = 'mediaclk:';\n        str += (o.id != null ? 'id=%s %s' : '%v%s');\n        str += (o.mediaClockValue != null ? '=%s' : '');\n        str += (o.rateNumerator != null ? ' rate=%s' : '');\n        str += (o.rateDenominator != null ? '/%s' : '');\n        return str;\n      }\n    },\n    {\n      // a=keywds:keywords\n      name: 'keywords',\n      reg: /^keywds:(.+)$/,\n      format: 'keywds:%s'\n    },\n    {\n      // a=content:main\n      name: 'content',\n      reg: /^content:(.+)/,\n      format: 'content:%s'\n    },\n    // BFCP https://tools.ietf.org/html/rfc4583\n    {\n      // a=floorctrl:c-s\n      name: 'bfcpFloorCtrl',\n      reg: /^floorctrl:(c-only|s-only|c-s)/,\n      format: 'floorctrl:%s'\n    },\n    {\n      // a=confid:1\n      name: 'bfcpConfId',\n      reg: /^confid:(\\d+)/,\n      format: 'confid:%s'\n    },\n    {\n      // a=userid:1\n      name: 'bfcpUserId',\n      reg: /^userid:(\\d+)/,\n      format: 'userid:%s'\n    },\n    {\n      // a=floorid:1\n      name: 'bfcpFloorId',\n      reg: /^floorid:(.+) (?:m-stream|mstrm):(.+)/,\n      names: ['id', 'mStream'],\n      format: 'floorid:%s mstrm:%s'\n    },\n    {\n      // any a= that we don't understand is kept verbatim on media.invalid\n      push: 'invalid',\n      names: ['value']\n    }\n  ]\n};\n\n// set sensible defaults to avoid polluting the grammar with boring details\nObject.keys(grammar).forEach(function (key) {\n  var objs = grammar[key];\n  objs.forEach(function (obj) {\n    if (!obj.reg) {\n      obj.reg = /(.*)/;\n    }\n    if (!obj.format) {\n      obj.format = '%s';\n    }\n  });\n});\n","var parser = require('./parser');\nvar writer = require('./writer');\n\nexports.write = writer;\nexports.parse = parser.parse;\nexports.parseParams = parser.parseParams;\nexports.parseFmtpConfig = parser.parseFmtpConfig; // Alias of parseParams().\nexports.parsePayloads = parser.parsePayloads;\nexports.parseRemoteCandidates = parser.parseRemoteCandidates;\nexports.parseImageAttributes = parser.parseImageAttributes;\nexports.parseSimulcastStreamList = parser.parseSimulcastStreamList;\n","var toIntIfInt = function (v) {\n  return String(Number(v)) === v ? Number(v) : v;\n};\n\nvar attachProperties = function (match, location, names, rawName) {\n  if (rawName && !names) {\n    location[rawName] = toIntIfInt(match[1]);\n  }\n  else {\n    for (var i = 0; i < names.length; i += 1) {\n      if (match[i+1] != null) {\n        location[names[i]] = toIntIfInt(match[i+1]);\n      }\n    }\n  }\n};\n\nvar parseReg = function (obj, location, content) {\n  var needsBlank = obj.name && obj.names;\n  if (obj.push && !location[obj.push]) {\n    location[obj.push] = [];\n  }\n  else if (needsBlank && !location[obj.name]) {\n    location[obj.name] = {};\n  }\n  var keyLocation = obj.push ?\n    {} :  // blank object that will be pushed\n    needsBlank ? location[obj.name] : location; // otherwise, named location or root\n\n  attachProperties(content.match(obj.reg), keyLocation, obj.names, obj.name);\n\n  if (obj.push) {\n    location[obj.push].push(keyLocation);\n  }\n};\n\nvar grammar = require('./grammar');\nvar validLine = RegExp.prototype.test.bind(/^([a-z])=(.*)/);\n\nexports.parse = function (sdp) {\n  var session = {}\n    , media = []\n    , location = session; // points at where properties go under (one of the above)\n\n  // parse lines we understand\n  sdp.split(/(\\r\\n|\\r|\\n)/).filter(validLine).forEach(function (l) {\n    var type = l[0];\n    var content = l.slice(2);\n    if (type === 'm') {\n      media.push({rtp: [], fmtp: []});\n      location = media[media.length-1]; // point at latest media line\n    }\n\n    for (var j = 0; j < (grammar[type] || []).length; j += 1) {\n      var obj = grammar[type][j];\n      if (obj.reg.test(content)) {\n        return parseReg(obj, location, content);\n      }\n    }\n  });\n\n  session.media = media; // link it up\n  return session;\n};\n\nvar paramReducer = function (acc, expr) {\n  var s = expr.split(/=(.+)/, 2);\n  if (s.length === 2) {\n    acc[s[0]] = toIntIfInt(s[1]);\n  } else if (s.length === 1 && expr.length > 1) {\n    acc[s[0]] = undefined;\n  }\n  return acc;\n};\n\nexports.parseParams = function (str) {\n  return str.split(/;\\s?/).reduce(paramReducer, {});\n};\n\n// For backward compatibility - alias will be removed in 3.0.0\nexports.parseFmtpConfig = exports.parseParams;\n\nexports.parsePayloads = function (str) {\n  return str.toString().split(' ').map(Number);\n};\n\nexports.parseRemoteCandidates = function (str) {\n  var candidates = [];\n  var parts = str.split(' ').map(toIntIfInt);\n  for (var i = 0; i < parts.length; i += 3) {\n    candidates.push({\n      component: parts[i],\n      ip: parts[i + 1],\n      port: parts[i + 2]\n    });\n  }\n  return candidates;\n};\n\nexports.parseImageAttributes = function (str) {\n  return str.split(' ').map(function (item) {\n    return item.substring(1, item.length-1).split(',').reduce(paramReducer, {});\n  });\n};\n\nexports.parseSimulcastStreamList = function (str) {\n  return str.split(';').map(function (stream) {\n    return stream.split(',').map(function (format) {\n      var scid, paused = false;\n\n      if (format[0] !== '~') {\n        scid = toIntIfInt(format);\n      } else {\n        scid = toIntIfInt(format.substring(1, format.length));\n        paused = true;\n      }\n\n      return {\n        scid: scid,\n        paused: paused\n      };\n    });\n  });\n};\n","var grammar = require('./grammar');\n\n// customized util.format - discards excess arguments and can void middle ones\nvar formatRegExp = /%[sdv%]/g;\nvar format = function (formatStr) {\n  var i = 1;\n  var args = arguments;\n  var len = args.length;\n  return formatStr.replace(formatRegExp, function (x) {\n    if (i >= len) {\n      return x; // missing argument\n    }\n    var arg = args[i];\n    i += 1;\n    switch (x) {\n    case '%%':\n      return '%';\n    case '%s':\n      return String(arg);\n    case '%d':\n      return Number(arg);\n    case '%v':\n      return '';\n    }\n  });\n  // NB: we discard excess arguments - they are typically undefined from makeLine\n};\n\nvar makeLine = function (type, obj, location) {\n  var str = obj.format instanceof Function ?\n    (obj.format(obj.push ? location : location[obj.name])) :\n    obj.format;\n\n  var args = [type + '=' + str];\n  if (obj.names) {\n    for (var i = 0; i < obj.names.length; i += 1) {\n      var n = obj.names[i];\n      if (obj.name) {\n        args.push(location[obj.name][n]);\n      }\n      else { // for mLine and push attributes\n        args.push(location[obj.names[i]]);\n      }\n    }\n  }\n  else {\n    args.push(location[obj.name]);\n  }\n  return format.apply(null, args);\n};\n\n// RFC specified order\n// TODO: extend this with all the rest\nvar defaultOuterOrder = [\n  'v', 'o', 's', 'i',\n  'u', 'e', 'p', 'c',\n  'b', 't', 'r', 'z', 'a'\n];\nvar defaultInnerOrder = ['i', 'c', 'b', 'a'];\n\n\nmodule.exports = function (session, opts) {\n  opts = opts || {};\n  // ensure certain properties exist\n  if (session.version == null) {\n    session.version = 0; // 'v=0' must be there (only defined version atm)\n  }\n  if (session.name == null) {\n    session.name = ' '; // 's= ' must be there if no meaningful name set\n  }\n  session.media.forEach(function (mLine) {\n    if (mLine.payloads == null) {\n      mLine.payloads = '';\n    }\n  });\n\n  var outerOrder = opts.outerOrder || defaultOuterOrder;\n  var innerOrder = opts.innerOrder || defaultInnerOrder;\n  var sdp = [];\n\n  // loop through outerOrder for matching properties on session\n  outerOrder.forEach(function (type) {\n    grammar[type].forEach(function (obj) {\n      if (obj.name in session && session[obj.name] != null) {\n        sdp.push(makeLine(type, obj, session));\n      }\n      else if (obj.push in session && session[obj.push] != null) {\n        session[obj.push].forEach(function (el) {\n          sdp.push(makeLine(type, obj, el));\n        });\n      }\n    });\n  });\n\n  // then for each media line, follow the innerOrder\n  session.media.forEach(function (mLine) {\n    sdp.push(makeLine('m', grammar.m[0], mLine));\n\n    innerOrder.forEach(function (type) {\n      grammar[type].forEach(function (obj) {\n        if (obj.name in mLine && mLine[obj.name] != null) {\n          sdp.push(makeLine(type, obj, mLine));\n        }\n        else if (obj.push in mLine && mLine[obj.push] != null) {\n          mLine[obj.push].forEach(function (el) {\n            sdp.push(makeLine(type, obj, el));\n          });\n        }\n      });\n    });\n  });\n\n  return sdp.join('\\r\\n') + '\\r\\n';\n};\n","/* eslint-env node */\n'use strict';\n\n// SDP helpers.\nconst SDPUtils = {};\n\n// Generate an alphanumeric identifier for cname or mids.\n// TODO: use UUIDs instead? https://gist.github.com/jed/982883\nSDPUtils.generateIdentifier = function() {\n  return Math.random().toString(36).substr(2, 10);\n};\n\n// The RTCP CNAME used by all peerconnections from the same JS.\nSDPUtils.localCName = SDPUtils.generateIdentifier();\n\n// Splits SDP into lines, dealing with both CRLF and LF.\nSDPUtils.splitLines = function(blob) {\n  return blob.trim().split('\\n').map(line => line.trim());\n};\n// Splits SDP into sessionpart and mediasections. Ensures CRLF.\nSDPUtils.splitSections = function(blob) {\n  const parts = blob.split('\\nm=');\n  return parts.map((part, index) => (index > 0 ?\n    'm=' + part : part).trim() + '\\r\\n');\n};\n\n// Returns the session description.\nSDPUtils.getDescription = function(blob) {\n  const sections = SDPUtils.splitSections(blob);\n  return sections && sections[0];\n};\n\n// Returns the individual media sections.\nSDPUtils.getMediaSections = function(blob) {\n  const sections = SDPUtils.splitSections(blob);\n  sections.shift();\n  return sections;\n};\n\n// Returns lines that start with a certain prefix.\nSDPUtils.matchPrefix = function(blob, prefix) {\n  return SDPUtils.splitLines(blob).filter(line => line.indexOf(prefix) === 0);\n};\n\n// Parses an ICE candidate line. Sample input:\n// candidate:702786350 2 udp 41819902 8.8.8.8 60769 typ relay raddr 8.8.8.8\n// rport 55996\"\n// Input can be prefixed with a=.\nSDPUtils.parseCandidate = function(line) {\n  let parts;\n  // Parse both variants.\n  if (line.indexOf('a=candidate:') === 0) {\n    parts = line.substring(12).split(' ');\n  } else {\n    parts = line.substring(10).split(' ');\n  }\n\n  const candidate = {\n    foundation: parts[0],\n    component: {1: 'rtp', 2: 'rtcp'}[parts[1]] || parts[1],\n    protocol: parts[2].toLowerCase(),\n    priority: parseInt(parts[3], 10),\n    ip: parts[4],\n    address: parts[4], // address is an alias for ip.\n    port: parseInt(parts[5], 10),\n    // skip parts[6] == 'typ'\n    type: parts[7],\n  };\n\n  for (let i = 8; i < parts.length; i += 2) {\n    switch (parts[i]) {\n      case 'raddr':\n        candidate.relatedAddress = parts[i + 1];\n        break;\n      case 'rport':\n        candidate.relatedPort = parseInt(parts[i + 1], 10);\n        break;\n      case 'tcptype':\n        candidate.tcpType = parts[i + 1];\n        break;\n      case 'ufrag':\n        candidate.ufrag = parts[i + 1]; // for backward compatibility.\n        candidate.usernameFragment = parts[i + 1];\n        break;\n      default: // extension handling, in particular ufrag. Don't overwrite.\n        if (candidate[parts[i]] === undefined) {\n          candidate[parts[i]] = parts[i + 1];\n        }\n        break;\n    }\n  }\n  return candidate;\n};\n\n// Translates a candidate object into SDP candidate attribute.\n// This does not include the a= prefix!\nSDPUtils.writeCandidate = function(candidate) {\n  const sdp = [];\n  sdp.push(candidate.foundation);\n\n  const component = candidate.component;\n  if (component === 'rtp') {\n    sdp.push(1);\n  } else if (component === 'rtcp') {\n    sdp.push(2);\n  } else {\n    sdp.push(component);\n  }\n  sdp.push(candidate.protocol.toUpperCase());\n  sdp.push(candidate.priority);\n  sdp.push(candidate.address || candidate.ip);\n  sdp.push(candidate.port);\n\n  const type = candidate.type;\n  sdp.push('typ');\n  sdp.push(type);\n  if (type !== 'host' && candidate.relatedAddress &&\n      candidate.relatedPort) {\n    sdp.push('raddr');\n    sdp.push(candidate.relatedAddress);\n    sdp.push('rport');\n    sdp.push(candidate.relatedPort);\n  }\n  if (candidate.tcpType && candidate.protocol.toLowerCase() === 'tcp') {\n    sdp.push('tcptype');\n    sdp.push(candidate.tcpType);\n  }\n  if (candidate.usernameFragment || candidate.ufrag) {\n    sdp.push('ufrag');\n    sdp.push(candidate.usernameFragment || candidate.ufrag);\n  }\n  return 'candidate:' + sdp.join(' ');\n};\n\n// Parses an ice-options line, returns an array of option tags.\n// Sample input:\n// a=ice-options:foo bar\nSDPUtils.parseIceOptions = function(line) {\n  return line.substr(14).split(' ');\n};\n\n// Parses a rtpmap line, returns RTCRtpCoddecParameters. Sample input:\n// a=rtpmap:111 opus/48000/2\nSDPUtils.parseRtpMap = function(line) {\n  let parts = line.substr(9).split(' ');\n  const parsed = {\n    payloadType: parseInt(parts.shift(), 10), // was: id\n  };\n\n  parts = parts[0].split('/');\n\n  parsed.name = parts[0];\n  parsed.clockRate = parseInt(parts[1], 10); // was: clockrate\n  parsed.channels = parts.length === 3 ? parseInt(parts[2], 10) : 1;\n  // legacy alias, got renamed back to channels in ORTC.\n  parsed.numChannels = parsed.channels;\n  return parsed;\n};\n\n// Generates a rtpmap line from RTCRtpCodecCapability or\n// RTCRtpCodecParameters.\nSDPUtils.writeRtpMap = function(codec) {\n  let pt = codec.payloadType;\n  if (codec.preferredPayloadType !== undefined) {\n    pt = codec.preferredPayloadType;\n  }\n  const channels = codec.channels || codec.numChannels || 1;\n  return 'a=rtpmap:' + pt + ' ' + codec.name + '/' + codec.clockRate +\n      (channels !== 1 ? '/' + channels : '') + '\\r\\n';\n};\n\n// Parses a extmap line (headerextension from RFC 5285). Sample input:\n// a=extmap:2 urn:ietf:params:rtp-hdrext:toffset\n// a=extmap:2/sendonly urn:ietf:params:rtp-hdrext:toffset\nSDPUtils.parseExtmap = function(line) {\n  const parts = line.substr(9).split(' ');\n  return {\n    id: parseInt(parts[0], 10),\n    direction: parts[0].indexOf('/') > 0 ? parts[0].split('/')[1] : 'sendrecv',\n    uri: parts[1],\n  };\n};\n\n// Generates an extmap line from RTCRtpHeaderExtensionParameters or\n// RTCRtpHeaderExtension.\nSDPUtils.writeExtmap = function(headerExtension) {\n  return 'a=extmap:' + (headerExtension.id || headerExtension.preferredId) +\n      (headerExtension.direction && headerExtension.direction !== 'sendrecv'\n        ? '/' + headerExtension.direction\n        : '') +\n      ' ' + headerExtension.uri + '\\r\\n';\n};\n\n// Parses a fmtp line, returns dictionary. Sample input:\n// a=fmtp:96 vbr=on;cng=on\n// Also deals with vbr=on; cng=on\nSDPUtils.parseFmtp = function(line) {\n  const parsed = {};\n  let kv;\n  const parts = line.substr(line.indexOf(' ') + 1).split(';');\n  for (let j = 0; j < parts.length; j++) {\n    kv = parts[j].trim().split('=');\n    parsed[kv[0].trim()] = kv[1];\n  }\n  return parsed;\n};\n\n// Generates a fmtp line from RTCRtpCodecCapability or RTCRtpCodecParameters.\nSDPUtils.writeFmtp = function(codec) {\n  let line = '';\n  let pt = codec.payloadType;\n  if (codec.preferredPayloadType !== undefined) {\n    pt = codec.preferredPayloadType;\n  }\n  if (codec.parameters && Object.keys(codec.parameters).length) {\n    const params = [];\n    Object.keys(codec.parameters).forEach(param => {\n      if (codec.parameters[param] !== undefined) {\n        params.push(param + '=' + codec.parameters[param]);\n      } else {\n        params.push(param);\n      }\n    });\n    line += 'a=fmtp:' + pt + ' ' + params.join(';') + '\\r\\n';\n  }\n  return line;\n};\n\n// Parses a rtcp-fb line, returns RTCPRtcpFeedback object. Sample input:\n// a=rtcp-fb:98 nack rpsi\nSDPUtils.parseRtcpFb = function(line) {\n  const parts = line.substr(line.indexOf(' ') + 1).split(' ');\n  return {\n    type: parts.shift(),\n    parameter: parts.join(' '),\n  };\n};\n\n// Generate a=rtcp-fb lines from RTCRtpCodecCapability or RTCRtpCodecParameters.\nSDPUtils.writeRtcpFb = function(codec) {\n  let lines = '';\n  let pt = codec.payloadType;\n  if (codec.preferredPayloadType !== undefined) {\n    pt = codec.preferredPayloadType;\n  }\n  if (codec.rtcpFeedback && codec.rtcpFeedback.length) {\n    // FIXME: special handling for trr-int?\n    codec.rtcpFeedback.forEach(fb => {\n      lines += 'a=rtcp-fb:' + pt + ' ' + fb.type +\n      (fb.parameter && fb.parameter.length ? ' ' + fb.parameter : '') +\n          '\\r\\n';\n    });\n  }\n  return lines;\n};\n\n// Parses a RFC 5576 ssrc media attribute. Sample input:\n// a=ssrc:3735928559 cname:something\nSDPUtils.parseSsrcMedia = function(line) {\n  const sp = line.indexOf(' ');\n  const parts = {\n    ssrc: parseInt(line.substr(7, sp - 7), 10),\n  };\n  const colon = line.indexOf(':', sp);\n  if (colon > -1) {\n    parts.attribute = line.substr(sp + 1, colon - sp - 1);\n    parts.value = line.substr(colon + 1);\n  } else {\n    parts.attribute = line.substr(sp + 1);\n  }\n  return parts;\n};\n\n// Parse a ssrc-group line (see RFC 5576). Sample input:\n// a=ssrc-group:semantics 12 34\nSDPUtils.parseSsrcGroup = function(line) {\n  const parts = line.substr(13).split(' ');\n  return {\n    semantics: parts.shift(),\n    ssrcs: parts.map(ssrc => parseInt(ssrc, 10)),\n  };\n};\n\n// Extracts the MID (RFC 5888) from a media section.\n// Returns the MID or undefined if no mid line was found.\nSDPUtils.getMid = function(mediaSection) {\n  const mid = SDPUtils.matchPrefix(mediaSection, 'a=mid:')[0];\n  if (mid) {\n    return mid.substr(6);\n  }\n};\n\n// Parses a fingerprint line for DTLS-SRTP.\nSDPUtils.parseFingerprint = function(line) {\n  const parts = line.substr(14).split(' ');\n  return {\n    algorithm: parts[0].toLowerCase(), // algorithm is case-sensitive in Edge.\n    value: parts[1].toUpperCase(), // the definition is upper-case in RFC 4572.\n  };\n};\n\n// Extracts DTLS parameters from SDP media section or sessionpart.\n// FIXME: for consistency with other functions this should only\n//   get the fingerprint line as input. See also getIceParameters.\nSDPUtils.getDtlsParameters = function(mediaSection, sessionpart) {\n  const lines = SDPUtils.matchPrefix(mediaSection + sessionpart,\n    'a=fingerprint:');\n  // Note: a=setup line is ignored since we use the 'auto' role in Edge.\n  return {\n    role: 'auto',\n    fingerprints: lines.map(SDPUtils.parseFingerprint),\n  };\n};\n\n// Serializes DTLS parameters to SDP.\nSDPUtils.writeDtlsParameters = function(params, setupType) {\n  let sdp = 'a=setup:' + setupType + '\\r\\n';\n  params.fingerprints.forEach(fp => {\n    sdp += 'a=fingerprint:' + fp.algorithm + ' ' + fp.value + '\\r\\n';\n  });\n  return sdp;\n};\n\n// Parses a=crypto lines into\n//   https://rawgit.com/aboba/edgertc/master/msortc-rs4.html#dictionary-rtcsrtpsdesparameters-members\nSDPUtils.parseCryptoLine = function(line) {\n  const parts = line.substr(9).split(' ');\n  return {\n    tag: parseInt(parts[0], 10),\n    cryptoSuite: parts[1],\n    keyParams: parts[2],\n    sessionParams: parts.slice(3),\n  };\n};\n\nSDPUtils.writeCryptoLine = function(parameters) {\n  return 'a=crypto:' + parameters.tag + ' ' +\n    parameters.cryptoSuite + ' ' +\n    (typeof parameters.keyParams === 'object'\n      ? SDPUtils.writeCryptoKeyParams(parameters.keyParams)\n      : parameters.keyParams) +\n    (parameters.sessionParams ? ' ' + parameters.sessionParams.join(' ') : '') +\n    '\\r\\n';\n};\n\n// Parses the crypto key parameters into\n//   https://rawgit.com/aboba/edgertc/master/msortc-rs4.html#rtcsrtpkeyparam*\nSDPUtils.parseCryptoKeyParams = function(keyParams) {\n  if (keyParams.indexOf('inline:') !== 0) {\n    return null;\n  }\n  const parts = keyParams.substr(7).split('|');\n  return {\n    keyMethod: 'inline',\n    keySalt: parts[0],\n    lifeTime: parts[1],\n    mkiValue: parts[2] ? parts[2].split(':')[0] : undefined,\n    mkiLength: parts[2] ? parts[2].split(':')[1] : undefined,\n  };\n};\n\nSDPUtils.writeCryptoKeyParams = function(keyParams) {\n  return keyParams.keyMethod + ':'\n    + keyParams.keySalt +\n    (keyParams.lifeTime ? '|' + keyParams.lifeTime : '') +\n    (keyParams.mkiValue && keyParams.mkiLength\n      ? '|' + keyParams.mkiValue + ':' + keyParams.mkiLength\n      : '');\n};\n\n// Extracts all SDES parameters.\nSDPUtils.getCryptoParameters = function(mediaSection, sessionpart) {\n  const lines = SDPUtils.matchPrefix(mediaSection + sessionpart,\n    'a=crypto:');\n  return lines.map(SDPUtils.parseCryptoLine);\n};\n\n// Parses ICE information from SDP media section or sessionpart.\n// FIXME: for consistency with other functions this should only\n//   get the ice-ufrag and ice-pwd lines as input.\nSDPUtils.getIceParameters = function(mediaSection, sessionpart) {\n  const ufrag = SDPUtils.matchPrefix(mediaSection + sessionpart,\n    'a=ice-ufrag:')[0];\n  const pwd = SDPUtils.matchPrefix(mediaSection + sessionpart,\n    'a=ice-pwd:')[0];\n  if (!(ufrag && pwd)) {\n    return null;\n  }\n  return {\n    usernameFragment: ufrag.substr(12),\n    password: pwd.substr(10),\n  };\n};\n\n// Serializes ICE parameters to SDP.\nSDPUtils.writeIceParameters = function(params) {\n  let sdp = 'a=ice-ufrag:' + params.usernameFragment + '\\r\\n' +\n      'a=ice-pwd:' + params.password + '\\r\\n';\n  if (params.iceLite) {\n    sdp += 'a=ice-lite\\r\\n';\n  }\n  return sdp;\n};\n\n// Parses the SDP media section and returns RTCRtpParameters.\nSDPUtils.parseRtpParameters = function(mediaSection) {\n  const description = {\n    codecs: [],\n    headerExtensions: [],\n    fecMechanisms: [],\n    rtcp: [],\n  };\n  const lines = SDPUtils.splitLines(mediaSection);\n  const mline = lines[0].split(' ');\n  for (let i = 3; i < mline.length; i++) { // find all codecs from mline[3..]\n    const pt = mline[i];\n    const rtpmapline = SDPUtils.matchPrefix(\n      mediaSection, 'a=rtpmap:' + pt + ' ')[0];\n    if (rtpmapline) {\n      const codec = SDPUtils.parseRtpMap(rtpmapline);\n      const fmtps = SDPUtils.matchPrefix(\n        mediaSection, 'a=fmtp:' + pt + ' ');\n      // Only the first a=fmtp:<pt> is considered.\n      codec.parameters = fmtps.length ? SDPUtils.parseFmtp(fmtps[0]) : {};\n      codec.rtcpFeedback = SDPUtils.matchPrefix(\n        mediaSection, 'a=rtcp-fb:' + pt + ' ')\n        .map(SDPUtils.parseRtcpFb);\n      description.codecs.push(codec);\n      // parse FEC mechanisms from rtpmap lines.\n      switch (codec.name.toUpperCase()) {\n        case 'RED':\n        case 'ULPFEC':\n          description.fecMechanisms.push(codec.name.toUpperCase());\n          break;\n        default: // only RED and ULPFEC are recognized as FEC mechanisms.\n          break;\n      }\n    }\n  }\n  SDPUtils.matchPrefix(mediaSection, 'a=extmap:').forEach(line => {\n    description.headerExtensions.push(SDPUtils.parseExtmap(line));\n  });\n  // FIXME: parse rtcp.\n  return description;\n};\n\n// Generates parts of the SDP media section describing the capabilities /\n// parameters.\nSDPUtils.writeRtpDescription = function(kind, caps) {\n  let sdp = '';\n\n  // Build the mline.\n  sdp += 'm=' + kind + ' ';\n  sdp += caps.codecs.length > 0 ? '9' : '0'; // reject if no codecs.\n  sdp += ' UDP/TLS/RTP/SAVPF ';\n  sdp += caps.codecs.map(codec => {\n    if (codec.preferredPayloadType !== undefined) {\n      return codec.preferredPayloadType;\n    }\n    return codec.payloadType;\n  }).join(' ') + '\\r\\n';\n\n  sdp += 'c=IN IP4 0.0.0.0\\r\\n';\n  sdp += 'a=rtcp:9 IN IP4 0.0.0.0\\r\\n';\n\n  // Add a=rtpmap lines for each codec. Also fmtp and rtcp-fb.\n  caps.codecs.forEach(codec => {\n    sdp += SDPUtils.writeRtpMap(codec);\n    sdp += SDPUtils.writeFmtp(codec);\n    sdp += SDPUtils.writeRtcpFb(codec);\n  });\n  let maxptime = 0;\n  caps.codecs.forEach(codec => {\n    if (codec.maxptime > maxptime) {\n      maxptime = codec.maxptime;\n    }\n  });\n  if (maxptime > 0) {\n    sdp += 'a=maxptime:' + maxptime + '\\r\\n';\n  }\n\n  if (caps.headerExtensions) {\n    caps.headerExtensions.forEach(extension => {\n      sdp += SDPUtils.writeExtmap(extension);\n    });\n  }\n  // FIXME: write fecMechanisms.\n  return sdp;\n};\n\n// Parses the SDP media section and returns an array of\n// RTCRtpEncodingParameters.\nSDPUtils.parseRtpEncodingParameters = function(mediaSection) {\n  const encodingParameters = [];\n  const description = SDPUtils.parseRtpParameters(mediaSection);\n  const hasRed = description.fecMechanisms.indexOf('RED') !== -1;\n  const hasUlpfec = description.fecMechanisms.indexOf('ULPFEC') !== -1;\n\n  // filter a=ssrc:... cname:, ignore PlanB-msid\n  const ssrcs = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:')\n    .map(line => SDPUtils.parseSsrcMedia(line))\n    .filter(parts => parts.attribute === 'cname');\n  const primarySsrc = ssrcs.length > 0 && ssrcs[0].ssrc;\n  let secondarySsrc;\n\n  const flows = SDPUtils.matchPrefix(mediaSection, 'a=ssrc-group:FID')\n    .map(line => {\n      const parts = line.substr(17).split(' ');\n      return parts.map(part => parseInt(part, 10));\n    });\n  if (flows.length > 0 && flows[0].length > 1 && flows[0][0] === primarySsrc) {\n    secondarySsrc = flows[0][1];\n  }\n\n  description.codecs.forEach(codec => {\n    if (codec.name.toUpperCase() === 'RTX' && codec.parameters.apt) {\n      let encParam = {\n        ssrc: primarySsrc,\n        codecPayloadType: parseInt(codec.parameters.apt, 10),\n      };\n      if (primarySsrc && secondarySsrc) {\n        encParam.rtx = {ssrc: secondarySsrc};\n      }\n      encodingParameters.push(encParam);\n      if (hasRed) {\n        encParam = JSON.parse(JSON.stringify(encParam));\n        encParam.fec = {\n          ssrc: primarySsrc,\n          mechanism: hasUlpfec ? 'red+ulpfec' : 'red',\n        };\n        encodingParameters.push(encParam);\n      }\n    }\n  });\n  if (encodingParameters.length === 0 && primarySsrc) {\n    encodingParameters.push({\n      ssrc: primarySsrc,\n    });\n  }\n\n  // we support both b=AS and b=TIAS but interpret AS as TIAS.\n  let bandwidth = SDPUtils.matchPrefix(mediaSection, 'b=');\n  if (bandwidth.length) {\n    if (bandwidth[0].indexOf('b=TIAS:') === 0) {\n      bandwidth = parseInt(bandwidth[0].substr(7), 10);\n    } else if (bandwidth[0].indexOf('b=AS:') === 0) {\n      // use formula from JSEP to convert b=AS to TIAS value.\n      bandwidth = parseInt(bandwidth[0].substr(5), 10) * 1000 * 0.95\n          - (50 * 40 * 8);\n    } else {\n      bandwidth = undefined;\n    }\n    encodingParameters.forEach(params => {\n      params.maxBitrate = bandwidth;\n    });\n  }\n  return encodingParameters;\n};\n\n// parses http://draft.ortc.org/#rtcrtcpparameters*\nSDPUtils.parseRtcpParameters = function(mediaSection) {\n  const rtcpParameters = {};\n\n  // Gets the first SSRC. Note that with RTX there might be multiple\n  // SSRCs.\n  const remoteSsrc = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:')\n    .map(line => SDPUtils.parseSsrcMedia(line))\n    .filter(obj => obj.attribute === 'cname')[0];\n  if (remoteSsrc) {\n    rtcpParameters.cname = remoteSsrc.value;\n    rtcpParameters.ssrc = remoteSsrc.ssrc;\n  }\n\n  // Edge uses the compound attribute instead of reducedSize\n  // compound is !reducedSize\n  const rsize = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-rsize');\n  rtcpParameters.reducedSize = rsize.length > 0;\n  rtcpParameters.compound = rsize.length === 0;\n\n  // parses the rtcp-mux attrіbute.\n  // Note that Edge does not support unmuxed RTCP.\n  const mux = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-mux');\n  rtcpParameters.mux = mux.length > 0;\n\n  return rtcpParameters;\n};\n\nSDPUtils.writeRtcpParameters = function(rtcpParameters) {\n  let sdp = '';\n  if (rtcpParameters.reducedSize) {\n    sdp += 'a=rtcp-rsize\\r\\n';\n  }\n  if (rtcpParameters.mux) {\n    sdp += 'a=rtcp-mux\\r\\n';\n  }\n  if (rtcpParameters.ssrc !== undefined && rtcpParameters.cname) {\n    sdp += 'a=ssrc:' + rtcpParameters.ssrc +\n      ' cname:' + rtcpParameters.cname + '\\r\\n';\n  }\n  return sdp;\n};\n\n\n// parses either a=msid: or a=ssrc:... msid lines and returns\n// the id of the MediaStream and MediaStreamTrack.\nSDPUtils.parseMsid = function(mediaSection) {\n  let parts;\n  const spec = SDPUtils.matchPrefix(mediaSection, 'a=msid:');\n  if (spec.length === 1) {\n    parts = spec[0].substr(7).split(' ');\n    return {stream: parts[0], track: parts[1]};\n  }\n  const planB = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:')\n    .map(line => SDPUtils.parseSsrcMedia(line))\n    .filter(msidParts => msidParts.attribute === 'msid');\n  if (planB.length > 0) {\n    parts = planB[0].value.split(' ');\n    return {stream: parts[0], track: parts[1]};\n  }\n};\n\n// SCTP\n// parses draft-ietf-mmusic-sctp-sdp-26 first and falls back\n// to draft-ietf-mmusic-sctp-sdp-05\nSDPUtils.parseSctpDescription = function(mediaSection) {\n  const mline = SDPUtils.parseMLine(mediaSection);\n  const maxSizeLine = SDPUtils.matchPrefix(mediaSection, 'a=max-message-size:');\n  let maxMessageSize;\n  if (maxSizeLine.length > 0) {\n    maxMessageSize = parseInt(maxSizeLine[0].substr(19), 10);\n  }\n  if (isNaN(maxMessageSize)) {\n    maxMessageSize = 65536;\n  }\n  const sctpPort = SDPUtils.matchPrefix(mediaSection, 'a=sctp-port:');\n  if (sctpPort.length > 0) {\n    return {\n      port: parseInt(sctpPort[0].substr(12), 10),\n      protocol: mline.fmt,\n      maxMessageSize,\n    };\n  }\n  const sctpMapLines = SDPUtils.matchPrefix(mediaSection, 'a=sctpmap:');\n  if (sctpMapLines.length > 0) {\n    const parts = sctpMapLines[0]\n      .substr(10)\n      .split(' ');\n    return {\n      port: parseInt(parts[0], 10),\n      protocol: parts[1],\n      maxMessageSize,\n    };\n  }\n};\n\n// SCTP\n// outputs the draft-ietf-mmusic-sctp-sdp-26 version that all browsers\n// support by now receiving in this format, unless we originally parsed\n// as the draft-ietf-mmusic-sctp-sdp-05 format (indicated by the m-line\n// protocol of DTLS/SCTP -- without UDP/ or TCP/)\nSDPUtils.writeSctpDescription = function(media, sctp) {\n  let output = [];\n  if (media.protocol !== 'DTLS/SCTP') {\n    output = [\n      'm=' + media.kind + ' 9 ' + media.protocol + ' ' + sctp.protocol + '\\r\\n',\n      'c=IN IP4 0.0.0.0\\r\\n',\n      'a=sctp-port:' + sctp.port + '\\r\\n',\n    ];\n  } else {\n    output = [\n      'm=' + media.kind + ' 9 ' + media.protocol + ' ' + sctp.port + '\\r\\n',\n      'c=IN IP4 0.0.0.0\\r\\n',\n      'a=sctpmap:' + sctp.port + ' ' + sctp.protocol + ' 65535\\r\\n',\n    ];\n  }\n  if (sctp.maxMessageSize !== undefined) {\n    output.push('a=max-message-size:' + sctp.maxMessageSize + '\\r\\n');\n  }\n  return output.join('');\n};\n\n// Generate a session ID for SDP.\n// https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-20#section-5.2.1\n// recommends using a cryptographically random +ve 64-bit value\n// but right now this should be acceptable and within the right range\nSDPUtils.generateSessionId = function() {\n  return Math.random().toString().substr(2, 21);\n};\n\n// Write boiler plate for start of SDP\n// sessId argument is optional - if not supplied it will\n// be generated randomly\n// sessVersion is optional and defaults to 2\n// sessUser is optional and defaults to 'thisisadapterortc'\nSDPUtils.writeSessionBoilerplate = function(sessId, sessVer, sessUser) {\n  let sessionId;\n  const version = sessVer !== undefined ? sessVer : 2;\n  if (sessId) {\n    sessionId = sessId;\n  } else {\n    sessionId = SDPUtils.generateSessionId();\n  }\n  const user = sessUser || 'thisisadapterortc';\n  // FIXME: sess-id should be an NTP timestamp.\n  return 'v=0\\r\\n' +\n      'o=' + user + ' ' + sessionId + ' ' + version +\n        ' IN IP4 127.0.0.1\\r\\n' +\n      's=-\\r\\n' +\n      't=0 0\\r\\n';\n};\n\n// Gets the direction from the mediaSection or the sessionpart.\nSDPUtils.getDirection = function(mediaSection, sessionpart) {\n  // Look for sendrecv, sendonly, recvonly, inactive, default to sendrecv.\n  const lines = SDPUtils.splitLines(mediaSection);\n  for (let i = 0; i < lines.length; i++) {\n    switch (lines[i]) {\n      case 'a=sendrecv':\n      case 'a=sendonly':\n      case 'a=recvonly':\n      case 'a=inactive':\n        return lines[i].substr(2);\n      default:\n        // FIXME: What should happen here?\n    }\n  }\n  if (sessionpart) {\n    return SDPUtils.getDirection(sessionpart);\n  }\n  return 'sendrecv';\n};\n\nSDPUtils.getKind = function(mediaSection) {\n  const lines = SDPUtils.splitLines(mediaSection);\n  const mline = lines[0].split(' ');\n  return mline[0].substr(2);\n};\n\nSDPUtils.isRejected = function(mediaSection) {\n  return mediaSection.split(' ', 2)[1] === '0';\n};\n\nSDPUtils.parseMLine = function(mediaSection) {\n  const lines = SDPUtils.splitLines(mediaSection);\n  const parts = lines[0].substr(2).split(' ');\n  return {\n    kind: parts[0],\n    port: parseInt(parts[1], 10),\n    protocol: parts[2],\n    fmt: parts.slice(3).join(' '),\n  };\n};\n\nSDPUtils.parseOLine = function(mediaSection) {\n  const line = SDPUtils.matchPrefix(mediaSection, 'o=')[0];\n  const parts = line.substr(2).split(' ');\n  return {\n    username: parts[0],\n    sessionId: parts[1],\n    sessionVersion: parseInt(parts[2], 10),\n    netType: parts[3],\n    addressType: parts[4],\n    address: parts[5],\n  };\n};\n\n// a very naive interpretation of a valid SDP.\nSDPUtils.isValidSDP = function(blob) {\n  if (typeof blob !== 'string' || blob.length === 0) {\n    return false;\n  }\n  const lines = SDPUtils.splitLines(blob);\n  for (let i = 0; i < lines.length; i++) {\n    if (lines[i].length < 2 || lines[i].charAt(1) !== '=') {\n      return false;\n    }\n    // TODO: check the modifier a bit more.\n  }\n  return true;\n};\n\n// Expose public methods.\nif (typeof module === 'object') {\n  module.exports = SDPUtils;\n}\n","/**\n * The errors for the conference.\n */\n\nexport enum JitsiConferenceErrors {\n    /**\n     * Indicates that client must be authenticated to create the conference.\n     */\n    AUTHENTICATION_REQUIRED = 'conference.authenticationRequired',\n\n    /**\n     * Indicates that chat error occurred.\n     */\n    CHAT_ERROR = 'conference.chatError',\n\n    /**\n     * Indicates that a settings error occurred.\n     */\n    SETTINGS_ERROR = 'conference.settingsError',\n\n    /**\n     * Indicates that conference has been destroyed.\n     */\n    CONFERENCE_DESTROYED = 'conference.destroyed',\n\n    /**\n     * Indicates that max users limit has been reached.\n     */\n    CONFERENCE_MAX_USERS = 'conference.max_users',\n\n    /**\n     * Indicates that a connection error occurred when trying to join a conference.\n     */\n    CONNECTION_ERROR = 'conference.connectionError',\n\n    /**\n     * Indicates that the client has been forced to restart by jicofo when the\n     * conference was migrated from one bridge to another.\n     */\n    CONFERENCE_RESTARTED = 'conference.restarted',\n\n    /**\n     * Indicates that a connection error is due to not allowed,\n     * occurred when trying to join a conference.\n     */\n    NOT_ALLOWED_ERROR = 'conference.connectionError.notAllowed',\n\n    /**\n     * Indicates that a connection error is due to not allowed,\n     * occurred when trying to join a conference, only approved members are allowed to join.\n     */\n    MEMBERS_ONLY_ERROR = 'conference.connectionError.membersOnly',\n\n    /**\n     * Indicates that a connection error is due to denied access to the room,\n     * occurred after joining a lobby room and access is denied by the room moderators.\n     */\n    CONFERENCE_ACCESS_DENIED = 'conference.connectionError.accessDenied',\n\n    /**\n     * Indicates that focus error happened.\n     */\n    FOCUS_DISCONNECTED = 'conference.focusDisconnected',\n\n    /**\n     * Indicates that focus left the conference.\n     */\n    FOCUS_LEFT = 'conference.focusLeft',\n\n    /**\n     * Indicates that graceful shutdown happened.\n     */\n    GRACEFUL_SHUTDOWN = 'conference.gracefulShutdown',\n\n    /**\n     * Indicates that the media connection has failed.\n     */\n    ICE_FAILED = 'conference.iceFailed',\n\n    /**\n     * Indicates that the versions of the server side components are incompatible\n     * with the client side.\n     */\n    INCOMPATIBLE_SERVER_VERSIONS = 'conference.incompatible_server_versions',\n\n    /**\n     * Indicates that offer/answer had failed.\n     */\n    OFFER_ANSWER_FAILED = 'conference.offerAnswerFailed',\n\n    /**\n     * Indicates that password cannot be set for this conference.\n     */\n    PASSWORD_NOT_SUPPORTED = 'conference.passwordNotSupported',\n\n    /**\n     * Indicates that a password is required in order to join the conference.\n     */\n    PASSWORD_REQUIRED = 'conference.passwordRequired',\n\n    /**\n     * Indicates that reservation system returned error.\n     */\n    RESERVATION_ERROR = 'conference.reservationError',\n\n    /**\n     * Indicates that there is no available videobridge.\n     */\n    VIDEOBRIDGE_NOT_AVAILABLE = 'conference.videobridgeNotAvailable'\n};\n\n// exported for backward compatibility\nexport const AUTHENTICATION_REQUIRED = JitsiConferenceErrors.AUTHENTICATION_REQUIRED;\nexport const CHAT_ERROR = JitsiConferenceErrors.CHAT_ERROR;\nexport const SETTINGS_ERROR = JitsiConferenceErrors.SETTINGS_ERROR;\nexport const CONFERENCE_DESTROYED = JitsiConferenceErrors.CONFERENCE_DESTROYED;\nexport const CONFERENCE_MAX_USERS = JitsiConferenceErrors.CONFERENCE_MAX_USERS;\nexport const CONNECTION_ERROR = JitsiConferenceErrors.CONNECTION_ERROR;\nexport const CONFERENCE_RESTARTED = JitsiConferenceErrors.CONFERENCE_RESTARTED;\nexport const NOT_ALLOWED_ERROR = JitsiConferenceErrors.NOT_ALLOWED_ERROR;\nexport const MEMBERS_ONLY_ERROR = JitsiConferenceErrors.MEMBERS_ONLY_ERROR;\nexport const CONFERENCE_ACCESS_DENIED = JitsiConferenceErrors.CONFERENCE_ACCESS_DENIED;\nexport const FOCUS_DISCONNECTED = JitsiConferenceErrors.FOCUS_DISCONNECTED;\nexport const FOCUS_LEFT = JitsiConferenceErrors.FOCUS_LEFT;\nexport const GRACEFUL_SHUTDOWN = JitsiConferenceErrors.GRACEFUL_SHUTDOWN;\nexport const ICE_FAILED = JitsiConferenceErrors.ICE_FAILED;\nexport const INCOMPATIBLE_SERVER_VERSIONS = JitsiConferenceErrors.INCOMPATIBLE_SERVER_VERSIONS;\nexport const OFFER_ANSWER_FAILED = JitsiConferenceErrors.OFFER_ANSWER_FAILED;\nexport const PASSWORD_NOT_SUPPORTED = JitsiConferenceErrors.PASSWORD_NOT_SUPPORTED;\nexport const PASSWORD_REQUIRED = JitsiConferenceErrors.PASSWORD_REQUIRED;\nexport const RESERVATION_ERROR = JitsiConferenceErrors.RESERVATION_ERROR;\nexport const VIDEOBRIDGE_NOT_AVAILABLE = JitsiConferenceErrors.VIDEOBRIDGE_NOT_AVAILABLE;\n","/**\n * The events for the conference.\n */\n\nexport enum JitsiConferenceEvents {\n    /**\n     * Event indicates that the current conference audio input switched between audio\n     * input states,i.e. with or without audio input.\n     */\n    AUDIO_INPUT_STATE_CHANGE = 'conference.audio_input_state_changed',\n\n    /**\n     * Event indicates that the permission for unmuting audio has changed based on the number of audio senders in the call\n     * and the audio sender limit configured in Jicofo.\n     */\n    AUDIO_UNMUTE_PERMISSIONS_CHANGED = 'conference.audio_unmute_permissions_changed',\n\n    /**\n     * Indicates that authentication status changed.\n     */\n    AUTH_STATUS_CHANGED = 'conference.auth_status_changed',\n\n    /**\n     * Fired just before the statistics module is disposed and it's the last chance\n     * to submit some logs to the statistics service (ex. CallStats if enabled),\n     * before it's disconnected.\n     */\n    BEFORE_STATISTICS_DISPOSED = 'conference.beforeStatisticsDisposed',\n\n    /**\n     * Indicates that an error occurred.\n     */\n    CONFERENCE_ERROR = 'conference.error',\n\n    /**\n     * Indicates that conference failed.\n     */\n    CONFERENCE_FAILED = 'conference.failed',\n\n    /**\n     * Indicates that conference is in progress of joining.\n     */\n    CONFERENCE_JOIN_IN_PROGRESS = 'conference.join_in_progress',\n\n    /**\n     * Indicates that conference has been joined. The event does NOT provide any\n     * parameters to its listeners.\n     */\n    CONFERENCE_JOINED = 'conference.joined',\n\n    /**\n     * Indicates that conference has been left.\n     */\n    CONFERENCE_LEFT = 'conference.left',\n\n    /**\n     * Indicates that the conference unique identifier has been set.\n     */\n    CONFERENCE_UNIQUE_ID_SET = 'conference.unique_id_set',\n\n    /**\n     * Indicates that the connection to the conference has been established\n     * XXX This is currently fired when the *ICE* connection enters 'connected'\n     * state for the first time.\n     */\n    CONNECTION_ESTABLISHED = 'conference.connectionEstablished',\n\n    /**\n     * Indicates that the connection to the conference has been interrupted for some\n     * reason.\n     * XXX This is currently fired when the *ICE* connection is interrupted.\n     */\n    CONNECTION_INTERRUPTED = 'conference.connectionInterrupted',\n\n    /**\n     * Indicates that the connection to the conference has been restored.\n     * XXX This is currently fired when the *ICE* connection is restored.\n     */\n    CONNECTION_RESTORED = 'conference.connectionRestored',\n\n    /**\n     * A connection to the video bridge's data channel has been established.\n     */\n    DATA_CHANNEL_OPENED = 'conference.dataChannelOpened',\n\n    /**\n     * A user has changed it display name\n     */\n    DISPLAY_NAME_CHANGED = 'conference.displayNameChanged',\n\n    /**\n     * The dominant speaker was changed.\n     */\n    DOMINANT_SPEAKER_CHANGED = 'conference.dominantSpeaker',\n\n    /**\n     * UTC conference timestamp when first participant joined.\n     */\n    CONFERENCE_CREATED_TIMESTAMP = 'conference.createdTimestamp',\n\n    /**\n     * Indicates that DTMF support changed.\n     */\n    DTMF_SUPPORT_CHANGED = 'conference.dtmfSupportChanged',\n\n    /**\n     * Indicates that a message from another participant is received on data\n     * channel.\n     */\n    ENDPOINT_MESSAGE_RECEIVED = 'conference.endpoint_message_received',\n\n    /**\n     * Indicates that a message for the remote endpoint statistics has been received on the bridge channel.\n     */\n    ENDPOINT_STATS_RECEIVED = 'conference.endpoint_stats_received',\n\n    /**\n     * NOTE This is lib-jitsi-meet internal event and can be removed at any time !\n     *\n     * Event emitted when conference transits, between one to one and multiparty JVB\n     * conference. If the conference switches to P2P it's neither one to one nor\n     * a multiparty JVB conference, but P2P (the status argument of this event will\n     * be <tt>false</tt>).\n     *\n     * The first argument is a boolean which carries the previous value and\n     * the seconds argument is a boolean with the new status. The event is emitted\n     * only if the previous and the new values are different.\n     *\n     * @type {string}\n     */\n    JVB121_STATUS = 'conference.jvb121Status',\n\n    /**\n     * You are kicked from the conference.\n     * @param {JitsiParticipant} the participant that initiated the kick.\n     */\n    KICKED = 'conference.kicked',\n\n    /**\n     * Participant was kicked from the conference.\n     * @param {JitsiParticipant} the participant that initiated the kick.\n     * @param {JitsiParticipant} the participant that was kicked.\n     */\n    PARTICIPANT_KICKED = 'conference.participant_kicked',\n\n    /**\n     * The Last N set is changed.\n     *\n     * @param {Array<string>|null} leavingEndpointIds the ids of all the endpoints\n     * which are leaving Last N\n     * @param {Array<string>|null} enteringEndpointIds the ids of all the endpoints\n     * which are entering Last N\n     */\n    LAST_N_ENDPOINTS_CHANGED = 'conference.lastNEndpointsChanged',\n\n    /**\n     * The forwarded sources set is changed.\n     *\n     * @param {Array<string>} leavingForwardedSources the sourceNames of all the tracks which are leaving forwarded\n     * sources\n     * @param {Array<string>} enteringForwardedSources the sourceNames of all the tracks which are entering forwarded\n     * sources\n     */\n    FORWARDED_SOURCES_CHANGED = 'conference.forwardedSourcesChanged',\n\n    /**\n     * Indicates that the room has been locked or unlocked.\n     */\n    LOCK_STATE_CHANGED = 'conference.lock_state_changed',\n\n    /**\n     * Indicates that the region of the media server (jitsi-videobridge) that we\n     * are connected to changed (or was initially set).\n     * @type {string} the region.\n     */\n    SERVER_REGION_CHANGED = 'conference.server_region_changed',\n\n    /**\n     * An event(library-private) fired when a new media session is added to the conference.\n     * @type {string}\n     * @private\n     */\n    _MEDIA_SESSION_STARTED = 'conference.media_session.started',\n\n    /**\n     * An event(library-private) fired when the conference switches the currently active media session.\n     * @type {string}\n     * @private\n     */\n    _MEDIA_SESSION_ACTIVE_CHANGED = 'conference.media_session.active_changed',\n\n    /**\n     * Indicates that the conference had changed to members only enabled/disabled.\n     * The first argument of this event is a <tt>boolean</tt> which when set to\n     * <tt>true</tt> means that the conference is running in members only mode.\n     * You may need to use Lobby if supported to ask for permissions to enter the conference.\n     */\n    MEMBERS_ONLY_CHANGED = 'conference.membersOnlyChanged',\n\n    /**\n     * New text message was received.\n     */\n    MESSAGE_RECEIVED = 'conference.messageReceived',\n\n    /**\n     * Event indicates that the current selected input device has no signal\n     */\n    NO_AUDIO_INPUT = 'conference.no_audio_input',\n\n    /**\n     * Event indicates that the current microphone used by the conference is noisy.\n     */\n    NOISY_MIC = 'conference.noisy_mic',\n\n    /**\n     * Indicates that a message from the local user or from the Prosody backend\n     * was received on the data channel.\n     */\n    NON_PARTICIPANT_MESSAGE_RECEIVED = 'conference.non_participant_message_received',\n\n    /**\n     * New private text message was received.\n     */\n    PRIVATE_MESSAGE_RECEIVED = 'conference.privateMessageReceived',\n\n    /**\n     * Event fired when JVB sends notification about interrupted/restored user's\n     * ICE connection status or we detect local problem with the video track.\n     * First argument is the ID of the participant and\n     * the seconds is a string indicating if the connection is currently\n     * - active - the connection is active\n     * - inactive - the connection is inactive, was intentionally interrupted by\n     * the bridge\n     * - interrupted - a network problem occurred\n     * - restoring - the connection was inactive and is restoring now\n     *\n     * The current status value can be obtained by calling\n     * JitsiParticipant.getConnectionStatus().\n     */\n    PARTICIPANT_CONN_STATUS_CHANGED = 'conference.participant_conn_status_changed',\n\n    /**\n     * Indicates that the features of the participant has been changed.\n     * TODO: there is a spelling mistake in this event name and associated constants\n     */\n    PARTCIPANT_FEATURES_CHANGED = 'conference.partcipant_features_changed',\n\n    /**\n     * Indicates that a the value of a specific property of a specific participant\n     * has changed.\n     */\n    PARTICIPANT_PROPERTY_CHANGED = 'conference.participant_property_changed',\n\n    /**\n     * Indicates that the conference has switched between JVB and P2P connections.\n     * The first argument of this event is a <tt>boolean</tt> which when set to\n     * <tt>true</tt> means that the conference is running on the P2P connection.\n     */\n    P2P_STATUS = 'conference.p2pStatus',\n\n    /**\n     * Indicates that phone number changed.\n     */\n    PHONE_NUMBER_CHANGED = 'conference.phoneNumberChanged',\n\n    /**\n     * The conference properties changed.\n     * @type {string}\n     */\n    PROPERTIES_CHANGED = 'conference.propertiesChanged',\n\n    /**\n     * Indicates that recording state changed.\n     */\n    RECORDER_STATE_CHANGED = 'conference.recorderStateChanged',\n\n    /**\n     * Indicates that video SIP GW state changed.\n     * @param {VideoSIPGWConstants} status.\n     */\n    VIDEO_SIP_GW_AVAILABILITY_CHANGED = 'conference.videoSIPGWAvailabilityChanged',\n\n    /**\n     * Indicates that video SIP GW Session state changed.\n     * @param {options} event - {\n     *     {string} address,\n     *     {VideoSIPGWConstants} oldState,\n     *     {VideoSIPGWConstants} newState,\n     *     {string} displayName}\n     * }.\n     */\n    VIDEO_SIP_GW_SESSION_STATE_CHANGED = 'conference.videoSIPGWSessionStateChanged',\n\n    /**\n     * Indicates that start muted settings changed.\n     */\n    START_MUTED_POLICY_CHANGED = 'conference.start_muted_policy_changed',\n\n    /**\n     * Indicates that the local user has started muted.\n     */\n    STARTED_MUTED = 'conference.started_muted',\n\n    /**\n     * Indicates that subject of the conference has changed.\n     */\n    SUBJECT_CHANGED = 'conference.subjectChanged',\n\n    /**\n     * Indicates that DTMF support changed.\n     */\n    SUSPEND_DETECTED = 'conference.suspendDetected',\n\n    /**\n     * Event indicates that local user is talking while he muted himself\n     */\n    TALK_WHILE_MUTED = 'conference.talk_while_muted',\n\n    /**\n     * A new media track was added to the conference. The event provides the\n     * following parameters to its listeners:\n     *\n     * @param {JitsiTrack} track the added JitsiTrack\n     */\n    TRACK_ADDED = 'conference.trackAdded',\n\n    /**\n     * Audio levels of a media track ( attached to the conference) was changed.\n     */\n    TRACK_AUDIO_LEVEL_CHANGED = 'conference.audioLevelsChanged',\n\n    /**\n     * A media track ( attached to the conference) mute status was changed.\n     * @param {JitsiParticipant|null} the participant that initiated the mute\n     * if it is a remote mute.\n     */\n    TRACK_MUTE_CHANGED = 'conference.trackMuteChanged',\n\n    /**\n     * The media track was removed from the conference. The event provides the\n     * following parameters to its listeners:\n     *\n     * @param {JitsiTrack} track the removed JitsiTrack\n     */\n    TRACK_REMOVED = 'conference.trackRemoved',\n\n    /**\n     * The source-add for unmuting of a media track was rejected by Jicofo.\n     *\n     */\n    TRACK_UNMUTE_REJECTED = 'conference.trackUnmuteRejected',\n\n    /**\n     * Notifies for transcription status changes. The event provides the\n     * following parameters to its listeners:\n     *\n     * @param {String} status - The new status.\n     */\n    TRANSCRIPTION_STATUS_CHANGED = 'conference.transcriptionStatusChanged',\n\n    /**\n     * A new user joined the conference.\n     */\n    USER_JOINED = 'conference.userJoined',\n\n    /**\n     * A user has left the conference.\n     */\n    USER_LEFT = 'conference.userLeft',\n\n    /**\n     * User role changed.\n     */\n    USER_ROLE_CHANGED = 'conference.roleChanged',\n\n    /**\n     * User status changed.\n     */\n    USER_STATUS_CHANGED = 'conference.statusChanged',\n\n    /**\n     * Event indicates that the permission for unmuting video has changed based on the number of video senders in the call\n     * and the video sender limit configured in Jicofo.\n     */\n    VIDEO_UNMUTE_PERMISSIONS_CHANGED = 'conference.video_unmute_permissions_changed',\n\n    /**\n     * Event indicates that the bot participant type changed.\n     */\n    BOT_TYPE_CHANGED = 'conference.bot_type_changed',\n\n    /**\n     * A new user joined the lobby room.\n     */\n    LOBBY_USER_JOINED = 'conference.lobby.userJoined',\n\n    /**\n     * A user from the lobby room has been update.\n     */\n    LOBBY_USER_UPDATED = 'conference.lobby.userUpdated',\n\n    /**\n     * A user left the lobby room.\n     */\n    LOBBY_USER_LEFT = 'conference.lobby.userLeft',\n\n    /**\n     * The local participant was approved to be able to unmute.\n     * @param {options} event - {\n     *     {MediaType} mediaType\n     * }.\n     */\n    AV_MODERATION_APPROVED = 'conference.av_moderation.approved',\n\n    /**\n     * The local participant was blocked to be able to unmute.\n     * @param {options} event - {\n     *     {MediaType} mediaType\n     * }.\n     */\n    AV_MODERATION_REJECTED = 'conference.av_moderation.rejected',\n\n    /**\n     * AV Moderation was enabled/disabled. The actor is the participant that is currently in the meeting,\n     * or undefined if that participant has left the meeting.\n     *\n     * @param {options} event - {\n     *     {boolean} enabled,\n     *     {MediaType} mediaType,\n     *     {JitsiParticipant} actor\n     * }.\n     */\n    AV_MODERATION_CHANGED = 'conference.av_moderation.changed',\n\n    /**\n     * AV Moderation, report for user being approved to unmute.\n     * @param {options} event - {\n     *     {JitsiParticipant} participant,\n     *     {MediaType} mediaType\n     * }.\n     */\n    AV_MODERATION_PARTICIPANT_APPROVED = 'conference.av_moderation.participant.approved',\n\n    /**\n     * AV Moderation, report for user being blocked to unmute.\n     * @param {options} event - {\n     *     {JitsiParticipant} participant,\n     *     {MediaType} mediaType\n     * }.\n     */\n    AV_MODERATION_PARTICIPANT_REJECTED = 'conference.av_moderation.participant.rejected',\n\n    /**\n     * A new facial expression is added with its duration for a participant\n     */\n    FACIAL_EXPRESSION_ADDED = 'conference.facial_expression.added',\n\n    /**\n     * Event fired when a participant is requested to join a given (breakout) room.\n     */\n    BREAKOUT_ROOMS_MOVE_TO_ROOM = 'conference.breakout-rooms.move-to-room',\n\n    /**\n     * Event fired when the breakout rooms data was updated.\n     */\n    BREAKOUT_ROOMS_UPDATED = 'conference.breakout-rooms.updated'\n};\n\n// exported for backward compatibility\nexport const AUDIO_INPUT_STATE_CHANGE = JitsiConferenceEvents.AUDIO_INPUT_STATE_CHANGE;\nexport const AUDIO_UNMUTE_PERMISSIONS_CHANGED = JitsiConferenceEvents.AUDIO_UNMUTE_PERMISSIONS_CHANGED;\nexport const AUTH_STATUS_CHANGED = JitsiConferenceEvents.AUTH_STATUS_CHANGED;\nexport const BEFORE_STATISTICS_DISPOSED = JitsiConferenceEvents.BEFORE_STATISTICS_DISPOSED;\nexport const CONFERENCE_ERROR = JitsiConferenceEvents.CONFERENCE_ERROR;\nexport const CONFERENCE_FAILED = JitsiConferenceEvents.CONFERENCE_FAILED;\nexport const CONFERENCE_JOIN_IN_PROGRESS = JitsiConferenceEvents.CONFERENCE_JOIN_IN_PROGRESS;\nexport const CONFERENCE_JOINED = JitsiConferenceEvents.CONFERENCE_JOINED;\nexport const CONFERENCE_LEFT = JitsiConferenceEvents.CONFERENCE_LEFT;\nexport const CONFERENCE_UNIQUE_ID_SET = JitsiConferenceEvents.CONFERENCE_UNIQUE_ID_SET;\nexport const CONNECTION_ESTABLISHED = JitsiConferenceEvents.CONNECTION_ESTABLISHED;\nexport const CONNECTION_INTERRUPTED = JitsiConferenceEvents.CONNECTION_INTERRUPTED;\nexport const CONNECTION_RESTORED = JitsiConferenceEvents.CONNECTION_RESTORED;\nexport const DATA_CHANNEL_OPENED = JitsiConferenceEvents.DATA_CHANNEL_OPENED;\nexport const DISPLAY_NAME_CHANGED = JitsiConferenceEvents.DISPLAY_NAME_CHANGED;\nexport const DOMINANT_SPEAKER_CHANGED = JitsiConferenceEvents.DOMINANT_SPEAKER_CHANGED;\nexport const CONFERENCE_CREATED_TIMESTAMP = JitsiConferenceEvents.CONFERENCE_CREATED_TIMESTAMP;\nexport const DTMF_SUPPORT_CHANGED = JitsiConferenceEvents.DTMF_SUPPORT_CHANGED;\nexport const ENDPOINT_MESSAGE_RECEIVED = JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED;\nexport const ENDPOINT_STATS_RECEIVED = JitsiConferenceEvents.ENDPOINT_STATS_RECEIVED;\nexport const JVB121_STATUS = JitsiConferenceEvents.JVB121_STATUS;\nexport const KICKED = JitsiConferenceEvents.KICKED;\nexport const PARTICIPANT_KICKED = JitsiConferenceEvents.PARTICIPANT_KICKED;\nexport const LAST_N_ENDPOINTS_CHANGED = JitsiConferenceEvents.LAST_N_ENDPOINTS_CHANGED;\nexport const FORWARDED_SOURCES_CHANGED = JitsiConferenceEvents.FORWARDED_SOURCES_CHANGED;\nexport const LOCK_STATE_CHANGED = JitsiConferenceEvents.LOCK_STATE_CHANGED;\nexport const SERVER_REGION_CHANGED = JitsiConferenceEvents.SERVER_REGION_CHANGED;\nexport const _MEDIA_SESSION_STARTED = JitsiConferenceEvents._MEDIA_SESSION_STARTED;\nexport const _MEDIA_SESSION_ACTIVE_CHANGED = JitsiConferenceEvents._MEDIA_SESSION_ACTIVE_CHANGED;\nexport const MEMBERS_ONLY_CHANGED = JitsiConferenceEvents.MEMBERS_ONLY_CHANGED;\nexport const MESSAGE_RECEIVED = JitsiConferenceEvents.MESSAGE_RECEIVED;\nexport const NO_AUDIO_INPUT = JitsiConferenceEvents.NO_AUDIO_INPUT;\nexport const NOISY_MIC = JitsiConferenceEvents.NOISY_MIC;\nexport const NON_PARTICIPANT_MESSAGE_RECEIVED = JitsiConferenceEvents.NON_PARTICIPANT_MESSAGE_RECEIVED;\nexport const PRIVATE_MESSAGE_RECEIVED = JitsiConferenceEvents.PRIVATE_MESSAGE_RECEIVED;\nexport const PARTICIPANT_CONN_STATUS_CHANGED = JitsiConferenceEvents.PARTICIPANT_CONN_STATUS_CHANGED;\nexport const PARTCIPANT_FEATURES_CHANGED = JitsiConferenceEvents.PARTCIPANT_FEATURES_CHANGED;\nexport const PARTICIPANT_PROPERTY_CHANGED = JitsiConferenceEvents.PARTICIPANT_PROPERTY_CHANGED;\nexport const P2P_STATUS = JitsiConferenceEvents.P2P_STATUS;\nexport const PHONE_NUMBER_CHANGED = JitsiConferenceEvents.PHONE_NUMBER_CHANGED;\nexport const PROPERTIES_CHANGED = JitsiConferenceEvents.PROPERTIES_CHANGED;\nexport const RECORDER_STATE_CHANGED = JitsiConferenceEvents.RECORDER_STATE_CHANGED;\nexport const VIDEO_SIP_GW_AVAILABILITY_CHANGED = JitsiConferenceEvents.VIDEO_SIP_GW_AVAILABILITY_CHANGED;\nexport const VIDEO_SIP_GW_SESSION_STATE_CHANGED = JitsiConferenceEvents.VIDEO_SIP_GW_SESSION_STATE_CHANGED;\nexport const START_MUTED_POLICY_CHANGED = JitsiConferenceEvents.START_MUTED_POLICY_CHANGED;\nexport const STARTED_MUTED = JitsiConferenceEvents.STARTED_MUTED;\nexport const SUBJECT_CHANGED = JitsiConferenceEvents.SUBJECT_CHANGED;\nexport const SUSPEND_DETECTED = JitsiConferenceEvents.SUSPEND_DETECTED;\nexport const TALK_WHILE_MUTED = JitsiConferenceEvents.TALK_WHILE_MUTED;\nexport const TRACK_ADDED = JitsiConferenceEvents.TRACK_ADDED;\nexport const TRACK_AUDIO_LEVEL_CHANGED = JitsiConferenceEvents.TRACK_AUDIO_LEVEL_CHANGED;\nexport const TRACK_MUTE_CHANGED = JitsiConferenceEvents.TRACK_MUTE_CHANGED;\nexport const TRACK_REMOVED = JitsiConferenceEvents.TRACK_REMOVED;\nexport const TRACK_UNMUTE_REJECTED = JitsiConferenceEvents.TRACK_UNMUTE_REJECTED;\nexport const TRANSCRIPTION_STATUS_CHANGED = JitsiConferenceEvents.TRANSCRIPTION_STATUS_CHANGED;\nexport const USER_JOINED = JitsiConferenceEvents.USER_JOINED;\nexport const USER_LEFT = JitsiConferenceEvents.USER_LEFT;\nexport const USER_ROLE_CHANGED = JitsiConferenceEvents.USER_ROLE_CHANGED;\nexport const USER_STATUS_CHANGED = JitsiConferenceEvents.USER_STATUS_CHANGED;\nexport const VIDEO_UNMUTE_PERMISSIONS_CHANGED = JitsiConferenceEvents.VIDEO_UNMUTE_PERMISSIONS_CHANGED;\nexport const BOT_TYPE_CHANGED = JitsiConferenceEvents.BOT_TYPE_CHANGED;\nexport const LOBBY_USER_JOINED = JitsiConferenceEvents.LOBBY_USER_JOINED;\nexport const LOBBY_USER_UPDATED = JitsiConferenceEvents.LOBBY_USER_UPDATED;\nexport const LOBBY_USER_LEFT = JitsiConferenceEvents.LOBBY_USER_LEFT;\nexport const AV_MODERATION_APPROVED = JitsiConferenceEvents.AV_MODERATION_APPROVED;\nexport const AV_MODERATION_REJECTED = JitsiConferenceEvents.AV_MODERATION_REJECTED;\nexport const AV_MODERATION_CHANGED = JitsiConferenceEvents.AV_MODERATION_CHANGED;\nexport const AV_MODERATION_PARTICIPANT_APPROVED = JitsiConferenceEvents.AV_MODERATION_PARTICIPANT_APPROVED;\nexport const AV_MODERATION_PARTICIPANT_REJECTED = JitsiConferenceEvents.AV_MODERATION_PARTICIPANT_REJECTED;\nexport const FACIAL_EXPRESSION_ADDED = JitsiConferenceEvents.FACIAL_EXPRESSION_ADDED;\nexport const BREAKOUT_ROOMS_MOVE_TO_ROOM = JitsiConferenceEvents.BREAKOUT_ROOMS_MOVE_TO_ROOM;\nexport const BREAKOUT_ROOMS_UPDATED = JitsiConferenceEvents.BREAKOUT_ROOMS_UPDATED;\n","export const CALLSTATS_SCRIPT_URL = 'https://api.callstats.io/static/callstats-ws.min.js';\n\n/**\n * The number of remote speakers for which the audio levels will be calculated using\n * RTCRtpReceiver#getSynchronizationSources. Limit the number of endpoints to save cpu on the client as this API call\n * is known to take longer to execute when there are many audio receivers.\n */\nexport const SPEAKERS_AUDIO_LEVELS = 5;\n","/**\n * The errors for the JitsiTrack objects.\n */\n\nexport enum JitsiTrackErrors {\n    /**\n     * An error which indicates that some of requested constraints in\n     * getUserMedia call were not satisfied.\n     */\n    CONSTRAINT_FAILED = 'gum.constraint_failed',\n\n    /**\n     * A generic error which indicates an error occurred while selecting\n     * a DesktopCapturerSource from the electron app.\n     */\n    ELECTRON_DESKTOP_PICKER_ERROR = 'gum.electron_desktop_picker_error',\n\n    /**\n     * An error which indicates a custom desktop picker could not be detected\n     * for the electron app.\n     */\n    ELECTRON_DESKTOP_PICKER_NOT_FOUND = 'gum.electron_desktop_picker_not_found',\n\n    /**\n     * Generic getUserMedia error.\n     */\n    GENERAL = 'gum.general',\n\n    /**\n     * An error which indicates that requested device was not found.\n     */\n    NOT_FOUND = 'gum.not_found',\n\n    /**\n     * An error which indicates that user denied permission to share requested\n     * device.\n     */\n    PERMISSION_DENIED = 'gum.permission_denied',\n\n    /**\n     * Generic error for screensharing failure.\n     */\n    SCREENSHARING_GENERIC_ERROR = 'gum.screensharing_generic_error',\n\n    /**\n     * An error which indicates that user canceled screen sharing window\n     * selection dialog.\n     */\n    SCREENSHARING_USER_CANCELED = 'gum.screensharing_user_canceled',\n\n    /**\n     * Indicates that the timeout passed to the obtainAudioAndVideoPermissions has expired without GUM resolving.\n     */\n    TIMEOUT = 'gum.timeout',\n\n    /**\n     * An error which indicates that track has been already disposed and cannot\n     * be longer used.\n     */\n    TRACK_IS_DISPOSED = 'track.track_is_disposed',\n\n    /**\n     * An error which indicates that track has no MediaStream associated.\n     */\n    TRACK_NO_STREAM_FOUND = 'track.no_stream_found',\n\n    /**\n     * An error which indicates that requested video resolution is not supported\n     * by a webcam.\n     */\n    UNSUPPORTED_RESOLUTION = 'gum.unsupported_resolution'\n}\n\n// exported for backward compatibility\nexport const CONSTRAINT_FAILED = JitsiTrackErrors.CONSTRAINT_FAILED;\nexport const ELECTRON_DESKTOP_PICKER_ERROR = JitsiTrackErrors.ELECTRON_DESKTOP_PICKER_ERROR;\nexport const ELECTRON_DESKTOP_PICKER_NOT_FOUND = JitsiTrackErrors.ELECTRON_DESKTOP_PICKER_NOT_FOUND;\nexport const GENERAL = JitsiTrackErrors.GENERAL;\nexport const NOT_FOUND = JitsiTrackErrors.NOT_FOUND;\nexport const PERMISSION_DENIED = JitsiTrackErrors.PERMISSION_DENIED;\nexport const SCREENSHARING_GENERIC_ERROR = JitsiTrackErrors.SCREENSHARING_GENERIC_ERROR;\nexport const SCREENSHARING_USER_CANCELED = JitsiTrackErrors.SCREENSHARING_USER_CANCELED;\nexport const TIMEOUT = JitsiTrackErrors.TIMEOUT;\nexport const TRACK_IS_DISPOSED = JitsiTrackErrors.TRACK_IS_DISPOSED;\nexport const TRACK_NO_STREAM_FOUND = JitsiTrackErrors.TRACK_NO_STREAM_FOUND;\nexport const UNSUPPORTED_RESOLUTION = JitsiTrackErrors.UNSUPPORTED_RESOLUTION;\n","import * as JitsiTrackErrors from './JitsiTrackErrors';\n\nconst TRACK_ERROR_TO_MESSAGE_MAP = {};\n\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.UNSUPPORTED_RESOLUTION]\n    = 'Video resolution is not supported: ';\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.SCREENSHARING_USER_CANCELED]\n    = 'User canceled screen sharing prompt';\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.SCREENSHARING_GENERIC_ERROR]\n    = 'Unknown error from screensharing';\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.ELECTRON_DESKTOP_PICKER_ERROR]\n    = 'Unkown error from desktop picker';\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.ELECTRON_DESKTOP_PICKER_NOT_FOUND]\n    = 'Failed to detect desktop picker';\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.GENERAL]\n    = 'Generic getUserMedia error';\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.PERMISSION_DENIED]\n    = 'User denied permission to use device(s): ';\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.NOT_FOUND]\n    = 'Requested device(s) was/were not found: ';\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.CONSTRAINT_FAILED]\n    = 'Constraint could not be satisfied: ';\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.TIMEOUT]\n    = 'Could not start media source. Timeout occured!';\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.TRACK_IS_DISPOSED]\n    = 'Track has been already disposed';\nTRACK_ERROR_TO_MESSAGE_MAP[JitsiTrackErrors.TRACK_NO_STREAM_FOUND]\n    = 'Track does not have an associated Media Stream';\n\n// FIXME: Using prototype inheritance because otherwise instanceof is not\n// working properly (see https://github.com/babel/babel/issues/3083)\n\n/**\n *\n * Represents an error that occurred to a JitsiTrack. Can represent various\n * types of errors. For error descriptions (@see JitsiTrackErrors).\n *\n * @extends Error\n *\n *\n * @constructor\n * @param {Object|string} error - error object or error name\n * @param {Object|string} (options) - getUserMedia constraints object or\n * error message\n * @param {('audio'|'video'|'desktop'|'screen'|'audiooutput')[]} (devices) -\n * list of getUserMedia requested devices\n */\nfunction JitsiTrackError(error, options, devices) {\n    if (typeof error === 'object' && typeof error.name !== 'undefined') {\n        /**\n         * Additional information about original getUserMedia error\n         * and constraints.\n         * @type {{\n         *     error: Object,\n         *     constraints: Object,\n         *     devices: Array.<'audio'|'video'|'desktop'|'screen'>\n         * }}\n         */\n        this.gum = {\n            error,\n            constraints: options,\n            devices: devices && Array.isArray(devices)\n                ? devices.slice(0)\n                : undefined\n        };\n\n        switch (error.name) {\n        case 'NotAllowedError':\n        case 'PermissionDeniedError':\n        case 'SecurityError':\n            this.name = JitsiTrackErrors.PERMISSION_DENIED;\n            this.message\n                = TRACK_ERROR_TO_MESSAGE_MAP[this.name]\n                    + (this.gum.devices || []).join(', ');\n            break;\n        case 'DevicesNotFoundError':\n        case 'NotFoundError':\n            this.name = JitsiTrackErrors.NOT_FOUND;\n            this.message\n                = TRACK_ERROR_TO_MESSAGE_MAP[this.name]\n                    + (this.gum.devices || []).join(', ');\n            break;\n        case 'ConstraintNotSatisfiedError':\n        case 'OverconstrainedError': {\n            const constraintName = error.constraintName || error.constraint;\n\n            // we treat deviceId as unsupported resolution, as we want to\n            // retry and finally if everything fails to remove deviceId from\n            // mandatory constraints\n            if (options\n                    && options.video\n                    && (!devices || devices.indexOf('video') > -1)\n                    && (constraintName === 'minWidth'\n                        || constraintName === 'maxWidth'\n                        || constraintName === 'minHeight'\n                        || constraintName === 'maxHeight'\n                        || constraintName === 'width'\n                        || constraintName === 'height'\n                        || constraintName === 'deviceId')) {\n                this.name = JitsiTrackErrors.UNSUPPORTED_RESOLUTION;\n                this.message\n                    = TRACK_ERROR_TO_MESSAGE_MAP[this.name]\n                        + getResolutionFromFailedConstraint(\n                            constraintName,\n                            options);\n            } else {\n                this.name = JitsiTrackErrors.CONSTRAINT_FAILED;\n                this.message\n                    = TRACK_ERROR_TO_MESSAGE_MAP[this.name]\n                        + error.constraintName;\n            }\n            break;\n        }\n\n        default:\n            this.name = JitsiTrackErrors.GENERAL;\n            this.message\n                = error.message || TRACK_ERROR_TO_MESSAGE_MAP[this.name];\n            break;\n        }\n    } else if (typeof error === 'string') {\n        if (TRACK_ERROR_TO_MESSAGE_MAP[error]) {\n            this.name = error;\n            this.message = options || TRACK_ERROR_TO_MESSAGE_MAP[error];\n        } else {\n            // this is some generic error that do not fit any of our\n            // pre-defined errors, so don't give it any specific name, just\n            // store message\n            this.message = error;\n        }\n    } else {\n        throw new Error('Invalid arguments');\n    }\n\n    this.stack = error.stack || new Error().stack;\n}\n\nJitsiTrackError.prototype = Object.create(Error.prototype);\nJitsiTrackError.prototype.constructor = JitsiTrackError;\n\n/**\n * Gets failed resolution constraint from corresponding object.\n * @param {string} failedConstraintName\n * @param {Object} constraints\n * @returns {string|number}\n */\nfunction getResolutionFromFailedConstraint(failedConstraintName, constraints) {\n    if (constraints && constraints.video && constraints.video.mandatory) {\n        switch (failedConstraintName) {\n        case 'width':\n            return constraints.video.mandatory.minWidth;\n        case 'height':\n            return constraints.video.mandatory.minHeight;\n        default:\n            return constraints.video.mandatory[failedConstraintName] || '';\n        }\n    }\n\n    return '';\n}\n\nexport default JitsiTrackError;\n","/**\n * This class exports constants and factory methods related to the analytics\n * API provided by AnalyticsAdapter. In order for entries in a database to be\n * somewhat easily traceable back to the code which produced them, events sent\n * through analytics should be defined here.\n *\n * Since the AnalyticsAdapter API can be used in different ways, for some events\n * it is more convenient to just define the event name as a constant. For other\n * events a factory function is easier.\n *\n * A general approach for adding a new event:\n * 1. Determine the event type: track, UI, page, or operational. If in doubt use\n * operational.\n * 2. Determine whether the event is related to other existing events, and\n * which fields are desired to be set: name, action, actionSubject, source.\n * 3. If the name is sufficient (the other fields are not important), use a\n * constant. Otherwise use a factory function.\n *\n * Note that the AnalyticsAdapter uses the events passed to its functions for\n * its own purposes, and might modify them. Because of this, factory functions\n * should create new objects.\n *\n */\n\nexport enum AnalyticsEvents {\n    /**\n     * The constant which identifies an event of type \"operational\".\n     */\n    TYPE_OPERATIONAL = 'operational',\n\n    /**\n     * The constant which identifies an event of type \"page\".\n     */\n    TYPE_PAGE = 'page',\n\n    /**\n     * The constant which identifies an event of type \"track\".\n     */\n    TYPE_TRACK = 'track',\n\n    /**\n     * The constant which identifies an event of type \"ui\".\n     */\n    TYPE_UI = 'ui',\n\n    /**\n     * The \"action\" value for Jingle events which indicates that the Jingle session\n     * was restarted (TODO: verify/fix the documentation)\n     */\n    ACTION_JINGLE_RESTART = 'restart',\n\n    /**\n     * The \"action\" value for Jingle events which indicates that a session-accept\n     * timed out (TODO: verify/fix the documentation)\n     */\n    ACTION_JINGLE_SA_TIMEOUT = 'session-accept.timeout',\n\n    /**\n     * The \"action\" value for Jingle events which indicates that a session-initiate\n     * was received.\n     */\n    ACTION_JINGLE_SI_RECEIVED = 'session-initiate.received',\n\n    /**\n     * The \"action\" value for Jingle events which indicates that a session-initiate\n     * not arrived within a timeout (the value is specified in\n     * the {@link JingleSessionPC}.\n     */\n    ACTION_JINGLE_SI_TIMEOUT = 'session-initiate.timeout',\n\n    /**\n     * A constant for the \"terminate\" action for Jingle events. TODO: verify/fix\n     * the documentation)\n     */\n    ACTION_JINGLE_TERMINATE = 'terminate',\n\n    /**\n     * The \"action\" value for Jingle events which indicates that a transport-replace\n     * was received.\n     */\n    ACTION_JINGLE_TR_RECEIVED = 'transport-replace.received',\n\n    /**\n     * The \"action\" value for Jingle events which indicates that a transport-replace\n     * succeeded (TODO: verify/fix the documentation)\n     */\n    ACTION_JINGLE_TR_SUCCESS = 'transport-replace.success',\n\n    /**\n     * The \"action\" value for P2P events which indicates that P2P session initiate message has been rejected by the client\n     * because the mandatory requirements were not met.\n     */\n    ACTION_P2P_DECLINED = 'decline',\n\n    /**\n     * The \"action\" value for P2P events which indicates that a connection was\n     * established (TODO: verify/fix the documentation)\n     */\n    ACTION_P2P_ESTABLISHED = 'established',\n\n    /**\n     * The \"action\" value for P2P events which indicates that something failed.\n     */\n    ACTION_P2P_FAILED = 'failed',\n\n    /**\n     * The \"action\" value for P2P events which indicates that a switch to\n     * jitsi-videobridge happened.\n     */\n    ACTION_P2P_SWITCH_TO_JVB = 'switch.to.jvb',\n\n    /**\n     * The name of an event which indicates an available device. We send one such\n     * event per available device once when the available devices are first known,\n     * and every time that they change\n     *\n     * Properties:\n     *      audio_input_device_count: the number of audio input devices available at\n     *          the time the event was sent.\n     *      audio_output_device_count: the number of audio output devices available\n     *          at the time the event was sent.\n     *      video_input_device_count: the number of video input devices available at\n     *          the time the event was sent.\n     *      video_output_device_count: the number of video output devices available\n     *          at the time the event was sent.\n     *      device_id: an identifier of the device described in this event.\n     *      device_group_id:\n     *      device_kind: one of 'audioinput', 'audiooutput', 'videoinput' or\n     *          'videooutput'.\n     *      device_label: a string which describes the device.\n     */\n    AVAILABLE_DEVICE = 'available.device',\n\n    /**\n     * This appears to be fired only in certain cases when the XMPP connection\n     * disconnects (and it was intentional?). It is currently never observed to\n     * fire in production.\n     *\n     * TODO: document\n     *\n     * Properties:\n     *      message: an error message\n     */\n    CONNECTION_DISCONNECTED = 'connection.disconnected',\n\n    /**\n     * Indicates that the user of the application provided feedback in terms of a\n     * rating (an integer from 1 to 5) and an optional comment.\n     * Properties:\n     *      value: the user's rating (an integer from 1 to 5)\n     *      comment: the user's comment\n     */\n    FEEDBACK = 'feedback',\n\n    /**\n     * Indicates the duration of a particular phase of the ICE connectivity\n     * establishment.\n     *\n     * Properties:\n     *      phase: the ICE phase (e.g. 'gathering', 'checking', 'establishment')\n     *      value: the duration in milliseconds.\n     *      p2p: whether the associated ICE connection is p2p or towards a\n     *          jitsi-videobridge\n     *      initiator: whether the local Jingle peer is the initiator or responder\n     *          in the Jingle session. XXX we probably actually care about the ICE\n     *          role (controlling vs controlled), and we assume that this correlates\n     *          with the Jingle initiator.\n     */\n    ICE_DURATION = 'ice.duration',\n\n    /**\n     * Indicates the difference in milliseconds between the ICE establishment time\n     * for the P2P and JVB connections (e.g. a value of 10 would indicate that the\n     * P2P connection took 10ms more than JVB connection to establish).\n     *\n     * Properties:\n     *      value: the difference in establishment durations in milliseconds.\n     *\n     */\n    ICE_ESTABLISHMENT_DURATION_DIFF = 'ice.establishment.duration.diff',\n\n    /**\n     * Indicates that the ICE state has changed.\n     *\n     * Properties:\n     *      state: the ICE state which was entered (e.g. 'checking', 'connected',\n     *          'completed', etc).\n     *      value: the time in milliseconds (as reported by\n     *          window.performance.now()) that the state change occurred.\n     *      p2p: whether the associated ICE connection is p2p or towards a\n     *          jitsi-videobridge\n     *      signalingState: The signaling state of the associated PeerConnection\n     *      reconnect: whether the associated Jingle session is in the process of\n     *          reconnecting (or is it ICE? TODO: verify/fix the documentation)\n     */\n    ICE_STATE_CHANGED = 'ice.state.changed',\n\n    /**\n     * Indicates that no bytes have been sent for the track.\n     *\n     * Properties:\n     *      mediaType: the media type of the local track ('audio' or 'video').\n     */\n    NO_BYTES_SENT = 'track.no-bytes-sent',\n\n    /**\n     * Indicates that a track was unmuted (?).\n     *\n     * Properties:\n     *      mediaType: the media type of the local track ('audio' or 'video').\n     *      trackType: the type of the track ('local' or 'remote').\n     *      value: TODO: document\n     */\n    TRACK_UNMUTED = 'track.unmuted'\n}\n\n// exported for backward compatibility\nexport const TYPE_OPERATIONAL = AnalyticsEvents.TYPE_OPERATIONAL;\nexport const TYPE_PAGE = AnalyticsEvents.TYPE_PAGE;\nexport const TYPE_TRACK = AnalyticsEvents.TYPE_TRACK;\nexport const TYPE_UI = AnalyticsEvents.TYPE_UI;\nexport const ACTION_JINGLE_RESTART = AnalyticsEvents.ACTION_JINGLE_RESTART;\nexport const ACTION_JINGLE_SA_TIMEOUT = AnalyticsEvents.ACTION_JINGLE_SA_TIMEOUT;\nexport const ACTION_JINGLE_SI_RECEIVED = AnalyticsEvents.ACTION_JINGLE_SI_RECEIVED;\nexport const ACTION_JINGLE_SI_TIMEOUT = AnalyticsEvents.ACTION_JINGLE_SI_TIMEOUT;\nexport const ACTION_JINGLE_TERMINATE = AnalyticsEvents.ACTION_JINGLE_TERMINATE;\nexport const ACTION_JINGLE_TR_RECEIVED = AnalyticsEvents.ACTION_JINGLE_TR_RECEIVED;\nexport const ACTION_JINGLE_TR_SUCCESS = AnalyticsEvents.ACTION_JINGLE_TR_SUCCESS;\nexport const ACTION_P2P_DECLINED = AnalyticsEvents.ACTION_P2P_DECLINED;\nexport const ACTION_P2P_ESTABLISHED = AnalyticsEvents.ACTION_P2P_ESTABLISHED;\nexport const ACTION_P2P_FAILED = AnalyticsEvents.ACTION_P2P_FAILED;\nexport const ACTION_P2P_SWITCH_TO_JVB = AnalyticsEvents.ACTION_P2P_SWITCH_TO_JVB;\nexport const AVAILABLE_DEVICE = AnalyticsEvents.AVAILABLE_DEVICE;\nexport const CONNECTION_DISCONNECTED = AnalyticsEvents.CONNECTION_DISCONNECTED;\nexport const FEEDBACK = AnalyticsEvents.FEEDBACK;\nexport const ICE_DURATION = AnalyticsEvents.ICE_DURATION;\nexport const ICE_ESTABLISHMENT_DURATION_DIFF = AnalyticsEvents.ICE_ESTABLISHMENT_DURATION_DIFF;\nexport const ICE_STATE_CHANGED = AnalyticsEvents.ICE_STATE_CHANGED;\nexport const NO_BYTES_SENT = AnalyticsEvents.NO_BYTES_SENT;\nexport const TRACK_UNMUTED = AnalyticsEvents.TRACK_UNMUTED;\n\n/**\n * Creates an operational event which indicates that we have received a\n * \"bridge down\" event from jicofo.\n */\nexport const createBridgeDownEvent = () => ( {\n    action: 'bridge.down',\n    actionSubject: 'bridge.down',\n    type: TYPE_OPERATIONAL\n} );\n\n/**\n * Creates an event which indicates that the XMPP connection failed\n * @param errorType TODO\n * @param errorMessage TODO\n * @param detail connection failed details.\n */\nexport const createConnectionFailedEvent = ( errorType: unknown, errorMessage: unknown, details: object ) => ( {\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\n    action: 'connection.failed',\n    attributes: {\n        'error_type': errorType,\n        'error_message': errorMessage,\n        ...details\n    }\n} );\n\n/**\n * Creates a conference event.\n *\n * @param action - The action of the event.\n * @param attributes - The attributes to be added to the event.\n */\nexport const createConferenceEvent = ( action: string, attributes: object ) => ( {\n    action,\n    attributes,\n    source: 'conference',\n    type: AnalyticsEvents.TYPE_OPERATIONAL\n} );\n\n/**\n * Creates an operational event which indicates that a particular connection\n * stage was reached (i.e. the XMPP connection transitioned to the \"connected\"\n * state).\n *\n * @param stage the stage which was reached\n * @param attributes additional attributes for the event. This should be an\n * object with a \"value\" property indicating a timestamp in milliseconds\n * relative to the beginning of the document's lifetime.\n *\n */\nexport const createConnectionStageReachedEvent = ( stage: unknown, attributes: object ) => ( {\n    action: 'connection.stage.reached',\n    actionSubject: stage,\n    attributes,\n    source: 'connection.stage.reached',\n    type: AnalyticsEvents.TYPE_OPERATIONAL\n} );\n\n/**\n * Creates an operational event for the end-to-end round trip time to a\n * specific remote participant.\n * @param participantId the ID of the remote participant.\n * @param region the region of the remote participant\n * @param rtt the rtt\n */\nexport const createE2eRttEvent = ( participantId: unknown, region: unknown, rtt: unknown ) => ( {\n    attributes: {\n        'participant_id': participantId,\n        region,\n        rtt\n    },\n    name: 'e2e_rtt',\n    type: AnalyticsEvents.TYPE_OPERATIONAL\n} );\n\n/**\n * Creates an event which indicates that the focus has left the MUC.\n */\nexport const createFocusLeftEvent = () => ( {\n    action: 'focus.left',\n    actionSubject: 'focus.left',\n    type: AnalyticsEvents.TYPE_OPERATIONAL\n} );\n\n/**\n * Creates an event related to a getUserMedia call.\n *\n * @param action the type of the result that the event represents: 'error',\n * 'success', 'warning', etc.\n * @param attributes the attributes to attach to the event.\n */\nexport const createGetUserMediaEvent = ( action: 'error' | 'success' | 'warning' | string, attributes: object = {} ) => ( {\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\n    source: 'get.user.media',\n    action,\n    attributes\n} );\n\n/**\n * Creates an event related to remote participant connection status changes.\n *\n * @param attributes the attributes to attach to the event.\n */\nexport const createParticipantConnectionStatusEvent = ( attributes: object = {} ) => ( {\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\n    source: 'peer.conn.status',\n    action: 'duration',\n    attributes\n} );\n\n/**\n * Creates an event related to remote track streaming status changes.\n *\n * @param attributes the attributes to attach to the event.\n */\nexport const createTrackStreamingStatusEvent = ( attributes: object = {} ) => ( {\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\n    source: 'track.streaming.status',\n    action: 'duration',\n    attributes\n} );\n\n/**\n * Creates an event for a Jingle-related event.\n * @param action the action of the event\n * @param attributes attributes to add to the event.\n */\nexport const createJingleEvent = ( action: unknown, attributes: object = {} ) => ( {\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\n    action,\n    source: 'jingle',\n    attributes\n} );\n\n/**\n * Creates an event which indicates that a local track was not able to read\n * data from its source (a camera or a microphone).\n *\n * @param mediaType the media type of the local track ('audio' or\n * 'video').\n */\nexport const createNoDataFromSourceEvent = ( mediaType: 'audio' | 'video' | string, value: unknown ) => ( {\n    attributes: {\n        'media_type': mediaType,\n        value\n    },\n    action: 'track.no.data.from.source',\n    type: AnalyticsEvents.TYPE_OPERATIONAL\n} );\n\n/**\n * Creates an event for a p2p-related event.\n * @param action the action of the event\n * @param attributes attributes to add to the event.\n */\nexport const createP2PEvent = ( action: unknown, attributes: object = {} ) => ( {\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\n    action,\n    source: 'p2p',\n    attributes\n} )\n\n/**\n * Indicates that we received a remote command to mute.\n */\nexport const createRemotelyMutedEvent = ( mediaType: unknown ) => ( {\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\n    action: 'remotely.muted',\n    mediaType\n} );\n\n/**\n * Creates an event which contains RTP statistics such as RTT and packet loss.\n *\n * All average RTP stats are currently reported under 1 event name, but with\n * different properties that allows to distinguish between a P2P call, a\n * call relayed through TURN or the JVB, and multiparty vs 1:1.\n *\n * The structure of the event is:\n *\n * {\n *      p2p: true,\n *      conferenceSize: 2,\n *      localCandidateType: \"relay\",\n *      remoteCandidateType: \"relay\",\n *      transportType: \"udp\",\n *\n *      // Average RTT of 200ms\n *      \"rtt.avg\": 200,\n *      \"rtt.samples\": \"[100, 200, 300]\",\n *\n *      // Average packet loss of 10%\n *      \"packet.loss.avg\": 10,\n *      \"packet.loss.samples\": '[5, 10, 15]'\n *\n *      // Difference in milliseconds in the end-to-end RTT between p2p and jvb.\n *      // The e2e RTT through jvb is 15ms shorter:\n *      \"rtt.diff\": 15,\n *\n *      // End-to-end RTT through JVB is ms.\n *      \"end2end.rtt.avg\" = 100\n * }\n *\n * Note that the value of the \"samples\" properties are (JSON encoded) strings,\n * and not JSON arrays, as events' attributes can not be nested. The samples are\n * currently included for debug purposes only and can be removed anytime soon\n * from the structure.\n *\n * Also note that not all of values are present in each event, as values are\n * obtained and calculated as part of different process/event pipe. For example\n * {@link ConnectionAvgStats} instances are doing the reports for each\n * {@link TraceablePeerConnection} and work independently from the main stats\n * pipe.\n */\nexport const createRtpStatsEvent = ( attributes: object ) => ( {\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\n    action: 'rtp.stats',\n    attributes\n} );\n\n/**\n * Creates an event which contains the round trip time (RTT) to a set of\n * regions.\n *\n * @param attributes\n */\nexport const createRttByRegionEvent = ( attributes: object ) => ( {\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\n    action: 'rtt.by.region',\n    attributes\n} );\n\n/**\n * Creates an event which contains the local and remote ICE candidate types\n * for the transport that is currently selected.\n *\n * @param attributes\n */\nexport const createTransportStatsEvent = ( attributes: object ) => ( {\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\n    action: 'transport.stats',\n    attributes\n} );\n\n/**\n * Creates an event which contains information about the audio output problem (the user id of the affected participant,\n * the local audio levels and the remote audio levels that triggered the event).\n *\n * @param userID - The user id of the affected participant.\n * @param localAudioLevels - The local audio levels.\n * @param remoteAudioLevels - The audio levels received from the participant.\n */\nexport const createAudioOutputProblemEvent = ( userID: string, localAudioLevels: unknown, remoteAudioLevels: unknown ) => ( {\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\n    action: 'audio.output.problem',\n    attributes: {\n        userID,\n        localAudioLevels,\n        remoteAudioLevels\n    }\n} );\n\n/**\n * Creates an event which contains an information related to the bridge channel close event.\n *\n * @param code - A code from {@link https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent}\n * @param reason - A string which describes the reason for closing the bridge channel.\n */\nexport const createBridgeChannelClosedEvent = ( code: string, reason: string ) => ( {\n    type: AnalyticsEvents.TYPE_OPERATIONAL,\n    action: 'bridge-channel.error',\n    attributes: {\n        code,\n        reason\n    }\n} );\n\n/**\n * Creates an event which indicates the Time To First Media (TTFM).\n * It is measured in milliseconds relative to the beginning of the document's\n * lifetime (i.e. the origin used by window.performance.now()), and it excludes\n * the following:\n * 1. The delay due to getUserMedia()\n * 2. The period between the MUC being joined and the reception of the Jingle\n * session-initiate from jicofo. This is because jicofo will not start a Jingle\n * session until there are at least 2 participants in the room.\n *\n * @param attributes the attributes to add to the event. Currently used fields:\n *      mediaType: the media type of the local track ('audio' or 'video').\n *      muted: whether the track has ever been muted (?)\n *      value: the TTMF in milliseconds.\n */\nexport const createTtfmEvent = ( attributes: object ) => createConnectionStageReachedEvent( 'ttfm', attributes );\n","export enum Events {\n    /**\n     * Notifies about audio level in RTP statistics by SSRC.\n     *\n     * @param ssrc - The synchronization source identifier (SSRC) of the\n     * endpoint/participant whose audio level is being reported.\n     * @param {number} audioLevel - The audio level of <tt>ssrc</tt> according to\n     * RTP statistics.\n     * @param {boolean} isLocal - <tt>true</tt> if <tt>ssrc</tt> identifies the\n     * local endpoint/participant; otherwise, <tt>false</tt>.\n     */\n    AUDIO_LEVEL = 'statistics.audioLevel',\n\n    /**\n     * An event fired just before the statistics module gets disposes and it's\n     * the last chance to submit some logs that will end up in stats services like\n     * CallStats (if enabled).\n     */\n    BEFORE_DISPOSED = 'statistics.before_disposed',\n\n    /**\n     * An event carrying all statistics by ssrc.\n     */\n    BYTE_SENT_STATS = 'statistics.byte_sent_stats',\n\n    /**\n     * An event carrying connection statistics.\n     *\n     * @param {object} connectionStats - The connection statistics carried by the\n     * event such as <tt>bandwidth</tt>, <tt>bitrate</tt>, <tt>packetLoss</tt>,\n     * <tt>resolution</tt>, and <tt>transport</tt>.\n     */\n    CONNECTION_STATS = 'statistics.connectionstats',\n\n    /**\n     * An event carrying performance stats.\n     */\n    LONG_TASKS_STATS = 'statistics.long_tasks_stats'\n};\n\n// exported for backward compatibility\nexport const AUDIO_LEVEL = Events.AUDIO_LEVEL;\nexport const BEFORE_DISPOSED = Events.BEFORE_DISPOSED;\nexport const BYTE_SENT_STATS = Events.BYTE_SENT_STATS;\nexport const CONNECTION_STATS = Events.CONNECTION_STATS;\nexport const LONG_TASKS_STATS = Events.LONG_TASKS_STATS;\n","// TODO: Maybe fix the values to 'Chrome', 'Internet Explorer', etc. Currently\n// this values needs to be as they are becuse they are going to analytics,\n// callstats, etc.\n\nexport const CHROME = 'chrome';\n\nexport const OPERA = 'opera';\n\nexport const FIREFOX = 'firefox';\n\nexport const INTERNET_EXPLORER = 'iexplorer';\n\nexport const SAFARI = 'safari';\n\nexport const NWJS = 'nwjs';\n\nexport const ELECTRON = 'electron';\n\nexport const REACT_NATIVE = 'react-native';\n\nexport const UNKNOWN = 'unknown';\n","import Bowser from 'bowser';\n\nimport {\n    CHROME,\n    OPERA,\n    FIREFOX,\n    INTERNET_EXPLORER,\n    SAFARI,\n    NWJS,\n    ELECTRON,\n    REACT_NATIVE,\n    UNKNOWN\n} from './browsers.js';\n\n/**\n * Maps the names of the browsers from bowser to the internal names defined in\n * ./browsers.js\n */\nconst bowserNameToJitsiName = {\n    'Chrome': CHROME,\n    'Chromium': CHROME,\n    'Opera': OPERA,\n    'Firefox': FIREFOX,\n    'Internet Explorer': INTERNET_EXPLORER,\n    'Safari': SAFARI\n};\n\n/**\n * Detects a Chromium based environent.\n *\n * NOTE: Here we cannot check solely for \"Chrome\" in the UA, because Edge has\n * it too. We need to check explicitly for chromium based Edge first and then\n * detect other chromium based browsers.\n *\n * @returns {Object|undefined} - The name (CHROME) and version.\n */\nfunction _detectChromiumBased() {\n    const userAgent = navigator.userAgent;\n    const browserInfo = {\n        name: UNKNOWN,\n        version: undefined\n    };\n\n    if (userAgent.match(/Chrome/) && !userAgent.match(/Edge/)) {\n        // Edge is currenly supported only on desktop and android.\n        if (userAgent.match(/Edg(A?)/)) {\n            // Compare the underlying chromium version.\n            const version = userAgent.match(/Chrome\\/([\\d.]+)/)[1];\n\n            if (Number.parseInt(version, 10) > 72) {\n                browserInfo.name = CHROME;\n                browserInfo.version = version;\n            }\n        } else {\n            browserInfo.name = CHROME;\n            browserInfo.version = userAgent.match(/Chrome\\/([\\d.]+)/)[1];\n        }\n    }\n\n    return browserInfo;\n}\n\n/**\n * Detects Electron environment.\n *\n * @returns {Object|undefined} - The name (ELECTRON) and version.\n */\nfunction _detectElectron() {\n    const userAgent = navigator.userAgent;\n\n    if (userAgent.match(/Electron/)) {\n        const version = userAgent.match(/Electron(?:\\s|\\/)([\\d.]+)/)[1];\n\n        return {\n            name: ELECTRON,\n            version\n        };\n    } else if (typeof window.JitsiMeetElectron !== 'undefined') {\n        return {\n            name: ELECTRON,\n            version: undefined\n        };\n    }\n}\n\n/**\n * Detects NWJS environment.\n *\n * @returns {Object|undefined} - The name (NWJS) and version.\n */\nfunction _detectNWJS() {\n    const userAgent = navigator.userAgent;\n\n    if (userAgent.match(/JitsiMeetNW/)) {\n        const version = userAgent.match(/JitsiMeetNW\\/([\\d.]+)/)[1];\n\n        return {\n            name: NWJS,\n            version\n        };\n    }\n}\n\n/**\n * Detects React Native environment.\n * @returns {Object|undefined} - The name (REACT_NATIVE) and version.\n */\nfunction _detectReactNative() {\n    const match\n        = navigator.userAgent.match(/\\b(react[ \\t_-]*native)(?:\\/(\\S+))?/i);\n    let version;\n\n    // If we're remote debugging a React Native app, it may be treated as\n    // Chrome. Check navigator.product as well and always return some version\n    // even if we can't get the real one.\n\n    if (match || navigator.product === 'ReactNative') {\n        let name;\n\n        if (match && match.length > 2) {\n            name = match[1];\n            version = match[2];\n        }\n        name || (name = 'react-native');\n        version || (version = 'unknown');\n\n        return {\n            name: REACT_NATIVE,\n            version\n        };\n    }\n}\n\n/**\n * Returns information about the current browser.\n * @param {Object} - The bowser instance.\n * @returns {Object} - The name and version of the browser.\n */\nfunction _detect(bowser) {\n    let browserInfo;\n    const detectors = [\n        _detectReactNative,\n        _detectElectron,\n        _detectNWJS\n    ];\n\n    // Try all browser detectors\n    for (let i = 0; i < detectors.length; i++) {\n        browserInfo = detectors[i]();\n        if (browserInfo) {\n            return browserInfo;\n        }\n    }\n\n    const name = bowser.getBrowserName();\n\n    if (name in bowserNameToJitsiName) {\n        return {\n            name: bowserNameToJitsiName[name],\n            version: bowser.getBrowserVersion()\n        };\n    }\n\n    // Detect other browsers with the Chrome engine, such as Vivaldi and Brave.\n    browserInfo = _detectChromiumBased();\n    if (browserInfo) {\n        return browserInfo;\n    }\n\n    return {\n        name: UNKNOWN,\n        version: undefined\n    };\n}\n\n/**\n * Implements browser detection.\n */\nexport default class BrowserDetection {\n    /**\n     * Creates new BrowserDetection instance.\n     *\n     * @param {Object} [browserInfo] - Information about the browser.\n     * @param {string} browserInfo.name - The name of the browser.\n     * @param {string} browserInfo.version - The version of the browser.\n     */\n    constructor(browserInfo) {\n        let name, version;\n\n        this._bowser = Bowser.getParser(navigator.userAgent);\n        if (typeof browserInfo === 'undefined') {\n            const detectedBrowserInfo = _detect(this._bowser);\n\n            name = detectedBrowserInfo.name;\n            version = detectedBrowserInfo.version;\n        } else if (browserInfo.name in bowserNameToJitsiName) {\n            name = bowserNameToJitsiName[browserInfo.name];\n            version = browserInfo.version;\n        } else {\n            name = UNKNOWN;\n            version = undefined;\n        }\n\n        this._name = name;\n        this._version = version;\n    }\n\n    /**\n     * Gets current browser name.\n     * @returns {string}\n     */\n    getName() {\n        return this._name;\n    }\n\n    /**\n     * Checks if current browser is Chrome.\n     * @returns {boolean}\n     */\n    isChrome() {\n        return this._name === CHROME;\n    }\n\n    /**\n     * Checks if current browser is Opera.\n     * @returns {boolean}\n     */\n    isOpera() {\n        return this._name === OPERA;\n    }\n\n    /**\n     * Checks if current browser is Firefox.\n     * @returns {boolean}\n     */\n    isFirefox() {\n        return this._name === FIREFOX;\n    }\n\n    /**\n     * Checks if current browser is Internet Explorer.\n     * @returns {boolean}\n     */\n    isIExplorer() {\n        return this._name === INTERNET_EXPLORER;\n    }\n\n    /**\n     * Checks if current browser is Safari.\n     * @returns {boolean}\n     */\n    isSafari() {\n        return this._name === SAFARI;\n    }\n\n    /**\n     * Checks if current environment is NWJS.\n     * @returns {boolean}\n     */\n    isNWJS() {\n        return this._name === NWJS;\n    }\n\n    /**\n     * Checks if current environment is Electron.\n     * @returns {boolean}\n     */\n    isElectron() {\n        return this._name === ELECTRON;\n    }\n\n    /**\n     * Checks if current environment is React Native.\n     * @returns {boolean}\n     */\n    isReactNative() {\n        return this._name === REACT_NATIVE;\n    }\n\n    /**\n     * Returns the version of the current browser.\n     * @returns {string}\n     */\n    getVersion() {\n        return this._version;\n    }\n\n    /**\n     * Check if the parsed browser matches the passed condition.\n     *\n     * @param {Object} checkTree - It's one or two layered object, which can include a\n     * platform or an OS on the first layer and should have browsers specs on the\n     * bottom layer.\n     * Eg. { chrome: '>71.1.0' }\n     *     { windows: { chrome: '<70.2' } }\n     * @returns {boolean | undefined} - Returns true if the browser satisfies the set\n     * conditions, false if not and undefined when the browser is not defined in the\n     * checktree object or when the current browser's version is unknown.\n     * @private\n     */\n    _checkCondition(checkTree) {\n        if (this._version) {\n            return this._bowser.satisfies(checkTree);\n        }\n    }\n\n    /**\n     * Compares the passed version with the current browser version.\n     *\n     * @param {*} version - The version to compare with. Anything different\n     * than string will be converted to string.\n     * @returns {boolean|undefined} - Returns true if the current version is\n     * greater than the passed version and false otherwise. Returns undefined if\n     * the current browser version is unknown.\n     */\n    isVersionGreaterThan(version) {\n        return this._checkCondition({ [this._name]: `>${version}` });\n    }\n\n    /**\n     * Compares the passed version with the current browser version.\n     *\n     * @param {*} version - The version to compare with. Anything different\n     * than string will be converted to string.\n     * @returns {boolean|undefined} - Returns true if the current version is\n     * lower than the passed version and false otherwise. Returns undefined if\n     * the current browser version is unknown.\n     */\n    isVersionLessThan(version) {\n        return this._checkCondition({ [this._name]: `<${version}` });\n    }\n\n    /**\n     * Compares the passed version with the current browser version.\n     *\n     * @param {*} version - The version to compare with. Anything different\n     * than string will be converted to string.\n     * @returns {boolean|undefined} - Returns true if the current version is\n     * equal to the passed version and false otherwise. Returns undefined if\n     * the current browser version is unknown.\n     * A loose-equality operator is used here so that it matches the sub-versions as well.\n     */\n    isVersionEqualTo(version) {\n        return this._checkCondition({ [this._name]: `~${version}` });\n    }\n}\n","import EventEmitter from 'events';\n\n/**\n * Dummy implementation of Storage interface.\n */\nclass DummyLocalStorage extends EventEmitter {\n\n    /**\n     * The object used for storage.\n     */\n    _storage = {};\n\n    /**\n     * Empties all keys out of the storage.\n     *\n     * @returns {void}\n     */\n    clear() {\n        this._storage = {};\n    }\n\n    /**\n     * Returns the number of data items stored in the Storage object.\n     *\n     * @returns {number} - The number of data items stored in the Storage object.\n     */\n    get length() {\n        return Object.keys(this._storage).length;\n    }\n\n    /**\n     * Will return that key's value associated to the passed key name.\n     *\n     * @param {string} keyName - The key name.\n     * @returns {*} - The key value.\n     */\n    getItem(keyName) {\n        return this._storage[keyName];\n    }\n\n    /**\n     * When passed a key name and value, will add that key to the storage,\n     * or update that key's value if it already exists.\n     *\n     * @param {string} keyName - The key name.\n     * @param {*} keyValue - The key value.\n     * @returns {void}\n     */\n    setItem(keyName, keyValue) {\n        this._storage[keyName] = keyValue;\n    }\n\n    /**\n     * When passed a key name, will remove that key from the storage.\n     *\n     * @param {string} keyName - The key name.\n     * @returns {void}\n     */\n    removeItem(keyName) {\n        delete this._storage[keyName];\n    }\n\n    /**\n     * When passed a number n, this method will return the name of the nth key in the storage.\n     *\n     * @param {number} idx - The index of the key.\n     * @returns {string} - The nth key name.\n     */\n    key(n) {\n        const keys = Object.keys(this._storage);\n\n        if (keys.length <= n) {\n            return undefined;\n        }\n\n        return keys[n];\n    }\n\n    /**\n     * Serializes the content of the storage.\n     *\n     * @returns {string} - The serialized content.\n     */\n    serialize() {\n        return JSON.stringify(this._storage);\n    }\n}\n\n/**\n * Wrapper class for browser's local storage object.\n */\nclass JitsiLocalStorage extends EventEmitter {\n    /**\n     * @constructor\n     * @param {Storage} storage browser's local storage object.\n     */\n    constructor() {\n        super();\n\n        try {\n            this._storage = window.localStorage;\n            this._localStorageDisabled = false;\n        } catch (ignore) {\n            // localStorage throws an exception.\n        }\n\n        if (!this._storage) { // Handles the case when window.localStorage is undefined or throws an exception.\n            console.warn('Local storage is disabled.');\n            this._storage = new DummyLocalStorage();\n            this._localStorageDisabled = true;\n        }\n    }\n\n    /**\n     * Returns true if window.localStorage is disabled and false otherwise.\n     *\n     * @returns {boolean} - True if window.localStorage is disabled and false otherwise.\n     */\n    isLocalStorageDisabled() {\n        return this._localStorageDisabled;\n    }\n\n    /**\n     * Empties all keys out of the storage.\n     *\n     * @returns {void}\n     */\n    clear() {\n        this._storage.clear();\n        this.emit('changed');\n    }\n\n    /**\n     * Returns the number of data items stored in the Storage object.\n     *\n     * @returns {number} - The number of data items stored in the Storage object.\n     */\n    get length() {\n        return this._storage.length;\n    }\n\n    /**\n     * Returns that passed key's value.\n     * @param {string} keyName the name of the key you want to retrieve\n     * the value of.\n     * @returns {String|null} the value of the key. If the key does not exist,\n     * null is returned.\n     */\n    getItem(keyName) {\n        return this._storage.getItem(keyName);\n    }\n\n    /**\n     * Adds a key to the storage, or update key's value if it already exists.\n     * @param {string} keyName - the name of the key you want to create/update.\n     * @param {string} keyValue - the value you want to give the key you are\n     * creating/updating.\n     * @param {boolean} dontEmitChangedEvent - If true a changed event won't be emitted.\n     */\n    setItem(keyName, keyValue, dontEmitChangedEvent = false) {\n        this._storage.setItem(keyName, keyValue);\n\n        if (!dontEmitChangedEvent) {\n            this.emit('changed');\n        }\n    }\n\n    /**\n     * Remove a key from the storage.\n     * @param {string} keyName the name of the key you want to remove.\n     */\n    removeItem(keyName) {\n        this._storage.removeItem(keyName);\n        this.emit('changed');\n    }\n\n    /**\n     * Returns the name of the nth key in the list, or null if n is greater\n     * than or equal to the number of key/value pairs in the object.\n     *\n     * @param {number} i - The index of the key in the list.\n     * @returns {string}\n     */\n    key(i) {\n        return this._storage.key(i);\n    }\n\n    /**\n     * Serializes the content of the storage.\n     *\n     * @returns {string} - The serialized content.\n     */\n    serialize() {\n        if (this.isLocalStorageDisabled()) {\n            return this._storage.serialize();\n        }\n\n        const length = this._storage.length;\n        const localStorageContent = {};\n\n        for (let i = 0; i < length; i++) {\n            const key = this._storage.key(i);\n\n            localStorageContent[key] = this._storage.getItem(key);\n        }\n\n        return JSON.stringify(localStorageContent);\n    }\n}\n\nexport const jitsiLocalStorage = new JitsiLocalStorage();\n","import { BrowserDetection } from '@jitsi/js-utils';\nimport { getLogger } from '@jitsi/logger';\n\nconst logger = getLogger(__filename);\n\n/* Minimum required Chrome / Chromium version. This applies also to derivatives. */\nconst MIN_REQUIRED_CHROME_VERSION = 72;\nconst MIN_REQUIRED_SAFARI_VERSION = 14;\nconst MIN_REQUIRED_IOS_VERSION = 14;\n\n// TODO: Move this code to js-utils.\n\n// NOTE: Now we are extending BrowserDetection in order to preserve\n// RTCBrowserType interface but maybe it worth exporting BrowserCapabilities\n// and BrowserDetection as separate objects in future.\n\n/**\n * Implements browser capabilities for lib-jitsi-meet.\n */\nexport default class BrowserCapabilities extends BrowserDetection {\n    /**\n     * Creates new BrowserCapabilities instance.\n     */\n    constructor() {\n        super();\n        logger.info(\n            `This appears to be ${this.getName()}, ver: ${this.getVersion()}`);\n    }\n\n    /**\n     * Tells whether or not the <tt>MediaStream/tt> is removed from the <tt>PeerConnection</tt> and disposed on video\n     * mute (in order to turn off the camera device). This is needed on Firefox because of the following bug\n     * https://bugzilla.mozilla.org/show_bug.cgi?id=1735951\n     *\n     * @return {boolean} <tt>true</tt> if the current browser supports this strategy or <tt>false</tt> otherwise.\n     */\n    doesVideoMuteByStreamRemove() {\n        return this.isChromiumBased() || this.isWebKitBased() || this.isFirefox();\n    }\n\n    /**\n     * Checks if the current browser is Chromium based, i.e., it's either Chrome / Chromium or uses it as its engine,\n     * but doesn't identify as Chrome.\n     *\n     * This includes the following browsers:\n     * - Chrome and Chromium.\n     * - Other browsers which use the Chrome engine, but are detected as Chrome, such as Brave and Vivaldi.\n     * - Browsers which are NOT Chrome but use it as their engine, and have custom detection code: Opera, Electron\n     *   and NW.JS.\n     * This excludes\n     * - Chrome on iOS since it uses WKWebView.\n     */\n    isChromiumBased() {\n        return (this.isChrome()\n            || this.isElectron()\n            || this.isNWJS()\n            || this.isOpera())\n            && !this.isWebKitBased();\n    }\n\n    /**\n     * Checks if the current platform is iOS.\n     *\n     * @returns {boolean}\n     */\n    isIosBrowser() {\n        const { userAgent, maxTouchPoints, platform } = navigator;\n\n        return Boolean(userAgent.match(/iP(ad|hone|od)/i))\n            || (maxTouchPoints && maxTouchPoints > 2 && /MacIntel/.test(platform));\n    }\n\n    /**\n     * Checks if the current browser is WebKit based. It's either\n     * Safari or uses WebKit as its engine.\n     *\n     * This includes Chrome and Firefox on iOS\n     *\n     * @returns {boolean}\n     */\n    isWebKitBased() {\n        // https://trac.webkit.org/changeset/236144/webkit/trunk/LayoutTests/webrtc/video-addLegacyTransceiver.html\n        return this._bowser.isEngine('webkit')\n            && typeof navigator.mediaDevices !== 'undefined'\n            && typeof navigator.mediaDevices.getUserMedia !== 'undefined'\n            && typeof window.RTCRtpTransceiver !== 'undefined'\n            // eslint-disable-next-line no-undef\n            && Object.keys(RTCRtpTransceiver.prototype).indexOf('currentDirection') > -1;\n    }\n\n    /**\n     * Checks whether current running context is a Trusted Web Application.\n     *\n     * @returns {boolean} Whether the current context is a TWA.\n     */\n    isTwa() {\n        return 'matchMedia' in window && window.matchMedia('(display-mode:standalone)').matches;\n    }\n\n    /**\n     * Checks if the current browser is supported.\n     *\n     * @returns {boolean} true if the browser is supported, false otherwise.\n     */\n    isSupported() {\n        if (this.isSafari() && this._getSafariVersion() < MIN_REQUIRED_SAFARI_VERSION) {\n            return false;\n        }\n\n        return (this.isChromiumBased() && this._getChromiumBasedVersion() >= MIN_REQUIRED_CHROME_VERSION)\n            || this.isFirefox()\n            || this.isReactNative()\n            || this.isWebKitBased();\n    }\n\n    /**\n     * Returns whether the browser is supported for Android\n     * @returns {boolean} true if the browser is supported for Android devices\n     */\n    isSupportedAndroidBrowser() {\n        return this.isChromiumBased() || this.isFirefox();\n    }\n\n    /**\n     * Returns whether the browser is supported for iOS\n     * @returns {boolean} true if the browser is supported for iOS devices\n     */\n    isSupportedIOSBrowser() {\n        return this._getIOSVersion() >= MIN_REQUIRED_IOS_VERSION;\n    }\n\n    /**\n     * Returns whether or not the current environment needs a user interaction\n     * with the page before any unmute can occur.\n     *\n     * @returns {boolean}\n     */\n    isUserInteractionRequiredForUnmute() {\n        return this.isFirefox() && this.isVersionLessThan('68');\n    }\n\n    /**\n     * Checks if the current browser triggers 'onmute'/'onunmute' events when\n     * user's connection is interrupted and the video stops playback.\n     * @returns {*|boolean} 'true' if the event is supported or 'false'\n     * otherwise.\n     */\n    supportsVideoMuteOnConnInterrupted() {\n        return this.isChromiumBased() || this.isReactNative();\n    }\n\n    /**\n     * Checks if the current browser reports upload and download bandwidth\n     * statistics.\n     * @return {boolean}\n     */\n    supportsBandwidthStatistics() {\n        // FIXME bandwidth stats are currently not implemented for FF on our\n        // side, but not sure if not possible ?\n        return !this.isFirefox() && !this.isWebKitBased();\n    }\n\n    /**\n     * Checks if the current browser supports setting codec preferences on the transceiver.\n     * @returns {boolean}\n     */\n    supportsCodecPreferences() {\n        return Boolean(window.RTCRtpTransceiver\n            && 'setCodecPreferences' in window.RTCRtpTransceiver.prototype\n            && window.RTCRtpReceiver\n            && typeof window.RTCRtpReceiver.getCapabilities !== 'undefined')\n\n            // this is not working on Safari because of the following bug\n            // https://bugs.webkit.org/show_bug.cgi?id=215567\n            && !this.isWebKitBased();\n    }\n\n    /**\n     * Checks if the current browser support the device change event.\n     * @return {boolean}\n     */\n    supportsDeviceChangeEvent() {\n        return navigator.mediaDevices\n            && typeof navigator.mediaDevices.ondevicechange !== 'undefined'\n            && typeof navigator.mediaDevices.addEventListener !== 'undefined';\n    }\n\n    /**\n     * Checks if the current browser supports RTT statistics for srflx local\n     * candidates through the legacy getStats() API.\n     */\n    supportsLocalCandidateRttStatistics() {\n        return this.isChromiumBased() || this.isReactNative() || this.isWebKitBased();\n    }\n\n    /**\n     * Checks if the current browser supports the Long Tasks API that lets us observe\n     * performance measurement events and be notified of tasks that take longer than\n     * 50ms to execute on the main thread.\n     */\n    supportsPerformanceObserver() {\n        return typeof window.PerformanceObserver !== 'undefined'\n            && PerformanceObserver.supportedEntryTypes.indexOf('longtask') > -1;\n    }\n\n    /**\n     * Checks if the current browser supports audio level stats on the receivers.\n     */\n    supportsReceiverStats() {\n        return typeof window.RTCRtpReceiver !== 'undefined'\n            && Object.keys(RTCRtpReceiver.prototype).indexOf('getSynchronizationSources') > -1\n\n            // Disable this on Safari because it is reporting 0.000001 as the audio levels for all\n            // remote audio tracks.\n            && !this.isWebKitBased();\n    }\n\n    /**\n     * Checks if the current browser reports round trip time statistics for\n     * the ICE candidate pair.\n     * @return {boolean}\n     */\n    supportsRTTStatistics() {\n        // Firefox does not seem to report RTT for ICE candidate pair:\n        // eslint-disable-next-line max-len\n        // https://www.w3.org/TR/webrtc-stats/#dom-rtcicecandidatepairstats-currentroundtriptime\n        // It does report mozRTT for RTP streams, but at the time of this\n        // writing it's value does not make sense most of the time\n        // (is reported as 1):\n        // https://bugzilla.mozilla.org/show_bug.cgi?id=1241066\n        // For Chrome and others we rely on 'googRtt'.\n        return !this.isFirefox();\n    }\n\n    /**\n     * Returns true if VP9 is supported by the client on the browser. VP9 is currently disabled on Firefox and Safari\n     * because of issues with rendering. Please check https://bugzilla.mozilla.org/show_bug.cgi?id=1492500,\n     * https://bugs.webkit.org/show_bug.cgi?id=231071 and https://bugs.webkit.org/show_bug.cgi?id=231074 for details.\n     */\n    supportsVP9() {\n        return this.isChromiumBased() || this.isReactNative();\n    }\n\n    /**\n     * Checks if the browser uses SDP munging for turning on simulcast.\n     *\n     * @returns {boolean}\n     */\n    usesSdpMungingForSimulcast() {\n        return this.isChromiumBased() || this.isReactNative() || this.isWebKitBased();\n    }\n\n    /**\n     * Checks if the browser uses webrtc-adapter. All browsers except React Native do.\n     *\n     * @returns {boolean}\n     */\n    usesAdapter() {\n        return !this.isReactNative();\n    }\n\n    /**\n     * Checks if the browser uses RIDs/MIDs for siganling the simulcast streams\n     * to the bridge instead of the ssrcs.\n     */\n    usesRidsForSimulcast() {\n        return false;\n    }\n\n    /**\n     * Checks if the browser supports getDisplayMedia.\n     * @returns {boolean} {@code true} if the browser supports getDisplayMedia.\n     */\n    supportsGetDisplayMedia() {\n        return typeof navigator.getDisplayMedia !== 'undefined'\n            || (typeof navigator.mediaDevices !== 'undefined'\n                && typeof navigator.mediaDevices.getDisplayMedia\n                    !== 'undefined');\n    }\n\n    /**\n     * Checks if the browser supports WebRTC Encoded Transform, an alternative\n     * to insertable streams.\n     *\n     * NOTE: At the time of this writing the only browser supporting this is\n     * Safari / WebKit, behind a flag.\n     *\n     * @returns {boolean} {@code true} if the browser supports it.\n     */\n    supportsEncodedTransform() {\n        return Boolean(window.RTCRtpScriptTransform);\n    }\n\n    /**\n     * Checks if the browser supports insertable streams, needed for E2EE.\n     * @returns {boolean} {@code true} if the browser supports insertable streams.\n     */\n    supportsInsertableStreams() {\n        if (!(typeof window.RTCRtpSender !== 'undefined'\n            && window.RTCRtpSender.prototype.createEncodedStreams)) {\n            return false;\n        }\n\n        // Feature-detect transferable streams which we need to operate in a worker.\n        // See https://groups.google.com/a/chromium.org/g/blink-dev/c/1LStSgBt6AM/m/hj0odB8pCAAJ\n        const stream = new ReadableStream();\n\n        try {\n            window.postMessage(stream, '*', [ stream ]);\n\n            return true;\n        } catch {\n            return false;\n        }\n    }\n\n    /**\n     * Whether the browser supports the RED format for audio.\n     */\n    supportsAudioRed() {\n        return Boolean(window.RTCRtpSender\n            && window.RTCRtpSender.getCapabilities\n            && window.RTCRtpSender.getCapabilities('audio').codecs.some(codec => codec.mimeType === 'audio/red')\n            && window.RTCRtpReceiver\n            && window.RTCRtpReceiver.getCapabilities\n            && window.RTCRtpReceiver.getCapabilities('audio').codecs.some(codec => codec.mimeType === 'audio/red'));\n    }\n\n    /**\n     * Checks if the browser supports unified plan.\n     *\n     * @returns {boolean}\n     */\n    supportsUnifiedPlan() {\n        return !this.isReactNative();\n    }\n\n    /**\n     * Checks if the browser supports voice activity detection via the @type {VADAudioAnalyser} service.\n     *\n     * @returns {boolean}\n     */\n    supportsVADDetection() {\n        return this.isChromiumBased();\n    }\n\n    /**\n     * Check if the browser supports the RTP RTX feature (and it is usable).\n     *\n     * @returns {boolean}\n     */\n    supportsRTX() {\n        // Disable RTX on Firefox up to 96 because we prefer simulcast over RTX\n        // see https://bugzilla.mozilla.org/show_bug.cgi?id=1738504\n        return !(this.isFirefox() && this.isVersionLessThan('96'));\n    }\n\n    /**\n     * Returns the version of a Chromium based browser.\n     *\n     * @returns {Number}\n     */\n    _getChromiumBasedVersion() {\n        if (this.isChromiumBased()) {\n            // NW.JS doesn't expose the Chrome version in the UA string.\n            if (this.isNWJS()) {\n                // eslint-disable-next-line no-undef\n                return Number.parseInt(process.versions.chromium, 10);\n            }\n\n            // Here we process all browsers which use the Chrome engine but\n            // don't necessarily identify as Chrome. We cannot use the version\n            // comparing functions because the Electron, Opera and NW.JS\n            // versions are inconsequential here, as we need to know the actual\n            // Chrome engine version.\n            const ua = navigator.userAgent;\n\n            if (ua.match(/Chrome/)) {\n                const version\n                    = Number.parseInt(ua.match(/Chrome\\/([\\d.]+)/)[1], 10);\n\n                return version;\n            }\n        }\n\n        return -1;\n    }\n\n    /**\n     * Returns the version of a Safari browser.\n     *\n     * @returns {Number}\n     */\n    _getSafariVersion() {\n        if (this.isSafari()) {\n            return Number.parseInt(this.getVersion(), 10);\n        }\n\n        return -1;\n    }\n\n    /**\n     * Returns the version of an ios browser.\n     *\n     * @returns {Number}\n     */\n    _getIOSVersion() {\n        if (this.isWebKitBased()) {\n            return Number.parseInt(this.getVersion(), 10);\n        }\n\n        return -1;\n    }\n}\n","import BrowserCapabilities from './BrowserCapabilities';\n\nexport default new BrowserCapabilities();\n","import { getLogger } from '@jitsi/logger';\n\nimport {\n    TYPE_OPERATIONAL,\n    TYPE_PAGE,\n    TYPE_TRACK,\n    TYPE_UI\n} from '../../service/statistics/AnalyticsEvents';\nimport browser from '../browser';\n\nconst MAX_CACHE_SIZE = 100;\n\n// eslist-disable-line no-undef\nconst logger = getLogger(__filename);\n\n/**\n * This class provides an API to lib-jitsi-meet and its users for sending\n * analytics events. It serves as a bridge to different backend implementations\n * (\"analytics handlers\") and a cache for events attempted to be sent before\n * the analytics handlers were enabled.\n *\n * The API is designed to be an easy replacement for the previous version of\n * this adapter, and is meant to be extended with more convenience methods.\n *\n *\n * The API calls are translated to objects with the following structure, which\n * are then passed to the sendEvent(event) function of the underlying handlers:\n *\n * {\n *    type,\n *\n *    action,\n *    actionSubject,\n *    actionSubjectId,\n *    attributes,\n *    categories,\n *    containerId,\n *    containerType,\n *    name,\n *    objectId,\n *    objectType,\n *    source,\n *    tags\n * }\n *\n * The 'type' is one of 'operational', 'page', 'track' or 'ui', and some of the\n * other properties are considered required according to the type.\n *\n * For events with type 'page', the required properties are: name.\n *\n * For events with type 'operational' and 'ui', the required properties are:\n * action, actionSubject, source\n *\n * For events with type 'page', the required properties are:\n * action, actionSubject, source, containerType, containerId, objectType,\n * objectId\n */\nclass AnalyticsAdapter {\n    /**\n     * Creates new AnalyticsAdapter instance.\n     */\n    constructor() {\n        this.reset();\n    }\n\n    /**\n     * Reset the state to the initial one.\n     *\n     * @returns {void}\n     */\n    reset() {\n        /**\n         * Whether this AnalyticsAdapter has been disposed of or not. Once this\n         * is set to true, the AnalyticsAdapter is disabled and does not accept\n         * any more events, and it can not be re-enabled.\n         * @type {boolean}\n         */\n        this.disposed = false;\n\n        /**\n         * The set of handlers to which events will be sent.\n         * @type {Set<any>}\n         */\n        this.analyticsHandlers = new Set();\n\n        /**\n         * The cache of events which are not sent yet. The cache is enabled\n         * while this field is truthy, and disabled otherwise.\n         * @type {Array}\n         */\n        this.cache = [];\n\n        /**\n         * Map of properties that will be added to every event. Note that the\n         * keys will be prefixed with \"permanent.\".\n         */\n        this.permanentProperties = {};\n\n        /**\n         * The name of the conference that this AnalyticsAdapter is associated\n         * with.\n         * @type {null}\n         */\n        this.conferenceName = '';\n\n        this.addPermanentProperties({\n            'user_agent': navigator.userAgent,\n            'browser_name': browser.getName()\n        });\n    }\n\n    /**\n     * Dispose analytics. Clears all handlers.\n     */\n    dispose() {\n        logger.warn('Disposing of analytics adapter.');\n\n        if (this.analyticsHandlers && this.analyticsHandlers.size > 0) {\n            this.analyticsHandlers.forEach(handler => {\n                if (typeof handler.dispose === 'function') {\n                    handler.dispose();\n                }\n            });\n        }\n\n        this.setAnalyticsHandlers([]);\n        this.disposed = true;\n    }\n\n    /**\n     * Sets the handlers that are going to be used to send analytics. Sends any\n     * cached events.\n     * @param {Array} handlers the handlers\n     */\n    setAnalyticsHandlers(handlers) {\n        if (this.disposed) {\n            return;\n        }\n\n        this.analyticsHandlers = new Set(handlers);\n\n        this._setUserProperties();\n\n        // Note that we disable the cache even if the set of handlers is empty.\n        const cache = this.cache;\n\n        this.cache = null;\n        if (cache) {\n            cache.forEach(event => this._sendEvent(event));\n        }\n    }\n\n    /**\n     * Set the user properties to the analytics handlers.\n     *\n     * @returns {void}\n     */\n    _setUserProperties() {\n        this.analyticsHandlers.forEach(handler => {\n            try {\n                handler.setUserProperties(this.permanentProperties);\n            } catch (error) {\n                logger.warn('Error in setUserProperties method of one of the '\n                    + `analytics handlers: ${error}`);\n            }\n        });\n    }\n\n    /**\n     * Adds a set of permanent properties to this this AnalyticsAdapter.\n     * Permanent properties will be added as \"attributes\" to events sent to\n     * the underlying \"analytics handlers\", and their keys will be prefixed\n     * by \"permanent_\", i.e. adding a permanent property {key: \"value\"} will\n     * result in {\"permanent_key\": \"value\"} object to be added to the\n     * \"attributes\" field of events.\n     *\n     * @param {Object} properties the properties to add\n     */\n    addPermanentProperties(properties) {\n        this.permanentProperties = {\n            ...this.permanentProperties,\n            ...properties\n        };\n\n        this._setUserProperties();\n    }\n\n    /**\n     * Sets the name of the conference that this AnalyticsAdapter is associated\n     * with.\n     * @param name the name to set.\n     */\n    setConferenceName(name) {\n        this.conferenceName = name;\n        this.addPermanentProperties({ 'conference_name': name });\n    }\n\n    /**\n     * Sends an event with a given name and given properties. The first\n     * parameter is either a string or an object. If it is a string, it is used\n     * as the event name and the second parameter is used at the attributes to\n     * attach to the event. If it is an object, it represents the whole event,\n     * including any desired attributes, and the second parameter is ignored.\n     *\n     * @param {String|Object} eventName either a string to be used as the name\n     * of the event, or an event object. If an event object is passed, the\n     * properties parameters is ignored.\n     * @param {Object} properties the properties/attributes to attach to the\n     * event, if eventName is a string.\n     */\n    sendEvent(eventName, properties = {}) {\n        if (this.disposed) {\n            return;\n        }\n\n        let event = null;\n\n        if (typeof eventName === 'string') {\n            event = {\n                type: TYPE_OPERATIONAL,\n                action: eventName,\n                actionSubject: eventName,\n                source: eventName,\n                attributes: properties\n            };\n        } else if (typeof eventName === 'object') {\n            event = eventName;\n        }\n\n        if (!this._verifyRequiredFields(event)) {\n            logger.error(\n                `Dropping a mis-formatted event: ${JSON.stringify(event)}`);\n\n            return;\n        }\n\n        this._sendEvent(event);\n    }\n\n    /**\n     * Checks whether an event has all of the required fields set, and tries\n     * to fill in some of the missing fields with reasonable default values.\n     * Returns true if after this operation the event has all of the required\n     * fields set, and false otherwise (if some of the required fields were not\n     * set and the attempt to fill them in with a default failed).\n     *\n     * @param event the event object.\n     * @return {boolean} true if the event (after the call to this function)\n     * contains all of the required fields, and false otherwise.\n     * @private\n     */\n    _verifyRequiredFields(event) {\n        if (!event) {\n            return false;\n        }\n\n        if (!event.type) {\n            event.type = TYPE_OPERATIONAL;\n        }\n\n        const type = event.type;\n\n        if (type !== TYPE_OPERATIONAL && type !== TYPE_PAGE\n            && type !== TYPE_UI && type !== TYPE_TRACK) {\n            logger.error(`Unknown event type: ${type}`);\n\n            return false;\n        }\n\n        if (type === TYPE_PAGE) {\n            return Boolean(event.name);\n        }\n\n        // Try to set some reasonable default values in case some of the\n        // parameters required by the handler API are missing.\n        event.action = event.action || event.name || event.actionSubject;\n        event.actionSubject = event.actionSubject || event.name || event.action;\n        event.source = event.source || event.name || event.action\n            || event.actionSubject;\n\n        if (!event.action || !event.actionSubject || !event.source) {\n            logger.error(\n                'Required field missing (action, actionSubject or source)');\n\n            return false;\n        }\n\n        // Track events have additional required fields.\n        if (type === TYPE_TRACK) {\n            event.objectType = event.objectType || 'generic-object-type';\n            event.containerType = event.containerType || 'conference';\n            if (event.containerType === 'conference' && !event.containerId) {\n                event.containerId = this.conferenceName;\n            }\n\n\n            if (!event.objectType || !event.objectId\n                || !event.containerType || !event.containerId) {\n                logger.error(\n                    'Required field missing (containerId, containerType, '\n                        + 'objectId or objectType)');\n\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * Saves an event to the cache, if the cache is enabled.\n     * @param event the event to save.\n     * @returns {boolean} true if the event was saved, and false otherwise (i.e.\n     * if the cache was disabled).\n     * @private\n     */\n    _maybeCacheEvent(event) {\n        if (this.cache) {\n            this.cache.push(event);\n\n            // We limit the size of the cache, in case the user fails to ever\n            // set the analytics handlers.\n            if (this.cache.length > MAX_CACHE_SIZE) {\n                this.cache.splice(0, 1);\n            }\n\n            return true;\n        }\n\n        return false;\n\n    }\n\n    /**\n     *\n     * @param event\n     * @private\n     */\n    _sendEvent(event) {\n        if (this._maybeCacheEvent(event)) {\n            // The event was consumed by the cache.\n        } else {\n            this.analyticsHandlers.forEach(handler => {\n                try {\n                    handler.sendEvent(event);\n                } catch (e) {\n                    logger.warn(`Error sending analytics event: ${e}`);\n                }\n            });\n        }\n    }\n}\n\nexport default new AnalyticsAdapter();\n","/* global callstats */\n\nimport browser from '../browser';\nimport GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';\n\nconst logger = require('@jitsi/logger').getLogger(__filename);\n\n/**\n * We define enumeration of wrtcFuncNames as we need them before\n * callstats is initialized to queue events.\n * @const\n * @see http://www.callstats.io/api/#enumeration-of-wrtcfuncnames\n */\nconst wrtcFuncNames = {\n    createOffer: 'createOffer',\n    createAnswer: 'createAnswer',\n    setLocalDescription: 'setLocalDescription',\n    setRemoteDescription: 'setRemoteDescription',\n    addIceCandidate: 'addIceCandidate',\n    getUserMedia: 'getUserMedia',\n    iceConnectionFailure: 'iceConnectionFailure',\n    signalingError: 'signalingError',\n    applicationLog: 'applicationLog'\n};\n\n/**\n * We define enumeration of fabricEvent as we need them before\n * callstats is initialized to queue events.\n * @const\n * @see http://www.callstats.io/api/#enumeration-of-fabricevent\n */\nconst fabricEvent = {\n    fabricHold: 'fabricHold',\n    fabricResume: 'fabricResume',\n    audioMute: 'audioMute',\n    audioUnmute: 'audioUnmute',\n    videoPause: 'videoPause',\n    videoResume: 'videoResume',\n    fabricUsageEvent: 'fabricUsageEvent',\n    fabricStats: 'fabricStats',\n    fabricTerminated: 'fabricTerminated',\n    screenShareStart: 'screenShareStart',\n    screenShareStop: 'screenShareStop',\n    dominantSpeaker: 'dominantSpeaker',\n    activeDeviceList: 'activeDeviceList'\n};\n\n/**\n * The user id to report to callstats as destination.\n * @type {string}\n */\nconst DEFAULT_REMOTE_USER = 'jitsi';\n\n/**\n * Type of pending reports, can be event or an error.\n * @type {{ERROR: string, EVENT: string}}\n */\nconst reportType = {\n    ERROR: 'error',\n    EVENT: 'event',\n    MST_WITH_USERID: 'mstWithUserID'\n};\n\n/**\n * Set of currently existing {@link CallStats} instances.\n * @type {Set<CallStats>}\n */\nlet _fabrics;\n\n/**\n * An instance of this class is a wrapper for the CallStats API fabric. A fabric\n * reports one peer connection to the CallStats backend and is allocated with\n * {@link callstats.addNewFabric}. It has a bunch of instance methods for\n * reporting various events. A fabric is considered disposed when\n * {@link CallStats.sendTerminateEvent} is executed.\n *\n * Currently only one backend instance can be created ever and it's done using\n * {@link CallStats.initBackend}. At the time of this writing there is no way to\n * explicitly shutdown the backend, but it's supposed to close it's connection\n * automatically, after all fabrics have been terminated.\n */\nexport default class CallStats {\n    /**\n     * A callback passed to {@link callstats.addNewFabric}.\n     * @param {string} error 'success' means ok\n     * @param {string} msg some more details\n     * @private\n     */\n    static _addNewFabricCallback(error, msg) {\n        if (CallStats.backend && error !== 'success') {\n            logger.error(`Monitoring status: ${error} msg: ${msg}`);\n        }\n    }\n\n    /**\n     * Callback passed to {@link callstats.initialize} (backend initialization)\n     * @param {string} error 'success' means ok\n     * @param {String} msg\n     * @private\n     */\n    static _initCallback(error, msg) {\n        logger.log(`CallStats Status: err=${error} msg=${msg}`);\n\n        // there is no lib, nothing to report to\n        if (error !== 'success') {\n            return;\n        }\n\n        CallStats.backendInitialized = true;\n\n        // I hate that\n        let atLeastOneFabric = false;\n        let defaultInstance = null;\n\n        for (const callStatsInstance of CallStats.fabrics.values()) {\n            if (!callStatsInstance.hasFabric) {\n                logger.debug('addNewFabric - initCallback');\n                if (callStatsInstance._addNewFabric()) {\n                    atLeastOneFabric = true;\n                    if (!defaultInstance) {\n                        defaultInstance = callStatsInstance;\n                    }\n                }\n            }\n        }\n\n        if (!atLeastOneFabric) {\n            return;\n        }\n\n        CallStats._emptyReportQueue(defaultInstance);\n    }\n\n    /**\n     * Empties report queue.\n     *\n     * @param {CallStats} csInstance - The callstats instance.\n     * @private\n     */\n    static _emptyReportQueue(csInstance) {\n        // There is no conference ID nor a PeerConnection available when some of\n        // the events are scheduled on the reportsQueue, so those will be\n        // reported on the first initialized fabric.\n        const defaultConfID = csInstance.confID;\n        const defaultPC = csInstance.peerconnection;\n\n        // notify callstats about failures if there were any\n        for (const report of CallStats.reportsQueue) {\n            if (report.type === reportType.ERROR) {\n                const errorData = report.data;\n\n                CallStats._reportError(\n                    csInstance,\n                    errorData.type,\n                    errorData.error,\n                    errorData.pc || defaultPC);\n            } else if (report.type === reportType.EVENT) {\n                // if we have and event to report and we failed to add\n                // fabric this event will not be reported anyway, returning\n                // an error\n                const eventData = report.data;\n\n                CallStats.backend.sendFabricEvent(\n                    report.pc || defaultPC,\n                    eventData.event,\n                    defaultConfID,\n                    eventData.eventData);\n            } else if (report.type === reportType.MST_WITH_USERID) {\n                const data = report.data;\n\n                CallStats.backend.associateMstWithUserID(\n                    report.pc || defaultPC,\n                    data.callStatsId,\n                    defaultConfID,\n                    data.ssrc,\n                    data.usageLabel,\n                    data.containerId\n                );\n            }\n        }\n        CallStats.reportsQueue.length = 0;\n    }\n\n    /* eslint-disable max-params */\n    /**\n     * Reports an error to callstats.\n     *\n     * @param {CallStats} [cs]\n     * @param type the type of the error, which will be one of the wrtcFuncNames\n     * @param error the error\n     * @param pc the peerconnection\n     * @private\n     */\n    static _reportError(cs, type, error, pc) {\n        let _error = error;\n\n        if (!_error) {\n            logger.warn('No error is passed!');\n            _error = new Error('Unknown error');\n        }\n        if (CallStats.backendInitialized && cs) {\n            CallStats.backend.reportError(pc, cs.confID, type, _error);\n        } else {\n            CallStats.reportsQueue.push({\n                type: reportType.ERROR,\n                data: {\n                    error: _error,\n                    pc,\n                    type\n                }\n            });\n        }\n\n        // else just ignore it\n    }\n\n    /* eslint-enable max-params */\n\n    /**\n     * Reports an error to callstats.\n     *\n     * @param {CallStats} cs\n     * @param event the type of the event, which will be one of the fabricEvent\n     * @param eventData additional data to pass to event\n     * @private\n     */\n    static _reportEvent(cs, event, eventData) {\n        const pc = cs && cs.peerconnection;\n        const confID = cs && cs.confID;\n\n        if (CallStats.backendInitialized && cs) {\n            CallStats.backend.sendFabricEvent(pc, event, confID, eventData);\n        } else {\n            CallStats.reportsQueue.push({\n                confID,\n                pc,\n                type: reportType.EVENT,\n                data: { event,\n                    eventData }\n            });\n        }\n    }\n\n    /**\n     * Wraps some of the CallStats API method and logs their calls with\n     * arguments on the debug logging level. Also wraps some of the backend\n     * methods execution into try catch blocks to not crash the app in case\n     * there is a problem with the backend itself.\n     * @param {callstats} theBackend\n     * @private\n     */\n    static _traceAndCatchBackendCalls(theBackend) {\n        const tryCatchMethods = [\n            'associateMstWithUserID',\n            'sendFabricEvent',\n            'sendUserFeedback'\n\n            // 'reportError', - this one needs special handling - see code below\n        ];\n\n        for (const methodName of tryCatchMethods) {\n            const originalMethod = theBackend[methodName];\n\n            theBackend[methodName] = function(...theArguments) {\n                try {\n                    return originalMethod.apply(theBackend, theArguments);\n                } catch (e) {\n                    GlobalOnErrorHandler.callErrorHandler(e);\n                }\n            };\n        }\n        const debugMethods = [\n            'associateMstWithUserID',\n            'sendFabricEvent',\n            'sendUserFeedback'\n\n            // 'reportError', - this one needs special handling - see code below\n        ];\n\n        for (const methodName of debugMethods) {\n            const originalMethod = theBackend[methodName];\n\n            theBackend[methodName] = function(...theArguments) {\n                logger.debug(methodName, theArguments);\n                originalMethod.apply(theBackend, theArguments);\n            };\n        }\n        const originalReportError = theBackend.reportError;\n\n        /* eslint-disable max-params */\n        theBackend.reportError = function(pc, cs, type, ...args) {\n            // Logs from the logger are submitted on the applicationLog event\n            // \"type\". Logging the arguments on the logger will create endless\n            // loop, because it will put all the logs to the logger queue again.\n            if (type === wrtcFuncNames.applicationLog) {\n                // NOTE otherArguments are not logged to the console on purpose\n                // to not log the whole log batch\n                // FIXME check the current logging level (currently not exposed\n                // by the logger implementation)\n                // NOTE it is not safe to log whole objects on react-native as\n                // those contain too many circular references and may crash\n                // the app.\n                if (!browser.isReactNative()) {\n                    console && console.debug('reportError', pc, cs, type);\n                }\n            } else {\n                logger.debug('reportError', pc, cs, type, ...args);\n            }\n            try {\n                originalReportError.call(theBackend, pc, cs, type, ...args);\n            } catch (exception) {\n                if (type === wrtcFuncNames.applicationLog) {\n                    console && console.error('reportError', exception);\n                } else {\n                    GlobalOnErrorHandler.callErrorHandler(exception);\n                }\n            }\n        };\n\n        /* eslint-enable max-params */\n    }\n\n    /**\n     * Returns the Set with the currently existing {@link CallStats} instances.\n     * Lazily initializes the Set to allow any Set polyfills to be applied.\n     * @type {Set<CallStats>}\n     */\n    static get fabrics() {\n        if (!_fabrics) {\n            _fabrics = new Set();\n        }\n\n        return _fabrics;\n    }\n\n    /**\n     * Initializes the CallStats backend. Should be called only if\n     * {@link CallStats.isBackendInitialized} returns <tt>false</tt>.\n     * @param {object} options\n     * @param {String} options.callStatsID CallStats credentials - ID\n     * @param {String} options.callStatsSecret CallStats credentials - secret\n     * @param {string} options.aliasName the <tt>aliasName</tt> part of\n     * the <tt>userID</tt> aka endpoint ID, see CallStats docs for more info.\n     * @param {string} options.userName the <tt>userName</tt> part of\n     * the <tt>userID</tt> aka display name, see CallStats docs for more info.\n     * @param {object} options.configParams the set of parameters\n     * to enable/disable certain features in the library. See CallStats docs for more info.\n     *\n     */\n    static initBackend(options) {\n        if (CallStats.backend) {\n            throw new Error('CallStats backend has been initialized already!');\n        }\n        try {\n            const CallStatsBackend = callstats;\n\n            CallStats.backend = new CallStatsBackend();\n            CallStats._traceAndCatchBackendCalls(CallStats.backend);\n            CallStats.userID = {\n                aliasName: options.aliasName,\n                userName: options.userName\n            };\n            CallStats.callStatsID = options.callStatsID;\n            CallStats.callStatsSecret = options.callStatsSecret;\n\n            const configParams = { ...options.configParams };\n\n            if (options.applicationName) {\n                configParams.applicationVersion = `${options.applicationName} (${browser.getName()})`;\n            }\n\n            if (options.confID) {\n                // we first check is there a tenant in the confID\n                const match = options.confID.match(/.*\\/(.*)\\/.*/);\n\n                // if there is no tenant, we will just set '/'\n                configParams.siteID = options.siteID || (match && match[1]) || '/';\n            }\n\n            // userID is generated or given by the origin server\n            CallStats.backend.initialize(\n                CallStats.callStatsID,\n                CallStats.callStatsSecret,\n                CallStats.userID,\n                CallStats._initCallback,\n                undefined,\n                configParams);\n\n            const getWiFiStatsMethod = options.getWiFiStatsMethod;\n\n            if (getWiFiStatsMethod) {\n                CallStats.backend.attachWifiStatsHandler(getWiFiStatsMethod);\n\n                getWiFiStatsMethod().then(result => {\n                    if (result) {\n                        logger.info('Reported wifi addresses:'\n                            , JSON.parse(result).addresses);\n                    }\n                })\n                .catch(() => {});// eslint-disable-line no-empty-function\n            }\n\n            return true;\n        } catch (e) {\n            // The callstats.io API failed to initialize (e.g. because its\n            // download did not succeed in general or on time). Further attempts\n            // to utilize it cannot possibly succeed.\n            GlobalOnErrorHandler.callErrorHandler(e);\n            CallStats.backend = null;\n            logger.error(e);\n\n            return false;\n        }\n    }\n\n    /**\n     * Checks if the CallStats backend has been created. It does not mean that\n     * it has been initialized, but only that the API instance has been\n     * allocated successfully.\n     * @return {boolean} <tt>true</tt> if backend exists or <tt>false</tt>\n     * otherwise\n     */\n    static isBackendInitialized() {\n        return Boolean(CallStats.backend);\n    }\n\n    /**\n     * Notifies CallStats about active device.\n     * @param {{deviceList: {String:String}}} devicesData list of devices with\n     * their data\n     * @param {CallStats} cs callstats instance related to the event\n     */\n    static sendActiveDeviceListEvent(devicesData, cs) {\n        CallStats._reportEvent(cs, fabricEvent.activeDeviceList, devicesData);\n    }\n\n    /**\n     * Notifies CallStats that there is a log we want to report.\n     *\n     * @param {Error} e error to send or {String} message\n     * @param {CallStats} cs callstats instance related to the error (optional)\n     */\n    static sendApplicationLog(e, cs) {\n        try {\n            CallStats._reportError(\n                cs,\n                wrtcFuncNames.applicationLog,\n                e,\n                cs && cs.peerconnection);\n        } catch (error) {\n            // If sendApplicationLog fails it should not be printed to\n            // the logger, because it will try to push the logs again\n            // (through sendApplicationLog) and an endless loop is created.\n            if (console && (typeof console.error === 'function')) {\n                // FIXME send analytics event as well\n                console.error('sendApplicationLog failed', error);\n            }\n        }\n    }\n\n    /**\n     * Sends the given feedback through CallStats.\n     *\n     * @param {string} conferenceID the conference ID for which the feedback\n     * will be reported.\n     * @param overall an integer between 1 and 5 indicating the\n     * user feedback\n     * @param comment detailed feedback from the user.\n     */\n    static sendFeedback(conferenceID, overall, comment) {\n        return new Promise((resolve, reject) => {\n            if (CallStats.backend) {\n                CallStats.backend.sendUserFeedback(\n                    conferenceID,\n                    {\n                        userID: CallStats.userID,\n                        overall,\n                        comment\n                    },\n                    (status, message) => {\n                        if (status === 'success') {\n                            resolve(message);\n                        } else {\n                            reject(message);\n                        }\n                    });\n            } else {\n                const reason = 'Failed to submit feedback to CallStats - no backend';\n\n                logger.error(reason);\n                reject(reason);\n            }\n        });\n    }\n\n    /**\n     * Notifies CallStats that getUserMedia failed.\n     *\n     * @param {Error} e error to send\n     * @param {CallStats} cs callstats instance related to the error (optional)\n     */\n    static sendGetUserMediaFailed(e, cs) {\n        CallStats._reportError(cs, wrtcFuncNames.getUserMedia, e, null);\n    }\n\n    /**\n     * Notifies CallStats for mute events\n     * @param mute {boolean} true for muted and false for not muted\n     * @param type {String} \"audio\"/\"video\"\n     * @param {CallStats} cs callstats instance related to the event\n     */\n    static sendMuteEvent(mute, type, cs) {\n        let event;\n\n        if (type === 'video') {\n            event = mute ? fabricEvent.videoPause : fabricEvent.videoResume;\n        } else {\n            event = mute ? fabricEvent.audioMute : fabricEvent.audioUnmute;\n        }\n\n        CallStats._reportEvent(cs, event);\n    }\n\n    /**\n     * Creates new CallStats instance that handles all callstats API calls for\n     * given {@link TraceablePeerConnection}. Each instance is meant to handle\n     * one CallStats fabric added with 'addFabric' API method for the\n     * {@link TraceablePeerConnection} instance passed in the constructor.\n     * @param {TraceablePeerConnection} tpc\n     * @param {Object} options\n     * @param {string} options.confID the conference ID that wil be used to\n     * report the session.\n     * @param {string} [options.remoteUserID='jitsi'] the remote user ID to\n     * which given <tt>tpc</tt> is connected.\n     */\n    constructor(tpc, options) {\n        this.confID = options.confID;\n        this.tpc = tpc;\n        this.peerconnection = tpc.peerconnection;\n        this.remoteUserID = options.remoteUserID || DEFAULT_REMOTE_USER;\n        this.hasFabric = false;\n\n        CallStats.fabrics.add(this);\n\n        if (CallStats.backendInitialized) {\n            this._addNewFabric();\n\n            // if this is the first fabric let's try to empty the\n            // report queue. Reports all events that we recorded between\n            // backend initialization and receiving the first fabric\n            if (CallStats.fabrics.size === 1) {\n                CallStats._emptyReportQueue(this);\n            }\n        }\n    }\n\n    /**\n     * Initializes CallStats fabric by calling \"addNewFabric\" for\n     * the peer connection associated with this instance.\n     * @return {boolean} true if the call was successful or false otherwise.\n     */\n    _addNewFabric() {\n        logger.info('addNewFabric', this.remoteUserID);\n        try {\n            const fabricAttributes = {\n                remoteEndpointType:\n                    this.tpc.isP2P\n                        ? CallStats.backend.endpointType.peer\n                        : CallStats.backend.endpointType.server\n            };\n            const ret\n                = CallStats.backend.addNewFabric(\n                    this.peerconnection,\n                    this.remoteUserID,\n                    CallStats.backend.fabricUsage.multiplex,\n                    this.confID,\n                    fabricAttributes,\n                    CallStats._addNewFabricCallback);\n\n            this.hasFabric = true;\n\n            const success = ret.status === 'success';\n\n            if (!success) {\n                logger.error('callstats fabric not initilized', ret.message);\n            }\n\n            return success;\n\n        } catch (error) {\n            GlobalOnErrorHandler.callErrorHandler(error);\n\n            return false;\n        }\n    }\n\n    /* eslint-disable max-params */\n\n    /**\n     * Lets CallStats module know where is given SSRC rendered by providing\n     * renderer tag ID.\n     * If the lib is not initialized yet queue the call for later, when it's\n     * ready.\n     * @param {number} ssrc the SSRC of the stream\n     * @param {boolean} isLocal indicates whether this the stream is local\n     * @param {string|null} streamEndpointId if the stream is not local the it\n     * needs to contain the stream owner's ID\n     * @param {string} usageLabel meaningful usage label of this stream like\n     *        'microphone', 'camera' or 'screen'.\n     * @param {string} containerId  the id of media 'audio' or 'video' tag which\n     *        renders the stream.\n     */\n    associateStreamWithVideoTag(\n            ssrc,\n            isLocal,\n            streamEndpointId,\n            usageLabel,\n            containerId) {\n        if (!CallStats.backend) {\n            return;\n        }\n\n        const callStatsId = isLocal ? CallStats.userID : streamEndpointId;\n\n        if (CallStats.backendInitialized) {\n            CallStats.backend.associateMstWithUserID(\n                this.peerconnection,\n                callStatsId,\n                this.confID,\n                ssrc,\n                usageLabel,\n                containerId);\n        } else {\n            CallStats.reportsQueue.push({\n                type: reportType.MST_WITH_USERID,\n                pc: this.peerconnection,\n                data: {\n                    callStatsId,\n                    containerId,\n                    ssrc,\n                    usageLabel\n                }\n            });\n        }\n    }\n\n    /* eslint-enable max-params */\n\n    /**\n     * Notifies CallStats that we are the new dominant speaker in the\n     * conference.\n     */\n    sendDominantSpeakerEvent() {\n        CallStats._reportEvent(this, fabricEvent.dominantSpeaker);\n    }\n\n    /**\n     * Notifies CallStats that the fabric for the underlying peerconnection was\n     * closed and no evens should be reported, after this call.\n     */\n    sendTerminateEvent() {\n        if (CallStats.backendInitialized) {\n            CallStats.backend.sendFabricEvent(\n                this.peerconnection,\n                CallStats.backend.fabricEvent.fabricTerminated,\n                this.confID);\n        }\n        CallStats.fabrics.delete(this);\n    }\n\n    /**\n     * Notifies CallStats for ice connection failed\n     */\n    sendIceConnectionFailedEvent() {\n        CallStats._reportError(\n            this,\n            wrtcFuncNames.iceConnectionFailure,\n            null,\n            this.peerconnection);\n    }\n\n    /**\n     * Notifies CallStats that peer connection failed to create offer.\n     *\n     * @param {Error} e error to send\n     */\n    sendCreateOfferFailed(e) {\n        CallStats._reportError(\n            this, wrtcFuncNames.createOffer, e, this.peerconnection);\n    }\n\n    /**\n     * Notifies CallStats that peer connection failed to create answer.\n     *\n     * @param {Error} e error to send\n     */\n    sendCreateAnswerFailed(e) {\n        CallStats._reportError(\n            this, wrtcFuncNames.createAnswer, e, this.peerconnection);\n    }\n\n    /**\n     * Sends either resume or hold event for the fabric associated with\n     * the underlying peerconnection.\n     * @param {boolean} isResume true to resume or false to hold\n     */\n    sendResumeOrHoldEvent(isResume) {\n        CallStats._reportEvent(\n            this,\n            isResume ? fabricEvent.fabricResume : fabricEvent.fabricHold);\n    }\n\n    /**\n     * Notifies CallStats for screen sharing events\n     * @param {boolean} start true for starting screen sharing and\n     * false for not stopping\n     * @param {string|null} ssrc - optional ssrc value, used only when\n     * starting screen sharing.\n     */\n    sendScreenSharingEvent(start, ssrc) {\n        let eventData;\n\n        if (ssrc) {\n            eventData = { ssrc };\n        }\n\n        CallStats._reportEvent(\n            this,\n            start ? fabricEvent.screenShareStart : fabricEvent.screenShareStop,\n            eventData);\n    }\n\n    /**\n     * Notifies CallStats that peer connection failed to set local description.\n     *\n     * @param {Error} e error to send\n     */\n    sendSetLocalDescFailed(e) {\n        CallStats._reportError(\n            this, wrtcFuncNames.setLocalDescription, e, this.peerconnection);\n    }\n\n    /**\n     * Notifies CallStats that peer connection failed to set remote description.\n     *\n     * @param {Error} e error to send\n     */\n    sendSetRemoteDescFailed(e) {\n        CallStats._reportError(\n            this, wrtcFuncNames.setRemoteDescription, e, this.peerconnection);\n    }\n\n    /**\n     * Notifies CallStats that peer connection failed to add ICE candidate.\n     *\n     * @param {Error} e error to send\n     */\n    sendAddIceCandidateFailed(e) {\n        CallStats._reportError(\n            this, wrtcFuncNames.addIceCandidate, e, this.peerconnection);\n    }\n}\n\n/**\n * The CallStats API backend instance\n * @type {callstats}\n */\nCallStats.backend = null;\n\n// some errors/events may happen before CallStats init\n// in this case we accumulate them in this array\n// and send them to callstats on init\nCallStats.reportsQueue = [];\n\n/**\n * Whether the library was successfully initialized(the backend) using its\n * initialize method.\n * @type {boolean}\n */\nCallStats.backendInitialized = false;\n\n/**\n * Part of the CallStats credentials - application ID\n * @type {string}\n */\nCallStats.callStatsID = null;\n\n/**\n * Part of the CallStats credentials - application secret\n * @type {string}\n */\nCallStats.callStatsSecret = null;\n\n/**\n * Local CallStats user ID structure. Can be set only once when\n * {@link backend} is initialized, so it's static for the time being.\n * See CallStats API for more info:\n * https://www.callstats.io/api/#userid\n * @type {object}\n */\nCallStats.userID = null;\n","/**\n * Provides statistics for the local stream.\n */\n\n/**\n * Size of the webaudio analyzer buffer.\n * @type {number}\n */\nconst WEBAUDIO_ANALYZER_FFT_SIZE = 2048;\n\n/**\n * Value of the webaudio analyzer smoothing time parameter.\n * @type {number}\n */\nconst WEBAUDIO_ANALYZER_SMOOTING_TIME = 0.8;\n\nwindow.AudioContext = window.AudioContext || window.webkitAudioContext;\n\nlet context = null;\n\nif (window.AudioContext) {\n    context = new AudioContext();\n\n    // XXX Not all browsers define a suspend method on AudioContext. As the\n    // invocation is at the (ES6 module) global execution level, it breaks the\n    // loading of the lib-jitsi-meet library in such browsers and, consequently,\n    // the loading of the very Web app that uses the lib-jitsi-meet library. For\n    // example, Google Chrome 40 on Android does not define the method but we\n    // still want to be able to load the lib-jitsi-meet library there and\n    // display a page which notifies the user that the Web app is not supported\n    // there.\n    context.suspend && context.suspend();\n}\n\n/**\n * Converts time domain data array to audio level.\n * @param samples the time domain data array.\n * @returns {number} the audio level\n */\nfunction timeDomainDataToAudioLevel(samples) {\n\n    let maxVolume = 0;\n\n    const length = samples.length;\n\n    for (let i = 0; i < length; i++) {\n        if (maxVolume < samples[i]) {\n            maxVolume = samples[i];\n        }\n    }\n\n    return parseFloat(((maxVolume - 127) / 128).toFixed(3));\n}\n\n/**\n * Animates audio level change\n * @param newLevel the new audio level\n * @param lastLevel the last audio level\n * @returns {Number} the audio level to be set\n */\nfunction animateLevel(newLevel, lastLevel) {\n    let value = 0;\n    const diff = lastLevel - newLevel;\n\n    if (diff > 0.2) {\n        value = lastLevel - 0.2;\n    } else if (diff < -0.4) {\n        value = lastLevel + 0.4;\n    } else {\n        value = newLevel;\n    }\n\n    return parseFloat(value.toFixed(3));\n}\n\n\n/**\n * <tt>LocalStatsCollector</tt> calculates statistics for the local stream.\n *\n * @param stream the local stream\n * @param interval stats refresh interval given in ms.\n * @param callback function that receives the audio levels.\n * @constructor\n */\nexport default function LocalStatsCollector(stream, interval, callback) {\n    this.stream = stream;\n    this.intervalId = null;\n    this.intervalMilis = interval;\n    this.audioLevel = 0;\n    this.callback = callback;\n}\n\n/**\n * Starts the collecting the statistics.\n */\nLocalStatsCollector.prototype.start = function() {\n    if (!LocalStatsCollector.isLocalStatsSupported()) {\n        return;\n    }\n    context.resume();\n    const analyser = context.createAnalyser();\n\n    analyser.smoothingTimeConstant = WEBAUDIO_ANALYZER_SMOOTING_TIME;\n    analyser.fftSize = WEBAUDIO_ANALYZER_FFT_SIZE;\n\n    const source = context.createMediaStreamSource(this.stream);\n\n    source.connect(analyser);\n\n    this.intervalId = setInterval(\n        () => {\n            const array = new Uint8Array(analyser.frequencyBinCount);\n\n            analyser.getByteTimeDomainData(array);\n            const audioLevel = timeDomainDataToAudioLevel(array);\n\n            // Set the audio levels always as NoAudioSignalDetection now\n            // uses audio levels from LocalStatsCollector and waits for\n            // atleast 4 secs for a no audio signal before displaying the\n            // notification on the UI.\n            this.audioLevel = animateLevel(audioLevel, this.audioLevel);\n            this.callback(this.audioLevel);\n        },\n        this.intervalMilis\n    );\n};\n\n/**\n * Stops collecting the statistics.\n */\nLocalStatsCollector.prototype.stop = function() {\n    if (this.intervalId) {\n        clearInterval(this.intervalId);\n        this.intervalId = null;\n    }\n};\n\n/**\n * Checks if the environment has the necessary conditions to support\n * collecting stats from local streams.\n *\n * @returns {boolean}\n */\nLocalStatsCollector.isLocalStatsSupported = function() {\n    return Boolean(context);\n};\n","\n/**\n * The method will increase the given number by 1. If the given counter is equal\n * or greater to {@link Number.MAX_SAFE_INTEGER} then it will be rolled back to\n * 1.\n * @param {number} number - An integer counter value to be incremented.\n * @return {number} the next counter value increased by 1 (see the description\n * above for exception).\n */\nexport function safeCounterIncrement(number) {\n    let nextValue = number;\n\n    if (number >= Number.MAX_SAFE_INTEGER) {\n        nextValue = 0;\n    }\n\n    return nextValue + 1;\n}\n\n/**\n * Calculates the average value of am Array of numbers.\n *\n * @param {Float32Array} valueArray - Array of numbers.\n * @returns {number} - Number array average.\n */\nexport function calculateAverage(valueArray) {\n    return valueArray.length > 0 ? valueArray.reduce((a, b) => a + b) / valueArray.length : 0;\n}\n\n/**\n * Calculates a unique hash for a given string similar to Java's\n * implementation of String.hashCode()\n *\n * @param {String} string - String whose hash has to be calculated.\n * @returns {number} - Unique hash code calculated.\n */\nexport function hashString(string) {\n    let hash = 0;\n\n    for (let i = 0; i < string.length; i++) {\n        hash += Math.pow(string.charCodeAt(i) * 31, string.length - i);\n\n        /* eslint-disable no-bitwise */\n        hash = hash & hash; // Convert to 32bit integer\n    }\n\n    return Math.abs(hash);\n}\n\n/**\n * Returns only the positive values from an array of numbers.\n *\n * @param {Float32Array} valueArray - Array of vad scores.\n * @returns {Array} - Array of positive numbers.\n */\nexport function filterPositiveValues(valueArray) {\n    return valueArray.filter(value => value >= 0);\n}\n\n/**\n * This class calculates a simple running average that continually changes\n * as more data points are collected and added.\n */\nexport class RunningAverage {\n    /**\n     * Creates an instance of the running average calculator.\n     */\n    constructor() {\n        this.average = 0;\n        this.n = 0;\n    }\n\n    /**\n     * Adds a new data point to the existing set of values and recomputes\n     * the running average.\n     * @param {number} value\n     * @returns {void}\n     */\n    addNext(value) {\n        if (typeof value !== 'number') {\n            return;\n        }\n        this.n += 1;\n        this.average = this.average + ((value - this.average) / this.n);\n    }\n\n    /**\n     * Obtains the average value for the current subset of values.\n     * @returns {number} - computed average.\n     */\n    getAverage() {\n        return this.average;\n    }\n}\n","\nimport { getLogger } from '@jitsi/logger';\n\nimport * as StatisticsEvents from '../../service/statistics/Events';\nimport { RunningAverage } from '../util/MathUtil';\n\nconst logger = getLogger(__filename);\nconst MILLI_SECONDS = 1000;\nconst SECONDS = 60;\n\n/**\n * This class creates an observer that monitors browser's performance measurement events\n * as they are recorded in the browser's performance timeline and computes an average and\n * a maximum value for the long task events. Tasks are classified as long tasks if they take\n * longer than 50ms to execute on the main thread.\n */\nexport class PerformanceObserverStats {\n    /**\n     * Creates a new instance of Performance observer statistics.\n     *\n     * @param {*} emitter Event emitter for emitting stats periodically\n     * @param {*} statsInterval interval for calculating the stats\n     */\n    constructor(emitter, statsInterval) {\n        this.eventEmitter = emitter;\n        this.longTasks = 0;\n        this.maxDuration = 0;\n        this.performanceStatsInterval = statsInterval;\n        this.stats = new RunningAverage();\n    }\n\n    /**\n     * Obtains the average rate of long tasks observed per min and the\n     * duration of the longest task recorded by the observer.\n     * @returns {Object}\n     */\n    getLongTasksStats() {\n        return {\n            avgRatePerMinute: (this.stats.getAverage() * SECONDS).toFixed(2), // calc rate per min\n            maxDurationMs: this.maxDuration\n        };\n    }\n\n    /**\n     * Starts the performance observer by registering the callback function\n     * that calculates the performance statistics periodically.\n     * @returns {void}\n     */\n    startObserver() {\n        // Create a handler for when the long task event is fired.\n        this.longTaskEventHandler = list => {\n            const entries = list.getEntries();\n\n            for (const task of entries) {\n                this.longTasks++;\n                this.maxDuration = Math.max(this.maxDuration, task.duration).toFixed(3);\n            }\n        };\n\n        // Create an observer for monitoring long tasks.\n        logger.info('Creating a Performance Observer for monitoring Long Tasks');\n        this.observer = new PerformanceObserver(this.longTaskEventHandler);\n        this.observer.observe({ type: 'longtask',\n            buffered: true });\n        const startTime = Date.now();\n\n        // Calculate the average # of events/sec and emit a stats event.\n        this.longTasksIntervalId = setInterval(() => {\n            const now = Date.now();\n            const interval = this._lastTimeStamp\n                ? (now - this._lastTimeStamp) / MILLI_SECONDS\n                : (now - startTime) / MILLI_SECONDS;\n            const rate = this.longTasks / interval;\n\n            this.stats.addNext(rate);\n            this.eventEmitter.emit(\n                StatisticsEvents.LONG_TASKS_STATS, this.getLongTasksStats());\n\n            // Reset the counter and start counting events again.\n            this.longTasks = 0;\n            this._lastTimeStamp = Date.now();\n        }, this.performanceStatsInterval);\n    }\n\n    /**\n     * Stops the performance observer.\n     * @returns {void}\n     */\n    stopObserver() {\n        this.observer && this.observer.disconnect();\n        this.longTaskEventHandler = null;\n        if (this.longTasksIntervalId) {\n            clearInterval(this.longTasksIntervalId);\n            this.longTasksIntervalId = null;\n        }\n    }\n}\n","export enum MediaType {\n    /**\n     * The audio type.\n     */\n    AUDIO = 'audio',\n\n    /**\n     * The presenter type.\n     */\n    PRESENTER = 'presenter',\n\n    /**\n     * The video type.\n     */\n    VIDEO = 'video'\n}\n","import { getLogger } from '@jitsi/logger';\n\nimport { MediaType } from '../../service/RTC/MediaType';\nimport * as StatisticsEvents from '../../service/statistics/Events';\nimport browser from '../browser';\n\nconst GlobalOnErrorHandler = require('../util/GlobalOnErrorHandler');\n\nconst logger = getLogger(__filename);\n\n/**\n * Calculates packet lost percent using the number of lost packets and the\n * number of all packet.\n * @param lostPackets the number of lost packets\n * @param totalPackets the number of all packets.\n * @returns {number} packet loss percent\n */\nfunction calculatePacketLoss(lostPackets, totalPackets) {\n    if (!totalPackets || totalPackets <= 0\n            || !lostPackets || lostPackets <= 0) {\n        return 0;\n    }\n\n    return Math.round((lostPackets / totalPackets) * 100);\n}\n\n/**\n * Holds \"statistics\" for a single SSRC.\n * @constructor\n */\nfunction SsrcStats() {\n    this.loss = {};\n    this.bitrate = {\n        download: 0,\n        upload: 0\n    };\n    this.resolution = {};\n    this.framerate = 0;\n    this.codec = '';\n}\n\n/**\n * Sets the \"loss\" object.\n * @param loss the value to set.\n */\nSsrcStats.prototype.setLoss = function(loss) {\n    this.loss = loss || {};\n};\n\n/**\n * Sets resolution that belong to the ssrc represented by this instance.\n * @param resolution new resolution value to be set.\n */\nSsrcStats.prototype.setResolution = function(resolution) {\n    this.resolution = resolution || {};\n};\n\n/**\n * Adds the \"download\" and \"upload\" fields from the \"bitrate\" parameter to\n * the respective fields of the \"bitrate\" field of this object.\n * @param bitrate an object holding the values to add.\n */\nSsrcStats.prototype.addBitrate = function(bitrate) {\n    this.bitrate.download += bitrate.download;\n    this.bitrate.upload += bitrate.upload;\n};\n\n/**\n * Resets the bit rate for given <tt>ssrc</tt> that belong to the peer\n * represented by this instance.\n */\nSsrcStats.prototype.resetBitrate = function() {\n    this.bitrate.download = 0;\n    this.bitrate.upload = 0;\n};\n\n/**\n * Sets the \"framerate\".\n * @param framerate the value to set.\n */\nSsrcStats.prototype.setFramerate = function(framerate) {\n    this.framerate = framerate || 0;\n};\n\nSsrcStats.prototype.setCodec = function(codec) {\n    this.codec = codec || '';\n};\n\n/**\n *\n */\nfunction ConferenceStats() {\n\n    /**\n     * The bandwidth\n     * @type {{}}\n     */\n    this.bandwidth = {};\n\n    /**\n     * The bit rate\n     * @type {{}}\n     */\n    this.bitrate = {};\n\n    /**\n     * The packet loss rate\n     * @type {{}}\n     */\n    this.packetLoss = null;\n\n    /**\n     * Array with the transport information.\n     * @type {Array}\n     */\n    this.transport = [];\n}\n\n/* eslint-disable max-params */\n\n/**\n * <tt>StatsCollector</tt> registers for stats updates of given\n * <tt>peerconnection</tt> in given <tt>interval</tt>. On each update particular\n * stats are extracted and put in {@link SsrcStats} objects. Once the processing\n * is done <tt>audioLevelsUpdateCallback</tt> is called with <tt>this</tt>\n * instance as an event source.\n *\n * @param peerconnection WebRTC PeerConnection object.\n * @param audioLevelsInterval\n * @param statsInterval stats refresh interval given in ms.\n * @param eventEmitter\n * @constructor\n */\nexport default function StatsCollector(peerconnection, audioLevelsInterval, statsInterval, eventEmitter) {\n    this.peerconnection = peerconnection;\n    this.baselineAudioLevelsReport = null;\n    this.currentAudioLevelsReport = null;\n    this.currentStatsReport = null;\n    this.previousStatsReport = null;\n    this.audioLevelReportHistory = {};\n    this.audioLevelsIntervalId = null;\n    this.eventEmitter = eventEmitter;\n    this.conferenceStats = new ConferenceStats();\n\n    // Updates stats interval\n    this.audioLevelsIntervalMilis = audioLevelsInterval;\n\n    this.speakerList = [];\n    this.statsIntervalId = null;\n    this.statsIntervalMilis = statsInterval;\n\n    /**\n     * Maps SSRC numbers to {@link SsrcStats}.\n     * @type {Map<number,SsrcStats}\n     */\n    this.ssrc2stats = new Map();\n}\n\n/**\n * Set the list of the remote speakers for which audio levels are to be calculated.\n *\n * @param {Array<string>} speakerList - Endpoint ids.\n * @returns {void}\n */\nStatsCollector.prototype.setSpeakerList = function(speakerList) {\n    this.speakerList = speakerList;\n};\n\n/**\n * Stops stats updates.\n */\nStatsCollector.prototype.stop = function() {\n    if (this.audioLevelsIntervalId) {\n        clearInterval(this.audioLevelsIntervalId);\n        this.audioLevelsIntervalId = null;\n    }\n\n    if (this.statsIntervalId) {\n        clearInterval(this.statsIntervalId);\n        this.statsIntervalId = null;\n    }\n};\n\n/**\n * Callback passed to <tt>getStats</tt> method.\n * @param error an error that occurred on <tt>getStats</tt> call.\n */\nStatsCollector.prototype.errorCallback = function(error) {\n    GlobalOnErrorHandler.callErrorHandler(error);\n    logger.error('Get stats error', error);\n    this.stop();\n};\n\n/**\n * Starts stats updates.\n */\nStatsCollector.prototype.start = function(startAudioLevelStats) {\n    if (startAudioLevelStats) {\n        if (browser.supportsReceiverStats()) {\n            logger.info('Using RTCRtpSynchronizationSource for remote audio levels');\n        }\n        this.audioLevelsIntervalId = setInterval(\n            () => {\n                if (browser.supportsReceiverStats()) {\n                    const audioLevels = this.peerconnection.getAudioLevels(this.speakerList);\n\n                    for (const ssrc in audioLevels) {\n                        if (audioLevels.hasOwnProperty(ssrc)) {\n                            // Use a scaling factor of 2.5 to report the same\n                            // audio levels that getStats reports.\n                            const audioLevel = audioLevels[ssrc] * 2.5;\n\n                            this.eventEmitter.emit(\n                                StatisticsEvents.AUDIO_LEVEL,\n                                this.peerconnection,\n                                Number.parseInt(ssrc, 10),\n                                audioLevel,\n                                false /* isLocal */);\n                        }\n                    }\n                } else {\n                    // Interval updates\n                    this.peerconnection.getStats()\n                        .then(report => {\n                            this.currentAudioLevelsReport = typeof report?.result === 'function'\n                                ? report.result()\n                                : report;\n                            this.processAudioLevelReport();\n                            this.baselineAudioLevelsReport = this.currentAudioLevelsReport;\n                        })\n                        .catch(error => this.errorCallback(error));\n                }\n            },\n            this.audioLevelsIntervalMilis\n        );\n    }\n\n    const processStats = () => {\n        // Interval updates\n        this.peerconnection.getStats()\n            .then(report => {\n                this.currentStatsReport = typeof report?.result === 'function'\n                    ? report.result()\n                    : report;\n\n                try {\n                    this.processStatsReport();\n                } catch (error) {\n                    GlobalOnErrorHandler.callErrorHandler(error);\n                    logger.error('Processing of RTP stats failed:', error);\n                }\n                this.previousStatsReport = this.currentStatsReport;\n            })\n            .catch(error => this.errorCallback(error));\n    };\n\n    processStats();\n    this.statsIntervalId = setInterval(processStats, this.statsIntervalMilis);\n};\n\n/**\n *\n */\nStatsCollector.prototype._processAndEmitReport = function() {\n    // process stats\n    const totalPackets = {\n        download: 0,\n        upload: 0\n    };\n    const lostPackets = {\n        download: 0,\n        upload: 0\n    };\n    let bitrateDownload = 0;\n    let bitrateUpload = 0;\n    const resolutions = {};\n    const framerates = {};\n    const codecs = {};\n    let audioBitrateDownload = 0;\n    let audioBitrateUpload = 0;\n    let audioCodec;\n    let videoBitrateDownload = 0;\n    let videoBitrateUpload = 0;\n    let videoCodec;\n\n    for (const [ ssrc, ssrcStats ] of this.ssrc2stats) {\n        // process packet loss stats\n        const loss = ssrcStats.loss;\n        const type = loss.isDownloadStream ? 'download' : 'upload';\n\n        totalPackets[type] += loss.packetsTotal;\n        lostPackets[type] += loss.packetsLost;\n\n        // process bitrate stats\n        bitrateDownload += ssrcStats.bitrate.download;\n        bitrateUpload += ssrcStats.bitrate.upload;\n\n        // collect resolutions and framerates\n        const track = this.peerconnection.getTrackBySSRC(ssrc);\n\n        if (track) {\n            if (track.isAudioTrack()) {\n                audioBitrateDownload += ssrcStats.bitrate.download;\n                audioBitrateUpload += ssrcStats.bitrate.upload;\n                audioCodec = ssrcStats.codec;\n            } else {\n                videoBitrateDownload += ssrcStats.bitrate.download;\n                videoBitrateUpload += ssrcStats.bitrate.upload;\n                videoCodec = ssrcStats.codec;\n            }\n\n            const participantId = track.getParticipantId();\n\n            if (participantId) {\n                const resolution = ssrcStats.resolution;\n\n                if (resolution.width\n                        && resolution.height\n                        && resolution.width !== -1\n                        && resolution.height !== -1) {\n                    const userResolutions = resolutions[participantId] || {};\n\n                    userResolutions[ssrc] = resolution;\n                    resolutions[participantId] = userResolutions;\n                }\n                if (ssrcStats.framerate !== 0) {\n                    const userFramerates = framerates[participantId] || {};\n\n                    userFramerates[ssrc] = ssrcStats.framerate;\n                    framerates[participantId] = userFramerates;\n                }\n                if (audioCodec && videoCodec) {\n                    const codecDesc = {\n                        'audio': audioCodec,\n                        'video': videoCodec\n                    };\n\n                    const userCodecs = codecs[participantId] || {};\n\n                    userCodecs[ssrc] = codecDesc;\n                    codecs[participantId] = userCodecs;\n                }\n            } else {\n                logger.error(`No participant ID returned by ${track}`);\n            }\n        }\n\n        ssrcStats.resetBitrate();\n    }\n\n    this.conferenceStats.bitrate = {\n        'upload': bitrateUpload,\n        'download': bitrateDownload\n    };\n\n    this.conferenceStats.bitrate.audio = {\n        'upload': audioBitrateUpload,\n        'download': audioBitrateDownload\n    };\n\n    this.conferenceStats.bitrate.video = {\n        'upload': videoBitrateUpload,\n        'download': videoBitrateDownload\n    };\n\n    this.conferenceStats.packetLoss = {\n        total:\n            calculatePacketLoss(\n                lostPackets.download + lostPackets.upload,\n                totalPackets.download + totalPackets.upload),\n        download:\n            calculatePacketLoss(lostPackets.download, totalPackets.download),\n        upload:\n            calculatePacketLoss(lostPackets.upload, totalPackets.upload)\n    };\n\n    const avgAudioLevels = {};\n    let localAvgAudioLevels;\n\n    Object.keys(this.audioLevelReportHistory).forEach(ssrc => {\n        const { data, isLocal } = this.audioLevelReportHistory[ssrc];\n        const avgAudioLevel = data.reduce((sum, currentValue) => sum + currentValue) / data.length;\n\n        if (isLocal) {\n            localAvgAudioLevels = avgAudioLevel;\n        } else {\n            const track = this.peerconnection.getTrackBySSRC(Number(ssrc));\n\n            if (track) {\n                const participantId = track.getParticipantId();\n\n                if (participantId) {\n                    avgAudioLevels[participantId] = avgAudioLevel;\n                }\n            }\n        }\n    });\n    this.audioLevelReportHistory = {};\n\n    this.eventEmitter.emit(\n        StatisticsEvents.CONNECTION_STATS,\n        this.peerconnection,\n        {\n            'bandwidth': this.conferenceStats.bandwidth,\n            'bitrate': this.conferenceStats.bitrate,\n            'packetLoss': this.conferenceStats.packetLoss,\n            'resolution': resolutions,\n            'framerate': framerates,\n            'codec': codecs,\n            'transport': this.conferenceStats.transport,\n            localAvgAudioLevels,\n            avgAudioLevels\n        });\n    this.conferenceStats.transport = [];\n};\n\n/**\n * Converts the value to a non-negative number.\n * If the value is either invalid or negative then 0 will be returned.\n * @param {*} v\n * @return {number}\n * @private\n */\nStatsCollector.prototype.getNonNegativeValue = function(v) {\n    let value = v;\n\n    if (typeof value !== 'number') {\n        value = Number(value);\n    }\n\n    if (isNaN(value)) {\n        return 0;\n    }\n\n    return Math.max(0, value);\n};\n\n/**\n * Calculates bitrate between before and now using a supplied field name and its\n * value in the stats.\n * @param {RTCInboundRtpStreamStats|RTCSentRtpStreamStats} now the current stats\n * @param {RTCInboundRtpStreamStats|RTCSentRtpStreamStats} before the\n * previous stats.\n * @param fieldName the field to use for calculations.\n * @return {number} the calculated bitrate between now and before.\n * @private\n */\nStatsCollector.prototype._calculateBitrate = function(now, before, fieldName) {\n    const bytesNow = this.getNonNegativeValue(now[fieldName]);\n    const bytesBefore = this.getNonNegativeValue(before[fieldName]);\n    const bytesProcessed = Math.max(0, bytesNow - bytesBefore);\n\n    const timeMs = now.timestamp - before.timestamp;\n    let bitrateKbps = 0;\n\n    if (timeMs > 0) {\n        // TODO is there any reason to round here?\n        bitrateKbps = Math.round((bytesProcessed * 8) / timeMs);\n    }\n\n    return bitrateKbps;\n};\n\n/**\n * Stats processing for spec-compliant RTCPeerConnection#getStats.\n */\nStatsCollector.prototype.processStatsReport = function() {\n    if (!this.previousStatsReport) {\n        return;\n    }\n    const byteSentStats = {};\n\n    this.currentStatsReport.forEach(now => {\n        // RTCIceCandidatePairStats - https://w3c.github.io/webrtc-stats/#candidatepair-dict*\n        if (now.type === 'candidate-pair' && now.nominated && now.state === 'succeeded') {\n            const availableIncomingBitrate = now.availableIncomingBitrate;\n            const availableOutgoingBitrate = now.availableOutgoingBitrate;\n\n            if (availableIncomingBitrate || availableOutgoingBitrate) {\n                this.conferenceStats.bandwidth = {\n                    'download': Math.round(availableIncomingBitrate / 1000),\n                    'upload': Math.round(availableOutgoingBitrate / 1000)\n                };\n            }\n\n            const remoteUsedCandidate = this.currentStatsReport.get(now.remoteCandidateId);\n            const localUsedCandidate = this.currentStatsReport.get(now.localCandidateId);\n\n            // RTCIceCandidateStats\n            // https://w3c.github.io/webrtc-stats/#icecandidate-dict*\n            if (remoteUsedCandidate && localUsedCandidate) {\n                const remoteIpAddress = browser.isChromiumBased()\n                    ? remoteUsedCandidate.ip\n                    : remoteUsedCandidate.address;\n                const remotePort = remoteUsedCandidate.port;\n                const ip = `${remoteIpAddress}:${remotePort}`;\n\n                const localIpAddress = browser.isChromiumBased()\n                    ? localUsedCandidate.ip\n                    : localUsedCandidate.address;\n                const localPort = localUsedCandidate.port;\n                const localip = `${localIpAddress}:${localPort}`;\n                const type = remoteUsedCandidate.protocol;\n\n                // Save the address unless it has been saved already.\n                const conferenceStatsTransport = this.conferenceStats.transport;\n\n                if (!conferenceStatsTransport.some(t =>\n                    t.ip === ip\n                    && t.type === type\n                    && t.localip === localip)) {\n                    conferenceStatsTransport.push({\n                        ip,\n                        type,\n                        localip,\n                        p2p: this.peerconnection.isP2P,\n                        localCandidateType: localUsedCandidate.candidateType,\n                        remoteCandidateType: remoteUsedCandidate.candidateType,\n                        networkType: localUsedCandidate.networkType,\n                        rtt: now.currentRoundTripTime * 1000\n                    });\n                }\n            }\n\n        // RTCReceivedRtpStreamStats\n        // https://w3c.github.io/webrtc-stats/#receivedrtpstats-dict*\n        // RTCSentRtpStreamStats\n        // https://w3c.github.io/webrtc-stats/#sentrtpstats-dict*\n        } else if (now.type === 'inbound-rtp' || now.type === 'outbound-rtp') {\n            const before = this.previousStatsReport.get(now.id);\n            const ssrc = this.getNonNegativeValue(now.ssrc);\n\n            if (!before || !ssrc) {\n                return;\n            }\n\n            let ssrcStats = this.ssrc2stats.get(ssrc);\n\n            if (!ssrcStats) {\n                ssrcStats = new SsrcStats();\n                this.ssrc2stats.set(ssrc, ssrcStats);\n            }\n\n            let isDownloadStream = true;\n            let key = 'packetsReceived';\n\n            if (now.type === 'outbound-rtp') {\n                isDownloadStream = false;\n                key = 'packetsSent';\n            }\n\n            let packetsNow = now[key];\n\n            if (!packetsNow || packetsNow < 0) {\n                packetsNow = 0;\n            }\n\n            const packetsBefore = this.getNonNegativeValue(before[key]);\n            const packetsDiff = Math.max(0, packetsNow - packetsBefore);\n\n            const packetsLostNow = this.getNonNegativeValue(now.packetsLost);\n            const packetsLostBefore = this.getNonNegativeValue(before.packetsLost);\n            const packetsLostDiff = Math.max(0, packetsLostNow - packetsLostBefore);\n\n            ssrcStats.setLoss({\n                packetsTotal: packetsDiff + packetsLostDiff,\n                packetsLost: packetsLostDiff,\n                isDownloadStream\n            });\n\n            // Get the resolution and framerate for only remote video sources here. For the local video sources,\n            // 'track' stats will be used since they have the updated resolution based on the simulcast streams\n            // currently being sent. Promise based getStats reports three 'outbound-rtp' streams and there will be\n            // more calculations needed to determine what is the highest resolution stream sent by the client if the\n            // 'outbound-rtp' stats are used.\n            if (now.type === 'inbound-rtp') {\n                const resolution = {\n                    height: now.frameHeight,\n                    width: now.frameWidth\n                };\n                const frameRate = now.framesPerSecond;\n\n                if (resolution.height && resolution.width) {\n                    ssrcStats.setResolution(resolution);\n                }\n                ssrcStats.setFramerate(Math.round(frameRate || 0));\n\n                ssrcStats.addBitrate({\n                    'download': this._calculateBitrate(now, before, 'bytesReceived'),\n                    'upload': 0\n                });\n            } else {\n                byteSentStats[ssrc] = this.getNonNegativeValue(now.bytesSent);\n                ssrcStats.addBitrate({\n                    'download': 0,\n                    'upload': this._calculateBitrate(now, before, 'bytesSent')\n                });\n            }\n\n            const codec = this.currentStatsReport.get(now.codecId);\n\n            if (codec) {\n                /**\n                 * The mime type has the following form: video/VP8 or audio/ISAC,\n                 * so we what to keep just the type after the '/', audio and video\n                 * keys will be added on the processing side.\n                 */\n                const codecShortType = codec.mimeType.split('/')[1];\n\n                codecShortType && ssrcStats.setCodec(codecShortType);\n            }\n\n        // Use track stats for resolution and framerate of the local video source.\n        // RTCVideoHandlerStats - https://w3c.github.io/webrtc-stats/#vststats-dict*\n        // RTCMediaHandlerStats - https://w3c.github.io/webrtc-stats/#mststats-dict*\n        } else if (now.type === 'track' && now.kind === MediaType.VIDEO && !now.remoteSource) {\n            const resolution = {\n                height: now.frameHeight,\n                width: now.frameWidth\n            };\n            const localVideoTracks = this.peerconnection.getLocalTracks(MediaType.VIDEO);\n\n            if (!localVideoTracks?.length) {\n                return;\n            }\n\n            const ssrc = this.peerconnection.getLocalSSRC(localVideoTracks[0]);\n\n            if (!ssrc) {\n                return;\n            }\n            let ssrcStats = this.ssrc2stats.get(ssrc);\n\n            if (!ssrcStats) {\n                ssrcStats = new SsrcStats();\n                this.ssrc2stats.set(ssrc, ssrcStats);\n            }\n            if (resolution.height && resolution.width) {\n                ssrcStats.setResolution(resolution);\n            }\n\n            // Calculate the frame rate. 'framesSent' is the total aggregate value for all the simulcast streams.\n            // Therefore, it needs to be divided by the total number of active simulcast streams.\n            let frameRate = now.framesPerSecond;\n\n            if (!frameRate) {\n                const before = this.previousStatsReport.get(now.id);\n\n                if (before) {\n                    const timeMs = now.timestamp - before.timestamp;\n\n                    if (timeMs > 0 && now.framesSent) {\n                        const numberOfFramesSinceBefore = now.framesSent - before.framesSent;\n\n                        frameRate = (numberOfFramesSinceBefore / timeMs) * 1000;\n                    }\n                }\n\n                if (!frameRate) {\n                    return;\n                }\n            }\n\n            // Get the number of simulcast streams currently enabled from TPC.\n            const numberOfActiveStreams = this.peerconnection.getActiveSimulcastStreams();\n\n            // Reset frame rate to 0 when video is suspended as a result of endpoint falling out of last-n.\n            frameRate = numberOfActiveStreams ? Math.round(frameRate / numberOfActiveStreams) : 0;\n            ssrcStats.setFramerate(frameRate);\n        }\n    });\n\n    this.eventEmitter.emit(StatisticsEvents.BYTE_SENT_STATS, this.peerconnection, byteSentStats);\n    this._processAndEmitReport();\n};\n\n/**\n * Stats processing logic.\n */\nStatsCollector.prototype.processAudioLevelReport = function() {\n    if (!this.baselineAudioLevelsReport) {\n        return;\n    }\n\n    this.currentAudioLevelsReport.forEach(now => {\n        if (now.type !== 'track') {\n            return;\n        }\n\n        // Audio level\n        const audioLevel = now.audioLevel;\n\n        if (!audioLevel) {\n            return;\n        }\n\n        const trackIdentifier = now.trackIdentifier;\n        const ssrc = this.peerconnection.getSsrcByTrackId(trackIdentifier);\n\n        if (ssrc) {\n            const isLocal\n                = ssrc === this.peerconnection.getLocalSSRC(\n                this.peerconnection.getLocalTracks(MediaType.AUDIO));\n\n            this.eventEmitter.emit(\n                StatisticsEvents.AUDIO_LEVEL,\n                this.peerconnection,\n                ssrc,\n                audioLevel,\n                isLocal);\n        }\n    });\n};\n\n","import EventEmitter from 'events';\n\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\nimport JitsiTrackError from '../../JitsiTrackError';\nimport { FEEDBACK } from '../../service/statistics/AnalyticsEvents';\nimport * as StatisticsEvents from '../../service/statistics/Events';\nimport browser from '../browser';\nimport ScriptUtil from '../util/ScriptUtil';\n\nimport analytics from './AnalyticsAdapter';\nimport CallStats from './CallStats';\nimport LocalStats from './LocalStatsCollector';\nimport { PerformanceObserverStats } from './PerformanceObserverStats';\nimport RTPStats from './RTPStatsCollector';\nimport { CALLSTATS_SCRIPT_URL } from './constants';\n\nconst logger = require('@jitsi/logger').getLogger(__filename);\n\n/**\n * Stores all active {@link Statistics} instances.\n * @type {Set<Statistics>}\n */\nlet _instances;\n\n/**\n * True if callstats API is loaded\n */\nlet isCallstatsLoaded = false;\n\n/**\n * Since callstats.io is a third party, we cannot guarantee the quality of their\n * service. More specifically, their server may take noticeably long time to\n * respond. Consequently, it is in our best interest (in the sense that the\n * intergration of callstats.io is pretty important to us but not enough to\n * allow it to prevent people from joining a conference) to (1) start\n * downloading their API as soon as possible and (2) do the downloading\n * asynchronously.\n *\n * @param {StatisticsOptions} options - Options to use for downloading and\n * initializing callstats backend.\n */\nfunction loadCallStatsAPI(options) {\n    if (!isCallstatsLoaded) {\n        ScriptUtil.loadScript(\n            options.customScriptUrl || CALLSTATS_SCRIPT_URL,\n            /* async */ true,\n            /* prepend */ true,\n            /* relativeURL */ undefined,\n            /* loadCallback */ () => _initCallStatsBackend(options)\n        );\n        isCallstatsLoaded = true;\n    }\n}\n\n/**\n * Initializes Callstats backend.\n *\n * @param {StatisticsOptions} options - The options to use for initializing\n * callstats backend.\n * @private\n */\nfunction _initCallStatsBackend(options) {\n    if (CallStats.isBackendInitialized()) {\n        return;\n    }\n\n    if (!CallStats.initBackend({\n        callStatsID: options.callStatsID,\n        callStatsSecret: options.callStatsSecret,\n        userName: options.userName,\n        aliasName: options.aliasName,\n        applicationName: options.applicationName,\n        getWiFiStatsMethod: options.getWiFiStatsMethod,\n        confID: options.confID,\n        siteID: options.siteID,\n        configParams: options.configParams\n    })) {\n        logger.error('CallStats Backend initialization failed bad');\n    }\n}\n\n/**\n * callstats strips any additional fields from Error except for \"name\", \"stack\",\n * \"message\" and \"constraintName\". So we need to bundle additional information\n * from JitsiTrackError into error passed to callstats to preserve valuable\n * information about error.\n * @param {JitsiTrackError} error\n */\nfunction formatJitsiTrackErrorForCallStats(error) {\n    const err = new Error();\n\n    // Just copy original stack from error\n    err.stack = error.stack;\n\n    // Combine name from error's name plus (possibly) name of original GUM error\n    err.name = (error.name || 'Unknown error') + (error.gum && error.gum.error\n        && error.gum.error.name ? ` - ${error.gum.error.name}` : '');\n\n    // Put all constraints into this field. For constraint failed errors we will\n    // still know which exactly constraint failed as it will be a part of\n    // message.\n    err.constraintName = error.gum && error.gum.constraints\n        ? JSON.stringify(error.gum.constraints) : '';\n\n    // Just copy error's message.\n    err.message = error.message;\n\n    return err;\n}\n\n/**\n * Init statistic options\n * @param options\n */\nStatistics.init = function(options) {\n    Statistics.audioLevelsEnabled = !options.disableAudioLevels;\n    if (typeof options.pcStatsInterval === 'number') {\n        Statistics.pcStatsInterval = options.pcStatsInterval;\n    }\n\n    if (typeof options.audioLevelsInterval === 'number') {\n        Statistics.audioLevelsInterval = options.audioLevelsInterval;\n    }\n\n    if (typeof options.longTasksStatsInterval === 'number') {\n        Statistics.longTasksStatsInterval = options.longTasksStatsInterval;\n    }\n\n    Statistics.disableThirdPartyRequests = options.disableThirdPartyRequests;\n};\n\n/**\n * The options to configure Statistics.\n * @typedef {Object} StatisticsOptions\n * @property {string} applicationName - The application name to pass to\n * callstats.\n * @property {string} aliasName - The alias name to use when initializing callstats.\n * @property {string} userName - The user name to use when initializing callstats.\n * @property {string} confID - The callstats conference ID to use.\n * @property {string} callStatsID - Callstats credentials - the id.\n * @property {string} callStatsSecret - Callstats credentials - the secret.\n * @property {string} customScriptUrl - A custom lib url to use when downloading\n * callstats library.\n * @property {string} roomName - The room name we are currently in.\n * @property {string} configParams - The set of parameters\n * to enable/disable certain features in the library. See CallStats docs for more info.\n */\n/**\n *\n * @param xmpp\n * @param {StatisticsOptions} options - The options to use creating the\n * Statistics.\n */\nexport default function Statistics(xmpp, options) {\n    /**\n     * {@link RTPStats} mapped by {@link TraceablePeerConnection.id} which\n     * collect RTP statistics for each peerconnection.\n     * @type {Map<string, RTPStats}\n     */\n    this.rtpStatsMap = new Map();\n    this.eventEmitter = new EventEmitter();\n    this.xmpp = xmpp;\n    this.options = options || {};\n\n    this.callStatsIntegrationEnabled\n        = this.options.callStatsID && this.options.callStatsSecret && this.options.enableCallStats\n\n            // Even though AppID and AppSecret may be specified, the integration\n            // of callstats.io may be disabled because of globally-disallowed\n            // requests to any third parties.\n            && (Statistics.disableThirdPartyRequests !== true);\n    if (this.callStatsIntegrationEnabled) {\n        this.callStatsApplicationLogsDisabled\n            = this.options.callStatsApplicationLogsDisabled;\n        if (browser.isReactNative()) {\n            _initCallStatsBackend(this.options);\n        } else {\n            loadCallStatsAPI(this.options);\n        }\n\n        if (!this.options.confID) {\n            logger.warn('\"confID\" is not defined');\n        }\n    }\n\n    /**\n     * Stores {@link CallStats} instances for each\n     * {@link TraceablePeerConnection} (one {@link CallStats} instance serves\n     * one TPC). The instances are mapped by {@link TraceablePeerConnection.id}.\n     * @type {Map<number, CallStats>}\n     */\n    this.callsStatsInstances = new Map();\n\n    Statistics.instances.add(this);\n}\nStatistics.audioLevelsEnabled = false;\nStatistics.audioLevelsInterval = 200;\nStatistics.pcStatsInterval = 10000;\nStatistics.disableThirdPartyRequests = false;\nStatistics.analytics = analytics;\n\nObject.defineProperty(Statistics, 'instances', {\n    /**\n     * Returns the Set holding all active {@link Statistics} instances. Lazily\n     * initializes the Set to allow any Set polyfills to be applied.\n     * @type {Set<Statistics>}\n     */\n    get() {\n        if (!_instances) {\n            _instances = new Set();\n        }\n\n        return _instances;\n    }\n});\n\n/**\n * Starts collecting RTP stats for given peerconnection.\n * @param {TraceablePeerConnection} peerconnection\n */\nStatistics.prototype.startRemoteStats = function(peerconnection) {\n    this.stopRemoteStats(peerconnection);\n\n    try {\n        const rtpStats\n            = new RTPStats(\n                peerconnection,\n                Statistics.audioLevelsInterval,\n                Statistics.pcStatsInterval,\n                this.eventEmitter);\n\n        rtpStats.start(Statistics.audioLevelsEnabled);\n        this.rtpStatsMap.set(peerconnection.id, rtpStats);\n    } catch (e) {\n        logger.error(`Failed to start collecting remote statistics: ${e}`);\n    }\n};\n\nStatistics.localStats = [];\n\nStatistics.startLocalStats = function(stream, callback) {\n    if (!Statistics.audioLevelsEnabled) {\n        return;\n    }\n    const localStats = new LocalStats(stream, Statistics.audioLevelsInterval,\n        callback);\n\n    this.localStats.push(localStats);\n    localStats.start();\n};\n\nStatistics.prototype.addAudioLevelListener = function(listener) {\n    if (!Statistics.audioLevelsEnabled) {\n        return;\n    }\n    this.eventEmitter.on(StatisticsEvents.AUDIO_LEVEL, listener);\n};\n\nStatistics.prototype.removeAudioLevelListener = function(listener) {\n    if (!Statistics.audioLevelsEnabled) {\n        return;\n    }\n    this.eventEmitter.removeListener(StatisticsEvents.AUDIO_LEVEL, listener);\n};\n\nStatistics.prototype.addBeforeDisposedListener = function(listener) {\n    this.eventEmitter.on(StatisticsEvents.BEFORE_DISPOSED, listener);\n};\n\nStatistics.prototype.removeBeforeDisposedListener = function(listener) {\n    this.eventEmitter.removeListener(\n        StatisticsEvents.BEFORE_DISPOSED, listener);\n};\n\nStatistics.prototype.addConnectionStatsListener = function(listener) {\n    this.eventEmitter.on(StatisticsEvents.CONNECTION_STATS, listener);\n};\n\nStatistics.prototype.removeConnectionStatsListener = function(listener) {\n    this.eventEmitter.removeListener(\n        StatisticsEvents.CONNECTION_STATS,\n        listener);\n};\n\nStatistics.prototype.addByteSentStatsListener = function(listener) {\n    this.eventEmitter.on(StatisticsEvents.BYTE_SENT_STATS, listener);\n};\n\nStatistics.prototype.removeByteSentStatsListener = function(listener) {\n    this.eventEmitter.removeListener(StatisticsEvents.BYTE_SENT_STATS,\n        listener);\n};\n\n/**\n * Add a listener that would be notified on a LONG_TASKS_STATS event.\n *\n * @param {Function} listener a function that would be called when notified.\n * @returns {void}\n */\nStatistics.prototype.addLongTasksStatsListener = function(listener) {\n    this.eventEmitter.on(StatisticsEvents.LONG_TASKS_STATS, listener);\n};\n\n/**\n * Creates an instance of {@link PerformanceObserverStats} and starts the\n * observer that records the stats periodically.\n *\n * @returns {void}\n */\nStatistics.prototype.attachLongTasksStats = function(conference) {\n    if (!browser.supportsPerformanceObserver()) {\n        logger.warn('Performance observer for long tasks not supported by browser!');\n\n        return;\n    }\n\n    this.performanceObserverStats = new PerformanceObserverStats(\n        this.eventEmitter,\n        Statistics.longTasksStatsInterval);\n\n    conference.on(\n        JitsiConferenceEvents.CONFERENCE_JOINED,\n        () => this.performanceObserverStats.startObserver());\n    conference.on(\n        JitsiConferenceEvents.CONFERENCE_LEFT,\n        () => this.performanceObserverStats.stopObserver());\n};\n\n/**\n * Obtains the current value of the LongTasks event statistics.\n *\n * @returns {Object|null} stats object if the observer has been\n * created, null otherwise.\n */\nStatistics.prototype.getLongTasksStats = function() {\n    return this.performanceObserverStats\n        ? this.performanceObserverStats.getLongTasksStats()\n        : null;\n};\n\n/**\n * Removes the given listener for the LONG_TASKS_STATS event.\n *\n * @param {Function} listener the listener we want to remove.\n * @returns {void}\n */\nStatistics.prototype.removeLongTasksStatsListener = function(listener) {\n    this.eventEmitter.removeListener(StatisticsEvents.LONG_TASKS_STATS, listener);\n};\n\n/**\n * Updates the list of speakers for which the audio levels are to be calculated. This is needed for the jvb pc only.\n *\n * @param {Array<string>} speakerList The list of remote endpoint ids.\n * @returns {void}\n */\nStatistics.prototype.setSpeakerList = function(speakerList) {\n    for (const rtpStats of Array.from(this.rtpStatsMap.values())) {\n        if (!rtpStats.peerconnection.isP2P) {\n            rtpStats.setSpeakerList(speakerList);\n        }\n    }\n};\n\nStatistics.prototype.dispose = function() {\n    try {\n        // NOTE Before reading this please see the comment in stopCallStats...\n        //\n        // Here we prevent from emitting the event twice in case it will be\n        // triggered from stopCallStats.\n        // If the event is triggered from here it means that the logs will not\n        // be submitted anyway (because there is no CallStats instance), but\n        // we're doing that for the sake of some kind of consistency.\n        if (!this.callsStatsInstances.size) {\n            this.eventEmitter.emit(StatisticsEvents.BEFORE_DISPOSED);\n        }\n        for (const callStats of this.callsStatsInstances.values()) {\n            this.stopCallStats(callStats.tpc);\n        }\n        for (const tpcId of this.rtpStatsMap.keys()) {\n            this._stopRemoteStats(tpcId);\n        }\n        if (this.eventEmitter) {\n            this.eventEmitter.removeAllListeners();\n        }\n    } finally {\n        Statistics.instances.delete(this);\n    }\n};\n\nStatistics.stopLocalStats = function(stream) {\n    if (!Statistics.audioLevelsEnabled) {\n        return;\n    }\n\n    for (let i = 0; i < Statistics.localStats.length; i++) {\n        if (Statistics.localStats[i].stream === stream) {\n            const localStats = Statistics.localStats.splice(i, 1);\n\n            localStats[0].stop();\n            break;\n        }\n    }\n};\n\n/**\n * Stops remote RTP stats for given peerconnection ID.\n * @param {string} tpcId {@link TraceablePeerConnection.id}\n * @private\n */\nStatistics.prototype._stopRemoteStats = function(tpcId) {\n    const rtpStats = this.rtpStatsMap.get(tpcId);\n\n    if (rtpStats) {\n        rtpStats.stop();\n        this.rtpStatsMap.delete(tpcId);\n    }\n};\n\n/**\n * Stops collecting RTP stats for given peerconnection\n * @param {TraceablePeerConnection} tpc\n */\nStatistics.prototype.stopRemoteStats = function(tpc) {\n    this._stopRemoteStats(tpc.id);\n};\n\n// CALSTATS METHODS\n\n/**\n * Initializes the callstats.io API.\n * @param {TraceablePeerConnection} tpc the {@link TraceablePeerConnection}\n * instance for which CalStats will be started.\n * @param {string} remoteUserID\n */\nStatistics.prototype.startCallStats = function(tpc, remoteUserID) {\n    if (!this.callStatsIntegrationEnabled) {\n        return;\n    } else if (this.callsStatsInstances.has(tpc.id)) {\n        logger.error('CallStats instance for ${tpc} exists already');\n\n        return;\n    }\n\n    logger.info(`Starting CallStats for ${tpc}...`);\n\n    const newInstance\n        = new CallStats(\n            tpc,\n            {\n                confID: this.options.confID,\n                remoteUserID\n            });\n\n    this.callsStatsInstances.set(tpc.id, newInstance);\n};\n\n/**\n * Obtains the list of *all* {@link CallStats} instances collected from every\n * valid {@link Statistics} instance.\n * @return {Set<CallStats>}\n * @private\n */\nStatistics._getAllCallStatsInstances = function() {\n    const csInstances = new Set();\n\n    for (const statistics of Statistics.instances) {\n        for (const cs of statistics.callsStatsInstances.values()) {\n            csInstances.add(cs);\n        }\n    }\n\n    return csInstances;\n};\n\n/**\n * Removes the callstats.io instances.\n */\nStatistics.prototype.stopCallStats = function(tpc) {\n    const callStatsInstance = this.callsStatsInstances.get(tpc.id);\n\n    if (callStatsInstance) {\n        // FIXME the original purpose of adding BEFORE_DISPOSED event was to be\n        // able to submit the last log batch from jitsi-meet to CallStats. After\n        // recent changes we dispose the CallStats earlier\n        // (before Statistics.dispose), so we need to emit this event here to\n        // give this last chance for final log batch submission.\n        //\n        // Eventually there should be a separate module called \"log storage\"\n        // which should emit proper events when it's underlying\n        // CallStats instance is going away.\n        if (this.callsStatsInstances.size === 1) {\n            this.eventEmitter.emit(StatisticsEvents.BEFORE_DISPOSED);\n        }\n        this.callsStatsInstances.delete(tpc.id);\n\n        // The fabric needs to be terminated when being stopped\n        callStatsInstance.sendTerminateEvent();\n    }\n};\n\n/**\n * Returns true if the callstats integration is enabled, otherwise returns\n * false.\n *\n * @returns true if the callstats integration is enabled, otherwise returns\n * false.\n */\nStatistics.prototype.isCallstatsEnabled = function() {\n    return this.callStatsIntegrationEnabled;\n};\n\n/**\n * Logs either resume or hold event for the given peer connection.\n * @param {TraceablePeerConnection} tpc the connection for which event will be\n * reported\n * @param {boolean} isResume true for resume or false for hold\n */\nStatistics.prototype.sendConnectionResumeOrHoldEvent = function(tpc, isResume) {\n    const instance = this.callsStatsInstances.get(tpc.id);\n\n    if (instance) {\n        instance.sendResumeOrHoldEvent(isResume);\n    }\n};\n\n/**\n * Notifies CallStats and analytics (if present) for ice connection failed\n * @param {TraceablePeerConnection} tpc connection on which failure occurred.\n */\nStatistics.prototype.sendIceConnectionFailedEvent = function(tpc) {\n    const instance = this.callsStatsInstances.get(tpc.id);\n\n    if (instance) {\n        instance.sendIceConnectionFailedEvent();\n    }\n};\n\n/**\n * Notifies CallStats for mute events\n * @param {TraceablePeerConnection} tpc connection on which failure occurred.\n * @param {boolean} muted true for muted and false for not muted\n * @param {String} type \"audio\"/\"video\"\n */\nStatistics.prototype.sendMuteEvent = function(tpc, muted, type) {\n    const instance = tpc && this.callsStatsInstances.get(tpc.id);\n\n    CallStats.sendMuteEvent(muted, type, instance);\n};\n\n/**\n * Notifies CallStats for screen sharing events\n * @param start {boolean} true for starting screen sharing and\n * false for not stopping\n * @param {string|null} ssrc - optional ssrc value, used only when\n * starting screen sharing.\n */\nStatistics.prototype.sendScreenSharingEvent\n    = function(start, ssrc) {\n        for (const cs of this.callsStatsInstances.values()) {\n            cs.sendScreenSharingEvent(start, ssrc);\n        }\n    };\n\n/**\n * Notifies the statistics module that we are now the dominant speaker of the\n * conference.\n * @param {String} roomJid - The room jid where the speaker event occurred.\n */\nStatistics.prototype.sendDominantSpeakerEvent = function(roomJid) {\n    for (const cs of this.callsStatsInstances.values()) {\n        cs.sendDominantSpeakerEvent();\n    }\n\n    // xmpp send dominant speaker event\n    this.xmpp.sendDominantSpeakerEvent(roomJid);\n};\n\n/**\n * Notifies about active device.\n * @param {{deviceList: {String:String}}} devicesData - list of devices with\n *      their data\n */\nStatistics.sendActiveDeviceListEvent = function(devicesData) {\n    const globalSet = Statistics._getAllCallStatsInstances();\n\n    if (globalSet.size) {\n        for (const cs of globalSet) {\n            CallStats.sendActiveDeviceListEvent(devicesData, cs);\n        }\n    } else {\n        CallStats.sendActiveDeviceListEvent(devicesData, null);\n    }\n};\n\n/* eslint-disable max-params */\n\n/**\n * Lets the underlying statistics module know where is given SSRC rendered by\n * providing renderer tag ID.\n * @param {TraceablePeerConnection} tpc the connection to which the stream\n * belongs to\n * @param {number} ssrc the SSRC of the stream\n * @param {boolean} isLocal\n * @param {string} userId\n * @param {string} usageLabel  meaningful usage label of this stream like\n *        'microphone', 'camera' or 'screen'.\n * @param {string} containerId the id of media 'audio' or 'video' tag which\n *        renders the stream.\n */\nStatistics.prototype.associateStreamWithVideoTag = function(\n        tpc,\n        ssrc,\n        isLocal,\n        userId,\n        usageLabel,\n        containerId) {\n    const instance = this.callsStatsInstances.get(tpc.id);\n\n    if (instance) {\n        instance.associateStreamWithVideoTag(\n            ssrc,\n            isLocal,\n            userId,\n            usageLabel,\n            containerId);\n    }\n};\n\n/* eslint-enable max-params */\n\n/**\n * Notifies CallStats that getUserMedia failed.\n *\n * @param {Error} e error to send\n */\nStatistics.sendGetUserMediaFailed = function(e) {\n    const error\n        = e instanceof JitsiTrackError\n            ? formatJitsiTrackErrorForCallStats(e) : e;\n    const globalSet = Statistics._getAllCallStatsInstances();\n\n    if (globalSet.size) {\n        for (const cs of globalSet) {\n            CallStats.sendGetUserMediaFailed(error, cs);\n        }\n    } else {\n        CallStats.sendGetUserMediaFailed(error, null);\n    }\n};\n\n/**\n * Notifies CallStats that peer connection failed to create offer.\n *\n * @param {Error} e error to send\n * @param {TraceablePeerConnection} tpc connection on which failure occurred.\n */\nStatistics.prototype.sendCreateOfferFailed = function(e, tpc) {\n    const instance = this.callsStatsInstances.get(tpc.id);\n\n    if (instance) {\n        instance.sendCreateOfferFailed(e);\n    }\n};\n\n/**\n * Notifies CallStats that peer connection failed to create answer.\n *\n * @param {Error} e error to send\n * @param {TraceablePeerConnection} tpc connection on which failure occured.\n */\nStatistics.prototype.sendCreateAnswerFailed = function(e, tpc) {\n    const instance = this.callsStatsInstances.get(tpc.id);\n\n    if (instance) {\n        instance.sendCreateAnswerFailed(e);\n    }\n};\n\n/**\n * Notifies CallStats that peer connection failed to set local description.\n *\n * @param {Error} e error to send\n * @param {TraceablePeerConnection} tpc connection on which failure occurred.\n */\nStatistics.prototype.sendSetLocalDescFailed = function(e, tpc) {\n    const instance = this.callsStatsInstances.get(tpc.id);\n\n    if (instance) {\n        instance.sendSetLocalDescFailed(e);\n    }\n};\n\n/**\n * Notifies CallStats that peer connection failed to set remote description.\n *\n * @param {Error} e error to send\n * @param {TraceablePeerConnection} tpc connection on which failure occurred.\n */\nStatistics.prototype.sendSetRemoteDescFailed = function(e, tpc) {\n    const instance = this.callsStatsInstances.get(tpc.id);\n\n    if (instance) {\n        instance.sendSetRemoteDescFailed(e);\n    }\n};\n\n/**\n * Notifies CallStats that peer connection failed to add ICE candidate.\n *\n * @param {Error} e error to send\n * @param {TraceablePeerConnection} tpc connection on which failure occurred.\n */\nStatistics.prototype.sendAddIceCandidateFailed = function(e, tpc) {\n    const instance = this.callsStatsInstances.get(tpc.id);\n\n    if (instance) {\n        instance.sendAddIceCandidateFailed(e);\n    }\n};\n\n/**\n * Adds to CallStats an application log.\n *\n * @param {String} m a log message to send or an {Error} object to be reported\n */\nStatistics.sendLog = function(m) {\n    const globalSubSet = new Set();\n\n    // FIXME we don't want to duplicate logs over P2P instance, but\n    // here we should go over instances and call this method for each\n    // unique conference ID rather than selecting the first one.\n    // We don't have such use case though, so leaving as is for now.\n    for (const stats of Statistics.instances) {\n        if (stats.callStatsApplicationLogsDisabled) {\n            return;\n        }\n\n        if (stats.callsStatsInstances.size) {\n            globalSubSet.add(stats.callsStatsInstances.values().next().value);\n        }\n    }\n\n    if (globalSubSet.size) {\n        for (const csPerStats of globalSubSet) {\n            CallStats.sendApplicationLog(m, csPerStats);\n        }\n    } else {\n        CallStats.sendApplicationLog(m, null);\n    }\n};\n\n/**\n * Sends the given feedback through CallStats.\n *\n * @param overall an integer between 1 and 5 indicating the user's rating.\n * @param comment the comment from the user.\n * @returns {Promise} Resolves when callstats feedback has been submitted\n * successfully.\n */\nStatistics.prototype.sendFeedback = function(overall, comment) {\n    // Statistics.analytics.sendEvent is currently fire and forget, without\n    // confirmation of successful send.\n    Statistics.analytics.sendEvent(\n        FEEDBACK,\n        {\n            rating: overall,\n            comment\n        });\n\n    return CallStats.sendFeedback(this.options.confID, overall, comment);\n};\n\nStatistics.LOCAL_JID = require('../../service/statistics/constants').LOCAL_JID;\n\n/**\n * Reports global error to CallStats.\n *\n * @param {Error} error\n */\nStatistics.reportGlobalError = function(error) {\n    if (error instanceof JitsiTrackError && error.gum) {\n        Statistics.sendGetUserMediaFailed(error);\n    } else {\n        Statistics.sendLog(error);\n    }\n};\n\n/**\n * Sends event to analytics and logs a message to the logger/console. Console\n * messages might also be logged to callstats automatically.\n *\n * @param {string | Object} event the event name, or an object which\n * represents the entire event.\n * @param {Object} properties properties to attach to the event (if an event\n * name as opposed to an event object is provided).\n */\nStatistics.sendAnalyticsAndLog = function(event, properties = {}) {\n    if (!event) {\n        logger.warn('No event or event name given.');\n\n        return;\n    }\n\n    let eventToLog;\n\n    // Also support an API with a single object as an event.\n    if (typeof event === 'object') {\n        eventToLog = event;\n    } else {\n        eventToLog = {\n            name: event,\n            properties\n        };\n    }\n\n    logger.log(JSON.stringify(eventToLog));\n\n    // We do this last, because it may modify the object which is passed.\n    this.analytics.sendEvent(event, properties);\n};\n\n/**\n * Sends event to analytics.\n *\n * @param {string | Object} eventName the event name, or an object which\n * represents the entire event.\n * @param {Object} properties properties to attach to the event\n */\nStatistics.sendAnalytics = function(eventName, properties = {}) {\n    this.analytics.sendEvent(eventName, properties);\n};\n","import { getLogger } from '@jitsi/logger';\nimport { Strophe } from 'strophe.js';\n\nimport * as JitsiConferenceErrors from './JitsiConferenceErrors';\nimport * as JitsiConferenceEvents from './JitsiConferenceEvents';\nimport { SPEAKERS_AUDIO_LEVELS } from './modules/statistics/constants';\nimport Statistics from './modules/statistics/statistics';\nimport EventEmitterForwarder from './modules/util/EventEmitterForwarder';\nimport { MediaType } from './service/RTC/MediaType';\nimport RTCEvents from './service/RTC/RTCEvents';\nimport { VideoType } from './service/RTC/VideoType';\nimport AuthenticationEvents\n    from './service/authentication/AuthenticationEvents';\nimport {\n    ACTION_JINGLE_SA_TIMEOUT,\n    createBridgeDownEvent,\n    createConnectionStageReachedEvent,\n    createFocusLeftEvent,\n    createJingleEvent,\n    createRemotelyMutedEvent\n} from './service/statistics/AnalyticsEvents';\nimport { XMPPEvents } from './service/xmpp/XMPPEvents';\n\nconst logger = getLogger(__filename);\n\n/**\n * Setups all event listeners related to conference\n * @param conference {JitsiConference} the conference\n */\nexport default function JitsiConferenceEventManager(conference) {\n    this.conference = conference;\n    this.xmppListeners = {};\n\n    // Listeners related to the conference only\n    conference.on(JitsiConferenceEvents.TRACK_MUTE_CHANGED,\n        track => {\n            if (!track.isLocal() || !conference.statistics) {\n                return;\n            }\n            const session\n                = track.isP2P\n                    ? conference.p2pJingleSession : conference.jvbJingleSession;\n\n            // TPC will be null, before the conference starts, but the event\n            // still should be queued\n            const tpc = (session && session.peerconnection) || null;\n\n            conference.statistics.sendMuteEvent(\n                tpc,\n                track.isMuted(),\n                track.getType());\n        });\n}\n\n/**\n * Setups event listeners related to conference.chatRoom\n */\nJitsiConferenceEventManager.prototype.setupChatRoomListeners = function() {\n    const conference = this.conference;\n    const chatRoom = conference.room;\n\n    this.chatRoomForwarder = new EventEmitterForwarder(chatRoom,\n        this.conference.eventEmitter);\n\n    chatRoom.addListener(XMPPEvents.ICE_RESTARTING, jingleSession => {\n        if (!jingleSession.isP2P) {\n            // If using DataChannel as bridge channel, it must be closed\n            // before ICE restart, otherwise Chrome will not trigger \"opened\"\n            // event for the channel established with the new bridge.\n            // TODO: This may be bypassed when using a WebSocket as bridge\n            // channel.\n            conference.rtc.closeBridgeChannel();\n        }\n\n        // else: there are no DataChannels in P2P session (at least for now)\n    });\n\n    chatRoom.addListener(XMPPEvents.PARTICIPANT_FEATURES_CHANGED, (from, features) => {\n        const participant = conference.getParticipantById(Strophe.getResourceFromJid(from));\n\n        if (participant) {\n            participant.setFeatures(features);\n            conference.eventEmitter.emit(JitsiConferenceEvents.PARTCIPANT_FEATURES_CHANGED, participant);\n        }\n    });\n\n    chatRoom.addListener(\n        XMPPEvents.ICE_RESTART_SUCCESS,\n        (jingleSession, offerIq) => {\n            // The JVB data chanel needs to be reopened in case the conference\n            // has been moved to a new bridge.\n            !jingleSession.isP2P\n                && conference._setBridgeChannel(\n                    offerIq, jingleSession.peerconnection);\n        });\n\n\n    chatRoom.addListener(XMPPEvents.AUDIO_MUTED_BY_FOCUS,\n        actor => {\n            // TODO: Add a way to differentiate between commands which caused\n            // us to mute and those that did not change our state (i.e. we were\n            // already muted).\n            Statistics.sendAnalytics(createRemotelyMutedEvent(MediaType.AUDIO));\n\n            conference.mutedByFocusActor = actor;\n\n            // set isMutedByFocus when setAudioMute Promise ends\n            conference.rtc.setAudioMute(true).then(\n                () => {\n                    conference.isMutedByFocus = true;\n                    conference.mutedByFocusActor = null;\n                })\n                .catch(\n                    error => {\n                        conference.mutedByFocusActor = null;\n                        logger.warn(\n                            'Error while audio muting due to focus request', error);\n                    });\n        }\n    );\n\n    chatRoom.addListener(XMPPEvents.VIDEO_MUTED_BY_FOCUS,\n        actor => {\n            // TODO: Add a way to differentiate between commands which caused\n            // us to mute and those that did not change our state (i.e. we were\n            // already muted).\n            Statistics.sendAnalytics(createRemotelyMutedEvent(MediaType.VIDEO));\n\n            conference.mutedVideoByFocusActor = actor;\n\n            // set isVideoMutedByFocus when setVideoMute Promise ends\n            conference.rtc.setVideoMute(true).then(\n                () => {\n                    conference.isVideoMutedByFocus = true;\n                    conference.mutedVideoByFocusActor = null;\n                })\n                .catch(\n                    error => {\n                        conference.mutedVideoByFocusActor = null;\n                        logger.warn(\n                            'Error while video muting due to focus request', error);\n                    });\n        }\n    );\n\n    this.chatRoomForwarder.forward(XMPPEvents.SUBJECT_CHANGED,\n        JitsiConferenceEvents.SUBJECT_CHANGED);\n\n    this.chatRoomForwarder.forward(XMPPEvents.MUC_JOINED,\n        JitsiConferenceEvents.CONFERENCE_JOINED);\n\n    this.chatRoomForwarder.forward(XMPPEvents.MUC_JOIN_IN_PROGRESS,\n        JitsiConferenceEvents.CONFERENCE_JOIN_IN_PROGRESS);\n\n    this.chatRoomForwarder.forward(XMPPEvents.MEETING_ID_SET,\n        JitsiConferenceEvents.CONFERENCE_UNIQUE_ID_SET);\n\n    // send some analytics events\n    chatRoom.addListener(XMPPEvents.MUC_JOINED,\n        () => {\n            this.conference._onMucJoined();\n\n            this.conference.isJvbConnectionInterrupted = false;\n\n            // TODO: Move all of the 'connectionTimes' logic to its own module.\n            Object.keys(chatRoom.connectionTimes).forEach(key => {\n                const event\n                    = createConnectionStageReachedEvent(\n                        `conference_${key}`,\n                        { value: chatRoom.connectionTimes[key] });\n\n                Statistics.sendAnalytics(event);\n            });\n\n            // TODO: Move all of the 'connectionTimes' logic to its own module.\n            Object.keys(chatRoom.xmpp.connectionTimes).forEach(key => {\n                const event\n                    = createConnectionStageReachedEvent(\n                        `xmpp_${key}`,\n                        { value: chatRoom.xmpp.connectionTimes[key] });\n\n                Statistics.sendAnalytics(event);\n            });\n        });\n\n    chatRoom.addListener(XMPPEvents.RENEGOTIATION_FAILED, (e, session) => {\n        if (!session.isP2P) {\n            conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_FAILED,\n                JitsiConferenceErrors.OFFER_ANSWER_FAILED, e);\n        }\n    });\n\n    this.chatRoomForwarder.forward(XMPPEvents.ROOM_JOIN_ERROR,\n        JitsiConferenceEvents.CONFERENCE_FAILED,\n        JitsiConferenceErrors.CONNECTION_ERROR);\n\n    this.chatRoomForwarder.forward(XMPPEvents.ROOM_CONNECT_ERROR,\n        JitsiConferenceEvents.CONFERENCE_FAILED,\n        JitsiConferenceErrors.CONNECTION_ERROR);\n    this.chatRoomForwarder.forward(XMPPEvents.ROOM_CONNECT_NOT_ALLOWED_ERROR,\n        JitsiConferenceEvents.CONFERENCE_FAILED,\n        JitsiConferenceErrors.NOT_ALLOWED_ERROR);\n    this.chatRoomForwarder.forward(XMPPEvents.ROOM_CONNECT_MEMBERS_ONLY_ERROR,\n        JitsiConferenceEvents.CONFERENCE_FAILED,\n        JitsiConferenceErrors.MEMBERS_ONLY_ERROR);\n\n    this.chatRoomForwarder.forward(XMPPEvents.ROOM_MAX_USERS_ERROR,\n        JitsiConferenceEvents.CONFERENCE_FAILED,\n        JitsiConferenceErrors.CONFERENCE_MAX_USERS);\n\n    this.chatRoomForwarder.forward(XMPPEvents.PASSWORD_REQUIRED,\n        JitsiConferenceEvents.CONFERENCE_FAILED,\n        JitsiConferenceErrors.PASSWORD_REQUIRED);\n\n    this.chatRoomForwarder.forward(XMPPEvents.AUTHENTICATION_REQUIRED,\n        JitsiConferenceEvents.CONFERENCE_FAILED,\n        JitsiConferenceErrors.AUTHENTICATION_REQUIRED);\n\n    this.chatRoomForwarder.forward(XMPPEvents.BRIDGE_DOWN,\n        JitsiConferenceEvents.CONFERENCE_FAILED,\n        JitsiConferenceErrors.VIDEOBRIDGE_NOT_AVAILABLE);\n    chatRoom.addListener(\n        XMPPEvents.BRIDGE_DOWN,\n        () => Statistics.sendAnalytics(createBridgeDownEvent()));\n\n    chatRoom.addListener(XMPPEvents.CONNECTION_RESTARTED,\n        jingleSession => {\n            conference._onConferenceRestarted(jingleSession);\n        });\n\n    this.chatRoomForwarder.forward(XMPPEvents.RESERVATION_ERROR,\n        JitsiConferenceEvents.CONFERENCE_FAILED,\n        JitsiConferenceErrors.RESERVATION_ERROR);\n    chatRoom.addListener(XMPPEvents.RESERVATION_ERROR,\n        () => {\n            conference.xmpp.connection.emuc.doLeave(conference.room.roomjid);\n        });\n\n    this.chatRoomForwarder.forward(XMPPEvents.GRACEFUL_SHUTDOWN,\n        JitsiConferenceEvents.CONFERENCE_FAILED,\n        JitsiConferenceErrors.GRACEFUL_SHUTDOWN);\n\n    chatRoom.addListener(XMPPEvents.CONNECTION_ICE_FAILED,\n        jingleSession => {\n            conference._onIceConnectionFailed(jingleSession);\n        });\n\n    this.chatRoomForwarder.forward(XMPPEvents.MUC_DESTROYED,\n        JitsiConferenceEvents.CONFERENCE_FAILED,\n        JitsiConferenceErrors.CONFERENCE_DESTROYED);\n\n    this.chatRoomForwarder.forward(XMPPEvents.CHAT_ERROR_RECEIVED,\n        JitsiConferenceEvents.CONFERENCE_ERROR,\n        JitsiConferenceErrors.CHAT_ERROR);\n\n    this.chatRoomForwarder.forward(XMPPEvents.SETTINGS_ERROR_RECEIVED,\n        JitsiConferenceEvents.CONFERENCE_ERROR,\n        JitsiConferenceErrors.SETTINGS_ERROR);\n\n    this.chatRoomForwarder.forward(XMPPEvents.FOCUS_DISCONNECTED,\n        JitsiConferenceEvents.CONFERENCE_FAILED,\n        JitsiConferenceErrors.FOCUS_DISCONNECTED);\n\n    chatRoom.addListener(XMPPEvents.FOCUS_LEFT,\n        () => {\n            Statistics.sendAnalytics(createFocusLeftEvent());\n            conference.eventEmitter.emit(\n                JitsiConferenceEvents.CONFERENCE_FAILED,\n                JitsiConferenceErrors.FOCUS_LEFT);\n        });\n\n    chatRoom.addListener(XMPPEvents.SESSION_ACCEPT_TIMEOUT,\n        jingleSession => {\n            Statistics.sendAnalyticsAndLog(\n                createJingleEvent(\n                    ACTION_JINGLE_SA_TIMEOUT,\n                    { p2p: jingleSession.isP2P }));\n        });\n\n    chatRoom.addListener(XMPPEvents.RECORDER_STATE_CHANGED,\n        (session, jid) => {\n\n            if (jid) {\n                const resource = Strophe.getResourceFromJid(jid);\n                const participant = conference.getParticipantById(resource) || resource;\n\n                if (session.getStatus() === 'off') {\n                    session.setTerminator(participant);\n                } else if (session.getStatus() === 'on') {\n                    session.setInitiator(participant);\n                }\n            }\n\n            conference.eventEmitter.emit(\n                JitsiConferenceEvents.RECORDER_STATE_CHANGED,\n                session);\n        });\n\n    this.chatRoomForwarder.forward(XMPPEvents.TRANSCRIPTION_STATUS_CHANGED,\n        JitsiConferenceEvents.TRANSCRIPTION_STATUS_CHANGED);\n\n    this.chatRoomForwarder.forward(XMPPEvents.VIDEO_SIP_GW_AVAILABILITY_CHANGED,\n        JitsiConferenceEvents.VIDEO_SIP_GW_AVAILABILITY_CHANGED);\n\n    this.chatRoomForwarder.forward(\n        XMPPEvents.VIDEO_SIP_GW_SESSION_STATE_CHANGED,\n        JitsiConferenceEvents.VIDEO_SIP_GW_SESSION_STATE_CHANGED);\n\n    this.chatRoomForwarder.forward(XMPPEvents.PHONE_NUMBER_CHANGED,\n        JitsiConferenceEvents.PHONE_NUMBER_CHANGED);\n\n    chatRoom.setParticipantPropertyListener((node, from) => {\n        const participant = conference.getParticipantById(from);\n\n        if (!participant) {\n            return;\n        }\n\n        participant.setProperty(\n            node.tagName.substring('jitsi_participant_'.length),\n            node.value);\n    });\n\n    chatRoom.addListener(XMPPEvents.KICKED,\n        conference.onMemberKicked.bind(conference));\n    chatRoom.addListener(XMPPEvents.SUSPEND_DETECTED,\n        conference.onSuspendDetected.bind(conference));\n\n    this.chatRoomForwarder.forward(XMPPEvents.MUC_LOCK_CHANGED,\n        JitsiConferenceEvents.LOCK_STATE_CHANGED);\n\n    this.chatRoomForwarder.forward(XMPPEvents.MUC_MEMBERS_ONLY_CHANGED,\n        JitsiConferenceEvents.MEMBERS_ONLY_CHANGED);\n\n    chatRoom.addListener(XMPPEvents.MUC_MEMBER_JOINED,\n        conference.onMemberJoined.bind(conference));\n    this.chatRoomForwarder.forward(XMPPEvents.MUC_LOBBY_MEMBER_JOINED,\n        JitsiConferenceEvents.LOBBY_USER_JOINED);\n    this.chatRoomForwarder.forward(XMPPEvents.MUC_LOBBY_MEMBER_UPDATED,\n        JitsiConferenceEvents.LOBBY_USER_UPDATED);\n    this.chatRoomForwarder.forward(XMPPEvents.MUC_LOBBY_MEMBER_LEFT,\n        JitsiConferenceEvents.LOBBY_USER_LEFT);\n    chatRoom.addListener(XMPPEvents.MUC_MEMBER_BOT_TYPE_CHANGED,\n        conference._onMemberBotTypeChanged.bind(conference));\n    chatRoom.addListener(XMPPEvents.MUC_MEMBER_LEFT,\n        conference.onMemberLeft.bind(conference));\n    this.chatRoomForwarder.forward(XMPPEvents.MUC_LEFT,\n        JitsiConferenceEvents.CONFERENCE_LEFT);\n    this.chatRoomForwarder.forward(XMPPEvents.MUC_DENIED_ACCESS,\n        JitsiConferenceEvents.CONFERENCE_FAILED,\n        JitsiConferenceErrors.CONFERENCE_ACCESS_DENIED);\n\n    chatRoom.addListener(XMPPEvents.DISPLAY_NAME_CHANGED,\n        conference.onDisplayNameChanged.bind(conference));\n\n    chatRoom.addListener(XMPPEvents.LOCAL_ROLE_CHANGED, role => {\n        conference.onLocalRoleChanged(role);\n\n        // log all events for the recorder operated by the moderator\n        if (conference.statistics && conference.isModerator()) {\n            conference.on(JitsiConferenceEvents.RECORDER_STATE_CHANGED,\n                recorderSession => {\n                    const logObject = {\n                        error: recorderSession.getError(),\n                        id: 'recorder_status',\n                        status: recorderSession.getStatus()\n                    };\n\n                    Statistics.sendLog(JSON.stringify(logObject));\n                });\n        }\n    });\n\n    chatRoom.addListener(XMPPEvents.MUC_ROLE_CHANGED,\n        conference.onUserRoleChanged.bind(conference));\n\n    chatRoom.addListener(AuthenticationEvents.IDENTITY_UPDATED,\n        (authEnabled, authIdentity) => {\n            conference.authEnabled = authEnabled;\n            conference.authIdentity = authIdentity;\n            conference.eventEmitter.emit(\n                JitsiConferenceEvents.AUTH_STATUS_CHANGED, authEnabled,\n                authIdentity);\n        });\n\n    chatRoom.addListener(\n        XMPPEvents.MESSAGE_RECEIVED,\n\n        // eslint-disable-next-line max-params\n        (jid, txt, myJid, ts) => {\n            const id = Strophe.getResourceFromJid(jid);\n\n            conference.eventEmitter.emit(\n                JitsiConferenceEvents.MESSAGE_RECEIVED,\n                id, txt, ts);\n        });\n\n    chatRoom.addListener(\n        XMPPEvents.PRIVATE_MESSAGE_RECEIVED,\n\n        // eslint-disable-next-line max-params\n        (jid, txt, myJid, ts) => {\n            const id = Strophe.getResourceFromJid(jid);\n\n            conference.eventEmitter.emit(\n                JitsiConferenceEvents.PRIVATE_MESSAGE_RECEIVED,\n                id, txt, ts);\n        });\n\n    chatRoom.addListener(XMPPEvents.PRESENCE_STATUS,\n        (jid, status) => {\n            const id = Strophe.getResourceFromJid(jid);\n            const participant = conference.getParticipantById(id);\n\n            if (!participant || participant._status === status) {\n                return;\n            }\n            participant._status = status;\n            conference.eventEmitter.emit(\n                JitsiConferenceEvents.USER_STATUS_CHANGED, id, status);\n        });\n\n    chatRoom.addListener(XMPPEvents.JSON_MESSAGE_RECEIVED,\n        (from, payload) => {\n            const id = Strophe.getResourceFromJid(from);\n            const participant = conference.getParticipantById(id);\n\n            if (participant) {\n                conference.eventEmitter.emit(\n                    JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,\n                    participant, payload);\n            } else {\n                conference.eventEmitter.emit(\n                    JitsiConferenceEvents.NON_PARTICIPANT_MESSAGE_RECEIVED,\n                    id, payload);\n            }\n        });\n\n    chatRoom.addPresenceListener('startmuted', (data, from) => {\n        let isModerator = false;\n\n        if (conference.myUserId() === from && conference.isModerator()) {\n            isModerator = true;\n        } else {\n            const participant = conference.getParticipantById(from);\n\n            if (participant && participant.isModerator()) {\n                isModerator = true;\n            }\n        }\n\n        if (!isModerator) {\n            return;\n        }\n\n        const startAudioMuted = data.attributes.audio === 'true';\n        const startVideoMuted = data.attributes.video === 'true';\n\n        let updated = false;\n\n        if (startAudioMuted !== conference.startMutedPolicy.audio) {\n            conference.startMutedPolicy.audio = startAudioMuted;\n            updated = true;\n        }\n\n        if (startVideoMuted !== conference.startMutedPolicy.video) {\n            conference.startMutedPolicy.video = startVideoMuted;\n            updated = true;\n        }\n\n        if (updated) {\n            conference.eventEmitter.emit(\n                JitsiConferenceEvents.START_MUTED_POLICY_CHANGED,\n                conference.startMutedPolicy\n            );\n        }\n    });\n\n    if (conference.statistics) {\n        // FIXME ICE related events should end up in RTCEvents eventually\n        chatRoom.addListener(XMPPEvents.CONNECTION_ICE_FAILED,\n            session => {\n                conference.statistics.sendIceConnectionFailedEvent(\n                    session.peerconnection);\n            });\n\n        // FIXME XMPPEvents.ADD_ICE_CANDIDATE_FAILED is never emitted\n        chatRoom.addListener(XMPPEvents.ADD_ICE_CANDIDATE_FAILED,\n            (e, pc) => {\n                conference.statistics.sendAddIceCandidateFailed(e, pc);\n            });\n    }\n\n    // Breakout rooms.\n    this.chatRoomForwarder.forward(XMPPEvents.BREAKOUT_ROOMS_MOVE_TO_ROOM,\n        JitsiConferenceEvents.BREAKOUT_ROOMS_MOVE_TO_ROOM);\n    this.chatRoomForwarder.forward(XMPPEvents.BREAKOUT_ROOMS_UPDATED,\n        JitsiConferenceEvents.BREAKOUT_ROOMS_UPDATED);\n};\n\n/**\n * Setups event listeners related to conference.rtc\n */\nJitsiConferenceEventManager.prototype.setupRTCListeners = function() {\n    const conference = this.conference;\n    const rtc = conference.rtc;\n\n    rtc.addListener(\n        RTCEvents.REMOTE_TRACK_ADDED,\n        conference.onRemoteTrackAdded.bind(conference));\n\n    rtc.addListener(\n        RTCEvents.REMOTE_TRACK_REMOVED,\n        conference.onRemoteTrackRemoved.bind(conference));\n\n    rtc.addListener(RTCEvents.DOMINANT_SPEAKER_CHANGED,\n        (dominant, previous) => {\n            if (conference.lastDominantSpeaker !== dominant && conference.room) {\n                conference.lastDominantSpeaker = dominant;\n                conference.eventEmitter.emit(\n                    JitsiConferenceEvents.DOMINANT_SPEAKER_CHANGED, dominant, previous);\n\n                if (previous && previous.length) {\n                    const speakerList = previous.slice(0);\n\n                    // Add the dominant speaker to the top of the list (exclude self).\n                    if (conference.myUserId !== dominant) {\n                        speakerList.splice(0, 0, dominant);\n                    }\n\n                    // Trim the list to the top 5 speakers only.\n                    if (speakerList.length > SPEAKERS_AUDIO_LEVELS) {\n                        speakerList.splice(SPEAKERS_AUDIO_LEVELS, speakerList.length - SPEAKERS_AUDIO_LEVELS);\n                    }\n                    conference.statistics && conference.statistics.setSpeakerList(speakerList);\n                }\n                if (conference.statistics && conference.myUserId() === dominant) {\n                    // We are the new dominant speaker.\n                    conference.statistics.sendDominantSpeakerEvent(conference.room.roomjid);\n                }\n            }\n        });\n\n    rtc.addListener(RTCEvents.DATA_CHANNEL_OPEN, () => {\n        const now = window.performance.now();\n        const key = 'data.channel.opened';\n\n        // TODO: Move all of the 'connectionTimes' logic to its own module.\n        logger.log(`(TIME) ${key}:\\t`, now);\n        conference.room.connectionTimes[key] = now;\n        Statistics.sendAnalytics(\n            createConnectionStageReachedEvent(key, { value: now }));\n\n        conference.eventEmitter.emit(JitsiConferenceEvents.DATA_CHANNEL_OPENED);\n    });\n\n    rtc.addListener(RTCEvents.ENDPOINT_MESSAGE_RECEIVED,\n        (from, payload) => {\n            const participant = conference.getParticipantById(from);\n\n            if (participant) {\n                conference.eventEmitter.emit(\n                    JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,\n                    participant, payload);\n            } else {\n                logger.warn(\n                    'Ignored ENDPOINT_MESSAGE_RECEIVED for not existing '\n                        + `participant: ${from}`,\n                    payload);\n            }\n        });\n\n    rtc.addListener(RTCEvents.ENDPOINT_STATS_RECEIVED,\n        (from, payload) => {\n            const participant = conference.getParticipantById(from);\n\n            if (participant) {\n                conference.eventEmitter.emit(JitsiConferenceEvents.ENDPOINT_STATS_RECEIVED, participant, payload);\n            } else {\n                logger.warn(`Ignoring ENDPOINT_STATS_RECEIVED for a non-existant participant: ${from}`);\n            }\n        });\n\n    rtc.addListener(RTCEvents.LOCAL_UFRAG_CHANGED,\n        (tpc, ufrag) => {\n            if (!tpc.isP2P) {\n                Statistics.sendLog(\n                    JSON.stringify({\n                        id: 'local_ufrag',\n                        value: ufrag\n                    }));\n            }\n        });\n    rtc.addListener(RTCEvents.REMOTE_UFRAG_CHANGED,\n        (tpc, ufrag) => {\n            if (!tpc.isP2P) {\n                Statistics.sendLog(\n                    JSON.stringify({\n                        id: 'remote_ufrag',\n                        value: ufrag\n                    }));\n            }\n        });\n\n    rtc.addListener(RTCEvents.CREATE_ANSWER_FAILED,\n        (e, tpc) => {\n            conference.statistics.sendCreateAnswerFailed(e, tpc);\n            if (!tpc.isP2P) {\n                conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_FAILED,\n                    JitsiConferenceErrors.OFFER_ANSWER_FAILED, e);\n            }\n        });\n\n    rtc.addListener(RTCEvents.CREATE_OFFER_FAILED,\n        (e, tpc) => {\n            conference.statistics.sendCreateOfferFailed(e, tpc);\n            if (!tpc.isP2P) {\n                conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_FAILED,\n                    JitsiConferenceErrors.OFFER_ANSWER_FAILED, e);\n            }\n        });\n\n    rtc.addListener(RTCEvents.SET_LOCAL_DESCRIPTION_FAILED,\n        (e, tpc) => {\n            conference.statistics.sendSetLocalDescFailed(e, tpc);\n            if (!tpc.isP2P) {\n                conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_FAILED,\n                    JitsiConferenceErrors.OFFER_ANSWER_FAILED, e);\n            }\n        });\n\n    rtc.addListener(RTCEvents.SET_REMOTE_DESCRIPTION_FAILED,\n        (e, tpc) => {\n            conference.statistics.sendSetRemoteDescFailed(e, tpc);\n            if (!tpc.isP2P) {\n                conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_FAILED,\n                    JitsiConferenceErrors.OFFER_ANSWER_FAILED, e);\n            }\n        });\n\n    rtc.addListener(RTCEvents.LOCAL_TRACK_SSRC_UPDATED,\n        (track, ssrc) => {\n            // when starting screen sharing, the track is created and when\n            // we do set local description and we process the ssrc we\n            // will be notified for it and we will report it with the event\n            // for screen sharing\n            if (track.isVideoTrack() && track.videoType === VideoType.DESKTOP) {\n                conference.statistics.sendScreenSharingEvent(true, ssrc);\n            }\n        });\n};\n\n/**\n * Removes event listeners related to conference.xmpp\n */\nJitsiConferenceEventManager.prototype.removeXMPPListeners = function() {\n    const conference = this.conference;\n\n    Object.keys(this.xmppListeners).forEach(eventName => {\n        conference.xmpp.removeListener(\n            eventName,\n            this.xmppListeners[eventName]);\n    });\n    this.xmppListeners = {};\n};\n\n\n/**\n * Setups event listeners related to conference.xmpp\n */\nJitsiConferenceEventManager.prototype.setupXMPPListeners = function() {\n    const conference = this.conference;\n\n    this._addConferenceXMPPListener(\n        XMPPEvents.CALL_INCOMING,\n        conference.onIncomingCall.bind(conference));\n    this._addConferenceXMPPListener(\n        XMPPEvents.CALL_ACCEPTED,\n        conference.onCallAccepted.bind(conference));\n    this._addConferenceXMPPListener(\n        XMPPEvents.TRANSPORT_INFO,\n        conference.onTransportInfo.bind(conference));\n    this._addConferenceXMPPListener(\n        XMPPEvents.CALL_ENDED,\n        conference.onCallEnded.bind(conference));\n\n    this._addConferenceXMPPListener(XMPPEvents.START_MUTED_FROM_FOCUS,\n        (audioMuted, videoMuted) => {\n            if (conference.options.config.ignoreStartMuted) {\n                return;\n            }\n\n            conference.startAudioMuted = audioMuted;\n            conference.startVideoMuted = videoMuted;\n\n            // mute existing local tracks because this is initial mute from\n            // Jicofo\n            conference.getLocalTracks().forEach(track => {\n                switch (track.getType()) {\n                case MediaType.AUDIO:\n                    conference.startAudioMuted && track.mute();\n                    break;\n                case MediaType.VIDEO:\n                    conference.startVideoMuted && track.mute();\n                    break;\n                }\n            });\n\n            conference.eventEmitter.emit(JitsiConferenceEvents.STARTED_MUTED);\n        });\n\n    this._addConferenceXMPPListener(XMPPEvents.CONFERENCE_TIMESTAMP_RECEIVED,\n        createdTimestamp => {\n            conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_CREATED_TIMESTAMP, createdTimestamp);\n        });\n\n    this._addConferenceXMPPListener(XMPPEvents.AV_MODERATION_CHANGED,\n        (value, mediaType, actorJid) => {\n            const actorParticipant = conference.getParticipants().find(p => p.getJid() === actorJid);\n\n            conference.eventEmitter.emit(JitsiConferenceEvents.AV_MODERATION_CHANGED, {\n                enabled: value,\n                mediaType,\n                actor: actorParticipant\n            });\n        });\n    this._addConferenceXMPPListener(XMPPEvents.AV_MODERATION_PARTICIPANT_APPROVED,\n        (mediaType, jid) => {\n            const participant = conference.getParticipantById(Strophe.getResourceFromJid(jid));\n\n            if (participant) {\n                conference.eventEmitter.emit(JitsiConferenceEvents.AV_MODERATION_PARTICIPANT_APPROVED, {\n                    participant,\n                    mediaType\n                });\n            }\n        });\n    this._addConferenceXMPPListener(XMPPEvents.AV_MODERATION_PARTICIPANT_REJECTED,\n        (mediaType, jid) => {\n            const participant = conference.getParticipantById(Strophe.getResourceFromJid(jid));\n\n            if (participant) {\n                conference.eventEmitter.emit(JitsiConferenceEvents.AV_MODERATION_PARTICIPANT_REJECTED, {\n                    participant,\n                    mediaType\n                });\n            }\n        });\n    this._addConferenceXMPPListener(XMPPEvents.AV_MODERATION_APPROVED,\n        value => conference.eventEmitter.emit(JitsiConferenceEvents.AV_MODERATION_APPROVED, { mediaType: value }));\n    this._addConferenceXMPPListener(XMPPEvents.AV_MODERATION_REJECTED,\n        value => {\n            conference.eventEmitter.emit(JitsiConferenceEvents.AV_MODERATION_REJECTED, { mediaType: value });\n        });\n};\n\n/**\n * Add XMPP listener and save its reference for remove on leave conference.\n */\nJitsiConferenceEventManager.prototype._addConferenceXMPPListener = function(\n        eventName, listener) {\n    this.xmppListeners[eventName] = listener;\n    this.conference.xmpp.addListener(eventName, listener);\n};\n\n/**\n * Setups event listeners related to conference.statistics\n */\nJitsiConferenceEventManager.prototype.setupStatisticsListeners = function() {\n    const conference = this.conference;\n\n    if (!conference.statistics) {\n        return;\n    }\n\n    /* eslint-disable max-params */\n    conference.statistics.addAudioLevelListener((tpc, ssrc, level, isLocal) => {\n        conference.rtc.setAudioLevel(tpc, ssrc, level, isLocal);\n    });\n\n    /* eslint-enable max-params */\n\n    // Forward the \"before stats disposed\" event\n    conference.statistics.addBeforeDisposedListener(() => {\n        conference.eventEmitter.emit(\n            JitsiConferenceEvents.BEFORE_STATISTICS_DISPOSED);\n    });\n\n    // if we are in startSilent mode we will not be sending/receiving so nothing to detect\n    if (!conference.options.config.startSilent) {\n        conference.statistics.addByteSentStatsListener((tpc, stats) => {\n            conference.getLocalTracks(MediaType.AUDIO).forEach(track => {\n                const ssrc = tpc.getLocalSSRC(track);\n\n                if (!ssrc || !stats.hasOwnProperty(ssrc)) {\n                    return;\n                }\n\n                track.onByteSentStatsReceived(tpc, stats[ssrc]);\n            });\n        });\n    }\n};\n","export enum JitsiTrackEvents {\n    /**\n     * The media track was removed to the conference.\n     */\n    LOCAL_TRACK_STOPPED = 'track.stopped',\n\n    /**\n     * Audio levels of a this track was changed.\n     * The first argument is a number with audio level value in range [0, 1].\n     * The second argument is a <tt>TraceablePeerConnection</tt> which is the peer\n     * connection which measured the audio level (one audio track can be added\n     * to multiple peer connection at the same time). This argument is optional for\n     * local tracks for which we can measure audio level without the peer\n     * connection (the value will be <tt>undefined</tt>).\n     *\n     * NOTE The second argument should be treated as library internal and can be\n     * removed at any time.\n     */\n    TRACK_AUDIO_LEVEL_CHANGED = 'track.audioLevelsChanged',\n\n    /**\n     * The audio output of the track was changed.\n     */\n    TRACK_AUDIO_OUTPUT_CHANGED = 'track.audioOutputChanged',\n\n    /**\n     * A media track mute status was changed.\n     */\n    TRACK_MUTE_CHANGED = 'track.trackMuteChanged',\n\n    /**\n     * The video type(\"camera\" or \"desktop\") of the track was changed.\n     */\n    TRACK_VIDEOTYPE_CHANGED = 'track.videoTypeChanged',\n\n    /**\n     * Indicates that the track is not receiving any data even though we expect it\n     * to receive data (i.e. the stream is not stopped).\n     */\n    NO_DATA_FROM_SOURCE = 'track.no_data_from_source',\n\n    /**\n     * Indicates that the local audio track is not receiving any audio input from\n     * the microphone that is currently selected.\n     */\n    NO_AUDIO_INPUT = 'track.no_audio_input',\n\n    /**\n     * Event fired whenever video track's streaming changes.\n     * First argument is the sourceName of the track and the second is a string indicating if the connection is currently\n     * - active - the connection is active.\n     * - inactive - the connection is inactive, was intentionally interrupted by the bridge because of low BWE or because\n     *   of the endpoint falling out of last N.\n     * - interrupted - a network problem occurred.\n     * - restoring - the connection was inactive and is restoring now.\n     *\n     * The current status value can be obtained by calling JitsiRemoteTrack.getTrackStreamingStatus().\n     */\n    TRACK_STREAMING_STATUS_CHANGED = 'track.streaming_status_changed'\n};\n\n// exported for backward compatibility\nexport const LOCAL_TRACK_STOPPED = JitsiTrackEvents.LOCAL_TRACK_STOPPED;\nexport const TRACK_AUDIO_LEVEL_CHANGED = JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED;\nexport const TRACK_AUDIO_OUTPUT_CHANGED = JitsiTrackEvents.TRACK_AUDIO_OUTPUT_CHANGED;\nexport const TRACK_MUTE_CHANGED = JitsiTrackEvents.TRACK_MUTE_CHANGED;\nexport const TRACK_VIDEOTYPE_CHANGED = JitsiTrackEvents.TRACK_VIDEOTYPE_CHANGED;\nexport const NO_DATA_FROM_SOURCE = JitsiTrackEvents.NO_DATA_FROM_SOURCE;\nexport const NO_AUDIO_INPUT = JitsiTrackEvents.NO_AUDIO_INPUT;\nexport const TRACK_STREAMING_STATUS_CHANGED = JitsiTrackEvents.TRACK_STREAMING_STATUS_CHANGED;\n","import { getLogger } from '@jitsi/logger';\n\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\nimport * as JitsiTrackEvents from '../../JitsiTrackEvents';\nimport { MediaType } from '../../service/RTC/MediaType';\nimport RTCEvents from '../../service/RTC/RTCEvents';\nimport { createParticipantConnectionStatusEvent } from '../../service/statistics/AnalyticsEvents';\nimport browser from '../browser';\nimport Statistics from '../statistics/statistics';\n\nconst logger = getLogger(__filename);\n\n/**\n * Default value of 500 milliseconds for {@link ParticipantConnectionStatus.outOfLastNTimeout}.\n *\n * @type {number}\n */\nconst DEFAULT_NOT_IN_LAST_N_TIMEOUT = 500;\n\n/**\n * Default value of 2500 milliseconds for {@link ParticipantConnectionStatus.p2pRtcMuteTimeout}.\n */\nconst DEFAULT_P2P_RTC_MUTE_TIMEOUT = 2500;\n\n/**\n * Default value of 10000 milliseconds for {@link ParticipantConnectionStatus.rtcMuteTimeout}.\n *\n * @type {number}\n */\nconst DEFAULT_RTC_MUTE_TIMEOUT = 10000;\n\n/**\n * The time to wait a track to be restored. Track which was out of lastN\n * should be inactive and when entering lastN it becomes restoring and when\n * data is received from bridge it will become active, but if no data is\n * received for some time we set status of that participant connection to\n * interrupted.\n * @type {number}\n */\nconst DEFAULT_RESTORING_TIMEOUT = 10000;\n\n/**\n * Participant connection statuses.\n *\n * @type {{\n *      ACTIVE: string,\n *      INACTIVE: string,\n *      INTERRUPTED: string,\n *      RESTORING: string\n * }}\n */\nexport const ParticipantConnectionStatus = {\n    /**\n     * Status indicating that connection is currently active.\n     */\n    ACTIVE: 'active',\n\n    /**\n     * Status indicating that connection is currently inactive.\n     * Inactive means the connection was stopped on purpose from the bridge,\n     * like exiting lastN or adaptivity decided to drop video because of not\n     * enough bandwidth.\n     */\n    INACTIVE: 'inactive',\n\n    /**\n     * Status indicating that connection is currently interrupted.\n     */\n    INTERRUPTED: 'interrupted',\n\n    /**\n     * Status indicating that connection is currently restoring.\n     */\n    RESTORING: 'restoring'\n};\n\n/**\n * Class is responsible for emitting\n * JitsiConferenceEvents.PARTICIPANT_CONN_STATUS_CHANGED events.\n */\nexport default class ParticipantConnectionStatusHandler {\n    /* eslint-disable max-params*/\n    /**\n     * Calculates the new {@link ParticipantConnectionStatus} based on\n     * the values given for some specific remote user. It is assumed that\n     * the conference is currently in the JVB mode (in contrary to the P2P mode)\n     * @param {boolean} isConnectionActiveByJvb true if the JVB did not get any\n     * data from the user for the last 15 seconds.\n     * @param {boolean} isInLastN indicates whether the user is in the last N\n     * set. When set to false it means that JVB is not sending any video for\n     * the user.\n     * @param {boolean} isRestoringTimedout if true it means that the user has\n     * been outside of last N too long to be considered\n     * {@link ParticipantConnectionStatus.RESTORING}.\n     * @param {boolean} isVideoMuted true if the user is video muted and we\n     * should not expect to receive any video.\n     * @param {boolean} isVideoTrackFrozen if the current browser support video\n     * frozen detection then it will be set to true when the video track is\n     * frozen. If the current browser does not support frozen detection the it's\n     * always false.\n     * @return {ParticipantConnectionStatus} the new connection status for\n     * the user for whom the values above were provided.\n     * @private\n     */\n    static _getNewStateForJvbMode(\n            isConnectionActiveByJvb,\n            isInLastN,\n            isRestoringTimedout,\n            isVideoMuted,\n            isVideoTrackFrozen) {\n        if (!isConnectionActiveByJvb) {\n            // when there is a connection problem signaled from jvb\n            // it means no media was flowing for at least 15secs, so both audio\n            // and video are most likely interrupted\n            return ParticipantConnectionStatus.INTERRUPTED;\n        } else if (isVideoMuted) {\n            // If the connection is active according to JVB and the user is\n            // video muted there is no way for the connection to be inactive,\n            // because the detection logic below only makes sense for video.\n            return ParticipantConnectionStatus.ACTIVE;\n        }\n\n        // Logic when isVideoTrackFrozen is supported\n        if (browser.supportsVideoMuteOnConnInterrupted()) {\n            if (!isVideoTrackFrozen) {\n                // If the video is playing we're good\n                return ParticipantConnectionStatus.ACTIVE;\n            } else if (isInLastN) {\n                return isRestoringTimedout\n                    ? ParticipantConnectionStatus.INTERRUPTED\n                    : ParticipantConnectionStatus.RESTORING;\n            }\n\n            return ParticipantConnectionStatus.INACTIVE;\n        }\n\n        // Because this browser is incapable of detecting frozen video we must\n        // rely on the lastN value\n        return isInLastN\n            ? ParticipantConnectionStatus.ACTIVE\n            : ParticipantConnectionStatus.INACTIVE;\n    }\n\n    /* eslint-enable max-params*/\n\n    /**\n     * In P2P mode we don't care about any values coming from the JVB and\n     * the connection status can be only active or interrupted.\n     * @param {boolean} isVideoMuted the user if video muted\n     * @param {boolean} isVideoTrackFrozen true if the video track for\n     * the remote user is currently frozen. If the current browser does not\n     * support video frozen detection then it's always false.\n     * @return {ParticipantConnectionStatus}\n     * @private\n     */\n    static _getNewStateForP2PMode(isVideoMuted, isVideoTrackFrozen) {\n        if (!browser.supportsVideoMuteOnConnInterrupted()) {\n            // There's no way to detect problems in P2P when there's no video\n            // track frozen detection...\n            return ParticipantConnectionStatus.ACTIVE;\n        }\n\n        return isVideoMuted || !isVideoTrackFrozen\n            ? ParticipantConnectionStatus.ACTIVE\n            : ParticipantConnectionStatus.INTERRUPTED;\n    }\n\n    /**\n     * Creates new instance of <tt>ParticipantConnectionStatus</tt>.\n     *\n     * @constructor\n     * @param {RTC} rtc the RTC service instance\n     * @param {JitsiConference} conference parent conference instance\n     * @param {Object} options\n     * @param {number} [options.p2pRtcMuteTimeout=2500] custom value for\n     * {@link ParticipantConnectionStatus.p2pRtcMuteTimeout}.\n     * @param {number} [options.rtcMuteTimeout=10000] custom value for\n     * {@link ParticipantConnectionStatus.rtcMuteTimeout}.\n     * @param {number} [options.outOfLastNTimeout=500] custom value for\n     * {@link ParticipantConnectionStatus.outOfLastNTimeout}.\n     */\n    constructor(rtc, conference, options) {\n        this.rtc = rtc;\n        this.conference = conference;\n\n        /**\n         * A map of the \"endpoint ID\"(which corresponds to the resource part\n         * of MUC JID(nickname)) to the timeout callback IDs scheduled using\n         * window.setTimeout.\n         * @type {Object.<string, number>}\n         */\n        this.trackTimers = {};\n\n        /**\n         * This map holds the endpoint connection status received from the JVB\n         * (as it might be different than the one stored in JitsiParticipant).\n         * Required for getting back in sync when remote video track is removed.\n         * @type {Object.<string, boolean>}\n         */\n        this.connStatusFromJvb = { };\n\n        /**\n         * If video track frozen detection through RTC mute event is supported,\n         * we wait some time until video track is considered frozen. But because\n         * when the user falls out of last N it is expected for the video to\n         * freeze this timeout must be significantly reduced in \"out of last N\"\n         * case.\n         *\n         * Basically this value is used instead of {@link rtcMuteTimeout} when\n         * user is not in last N.\n         * @type {number}\n         */\n        this.outOfLastNTimeout\n            = typeof options.outOfLastNTimeout === 'number'\n                ? options.outOfLastNTimeout : DEFAULT_NOT_IN_LAST_N_TIMEOUT;\n\n        /**\n         * How long we are going to wait for the corresponding signaling mute event after the RTC video track muted\n         * event is fired on the Media stream, before the connection interrupted is fired. The default value is\n         * {@link DEFAULT_P2P_RTC_MUTE_TIMEOUT}.\n         *\n         * @type {number} amount of time in milliseconds.\n         */\n        this.p2pRtcMuteTimeout = typeof options.p2pRtcMuteTimeout === 'number'\n            ? options.p2pRtcMuteTimeout : DEFAULT_P2P_RTC_MUTE_TIMEOUT;\n\n        /**\n         * How long we're going to wait after the RTC video track muted event\n         * for the corresponding signalling mute event, before the connection\n         * interrupted is fired. The default value is\n         * {@link DEFAULT_RTC_MUTE_TIMEOUT}.\n         *\n         * @type {number} amount of time in milliseconds\n         */\n        this.rtcMuteTimeout\n            = typeof options.rtcMuteTimeout === 'number'\n                ? options.rtcMuteTimeout : DEFAULT_RTC_MUTE_TIMEOUT;\n\n        /**\n         * This map holds a timestamp indicating  when participant's video track\n         * was RTC muted (it is assumed that each participant can have only 1\n         * video track at a time). The purpose of storing the timestamp is to\n         * avoid the transition to disconnected status in case of legitimate\n         * video mute operation where the signalling video muted event can\n         * arrive shortly after RTC muted event.\n         *\n         * The key is participant's ID which is the same as endpoint id in\n         * the Colibri conference allocated on the JVB.\n         *\n         * The value is a timestamp measured in milliseconds obtained with\n         * <tt>Date.now()</tt>.\n         *\n         * FIXME merge this logic with NO_DATA_FROM_SOURCE event\n         *       implemented in JitsiLocalTrack by extending the event to\n         *       the remote track and allowing to set different timeout for\n         *       local and remote tracks.\n         *\n         * @type {Object.<string, number>}\n         */\n        this.rtcMutedTimestamp = { };\n        logger.info(`RtcMuteTimeout set to: ${this.rtcMuteTimeout}`);\n\n        /**\n         * This map holds the timestamps indicating when participant's video\n         * entered lastN set. Participants entering lastN will have connection\n         * status restoring and when we start receiving video will become\n         * active, but if video is not received for certain time\n         * {@link DEFAULT_RESTORING_TIMEOUT} that participant connection status\n         * will become interrupted.\n         *\n         * @type {Map<string, number>}\n         */\n        this.enteredLastNTimestamp = new Map();\n\n        /**\n         * A map of the \"endpoint ID\"(which corresponds to the resource part\n         * of MUC JID(nickname)) to the restoring timeout callback IDs\n         * scheduled using window.setTimeout.\n         *\n         * @type {Map<string, number>}\n         */\n        this.restoringTimers = new Map();\n\n        /**\n         * A map that holds the current connection status (along with all the internal events that happen\n         * while in that state).\n         *\n         * The goal is to send this information to the analytics backend for post-mortem analysis.\n         */\n        this.connectionStatusMap = new Map();\n    }\n\n    /**\n     * Gets the video frozen timeout for given user.\n     * @param {string} id endpoint/participant ID\n     * @return {number} how long are we going to wait since RTC video muted\n     * even, before a video track is considered frozen.\n     * @private\n     */\n    _getVideoFrozenTimeout(id) {\n        return this.rtc.isInLastN(id)\n            ? this.rtcMuteTimeout\n            : this.conference.isP2PActive() ? this.p2pRtcMuteTimeout : this.outOfLastNTimeout;\n    }\n\n    /**\n     * Initializes <tt>ParticipantConnectionStatus</tt> and bind required event\n     * listeners.\n     */\n    init() {\n\n        this._onEndpointConnStatusChanged\n            = this.onEndpointConnStatusChanged.bind(this);\n\n        this.rtc.addListener(\n            RTCEvents.ENDPOINT_CONN_STATUS_CHANGED,\n            this._onEndpointConnStatusChanged);\n\n        // Handles P2P status changes\n        this._onP2PStatus = this.refreshConnectionStatusForAll.bind(this);\n        this.conference.on(JitsiConferenceEvents.P2P_STATUS, this._onP2PStatus);\n\n        // Used to send analytics events for the participant that left the call.\n        this._onUserLeft = this.onUserLeft.bind(this);\n        this.conference.on(JitsiConferenceEvents.USER_LEFT, this._onUserLeft);\n\n        // On some browsers MediaStreamTrack trigger \"onmute\"/\"onunmute\"\n        // events for video type tracks when they stop receiving data which is\n        // often a sign that remote user is having connectivity issues\n        if (browser.supportsVideoMuteOnConnInterrupted()) {\n\n            this._onTrackRtcMuted = this.onTrackRtcMuted.bind(this);\n            this.rtc.addListener(\n                RTCEvents.REMOTE_TRACK_MUTE, this._onTrackRtcMuted);\n\n            this._onTrackRtcUnmuted = this.onTrackRtcUnmuted.bind(this);\n            this.rtc.addListener(\n                RTCEvents.REMOTE_TRACK_UNMUTE, this._onTrackRtcUnmuted);\n\n            // Track added/removed listeners are used to bind \"mute\"/\"unmute\"\n            // event handlers\n            this._onRemoteTrackAdded = this.onRemoteTrackAdded.bind(this);\n            this.conference.on(\n                JitsiConferenceEvents.TRACK_ADDED,\n                this._onRemoteTrackAdded);\n\n            this._onRemoteTrackRemoved = this.onRemoteTrackRemoved.bind(this);\n            this.conference.on(\n                JitsiConferenceEvents.TRACK_REMOVED,\n                this._onRemoteTrackRemoved);\n\n            // Listened which will be bound to JitsiRemoteTrack to listen for\n            // signalling mute/unmute events.\n            this._onSignallingMuteChanged\n                = this.onSignallingMuteChanged.bind(this);\n\n            // Used to send an analytics event when the video type changes.\n            this._onTrackVideoTypeChanged\n                = this.onTrackVideoTypeChanged.bind(this);\n        }\n\n        this._onLastNChanged = this._onLastNChanged.bind(this);\n        this.conference.on(\n            JitsiConferenceEvents.LAST_N_ENDPOINTS_CHANGED,\n            this._onLastNChanged);\n\n        this._onLastNValueChanged\n            = this.refreshConnectionStatusForAll.bind(this);\n        this.rtc.on(\n            RTCEvents.LASTN_VALUE_CHANGED, this._onLastNValueChanged);\n    }\n\n    /**\n     * Removes all event listeners and disposes of all resources held by this\n     * instance.\n     */\n    dispose() {\n\n        this.rtc.removeListener(\n            RTCEvents.ENDPOINT_CONN_STATUS_CHANGED,\n            this._onEndpointConnStatusChanged);\n\n        if (browser.supportsVideoMuteOnConnInterrupted()) {\n            this.rtc.removeListener(\n                RTCEvents.REMOTE_TRACK_MUTE,\n                this._onTrackRtcMuted);\n            this.rtc.removeListener(\n                RTCEvents.REMOTE_TRACK_UNMUTE,\n                this._onTrackRtcUnmuted);\n\n            this.conference.off(\n                JitsiConferenceEvents.TRACK_ADDED,\n                this._onRemoteTrackAdded);\n            this.conference.off(\n                JitsiConferenceEvents.TRACK_REMOVED,\n                this._onRemoteTrackRemoved);\n        }\n\n        this.conference.off(\n            JitsiConferenceEvents.LAST_N_ENDPOINTS_CHANGED,\n            this._onLastNChanged);\n\n        this.rtc.removeListener(\n            RTCEvents.LASTN_VALUE_CHANGED, this._onLastNValueChanged);\n\n        this.conference.off(\n            JitsiConferenceEvents.P2P_STATUS, this._onP2PStatus);\n\n        this.conference.off(\n            JitsiConferenceEvents.USER_LEFT, this._onUserLeft);\n\n        const participantIds = Object.keys(this.trackTimers);\n\n        for (const participantId of participantIds) {\n            this.clearTimeout(participantId);\n            this.clearRtcMutedTimestamp(participantId);\n        }\n\n        for (const id in this.connectionStatusMap) {\n            if (this.connectionStatusMap.hasOwnProperty(id)) {\n                this.onUserLeft(id);\n            }\n        }\n\n        // Clear RTC connection status cache\n        this.connStatusFromJvb = {};\n    }\n\n    /**\n     * Handles RTCEvents.ENDPOINT_CONN_STATUS_CHANGED triggered when we receive\n     * notification over the data channel from the bridge about endpoint's\n     * connection status update.\n     * @param {string} endpointId - The endpoint ID(MUC nickname/resource JID).\n     * @param {boolean} isActive - true if the connection is OK or false otherwise.\n     */\n    onEndpointConnStatusChanged(endpointId, isActive) {\n\n        logger.debug(\n            `Detector RTCEvents.ENDPOINT_CONN_STATUS_CHANGED(${Date.now()}): ${\n                endpointId}: ${isActive}`);\n\n        // Filter out events for the local JID for now\n        if (endpointId !== this.conference.myUserId()) {\n            // Store the status received over the data channels\n            this.connStatusFromJvb[endpointId] = isActive;\n            this.figureOutConnectionStatus(endpointId);\n        }\n    }\n\n    /**\n     * Changes connection status.\n     * @param {JitsiParticipant} participant\n     * @param newStatus\n     */\n    _changeConnectionStatus(participant, newStatus) {\n        if (participant.getConnectionStatus() !== newStatus) {\n\n            const endpointId = participant.getId();\n\n            participant._setConnectionStatus(newStatus);\n\n            logger.debug(\n                `Emit endpoint conn status(${Date.now()}) ${endpointId}: ${\n                    newStatus}`);\n\n            // Log the event on CallStats\n            Statistics.sendLog(\n                JSON.stringify({\n                    id: 'peer.conn.status',\n                    participant: endpointId,\n                    status: newStatus\n                }));\n\n\n            this.conference.eventEmitter.emit(\n                JitsiConferenceEvents.PARTICIPANT_CONN_STATUS_CHANGED,\n                endpointId, newStatus);\n        }\n    }\n\n    /**\n     * Reset the postponed \"connection interrupted\" event which was previously\n     * scheduled as a timeout on RTC 'onmute' event.\n     *\n     * @param {string} participantId - The participant for which the \"connection\n     * interrupted\" timeout was scheduled.\n     */\n    clearTimeout(participantId) {\n        if (this.trackTimers[participantId]) {\n            window.clearTimeout(this.trackTimers[participantId]);\n            this.trackTimers[participantId] = null;\n        }\n    }\n\n    /**\n     * Clears the timestamp of the RTC muted event for participant's video track\n     * @param {string} participantId the id of the conference participant which\n     * is the same as the Colibri endpoint ID of the video channel allocated for\n     * the user on the videobridge.\n     */\n    clearRtcMutedTimestamp(participantId) {\n        this.rtcMutedTimestamp[participantId] = null;\n    }\n\n    /**\n     * Bind signalling mute event listeners for video {JitsiRemoteTrack} when\n     * a new one is added to the conference.\n     *\n     * @param {JitsiTrack} remoteTrack - The {JitsiTrack} which is being added to\n     * the conference.\n     */\n    onRemoteTrackAdded(remoteTrack) {\n        if (!remoteTrack.isLocal()\n                && remoteTrack.getType() === MediaType.VIDEO) {\n\n            logger.debug(\n                `Detector on remote track added for: ${\n                    remoteTrack.getParticipantId()}`);\n\n            remoteTrack.on(\n                JitsiTrackEvents.TRACK_MUTE_CHANGED,\n                this._onSignallingMuteChanged);\n            remoteTrack.on(\n                JitsiTrackEvents.TRACK_VIDEOTYPE_CHANGED,\n                videoType => this._onTrackVideoTypeChanged(remoteTrack, videoType));\n        }\n    }\n\n    /**\n     * Removes all event listeners bound to the remote video track and clears\n     * any related timeouts.\n     *\n     * @param {JitsiRemoteTrack} remoteTrack - The remote track which is being\n     * removed from the conference.\n     */\n    onRemoteTrackRemoved(remoteTrack) {\n        if (!remoteTrack.isLocal()\n                && remoteTrack.getType() === MediaType.VIDEO) {\n\n            const endpointId = remoteTrack.getParticipantId();\n\n            logger.debug(`Detector on remote track removed: ${endpointId}`);\n\n            remoteTrack.off(\n                JitsiTrackEvents.TRACK_MUTE_CHANGED,\n                this._onSignallingMuteChanged);\n\n            this.clearTimeout(endpointId);\n            this.clearRtcMutedTimestamp(endpointId);\n\n            this.figureOutConnectionStatus(endpointId);\n        }\n    }\n\n    /**\n     * Checks if given participant's video is considered frozen.\n     * @param {JitsiParticipant} participant - The participant.\n     * @return {boolean} <tt>true</tt> if the video has frozen for given\n     * participant or <tt>false</tt> when it's either not considered frozen\n     * (yet) or if freeze detection is not supported by the current browser.\n     *\n     * FIXME merge this logic with NO_DATA_FROM_SOURCE event\n     *       implemented in JitsiLocalTrack by extending the event to\n     *       the remote track and allowing to set different timeout for\n     *       local and remote tracks.\n     *\n     */\n    isVideoTrackFrozen(participant) {\n        if (!browser.supportsVideoMuteOnConnInterrupted()) {\n            return false;\n        }\n\n        const id = participant.getId();\n        const hasAnyVideoRTCMuted = participant.hasAnyVideoTrackWebRTCMuted();\n        const rtcMutedTimestamp = this.rtcMutedTimestamp[id];\n        const timeout = this._getVideoFrozenTimeout(id);\n\n        return hasAnyVideoRTCMuted\n            && typeof rtcMutedTimestamp === 'number'\n            && (Date.now() - rtcMutedTimestamp) >= timeout;\n    }\n\n    /**\n     * Goes over every participant and updates connectivity status.\n     * Should be called when a parameter which affects all of the participants\n     * is changed (P2P for example).\n     */\n    refreshConnectionStatusForAll() {\n        const participants = this.conference.getParticipants();\n\n        for (const participant of participants) {\n            this.figureOutConnectionStatus(participant.getId());\n        }\n    }\n\n    /**\n     * Figures out (and updates) the current connectivity status for\n     * the participant identified by the given id.\n     *\n     * @param {string} id - The participant's id (MUC nickname or Colibri endpoint ID).\n     */\n    figureOutConnectionStatus(id) {\n        const participant = this.conference.getParticipantById(id);\n\n        if (!participant) {\n            // Probably the participant is no longer in the conference\n            // (at the time of writing this code, participant is\n            // detached from the conference and TRACK_REMOVED events are\n            // fired),\n            // so we don't care, but let's print a log message for debugging purposes.\n            logger.debug(`figure out conn status - no participant for: ${id}`);\n\n            return;\n        }\n\n        const inP2PMode = this.conference.isP2PActive();\n        const isRestoringTimedOut = this._isRestoringTimedout(id);\n        const audioOnlyMode = this.conference.getLastN() === 0;\n\n        // NOTE Overriding videoMuted to true for audioOnlyMode should disable\n        // any detection based on video playback or the last N.\n        const isVideoMuted = participant.isVideoMuted() || audioOnlyMode;\n        const isVideoTrackFrozen = this.isVideoTrackFrozen(participant);\n        const isInLastN = this.rtc.isInLastN(id);\n        let isConnActiveByJvb = this.connStatusFromJvb[id];\n\n        if (typeof isConnActiveByJvb !== 'boolean') {\n            // If no status was received from the JVB it means that it's active\n            // (the bridge does not send notification unless there is a problem)\n            isConnActiveByJvb = true;\n        }\n\n        const newState\n            = inP2PMode\n                ? ParticipantConnectionStatusHandler._getNewStateForP2PMode(\n                    isVideoMuted,\n                    isVideoTrackFrozen)\n                : ParticipantConnectionStatusHandler._getNewStateForJvbMode(\n                    isConnActiveByJvb,\n                    isInLastN,\n                    isRestoringTimedOut,\n                    isVideoMuted,\n                    isVideoTrackFrozen);\n\n        // if the new state is not restoring clear timers and timestamps\n        // that we use to track the restoring state\n        if (newState !== ParticipantConnectionStatus.RESTORING) {\n            this._clearRestoringTimer(id);\n        }\n\n        logger.debug(\n            `Figure out conn status for ${id}, is video muted: ${\n                isVideoMuted} is active(jvb): ${\n                isConnActiveByJvb} video track frozen: ${\n                isVideoTrackFrozen} p2p mode: ${\n                inP2PMode} is in last N: ${\n                isInLastN} currentStatus => newStatus: ${\n                participant.getConnectionStatus()} => ${newState}`);\n\n        const oldConnectionStatus = this.connectionStatusMap[id] || {};\n\n        // Send an analytics event (guard on either the p2p flag or the connection status has changed\n        // since the last time this code block run).\n        if (!('p2p' in oldConnectionStatus)\n            || !('connectionStatus' in oldConnectionStatus)\n            || oldConnectionStatus.p2p !== inP2PMode\n            || oldConnectionStatus.connectionStatus !== newState) {\n\n            const nowMs = Date.now();\n\n            this.maybeSendParticipantConnectionStatusEvent(id, nowMs);\n\n            this.connectionStatusMap[id] = {\n                ...oldConnectionStatus,\n                connectionStatus: newState,\n                p2p: inP2PMode,\n                startedMs: nowMs\n            };\n\n            // sometimes (always?) we're late to hook the TRACK_VIDEOTYPE_CHANGED event and the\n            // video type is not in oldConnectionStatus.\n            if (!('videoType' in this.connectionStatusMap[id])) {\n                const videoTracks = participant.getTracksByMediaType(MediaType.VIDEO);\n\n                if (Array.isArray(videoTracks) && videoTracks.length !== 0) {\n                    this.connectionStatusMap[id].videoType = videoTracks[0].videoType;\n                }\n            }\n        }\n        this._changeConnectionStatus(participant, newState);\n    }\n\n    /**\n     * Computes the duration of the current connection status for the participant with the specified id (i.e. 15 seconds\n     * in the INTERRUPTED state) and sends a participant connection status event.\n     * @param {string} id - The jid of the participant.\n     * @param {Number} nowMs - The current time (in millis).\n     * @returns {void}\n     */\n    maybeSendParticipantConnectionStatusEvent(id, nowMs) {\n        const participantConnectionStatus = this.connectionStatusMap[id];\n\n        if (participantConnectionStatus\n            && 'startedMs' in participantConnectionStatus\n            && 'videoType' in participantConnectionStatus\n            && 'connectionStatus' in participantConnectionStatus\n            && 'p2p' in participantConnectionStatus) {\n            participantConnectionStatus.value = nowMs - participantConnectionStatus.startedMs;\n            Statistics.sendAnalytics(\n                createParticipantConnectionStatusEvent(participantConnectionStatus));\n        }\n    }\n\n    /**\n     * On change in Last N set check all leaving and entering participants to\n     * change their corresponding statuses.\n     *\n     * @param {Array<string>} leavingLastN - The array of ids leaving lastN.\n     * @param {Array<string>} enteringLastN - The array of ids entering lastN.\n     * @private\n     */\n    _onLastNChanged(leavingLastN = [], enteringLastN = []) {\n        const now = Date.now();\n\n        logger.debug(`LastN endpoints changed leaving=${leavingLastN}, entering=${enteringLastN} at ${now}`);\n\n        // If the browser doesn't fire the mute/onmute events when the remote peer stops/starts sending media,\n        // calculate the connection status for all the endpoints since it won't get triggered automatically on\n        // the endpoint that has started/stopped receiving media.\n        if (!browser.supportsVideoMuteOnConnInterrupted()) {\n            this.refreshConnectionStatusForAll();\n        }\n\n        for (const id of leavingLastN) {\n            this.enteredLastNTimestamp.delete(id);\n            this._clearRestoringTimer(id);\n            browser.supportsVideoMuteOnConnInterrupted() && this.figureOutConnectionStatus(id);\n        }\n        for (const id of enteringLastN) {\n            // store the timestamp this id is entering lastN\n            this.enteredLastNTimestamp.set(id, now);\n            browser.supportsVideoMuteOnConnInterrupted() && this.figureOutConnectionStatus(id);\n        }\n    }\n\n    /**\n     * Clears the restoring timer for participant's video track and the\n     * timestamp for entering lastN.\n     *\n     * @param {string} participantId - The id of the conference participant which\n     * is the same as the Colibri endpoint ID of the video channel allocated for\n     * the user on the videobridge.\n     */\n    _clearRestoringTimer(participantId) {\n        const rTimer = this.restoringTimers.get(participantId);\n\n        if (rTimer) {\n            clearTimeout(rTimer);\n            this.restoringTimers.delete(participantId);\n        }\n    }\n\n    /**\n     * Checks whether a track had stayed enough in restoring state, compares\n     * current time and the time the track entered in lastN. If it hasn't\n     * timedout and there is no timer added, add new timer in order to give it\n     * more time to become active or mark it as interrupted on next check.\n     *\n     * @param {string} participantId - The id of the conference participant which\n     * is the same as the Colibri endpoint ID of the video channel allocated for\n     * the user on the videobridge.\n     * @returns {boolean} <tt>true</tt> if the track was in restoring state\n     * more than the timeout ({@link DEFAULT_RESTORING_TIMEOUT}.) in order to\n     * set its status to interrupted.\n     * @private\n     */\n    _isRestoringTimedout(participantId) {\n        const enteredLastNTimestamp\n            = this.enteredLastNTimestamp.get(participantId);\n\n        if (enteredLastNTimestamp\n            && (Date.now() - enteredLastNTimestamp)\n                >= DEFAULT_RESTORING_TIMEOUT) {\n            return true;\n        }\n\n        // still haven't reached timeout, if there is no timer scheduled,\n        // schedule one so we can track the restoring state and change it after\n        // reaching the timeout\n        const rTimer = this.restoringTimers.get(participantId);\n\n        if (!rTimer) {\n            this.restoringTimers.set(participantId, setTimeout(\n                () => this.figureOutConnectionStatus(participantId),\n                DEFAULT_RESTORING_TIMEOUT));\n        }\n\n        return false;\n    }\n\n    /**\n     * Sends a last/final participant connection status event for the participant that left the conference.\n     * @param {string} id - The id of the participant that left the conference.\n     * @returns {void}\n     */\n    onUserLeft(id) {\n        this.maybeSendParticipantConnectionStatusEvent(id, Date.now());\n        delete this.connectionStatusMap[id];\n    }\n\n    /**\n     * Handles RTC 'onmute' event for the video track.\n     *\n     * @param {JitsiRemoteTrack} track - The video track for which 'onmute' event\n     * will be processed.\n     */\n    onTrackRtcMuted(track) {\n        const participantId = track.getParticipantId();\n        const participant = this.conference.getParticipantById(participantId);\n\n        logger.debug(`Detector track RTC muted: ${participantId}`, Date.now());\n        if (!participant) {\n            logger.error(`No participant for id: ${participantId}`);\n\n            return;\n        }\n        this.rtcMutedTimestamp[participantId] = Date.now();\n        if (!participant.isVideoMuted()) {\n            // If the user is not muted according to the signalling we'll give\n            // it some time, before the connection interrupted event is\n            // triggered.\n            this.clearTimeout(participantId);\n\n            // The timeout is reduced when user is not in the last N\n            const timeout = this._getVideoFrozenTimeout(participantId);\n\n            this.trackTimers[participantId] = window.setTimeout(() => {\n                logger.debug(\n                    `Set RTC mute timeout for: ${participantId}\\\n                     of ${timeout} ms`);\n                this.clearTimeout(participantId);\n                this.figureOutConnectionStatus(participantId);\n            }, timeout);\n        }\n    }\n\n    /**\n     * Handles RTC 'onunmute' event for the video track.\n     *\n     * @param {JitsiRemoteTrack} track - The video track for which 'onunmute'\n     * event will be processed.\n     */\n    onTrackRtcUnmuted(track) {\n        const participantId = track.getParticipantId();\n\n        logger.debug(\n            `Detector track RTC unmuted: ${participantId}`, Date.now());\n\n        this.clearTimeout(participantId);\n        this.clearRtcMutedTimestamp(participantId);\n\n        this.figureOutConnectionStatus(participantId);\n    }\n\n    /**\n     * Here the signalling \"mute\"/\"unmute\" events are processed.\n     *\n     * @param {JitsiRemoteTrack} track - The remote video track for which\n     * the signalling mute/unmute event will be processed.\n     */\n    onSignallingMuteChanged(track) {\n        const participantId = track.getParticipantId();\n\n        logger.debug(\n            `Detector on track signalling mute changed: ${participantId}`,\n            track.isMuted());\n\n        this.figureOutConnectionStatus(participantId);\n    }\n\n    /**\n     * Sends a participant connection status event as a result of the video type\n     * changing.\n     * @param {JitsiRemoteTrack} track - The track.\n     * @param {VideoType} type - The video type.\n     * @returns {void}\n     */\n    onTrackVideoTypeChanged(track, type) {\n        const id = track.getParticipantId();\n        const nowMs = Date.now();\n\n        this.maybeSendParticipantConnectionStatusEvent(id, nowMs);\n\n        this.connectionStatusMap[id] = {\n            ...this.connectionStatusMap[id] || {},\n            videoType: type,\n            startedMs: nowMs\n        };\n    }\n}\n","\nimport { Strophe } from 'strophe.js';\n\n\nimport * as JitsiConferenceEvents from './JitsiConferenceEvents';\nimport { ParticipantConnectionStatus }\n    from './modules/connectivity/ParticipantConnectionStatus';\nimport { MediaType } from './service/RTC/MediaType';\n\n/**\n * Represents a participant in (i.e. a member of) a conference.\n */\nexport default class JitsiParticipant {\n\n    /* eslint-disable max-params */\n\n    /**\n     * Initializes a new JitsiParticipant instance.\n     *\n     * @constructor\n     * @param jid the conference XMPP jid\n     * @param conference\n     * @param displayName\n     * @param {Boolean} hidden - True if the new JitsiParticipant instance is to\n     * represent a hidden participant; otherwise, false.\n     * @param {string} statsID - optional participant statsID\n     * @param {string} status - the initial status if any.\n     * @param {object} identity - the xmpp identity\n     * @param {boolean?} isReplacing - whether this is a participant replacing another into the meeting.\n     * @param {boolean?} isReplaced - whether this is a participant to be kicked and replaced into the meeting.\n     */\n    constructor(jid, conference, displayName, hidden, statsID, status, identity, isReplacing, isReplaced) {\n        this._jid = jid;\n        this._id = Strophe.getResourceFromJid(jid);\n        this._conference = conference;\n        this._displayName = displayName;\n        this._supportsDTMF = false;\n        this._tracks = [];\n        this._role = 'none';\n        this._status = status;\n        this._hidden = hidden;\n        this._statsID = statsID;\n        this._connectionStatus = ParticipantConnectionStatus.ACTIVE;\n        this._properties = {};\n        this._identity = identity;\n        this._isReplacing = isReplacing;\n        this._isReplaced = isReplaced;\n        this._features = new Set();\n    }\n\n    /* eslint-enable max-params */\n\n    /**\n     * @returns {JitsiConference} The conference that this participant belongs\n     * to.\n     */\n    getConference() {\n        return this._conference;\n    }\n\n    /**\n     * Gets the value of a property of this participant.\n     */\n    getProperty(name) {\n        return this._properties[name];\n    }\n\n    /**\n     * Checks whether this <tt>JitsiParticipant</tt> has any video tracks which\n     * are muted according to their underlying WebRTC <tt>MediaStreamTrack</tt>\n     * muted status.\n     * @return {boolean} <tt>true</tt> if this <tt>participant</tt> contains any\n     * video <tt>JitsiTrack</tt>s which are muted as defined in\n     * {@link JitsiTrack.isWebRTCTrackMuted}.\n     */\n    hasAnyVideoTrackWebRTCMuted() {\n        return (\n            this.getTracks().some(\n                jitsiTrack =>\n                    jitsiTrack.getType() === MediaType.VIDEO\n                        && jitsiTrack.isWebRTCTrackMuted()));\n    }\n\n    /**\n     * Updates participant's connection status.\n     * @param {string} state the current participant connection state.\n     * {@link ParticipantConnectionStatus}.\n     * @private\n     */\n    _setConnectionStatus(status) {\n        this._connectionStatus = status;\n    }\n\n    /**\n     * Return participant's connectivity status.\n     *\n     * @returns {string} the connection status\n     * <tt>ParticipantConnectionStatus</tt> of the user.\n     * {@link ParticipantConnectionStatus}.\n     */\n    getConnectionStatus() {\n        return this._connectionStatus;\n    }\n\n    /**\n     * Sets the value of a property of this participant, and fires an event if\n     * the value has changed.\n     * @name the name of the property.\n     * @value the value to set.\n     */\n    setProperty(name, value) {\n        const oldValue = this._properties[name];\n\n        if (value !== oldValue) {\n            this._properties[name] = value;\n            this._conference.eventEmitter.emit(\n                JitsiConferenceEvents.PARTICIPANT_PROPERTY_CHANGED,\n                this,\n                name,\n                oldValue,\n                value);\n        }\n    }\n\n    /**\n     * @returns {Array.<JitsiTrack>} The list of media tracks for this\n     * participant.\n     */\n    getTracks() {\n        return this._tracks.slice();\n    }\n\n    /**\n     * @param {MediaType} mediaType\n     * @returns {Array.<JitsiTrack>} an array of media tracks for this\n     * participant, for given media type.\n     */\n    getTracksByMediaType(mediaType) {\n        return this.getTracks().filter(track => track.getType() === mediaType);\n    }\n\n    /**\n     * @returns {String} The ID of this participant.\n     */\n    getId() {\n        return this._id;\n    }\n\n    /**\n     * @returns {String} The JID of this participant.\n     */\n    getJid() {\n        return this._jid;\n    }\n\n    /**\n     * @returns {String} The human-readable display name of this participant.\n     */\n    getDisplayName() {\n        return this._displayName;\n    }\n\n    /**\n     * @returns {String} The stats ID of this participant.\n     */\n    getStatsID() {\n        return this._statsID;\n    }\n\n    /**\n     * @returns {String} The status of the participant.\n     */\n    getStatus() {\n        return this._status;\n    }\n\n    /**\n     * @returns {Boolean} Whether this participant is a moderator or not.\n     */\n    isModerator() {\n        return this._role === 'moderator';\n    }\n\n    /**\n     * @returns {Boolean} Whether this participant is a hidden participant. Some\n     * special system participants may want to join hidden (like for example the\n     * recorder).\n     */\n    isHidden() {\n        return this._hidden;\n    }\n\n    /**\n     * @returns {Boolean} Whether this participant is a hidden participant. Some\n     * special system participants may want to join hidden (like for example the\n     * recorder).\n     */\n    isHiddenFromRecorder() {\n        return Boolean(this._identity?.user?.['hidden-from-recorder']);\n    }\n\n    /**\n     * @returns {Boolean} Whether this participant replaces another participant\n     * from the meeting.\n     */\n    isReplacing() {\n        return this._isReplacing;\n    }\n\n    /**\n     * @returns {Boolean} Wheter this participants will be replaced by another\n     * participant in the meeting.\n     */\n    isReplaced() {\n        return this._isReplaced;\n    }\n\n    /**\n     * @returns {Boolean} Whether this participant has muted their audio.\n     */\n    isAudioMuted() {\n        return this._isMediaTypeMuted(MediaType.AUDIO);\n    }\n\n    /**\n     * Determines whether all JitsiTracks which are of a specific MediaType and\n     * which belong to this JitsiParticipant are muted.\n     *\n     * @param {MediaType} mediaType - The MediaType of the JitsiTracks to be\n     * checked.\n     * @private\n     * @returns {Boolean} True if all JitsiTracks which are of the specified\n     * mediaType and which belong to this JitsiParticipant are muted; otherwise,\n     * false.\n     */\n    _isMediaTypeMuted(mediaType) {\n        return this.getTracks().reduce(\n            (muted, track) =>\n                muted && (track.getType() !== mediaType || track.isMuted()),\n            true);\n    }\n\n    /**\n     * @returns {Boolean} Whether this participant has muted their video.\n     */\n    isVideoMuted() {\n        return this._isMediaTypeMuted(MediaType.VIDEO);\n    }\n\n    /**\n     * @returns {String} The role of this participant.\n     */\n    getRole() {\n        return this._role;\n    }\n\n    /**\n     * Sets a new participant role.\n     * @param {String} newRole - the new role.\n     */\n    setRole(newRole) {\n        this._role = newRole;\n    }\n\n    /**\n     * Sets whether participant is replacing another based on jwt.\n     * @param {String} newIsReplacing - whether is replacing.\n     */\n    setIsReplacing(newIsReplacing) {\n        this._isReplacing = newIsReplacing;\n    }\n\n    /**\n     * Sets whether participant is being replaced by another based on jwt.\n     * @param {boolean} newIsReplaced - whether is being replaced.\n     */\n    setIsReplaced(newIsReplaced) {\n        this._isReplaced = newIsReplaced;\n    }\n\n    /**\n     *\n     */\n    supportsDTMF() {\n        return this._supportsDTMF;\n    }\n\n    /**\n     * Returns a set with the features for the participant.\n     * @returns {Promise<Set<String>, Error>}\n     */\n    getFeatures() {\n        return Promise.resolve(this._features);\n    }\n\n    /**\n     * Checks current set features.\n     * @param {String} feature - the feature to check.\n     * @return {boolean} <tt>true</tt> if this <tt>participant</tt> contains the\n     * <tt>feature</tt>.\n     */\n    hasFeature(feature) {\n        return this._features.has(feature);\n    }\n\n    /**\n     * Set new features.\n     * @param {Set<String>|undefined} newFeatures - Sets new features.\n     */\n    setFeatures(newFeatures) {\n        this._features = newFeatures || new Set();\n    }\n\n    /**\n     * Returns the bot type for the participant.\n     *\n     * @returns {string|undefined} - The bot type of the participant.\n     */\n    getBotType() {\n        return this._botType;\n    }\n\n    /**\n     * Sets the bot type for the participant.\n     * @param {String} newBotType - The new bot type to set.\n     */\n    setBotType(newBotType) {\n        this._botType = newBotType;\n    }\n}\n","/**\n * The events for the connection.\n */\n\nexport enum JitsiConnectionEvents {\n    /**\n     * Indicates that the connection has been disconnected. The event provides\n     * the following parameters to its listeners:\n     *\n     * @param msg {string} a message associated with the disconnect such as the\n     * last (known) error message\n     */\n    CONNECTION_DISCONNECTED = 'connection.connectionDisconnected',\n\n    /**\n     * Indicates that the connection has been established. The event provides\n     * the following parameters to its listeners:\n     *\n     * @param id {string} the ID of the local endpoint/participant/peer (within\n     * the context of the established connection)\n     */\n    CONNECTION_ESTABLISHED = 'connection.connectionEstablished',\n\n    /**\n     * Indicates that the connection has been failed for some reason. The event\n     * provides the following parameters to its listeners:\n     *\n     * @param errType {JitsiConnectionErrors} the type of error associated with\n     * the failure\n     * @param errReason {string} the error (message) associated with the failure\n     * @param credentials {object} the credentials used to connect (if any)\n     * @param errReasonDetails {object} an optional object with details about\n     * the error, like shard moving, suspending. Used for analytics purposes.\n     */\n    CONNECTION_FAILED = 'connection.connectionFailed',\n\n    /**\n     * Indicates that the performed action cannot be executed because the\n     * connection is not in the correct state(connected, disconnected, etc.)\n     */\n    WRONG_STATE = 'connection.wrongState',\n\n    /**\n     * Indicates that the display name is required over this connection and need to be supplied when\n     * joining the room.\n     * There are cases like lobby room where display name is required.\n     */\n    DISPLAY_NAME_REQUIRED = 'connection.display_name_required'\n};\n\n// exported for backward compatibility\nexport const CONNECTION_DISCONNECTED = JitsiConnectionEvents.CONNECTION_DISCONNECTED;\nexport const CONNECTION_ESTABLISHED = JitsiConnectionEvents.CONNECTION_ESTABLISHED;\nexport const CONNECTION_FAILED = JitsiConnectionEvents.CONNECTION_FAILED;\nexport const WRONG_STATE = JitsiConnectionEvents.WRONG_STATE;\nexport const DISPLAY_NAME_REQUIRED = JitsiConnectionEvents.DISPLAY_NAME_REQUIRED;\n","/**\n * The errors for the connection.\n */\n\nexport enum JitsiConnectionErrors {\n    /**\n     * Indicates that the connection was dropped with an error which was most likely\n     * caused by some networking issues. The dropped term in this context means that\n     * the connection was closed unexpectedly (not on user's request).\n     *\n     * One example is 'item-not-found' error thrown by Prosody when the BOSH session\n     * times out after 60 seconds of inactivity. On the other hand 'item-not-found'\n     * could also happen when BOSH request is sent to the server with the session-id\n     * that is not know to the server. But this should not happen in lib-jitsi-meet\n     * case as long as the service is configured correctly (there is no bug).\n     */\n    CONNECTION_DROPPED_ERROR = 'connection.droppedError',\n\n    /**\n     * Not specified errors.\n     */\n    OTHER_ERROR = 'connection.otherError',\n\n    /**\n     * Indicates that a password is required in order to join the conference.\n     */\n    PASSWORD_REQUIRED = 'connection.passwordRequired',\n\n    /**\n     * Indicates that the connection was dropped, because of too many 5xx HTTP\n     * errors on BOSH requests.\n     */\n    SERVER_ERROR = 'connection.serverError'\n};\n\n// exported for backward compatibility\nexport const CONNECTION_DROPPED_ERROR = JitsiConnectionErrors.CONNECTION_DROPPED_ERROR;\nexport const OTHER_ERROR = JitsiConnectionErrors.OTHER_ERROR;\nexport const PASSWORD_REQUIRED = JitsiConnectionErrors.PASSWORD_REQUIRED;\nexport const SERVER_ERROR = JitsiConnectionErrors.SERVER_ERROR;\n","\n/**\n * Promise-like object which can be passed around for resolving it later. It\n * implements the \"thenable\" interface, so it can be used wherever a Promise\n * could be used.\n *\n * In addition a \"reject on timeout\" functionality is provided.\n */\nexport default class Deferred {\n    /**\n     * Instantiates a Deferred object.\n     */\n    constructor() {\n        this.promise = new Promise((resolve, reject) => {\n            this.resolve = (...args) => {\n                this.clearRejectTimeout();\n                resolve(...args);\n            };\n            this.reject = (...args) => {\n                this.clearRejectTimeout();\n                reject(...args);\n            };\n        });\n        this.then = this.promise.then.bind(this.promise);\n        this.catch = this.promise.catch.bind(this.promise);\n    }\n\n    /**\n     * Clears the reject timeout.\n     */\n    clearRejectTimeout() {\n        clearTimeout(this._timeout);\n    }\n\n    /**\n     * Rejects the promise after the given timeout.\n     */\n    setRejectTimeout(ms) {\n        this._timeout = setTimeout(() => {\n            this.reject(new Error('timeout'));\n        }, ms);\n    }\n}\n","import EventEmitter from 'events';\n\n/**\n * The class implements basic event operations - add/remove listener.\n * NOTE: The purpose of the class is to be extended in order to add\n * this functionality to other classes.\n */\nexport default class Listenable {\n    /**\n     * Creates new instance.\n     * @param {EventEmitter} eventEmitter\n     * @constructor\n     */\n    constructor(eventEmitter = new EventEmitter()) {\n        this.eventEmitter = eventEmitter;\n\n        // aliases for addListener/removeListener\n        this.addEventListener = this.on = this.addListener;\n        this.removeEventListener = this.off = this.removeListener;\n    }\n\n    /**\n     * Adds new listener.\n     * @param {String} eventName the name of the event\n     * @param {Function} listener the listener.\n     * @returns {Function} - The unsubscribe function.\n     */\n    addListener(eventName, listener) {\n        this.eventEmitter.addListener(eventName, listener);\n\n        return () => this.removeEventListener(eventName, listener);\n    }\n\n    /**\n     * Removes listener.\n     * @param {String} eventName the name of the event that triggers the\n     * listener\n     * @param {Function} listener the listener.\n     */\n    removeListener(eventName, listener) {\n        this.eventEmitter.removeListener(eventName, listener);\n    }\n}\n","/* global RTCRtpScriptTransform */\n\nimport { getLogger } from '@jitsi/logger';\n\nconst logger = getLogger(__filename);\n\n// Flag to set on senders / receivers to avoid setting up the encryption transform\n// more than once.\nconst kJitsiE2EE = Symbol('kJitsiE2EE');\n\n/**\n * Context encapsulating the cryptography bits required for E2EE.\n * This uses the WebRTC Insertable Streams API which is explained in\n *   https://github.com/alvestrand/webrtc-media-streams/blob/master/explainer.md\n * that provides access to the encoded frames and allows them to be transformed.\n *\n * The encoded frame format is explained below in the _encodeFunction method.\n * High level design goals were:\n * - do not require changes to existing SFUs and retain (VP8) metadata.\n * - allow the SFU to rewrite SSRCs, timestamp, pictureId.\n * - allow for the key to be rotated frequently.\n */\nexport default class E2EEcontext {\n    /**\n     * Build a new E2EE context instance, which will be used in a given conference.\n     * @param {boolean} [options.sharedKey] - whether there is a uniques key shared amoung all participants.\n     */\n    constructor({ sharedKey } = {}) {\n        // Determine the URL for the worker script. Relative URLs are relative to\n        // the entry point, not the script that launches the worker.\n        let baseUrl = '';\n        const ljm = document.querySelector('script[src*=\"lib-jitsi-meet\"]');\n\n        if (ljm) {\n            const idx = ljm.src.lastIndexOf('/');\n\n            baseUrl = `${ljm.src.substring(0, idx)}/`;\n        }\n\n        let workerUrl = `${baseUrl}lib-jitsi-meet.e2ee-worker.js`;\n\n        // If there is no baseUrl then we create the worker in a normal way\n        // as you cant load scripts inside blobs from relative paths.\n        // See: https://www.html5rocks.com/en/tutorials/workers/basics/#toc-inlineworkers-loadingscripts\n        if (baseUrl && baseUrl !== '/') {\n            // Initialize the E2EE worker. In order to avoid CORS issues, start the worker and have it\n            // synchronously load the JS.\n            const workerBlob\n                = new Blob([ `importScripts(\"${workerUrl}\");` ], { type: 'application/javascript' });\n\n            workerUrl = window.URL.createObjectURL(workerBlob);\n        }\n\n        this._worker = new Worker(workerUrl, { name: 'E2EE Worker' });\n\n        this._worker.onerror = e => logger.error(e);\n\n        this._worker.postMessage({\n            operation: 'initialize',\n            sharedKey\n        });\n    }\n\n    /**\n     * Cleans up all state associated with the given participant. This is needed when a\n     * participant leaves the current conference.\n     *\n     * @param {string} participantId - The participant that just left.\n     */\n    cleanup(participantId) {\n        this._worker.postMessage({\n            operation: 'cleanup',\n            participantId\n        });\n    }\n\n    /**\n     * Cleans up all state associated with all participants in the conference. This is needed when disabling e2ee.\n     *\n     */\n    cleanupAll() {\n        this._worker.postMessage({\n            operation: 'cleanupAll'\n        });\n    }\n\n    /**\n     * Handles the given {@code RTCRtpReceiver} by creating a {@code TransformStream} which will inject\n     * a frame decoder.\n     *\n     * @param {RTCRtpReceiver} receiver - The receiver which will get the decoding function injected.\n     * @param {string} kind - The kind of track this receiver belongs to.\n     * @param {string} participantId - The participant id that this receiver belongs to.\n     */\n    handleReceiver(receiver, kind, participantId) {\n        if (receiver[kJitsiE2EE]) {\n            return;\n        }\n        receiver[kJitsiE2EE] = true;\n\n        if (window.RTCRtpScriptTransform) {\n            const options = {\n                operation: 'decode',\n                participantId\n            };\n\n            receiver.transform = new RTCRtpScriptTransform(this._worker, options);\n        } else {\n            const receiverStreams = receiver.createEncodedStreams();\n\n            this._worker.postMessage({\n                operation: 'decode',\n                readableStream: receiverStreams.readable,\n                writableStream: receiverStreams.writable,\n                participantId\n            }, [ receiverStreams.readable, receiverStreams.writable ]);\n        }\n    }\n\n    /**\n     * Handles the given {@code RTCRtpSender} by creating a {@code TransformStream} which will inject\n     * a frame encoder.\n     *\n     * @param {RTCRtpSender} sender - The sender which will get the encoding function injected.\n     * @param {string} kind - The kind of track this sender belongs to.\n     * @param {string} participantId - The participant id that this sender belongs to.\n     */\n    handleSender(sender, kind, participantId) {\n        if (sender[kJitsiE2EE]) {\n            return;\n        }\n        sender[kJitsiE2EE] = true;\n\n        if (window.RTCRtpScriptTransform) {\n            const options = {\n                operation: 'encode',\n                participantId\n            };\n\n            sender.transform = new RTCRtpScriptTransform(this._worker, options);\n        } else {\n            const senderStreams = sender.createEncodedStreams();\n\n            this._worker.postMessage({\n                operation: 'encode',\n                readableStream: senderStreams.readable,\n                writableStream: senderStreams.writable,\n                participantId\n            }, [ senderStreams.readable, senderStreams.writable ]);\n        }\n    }\n\n    /**\n     * Set the E2EE key for the specified participant.\n     *\n     * @param {string} participantId - the ID of the participant who's key we are setting.\n     * @param {Uint8Array | boolean} key - they key for the given participant.\n     * @param {Number} keyIndex - the key index.\n     */\n    setKey(participantId, key, keyIndex) {\n        this._worker.postMessage({\n            operation: 'setKey',\n            key,\n            keyIndex,\n            participantId\n        });\n    }\n}\n","import { getLogger } from '@jitsi/logger';\n\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\nimport RTCEvents from '../../service/RTC/RTCEvents';\nimport browser from '../browser';\nimport Deferred from '../util/Deferred';\nimport Listenable from '../util/Listenable';\n\nimport E2EEContext from './E2EEContext';\n\nconst logger = getLogger(__filename);\n\n/**\n * Abstract class that integrates {@link E2EEContext} with a key management system.\n */\nexport class KeyHandler extends Listenable {\n    /**\n     * Build a new KeyHandler instance, which will be used in a given conference.\n     * @param {JitsiConference} conference - the current conference.\n     * @param {object} options - the options passed to {E2EEContext}, see implemention.\n     */\n    constructor(conference, options = {}) {\n        super();\n\n        this.conference = conference;\n        this.e2eeCtx = new E2EEContext(options);\n\n        this.enabled = false;\n        this._enabling = undefined;\n\n        // Conference media events in order to attach the encryptor / decryptor.\n        // FIXME add events to TraceablePeerConnection which will allow to see when there's new receiver or sender\n        // added instead of shenanigans around conference track events and track muted.\n        //\n\n        this.conference.on(\n            JitsiConferenceEvents._MEDIA_SESSION_STARTED,\n            this._onMediaSessionStarted.bind(this));\n        this.conference.on(\n            JitsiConferenceEvents.TRACK_ADDED,\n            track => track.isLocal() && this._onLocalTrackAdded(track));\n        this.conference.rtc.on(\n            RTCEvents.REMOTE_TRACK_ADDED,\n            (track, tpc) => this._setupReceiverE2EEForTrack(tpc, track));\n        this.conference.on(\n            JitsiConferenceEvents.TRACK_MUTE_CHANGED,\n            this._trackMuteChanged.bind(this));\n    }\n\n    /**\n     * Indicates whether E2EE is currently enabled or not.\n     *\n     * @returns {boolean}\n     */\n    isEnabled() {\n        return this.enabled;\n    }\n\n    /**\n     * Enables / disables End-To-End encryption.\n     *\n     * @param {boolean} enabled - whether E2EE should be enabled or not.\n     * @returns {void}\n     */\n    async setEnabled(enabled) {\n        if (enabled === this.enabled) {\n            return;\n        }\n\n        this._enabling && await this._enabling;\n\n        this._enabling = new Deferred();\n\n        this.enabled = enabled;\n\n        if (!enabled) {\n            this.e2eeCtx.cleanupAll();\n        }\n\n        this._setEnabled && await this._setEnabled(enabled);\n\n        this.conference.setLocalParticipantProperty('e2ee.enabled', enabled);\n\n        this.conference._restartMediaSessions();\n\n        this._enabling.resolve();\n    }\n\n    /**\n     * Sets the key for End-to-End encryption.\n     *\n     * @returns {void}\n     */\n    setEncryptionKey() {\n        throw new Error('Not implemented by subclass');\n    }\n\n    /**\n     * Setup E2EE on the new track that has been added to the conference, apply it on all the open peerconnections.\n     * @param {JitsiLocalTrack} track - the new track that's being added to the conference.\n     * @private\n     */\n    _onLocalTrackAdded(track) {\n        for (const session of this.conference.getMediaSessions()) {\n            this._setupSenderE2EEForTrack(session, track);\n        }\n    }\n\n    /**\n     * Setups E2E encryption for the new session.\n     * @param {JingleSessionPC} session - the new media session.\n     * @private\n     */\n    _onMediaSessionStarted(session) {\n        const localTracks = this.conference.getLocalTracks();\n\n        for (const track of localTracks) {\n            this._setupSenderE2EEForTrack(session, track);\n        }\n    }\n\n    /**\n     * Setup E2EE for the receiving side.\n     *\n     * @private\n     */\n    _setupReceiverE2EEForTrack(tpc, track) {\n        if (!this.enabled) {\n            return;\n        }\n\n        const receiver = tpc.findReceiverForTrack(track.track);\n\n        if (receiver) {\n            this.e2eeCtx.handleReceiver(receiver, track.getType(), track.getParticipantId());\n        } else {\n            logger.warn(`Could not handle E2EE for ${track}: receiver not found in: ${tpc}`);\n        }\n    }\n\n    /**\n     * Setup E2EE for the sending side.\n     *\n     * @param {JingleSessionPC} session - the session which sends the media produced by the track.\n     * @param {JitsiLocalTrack} track - the local track for which e2e encoder will be configured.\n     * @private\n     */\n    _setupSenderE2EEForTrack(session, track) {\n        if (!this.enabled) {\n            return;\n        }\n\n        const pc = session.peerconnection;\n        const sender = pc && pc.findSenderForTrack(track.track);\n\n        if (sender) {\n            this.e2eeCtx.handleSender(sender, track.getType(), track.getParticipantId());\n        } else {\n            logger.warn(`Could not handle E2EE for ${track}: sender not found in ${pc}`);\n        }\n    }\n\n    /**\n     * Setup E2EE on the sender that is created for the unmuted local video track.\n     * @param {JitsiLocalTrack} track - the track for which muted status has changed.\n     * @private\n     */\n    _trackMuteChanged(track) {\n        if (browser.doesVideoMuteByStreamRemove() && track.isLocal() && track.isVideoTrack() && !track.isMuted()) {\n            for (const session of this.conference.getMediaSessions()) {\n                this._setupSenderE2EEForTrack(session, track);\n            }\n        }\n    }\n}\n","import { KeyHandler } from './KeyHandler';\n\n/**\n * This module integrates {@link E2EEContext} with {external} in order to set the keys for encryption.\n */\nexport class ExternallyManagedKeyHandler extends KeyHandler {\n    /**\n     * Build a new ExternallyManagedKeyHandler instance, which will be used in a given conference.\n     * @param conference - the current conference.\n     */\n    constructor(conference) {\n        super(conference, { sharedKey: true });\n    }\n\n    /**\n     * Sets the key and index for End-to-End encryption.\n     *\n     * @param {CryptoKey} [keyInfo.encryptionKey] - encryption key.\n     * @param {Number} [keyInfo.index] - the index of the encryption key.\n     * @returns {void}\n     */\n    setKey(keyInfo) {\n        this.e2eeCtx.setKey(undefined, { encryptionKey: keyInfo.encryptionKey }, keyInfo.index);\n    }\n}\n","// Unique ID creation requires a high quality random # generator. In the browser we therefore\n// require the crypto API and do not support built-in fallback to lower quality random number\n// generators (like Math.random()).\nvar getRandomValues;\nvar rnds8 = new Uint8Array(16);\nexport default function rng() {\n  // lazy load so that environments that need to polyfill have a chance to do so\n  if (!getRandomValues) {\n    // getRandomValues needs to be invoked in a context where \"this\" is a Crypto implementation. Also,\n    // find the complete implementation of crypto (msCrypto) on IE11.\n    getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto) || typeof msCrypto !== 'undefined' && typeof msCrypto.getRandomValues === 'function' && msCrypto.getRandomValues.bind(msCrypto);\n\n    if (!getRandomValues) {\n      throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported');\n    }\n  }\n\n  return getRandomValues(rnds8);\n}","export default /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i;","import REGEX from './regex.js';\n\nfunction validate(uuid) {\n  return typeof uuid === 'string' && REGEX.test(uuid);\n}\n\nexport default validate;","import validate from './validate.js';\n/**\n * Convert array of 16 byte values to UUID string format of the form:\n * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX\n */\n\nvar byteToHex = [];\n\nfor (var i = 0; i < 256; ++i) {\n  byteToHex.push((i + 0x100).toString(16).substr(1));\n}\n\nfunction stringify(arr) {\n  var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n  // Note: Be careful editing this code!  It's been tuned for performance\n  // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434\n  var uuid = (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase(); // Consistency check for valid UUID.  If this throws, it's likely due to one\n  // of the following:\n  // - One or more input array values don't map to a hex octet (leading to\n  // \"undefined\" in the uuid)\n  // - Invalid input values for the RFC `version` or `variant` fields\n\n  if (!validate(uuid)) {\n    throw TypeError('Stringified UUID is invalid');\n  }\n\n  return uuid;\n}\n\nexport default stringify;","import rng from './rng.js';\nimport stringify from './stringify.js';\n\nfunction v4(options, buf, offset) {\n  options = options || {};\n  var rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`\n\n  rnds[6] = rnds[6] & 0x0f | 0x40;\n  rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided\n\n  if (buf) {\n    offset = offset || 0;\n\n    for (var i = 0; i < 16; ++i) {\n      buf[offset + i] = rnds[i];\n    }\n\n    return buf;\n  }\n\n  return stringify(rnds);\n}\n\nexport default v4;","/* global Olm */\n\nimport { getLogger } from '@jitsi/logger';\nimport base64js from 'base64-js';\nimport isEqual from 'lodash.isequal';\nimport { v4 as uuidv4 } from 'uuid';\n\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\nimport Deferred from '../util/Deferred';\nimport Listenable from '../util/Listenable';\nimport { FEATURE_E2EE, JITSI_MEET_MUC_TYPE } from '../xmpp/xmpp';\n\nconst logger = getLogger(__filename);\n\nconst REQ_TIMEOUT = 5 * 1000;\nconst OLM_MESSAGE_TYPE = 'olm';\nconst OLM_MESSAGE_TYPES = {\n    ERROR: 'error',\n    KEY_INFO: 'key-info',\n    KEY_INFO_ACK: 'key-info-ack',\n    SESSION_ACK: 'session-ack',\n    SESSION_INIT: 'session-init'\n};\n\nconst kOlmData = Symbol('OlmData');\n\nconst OlmAdapterEvents = {\n    OLM_ID_KEY_READY: 'olm.id_key_ready',\n    PARTICIPANT_E2EE_CHANNEL_READY: 'olm.participant_e2ee_channel_ready',\n    PARTICIPANT_KEY_UPDATED: 'olm.partitipant_key_updated'\n};\n\n/**\n * This class implements an End-to-End Encrypted communication channel between every two peers\n * in the conference. This channel uses libolm to achieve E2EE.\n *\n * The created channel is then used to exchange the secret key that each participant will use\n * to encrypt the actual media (see {@link E2EEContext}).\n *\n * A simple JSON message based protocol is implemented, which follows a request - response model:\n * - session-init: Initiates an olm session establishment procedure. This message will be sent\n *                 by the participant who just joined, to everyone else.\n * - session-ack: Completes the olm session etablishment. This messsage may contain ancilliary\n *                encrypted data, more specifically the sender's current key.\n * - key-info: Includes the sender's most up to date key information.\n * - key-info-ack: Acknowledges the reception of a key-info request. In addition, it may contain\n *                 the sender's key information, if available.\n * - error: Indicates a request processing error has occurred.\n *\n * These requessts and responses are transport independent. Currently they are sent using XMPP\n * MUC private messages.\n */\nexport class OlmAdapter extends Listenable {\n    /**\n     * Creates an adapter instance for the given conference.\n     */\n    constructor(conference) {\n        super();\n\n        this._conf = conference;\n        this._init = new Deferred();\n        this._key = undefined;\n        this._keyIndex = -1;\n        this._reqs = new Map();\n        this._sessionInitialization = undefined;\n\n        if (OlmAdapter.isSupported()) {\n            this._bootstrapOlm();\n\n            this._conf.on(JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED, this._onEndpointMessageReceived.bind(this));\n            this._conf.on(JitsiConferenceEvents.CONFERENCE_LEFT, this._onConferenceLeft.bind(this));\n            this._conf.on(JitsiConferenceEvents.USER_LEFT, this._onParticipantLeft.bind(this));\n            this._conf.on(JitsiConferenceEvents.PARTICIPANT_PROPERTY_CHANGED,\n                this._onParticipantPropertyChanged.bind(this));\n        } else {\n            this._init.reject(new Error('Olm not supported'));\n        }\n    }\n\n    /**\n     * Starts new olm sessions with every other participant that has the participantId \"smaller\" the localParticipantId.\n     */\n    async initSessions() {\n        if (this._sessionInitialization) {\n            throw new Error('OlmAdapter initSessions called multiple times');\n        } else {\n            this._sessionInitialization = new Deferred();\n\n            await this._init;\n\n            const promises = [];\n            const localParticipantId = this._conf.myUserId();\n\n            for (const participant of this._conf.getParticipants()) {\n                if (participant.hasFeature(FEATURE_E2EE) && localParticipantId < participant.getId()) {\n                    promises.push(this._sendSessionInit(participant));\n                }\n            }\n\n            await Promise.allSettled(promises);\n\n            // TODO: retry failed ones.\n\n            this._sessionInitialization.resolve();\n            this._sessionInitialization = undefined;\n        }\n    }\n\n    /**\n     * Indicates if olm is supported on the current platform.\n     *\n     * @returns {boolean}\n     */\n    static isSupported() {\n        return typeof window.Olm !== 'undefined';\n    }\n\n    /**\n     * Updates the current participant key and distributes it to all participants in the conference\n     * by sending a key-info message.\n     *\n     * @param {Uint8Array|boolean} key - The new key.\n     * @retrns {Promise<Number>}\n     */\n    async updateKey(key) {\n        // Store it locally for new sessions.\n        this._key = key;\n        this._keyIndex++;\n\n        // Broadcast it.\n        const promises = [];\n\n        for (const participant of this._conf.getParticipants()) {\n            const pId = participant.getId();\n            const olmData = this._getParticipantOlmData(participant);\n\n            // TODO: skip those who don't support E2EE.\n            if (!olmData.session) {\n                logger.warn(`Tried to send key to participant ${pId} but we have no session`);\n\n                // eslint-disable-next-line no-continue\n                continue;\n            }\n\n            const uuid = uuidv4();\n            const data = {\n                [JITSI_MEET_MUC_TYPE]: OLM_MESSAGE_TYPE,\n                olm: {\n                    type: OLM_MESSAGE_TYPES.KEY_INFO,\n                    data: {\n                        ciphertext: this._encryptKeyInfo(olmData.session),\n                        uuid\n                    }\n                }\n            };\n            const d = new Deferred();\n\n            d.setRejectTimeout(REQ_TIMEOUT);\n            d.catch(() => {\n                this._reqs.delete(uuid);\n            });\n            this._reqs.set(uuid, d);\n            promises.push(d);\n\n            this._sendMessage(data, pId);\n        }\n\n        await Promise.allSettled(promises);\n\n        // TODO: retry failed ones?\n\n        return this._keyIndex;\n    }\n\n    /**\n     * Updates the current participant key.\n     * @param {Uint8Array|boolean} key - The new key.\n     * @returns {number}\n    */\n    updateCurrentKey(key) {\n        this._key = key;\n\n        return this._keyIndex;\n    }\n\n    /**\n     * Frees the olmData session for the given participant.\n     *\n     */\n    clearParticipantSession(participant) {\n        const olmData = this._getParticipantOlmData(participant);\n\n        if (olmData.session) {\n            olmData.session.free();\n            olmData.session = undefined;\n        }\n    }\n\n\n    /**\n     * Frees the olmData sessions for all participants.\n     *\n     */\n    clearAllParticipantsSessions() {\n        for (const participant of this._conf.getParticipants()) {\n            this.clearParticipantSession(participant);\n        }\n    }\n\n    /**\n     * Internal helper to bootstrap the olm library.\n     *\n     * @returns {Promise<void>}\n     * @private\n     */\n    async _bootstrapOlm() {\n        logger.debug('Initializing Olm...');\n\n        try {\n            await Olm.init();\n\n            this._olmAccount = new Olm.Account();\n            this._olmAccount.create();\n\n            const idKeys = JSON.parse(this._olmAccount.identity_keys());\n\n            this._idKey = idKeys.curve25519;\n\n            logger.debug(`Olm ${Olm.get_library_version().join('.')} initialized`);\n            this._init.resolve();\n            this._onIdKeyReady(this._idKey);\n        } catch (e) {\n            logger.error('Failed to initialize Olm', e);\n            this._init.reject(e);\n        }\n\n    }\n\n    /**\n     * Publishes our own Olmn id key in presence.\n     * @private\n     */\n    _onIdKeyReady(idKey) {\n        logger.debug(`Olm id key ready: ${idKey}`);\n\n        // Publish it in presence.\n        this._conf.setLocalParticipantProperty('e2ee.idKey', idKey);\n    }\n\n    /**\n     * Event posted when the E2EE signalling channel has been established with the given participant.\n     * @private\n     */\n    _onParticipantE2EEChannelReady(id) {\n        logger.debug(`E2EE channel with participant ${id} is ready`);\n    }\n\n    /**\n     * Internal helper for encrypting the current key information for a given participant.\n     *\n     * @param {Olm.Session} session - Participant's session.\n     * @returns {string} - The encrypted text with the key information.\n     * @private\n     */\n    _encryptKeyInfo(session) {\n        const keyInfo = {};\n\n        if (this._key !== undefined) {\n            keyInfo.key = this._key ? base64js.fromByteArray(this._key) : false;\n            keyInfo.keyIndex = this._keyIndex;\n        }\n\n        return session.encrypt(JSON.stringify(keyInfo));\n    }\n\n    /**\n     * Internal helper for getting the olm related data associated with a participant.\n     *\n     * @param {JitsiParticipant} participant - Participant whose data wants to be extracted.\n     * @returns {Object}\n     * @private\n     */\n    _getParticipantOlmData(participant) {\n        participant[kOlmData] = participant[kOlmData] || {};\n\n        return participant[kOlmData];\n    }\n\n    /**\n     * Handles leaving the conference, cleaning up olm sessions.\n     *\n     * @private\n     */\n    async _onConferenceLeft() {\n        logger.debug('Conference left');\n\n        await this._init;\n\n        for (const participant of this._conf.getParticipants()) {\n            this._onParticipantLeft(participant.getId(), participant);\n        }\n\n        if (this._olmAccount) {\n            this._olmAccount.free();\n            this._olmAccount = undefined;\n        }\n    }\n\n    /**\n     * Main message handler. Handles 1-to-1 messages received from other participants\n     * and send the appropriate replies.\n     *\n     * @private\n     */\n    async _onEndpointMessageReceived(participant, payload) {\n        if (payload[JITSI_MEET_MUC_TYPE] !== OLM_MESSAGE_TYPE) {\n            return;\n        }\n\n        if (!payload.olm) {\n            logger.warn('Incorrectly formatted message');\n\n            return;\n        }\n\n        await this._init;\n\n        const msg = payload.olm;\n        const pId = participant.getId();\n        const olmData = this._getParticipantOlmData(participant);\n\n        switch (msg.type) {\n        case OLM_MESSAGE_TYPES.SESSION_INIT: {\n            if (olmData.session) {\n                logger.warn(`Participant ${pId} already has a session`);\n\n                this._sendError(participant, 'Session already established');\n            } else {\n                // Create a session for communicating with this participant.\n\n                const session = new Olm.Session();\n\n                session.create_outbound(this._olmAccount, msg.data.idKey, msg.data.otKey);\n                olmData.session = session;\n\n                // Send ACK\n                const ack = {\n                    [JITSI_MEET_MUC_TYPE]: OLM_MESSAGE_TYPE,\n                    olm: {\n                        type: OLM_MESSAGE_TYPES.SESSION_ACK,\n                        data: {\n                            ciphertext: this._encryptKeyInfo(session),\n                            uuid: msg.data.uuid\n                        }\n                    }\n                };\n\n                this._sendMessage(ack, pId);\n                this._onParticipantE2EEChannelReady(pId);\n            }\n            break;\n        }\n        case OLM_MESSAGE_TYPES.SESSION_ACK: {\n            if (olmData.session) {\n                logger.warn(`Participant ${pId} already has a session`);\n\n                this._sendError(participant, 'No session found');\n            } else if (msg.data.uuid === olmData.pendingSessionUuid) {\n                const { ciphertext } = msg.data;\n                const d = this._reqs.get(msg.data.uuid);\n                const session = new Olm.Session();\n\n                session.create_inbound(this._olmAccount, ciphertext.body);\n\n                // Remove OT keys that have been used to setup this session.\n                this._olmAccount.remove_one_time_keys(session);\n\n                // Decrypt first message.\n                const data = session.decrypt(ciphertext.type, ciphertext.body);\n\n                olmData.session = session;\n                olmData.pendingSessionUuid = undefined;\n\n                this._onParticipantE2EEChannelReady(pId);\n\n                this._reqs.delete(msg.data.uuid);\n                d.resolve();\n\n                const json = safeJsonParse(data);\n\n                if (json.key) {\n                    const key = base64js.toByteArray(json.key);\n                    const keyIndex = json.keyIndex;\n\n                    olmData.lastKey = key;\n                    this.eventEmitter.emit(OlmAdapterEvents.PARTICIPANT_KEY_UPDATED, pId, key, keyIndex);\n                }\n            } else {\n                logger.warn('Received ACK with the wrong UUID');\n\n                this._sendError(participant, 'Invalid UUID');\n            }\n            break;\n        }\n        case OLM_MESSAGE_TYPES.ERROR: {\n            logger.error(msg.data.error);\n\n            break;\n        }\n        case OLM_MESSAGE_TYPES.KEY_INFO: {\n            if (olmData.session) {\n                const { ciphertext } = msg.data;\n                const data = olmData.session.decrypt(ciphertext.type, ciphertext.body);\n                const json = safeJsonParse(data);\n\n                if (json.key !== undefined && json.keyIndex !== undefined) {\n                    const key = json.key ? base64js.toByteArray(json.key) : false;\n                    const keyIndex = json.keyIndex;\n\n                    if (!isEqual(olmData.lastKey, key)) {\n                        olmData.lastKey = key;\n                        this.eventEmitter.emit(OlmAdapterEvents.PARTICIPANT_KEY_UPDATED, pId, key, keyIndex);\n                    }\n\n                    // Send ACK.\n                    const ack = {\n                        [JITSI_MEET_MUC_TYPE]: OLM_MESSAGE_TYPE,\n                        olm: {\n                            type: OLM_MESSAGE_TYPES.KEY_INFO_ACK,\n                            data: {\n                                ciphertext: this._encryptKeyInfo(olmData.session),\n                                uuid: msg.data.uuid\n                            }\n                        }\n                    };\n\n                    this._sendMessage(ack, pId);\n                }\n            } else {\n                logger.debug(`Received key info message from ${pId} but we have no session for them!`);\n\n                this._sendError(participant, 'No session found while processing key-info');\n            }\n            break;\n        }\n        case OLM_MESSAGE_TYPES.KEY_INFO_ACK: {\n            if (olmData.session) {\n                const { ciphertext } = msg.data;\n                const data = olmData.session.decrypt(ciphertext.type, ciphertext.body);\n                const json = safeJsonParse(data);\n\n                if (json.key !== undefined && json.keyIndex !== undefined) {\n                    const key = json.key ? base64js.toByteArray(json.key) : false;\n                    const keyIndex = json.keyIndex;\n\n                    if (!isEqual(olmData.lastKey, key)) {\n                        olmData.lastKey = key;\n                        this.eventEmitter.emit(OlmAdapterEvents.PARTICIPANT_KEY_UPDATED, pId, key, keyIndex);\n                    }\n                }\n\n                const d = this._reqs.get(msg.data.uuid);\n\n                this._reqs.delete(msg.data.uuid);\n                d.resolve();\n            } else {\n                logger.debug(`Received key info ack message from ${pId} but we have no session for them!`);\n\n                this._sendError(participant, 'No session found while processing key-info-ack');\n            }\n            break;\n        }\n        }\n    }\n\n    /**\n     * Handles a participant leaving. When a participant leaves their olm session is destroyed.\n     *\n     * @private\n     */\n    _onParticipantLeft(id, participant) {\n        logger.debug(`Participant ${id} left`);\n\n        this.clearParticipantSession(participant);\n    }\n\n    /**\n    * Handles an update in a participant's presence property.\n    *\n    * @param {JitsiParticipant} participant - The participant.\n    * @param {string} name - The name of the property that changed.\n    * @param {*} oldValue - The property's previous value.\n    * @param {*} newValue - The property's new value.\n    * @private\n    */\n    async _onParticipantPropertyChanged(participant, name, oldValue, newValue) {\n        switch (name) {\n        case 'e2ee.enabled':\n            if (newValue && this._conf.isE2EEEnabled()) {\n                const localParticipantId = this._conf.myUserId();\n                const participantId = participant.getId();\n                const participantFeatures = await participant.getFeatures();\n\n                if (participantFeatures.has(FEATURE_E2EE) && localParticipantId < participantId) {\n                    if (this._sessionInitialization) {\n                        await this._sessionInitialization;\n                    }\n                    await this._sendSessionInit(participant);\n\n                    const olmData = this._getParticipantOlmData(participant);\n                    const uuid = uuidv4();\n                    const data = {\n                        [JITSI_MEET_MUC_TYPE]: OLM_MESSAGE_TYPE,\n                        olm: {\n                            type: OLM_MESSAGE_TYPES.KEY_INFO,\n                            data: {\n                                ciphertext: this._encryptKeyInfo(olmData.session),\n                                uuid\n                            }\n                        }\n                    };\n\n                    this._sendMessage(data, participantId);\n                }\n            }\n            break;\n        }\n    }\n\n    /**\n     * Builds and sends an error message to the target participant.\n     *\n     * @param {JitsiParticipant} participant - The target participant.\n     * @param {string} error - The error message.\n     * @returns {void}\n     */\n    _sendError(participant, error) {\n        const pId = participant.getId();\n        const err = {\n            [JITSI_MEET_MUC_TYPE]: OLM_MESSAGE_TYPE,\n            olm: {\n                type: OLM_MESSAGE_TYPES.ERROR,\n                data: {\n                    error\n                }\n            }\n        };\n\n        this._sendMessage(err, pId);\n    }\n\n    /**\n     * Internal helper to send the given object to the given participant ID.\n     * This function merely exists so the transport can be easily swapped.\n     * Currently messages are transmitted via XMPP MUC private messages.\n     *\n     * @param {object} data - The data that will be sent to the target participant.\n     * @param {string} participantId - ID of the target participant.\n     */\n    _sendMessage(data, participantId) {\n        this._conf.sendMessage(data, participantId);\n    }\n\n    /**\n     * Builds and sends the session-init request to the target participant.\n     *\n     * @param {JitsiParticipant} participant - Participant to whom we'll send the request.\n     * @returns {Promise} - The promise will be resolved when the session-ack is received.\n     * @private\n     */\n    _sendSessionInit(participant) {\n        const pId = participant.getId();\n        const olmData = this._getParticipantOlmData(participant);\n\n        if (olmData.session) {\n            logger.warn(`Tried to send session-init to ${pId} but we already have a session`);\n\n            return Promise.reject();\n        }\n\n        if (olmData.pendingSessionUuid !== undefined) {\n            logger.warn(`Tried to send session-init to ${pId} but we already have a pending session`);\n\n            return Promise.reject();\n        }\n\n        // Generate a One Time Key.\n        this._olmAccount.generate_one_time_keys(1);\n\n        const otKeys = JSON.parse(this._olmAccount.one_time_keys());\n        const otKey = Object.values(otKeys.curve25519)[0];\n\n        if (!otKey) {\n            return Promise.reject(new Error('No one-time-keys generated'));\n        }\n\n        // Mark the OT keys (one really) as published so they are not reused.\n        this._olmAccount.mark_keys_as_published();\n\n        const uuid = uuidv4();\n        const init = {\n            [JITSI_MEET_MUC_TYPE]: OLM_MESSAGE_TYPE,\n            olm: {\n                type: OLM_MESSAGE_TYPES.SESSION_INIT,\n                data: {\n                    idKey: this._idKey,\n                    otKey,\n                    uuid\n                }\n            }\n        };\n\n        const d = new Deferred();\n\n        d.setRejectTimeout(REQ_TIMEOUT);\n        d.catch(() => {\n            this._reqs.delete(uuid);\n            olmData.pendingSessionUuid = undefined;\n        });\n        this._reqs.set(uuid, d);\n\n        this._sendMessage(init, pId);\n\n        // Store the UUID for matching with the ACK.\n        olmData.pendingSessionUuid = uuid;\n\n        return d;\n    }\n}\n\n/**\n * Helper to ensure JSON parsing always returns an object.\n *\n * @param {string} data - The data that needs to be parsed.\n * @returns {object} - Parsed data or empty object in case of failure.\n */\nfunction safeJsonParse(data) {\n    try {\n        return JSON.parse(data);\n    } catch (e) {\n        return {};\n    }\n}\n\nOlmAdapter.events = OlmAdapterEvents;\n","import { getLogger } from '@jitsi/logger';\nimport debounce from 'lodash.debounce';\n\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\n\nimport { KeyHandler } from './KeyHandler';\nimport { OlmAdapter } from './OlmAdapter';\nimport { importKey, ratchet } from './crypto-utils';\n\nconst logger = getLogger(__filename);\n\n// Period which we'll wait before updating / rotating our keys when a participant\n// joins or leaves.\nconst DEBOUNCE_PERIOD = 5000;\n\n/**\n * This module integrates {@link E2EEContext} with {@link OlmAdapter} in order to distribute the keys for encryption.\n */\nexport class ManagedKeyHandler extends KeyHandler {\n    /**\n     * Build a new AutomaticKeyHandler instance, which will be used in a given conference.\n     */\n    constructor(conference) {\n        super(conference);\n\n        this._key = undefined;\n        this._conferenceJoined = false;\n\n        this._olmAdapter = new OlmAdapter(conference);\n\n        this._rotateKey = debounce(this._rotateKeyImpl, DEBOUNCE_PERIOD);\n        this._ratchetKey = debounce(this._ratchetKeyImpl, DEBOUNCE_PERIOD);\n\n        // Olm signalling events.\n        this._olmAdapter.on(\n            OlmAdapter.events.PARTICIPANT_KEY_UPDATED,\n            this._onParticipantKeyUpdated.bind(this));\n\n        this.conference.on(\n            JitsiConferenceEvents.PARTICIPANT_PROPERTY_CHANGED,\n            this._onParticipantPropertyChanged.bind(this));\n        this.conference.on(\n            JitsiConferenceEvents.USER_JOINED,\n            this._onParticipantJoined.bind(this));\n        this.conference.on(\n            JitsiConferenceEvents.USER_LEFT,\n            this._onParticipantLeft.bind(this));\n        this.conference.on(\n                JitsiConferenceEvents.CONFERENCE_JOINED,\n                () => {\n                    this._conferenceJoined = true;\n                });\n    }\n\n    /**\n     * When E2EE is enabled it initializes sessions and sets the key.\n     * Cleans up the sessions when disabled.\n     *\n     * @param {boolean} enabled - whether E2EE should be enabled or not.\n     * @returns {void}\n     */\n    async _setEnabled(enabled) {\n        if (enabled) {\n            await this._olmAdapter.initSessions();\n        } else {\n            this._olmAdapter.clearAllParticipantsSessions();\n        }\n\n        // Generate a random key in case we are enabling.\n        this._key = enabled ? this._generateKey() : false;\n\n        // Send it to others using the E2EE olm channel.\n        const index = await this._olmAdapter.updateKey(this._key);\n\n        // Set our key so we begin encrypting.\n        this.e2eeCtx.setKey(this.conference.myUserId(), this._key, index);\n    }\n\n    /**\n     * Handles an update in a participant's presence property.\n     *\n     * @param {JitsiParticipant} participant - The participant.\n     * @param {string} name - The name of the property that changed.\n     * @param {*} oldValue - The property's previous value.\n     * @param {*} newValue - The property's new value.\n     * @private\n     */\n    async _onParticipantPropertyChanged(participant, name, oldValue, newValue) {\n        switch (name) {\n        case 'e2ee.idKey':\n            logger.debug(`Participant ${participant.getId()} updated their id key: ${newValue}`);\n            break;\n        case 'e2ee.enabled':\n            if (!newValue && this.enabled) {\n                this._olmAdapter.clearParticipantSession(participant);\n            }\n            break;\n        }\n    }\n\n    /**\n     * Advances (using ratcheting) the current key when a new participant joins the conference.\n     * @private\n     */\n    _onParticipantJoined() {\n        if (this._conferenceJoined && this.enabled) {\n            this._ratchetKey();\n        }\n    }\n\n    /**\n     * Rotates the current key when a participant leaves the conference.\n     * @private\n     */\n    _onParticipantLeft(id) {\n        this.e2eeCtx.cleanup(id);\n\n        if (this.enabled) {\n            this._rotateKey();\n        }\n    }\n\n    /**\n     * Rotates the local key. Rotating the key implies creating a new one, then distributing it\n     * to all participants and once they all received it, start using it.\n     *\n     * @private\n     */\n    async _rotateKeyImpl() {\n        logger.debug('Rotating key');\n\n        this._key = this._generateKey();\n        const index = await this._olmAdapter.updateKey(this._key);\n\n        this.e2eeCtx.setKey(this.conference.myUserId(), this._key, index);\n    }\n\n    /**\n     * Advances the current key by using ratcheting.\n     *\n     * @private\n     */\n    async _ratchetKeyImpl() {\n        logger.debug('Ratchetting key');\n\n        const material = await importKey(this._key);\n        const newKey = await ratchet(material);\n\n        this._key = new Uint8Array(newKey);\n\n        const index = this._olmAdapter.updateCurrentKey(this._key);\n\n        this.e2eeCtx.setKey(this.conference.myUserId(), this._key, index);\n    }\n\n    /**\n     * Handles an update in a participant's key.\n     *\n     * @param {string} id - The participant ID.\n     * @param {Uint8Array | boolean} key - The new key for the participant.\n     * @param {Number} index - The new key's index.\n     * @private\n     */\n    _onParticipantKeyUpdated(id, key, index) {\n        logger.debug(`Participant ${id} updated their key`);\n\n        this.e2eeCtx.setKey(id, key, index);\n    }\n\n    /**\n     * Generates a new 256 bit random key.\n     *\n     * @returns {Uint8Array}\n     * @private\n     */\n    _generateKey() {\n        return window.crypto.getRandomValues(new Uint8Array(32));\n    }\n}\n","/**\n * Derives a set of keys from the master key.\n * @param {CryptoKey} material - master key to derive from\n *\n * See https://tools.ietf.org/html/draft-omara-sframe-00#section-4.3.1\n */\nexport async function deriveKeys(material) {\n    const info = new ArrayBuffer();\n    const textEncoder = new TextEncoder();\n\n    // https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/deriveKey#HKDF\n    // https://developer.mozilla.org/en-US/docs/Web/API/HkdfParams\n    const encryptionKey = await crypto.subtle.deriveKey({\n        name: 'HKDF',\n        salt: textEncoder.encode('JFrameEncryptionKey'),\n        hash: 'SHA-256',\n        info\n    }, material, {\n        name: 'AES-GCM',\n        length: 128\n    }, false, [ 'encrypt', 'decrypt' ]);\n\n    return {\n        material,\n        encryptionKey\n    };\n}\n\n/**\n * Ratchets a key. See\n * https://tools.ietf.org/html/draft-omara-sframe-00#section-4.3.5.1\n * @param {CryptoKey} material - base key material\n * @returns {ArrayBuffer} - ratcheted key material\n */\nexport async function ratchet(material) {\n    const textEncoder = new TextEncoder();\n\n    // https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/deriveBits\n    return crypto.subtle.deriveBits({\n        name: 'HKDF',\n        salt: textEncoder.encode('JFrameRatchetKey'),\n        hash: 'SHA-256',\n        info: new ArrayBuffer()\n    }, material, 256);\n}\n\n/**\n * Converts a raw key into a WebCrypto key object with default options\n * suitable for our usage.\n * @param {ArrayBuffer} keyBytes - raw key\n * @param {Array} keyUsages - key usages, see importKey documentation\n * @returns {CryptoKey} - the WebCrypto key.\n */\nexport async function importKey(keyBytes) {\n    // https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey\n    return crypto.subtle.importKey('raw', keyBytes, 'HKDF', false, [ 'deriveBits', 'deriveKey' ]);\n}\n","import browser from '../browser';\n\nimport { ExternallyManagedKeyHandler } from './ExternallyManagedKeyHandler';\nimport { ManagedKeyHandler } from './ManagedKeyHandler';\nimport { OlmAdapter } from './OlmAdapter';\n\n/**\n * This module integrates {@link KeyHandler} with {@link JitsiConference} in order to enable E2E encryption.\n */\nexport class E2EEncryption {\n    /**\n     * A constructor.\n     * @param {JitsiConference} conference - The conference instance for which E2E encryption is to be enabled.\n     */\n    constructor(conference) {\n        const { e2ee = {} } = conference.options.config;\n\n        this._externallyManaged = e2ee.externallyManagedKey;\n\n        if (this._externallyManaged) {\n            this._keyHandler = new ExternallyManagedKeyHandler(conference);\n        } else {\n            this._keyHandler = new ManagedKeyHandler(conference);\n        }\n    }\n\n    /**\n     * Indicates if E2EE is supported in the current platform.\n     *\n     * @param {object} config - Global configuration.\n     * @returns {boolean}\n     */\n    static isSupported(config) {\n        const { e2ee = {} } = config;\n\n        if (!e2ee.externallyManagedKey && !OlmAdapter.isSupported()) {\n            return false;\n        }\n\n        return !(config.testing && config.testing.disableE2EE)\n            && (browser.supportsInsertableStreams()\n                || (config.enableEncodedTransformSupport && browser.supportsEncodedTransform()));\n    }\n\n    /**\n     * Indicates whether E2EE is currently enabled or not.\n     *\n     * @returns {boolean}\n     */\n    isEnabled() {\n        return this._keyHandler.isEnabled();\n    }\n\n    /**\n     * Enables / disables End-To-End encryption.\n     *\n     * @param {boolean} enabled - whether E2EE should be enabled or not.\n     * @returns {void}\n     */\n    async setEnabled(enabled) {\n        await this._keyHandler.setEnabled(enabled);\n    }\n\n    /**\n     * Sets the key and index for End-to-End encryption.\n     *\n     * @param {CryptoKey} [keyInfo.encryptionKey] - encryption key.\n     * @param {Number} [keyInfo.index] - the index of the encryption key.\n     * @returns {void}\n     */\n    setEncryptionKey(keyInfo) {\n        this._keyHandler.setKey(keyInfo);\n    }\n}\n","import $ from 'jquery';\nimport { b64_sha1, Strophe } from 'strophe.js'; // eslint-disable-line camelcase\n\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\nimport Listenable from '../util/Listenable';\n\n/**\n * The property\n */\nconst IDENTITY_PROPERTIES = [ 'category', 'type', 'lang', 'name' ];\nconst IDENTITY_PROPERTIES_FOR_COMPARE = [ 'category', 'type', 'lang' ];\nconst HASH = 'sha-1';\n\n/**\n *\n * @param a\n * @param b\n */\nfunction compareIdentities(a, b) {\n    let res = 0;\n\n    IDENTITY_PROPERTIES_FOR_COMPARE.some(key =>\n        (res = ((a[key] > b[key]) && 1) || ((a[key] < b[key]) && -1)) !== 0\n    );\n\n    return res;\n}\n\n/**\n * Produces a sha-1 from provided identity and features values.\n *\n * @param {Array<Object>} identities - The identity objects.\n * @param {Array<string>} features - The features.\n * @returns {string}\n */\nfunction generateSha(identities, features) {\n    const sortedIdentities = identities.sort(compareIdentities).reduce(\n        (accumulatedValue, identity) => `${\n            IDENTITY_PROPERTIES.reduce(\n                (tmp, key, idx) =>\n                    tmp\n                        + (idx === 0 ? '' : '/')\n                        + (identity[key] ? identity[key] : ''),\n                '')\n        }<`, '');\n    const sortedFeatures = features.sort().reduce(\n        (tmp, feature) => `${tmp + feature}<`, '');\n\n    return b64_sha1(sortedIdentities + sortedFeatures);\n}\n\n/**\n * Parses the disco-info node and returns the sets of features and identities.\n * @param {String} node The node with results to parse.\n * @returns {{features: Set<any>, identities: Set<any>}}\n */\nexport function parseDiscoInfo(node) {\n    const features = new Set();\n    const identities = new Set();\n\n    $(node).find('>query>feature')\n        .each((_, el) => features.add(el.getAttribute('var')));\n    $(node).find('>query>identity')\n        .each((_, el) => identities.add({\n            type: el.getAttribute('type'),\n            name: el.getAttribute('name'),\n            category: el.getAttribute('category')\n        }));\n\n    return {\n        features,\n        identities\n    };\n}\n\n/**\n * Implements xep-0115 ( http://xmpp.org/extensions/xep-0115.html )\n */\nexport default class Caps extends Listenable {\n    /**\n     * Constructs new Caps instance.\n     * @param {Strophe.Connection} connection the strophe connection object\n     * @param {String} node the value of the node attribute of the \"c\" xml node\n     * that will be sent to the other participants\n     */\n    constructor(connection = {}, node = 'http://jitsi.org/jitsimeet') {\n        super();\n        this.node = node;\n        this.disco = connection.disco;\n        if (!this.disco) {\n            throw new Error(\n                'Missing strophe-plugins '\n                + '(disco plugin is required)!');\n        }\n\n        this.version = '';\n        this.rooms = new Set();\n\n        // We keep track of features added outside the library and we publish them\n        // in the presence of the participant for simplicity, avoiding the disco info request-response.\n        this.externalFeatures = new Set();\n\n        const emuc = connection.emuc;\n\n        emuc.addListener(XMPPEvents.EMUC_ROOM_ADDED,\n            room => this._addChatRoom(room));\n        emuc.addListener(XMPPEvents.EMUC_ROOM_REMOVED,\n            room => this._removeChatRoom(room));\n        Object.keys(emuc.rooms).forEach(jid => {\n            this._addChatRoom(emuc.rooms[jid]);\n        });\n\n        Strophe.addNamespace('CAPS', 'http://jabber.org/protocol/caps');\n        this.disco.addFeature(Strophe.NS.CAPS);\n    }\n\n    /**\n     * Adds new feature to the list of supported features for the local\n     * participant\n     * @param {String} feature the name of the feature.\n     * @param {boolean} submit if true - new presence with updated \"c\" node\n     * will be sent.\n     * @param {boolean} external whether this feature was added externally to the library.\n     * We put features used directly by the clients (is jibri, remote-control enabled etc.) in the presence\n     * to avoid additional disco-info queries by those clients.\n     */\n    addFeature(feature, submit = false, external = false) {\n        this.disco.addFeature(feature);\n        this._generateVersion();\n\n        if (external && !this.externalFeatures.has(feature)) {\n            this.externalFeatures.add(feature);\n            this.rooms.forEach(room => this._updateRoomWithExternalFeatures(room));\n        }\n\n        if (submit) {\n            this.submit();\n        }\n    }\n\n    /**\n     * Removes a feature from the list of supported features for the local\n     * participant\n     * @param {String} feature the name of the feature.\n     * @param {boolean} submit if true - new presence with updated \"c\" node\n     * will be sent.\n     * @param {boolean} external whether this feature was added externally to the library.\n     */\n    removeFeature(feature, submit = false, external = false) {\n        this.disco.removeFeature(feature);\n        this._generateVersion();\n\n        if (external && this.externalFeatures.has(feature)) {\n            this.externalFeatures.delete(feature);\n            this.rooms.forEach(room => this._updateRoomWithExternalFeatures(room));\n        }\n\n        if (submit) {\n            this.submit();\n        }\n    }\n\n    /**\n     * Sends new presence stanza for every room from the list of rooms.\n     */\n    submit() {\n        this.rooms.forEach(room => room.sendPresence());\n    }\n\n    /**\n     * Updates the presences in the room based on the current values in externalFeatures.\n     * @param {ChatRoom} room the room to update.\n     * @private\n     */\n    _updateRoomWithExternalFeatures(room) {\n        if (this.externalFeatures.size === 0) {\n            room.removeFromPresence('features');\n        } else {\n            const children = [];\n\n            this.externalFeatures.forEach(f => {\n                children.push({\n                    'tagName': 'feature',\n                    attributes: { 'var': f }\n                });\n            });\n\n            room.addOrReplaceInPresence('features', { children });\n        }\n    }\n\n    /**\n     * Returns a set with the features for a host.\n     * @param {String} jid the jid of the host\n     * @param {int} timeout the timeout in ms for reply from the host.\n     * @returns {Promise<Set<String>, Error>}\n     */\n    getFeaturesAndIdentities(jid, node, timeout = 5000) {\n        return this._getDiscoInfo(jid, node, timeout);\n    }\n\n    /**\n     * Returns a set with the features and identities for a host.\n     * @param {String} jid the jid of the host\n     * @param {String|null} node the node to query\n     * @param {int} timeout the timeout in ms for reply from the host.\n     * @returns {Promise<Object>}\n     * @private\n     */\n    _getDiscoInfo(jid, node, timeout) {\n        return new Promise((resolve, reject) =>\n            this.disco.info(jid, node, response => {\n                resolve(parseDiscoInfo(response));\n            }, reject, timeout)\n        );\n    }\n\n    /**\n     * Adds ChatRoom instance to the list of rooms. Adds listeners to the room\n     * and adds \"c\" element to the presences of the room.\n     * @param {ChatRoom} room the room.\n     */\n    _addChatRoom(room) {\n        this.rooms.add(room);\n        this._fixChatRoomPresenceMap(room);\n\n        this._updateRoomWithExternalFeatures(room);\n    }\n\n    /**\n     * Removes ChatRoom instance from the list of rooms. Removes listeners\n     * added from the Caps class.\n     * @param {ChatRoom} room the room.\n     */\n    _removeChatRoom(room) {\n        this.rooms.delete(room);\n    }\n\n    /**\n     * Creates/updates the \"c\" xml node into the presence of the passed room.\n     * @param {ChatRoom} room the room.\n     */\n    _fixChatRoomPresenceMap(room) {\n        room.addOrReplaceInPresence('c', {\n            attributes: {\n                xmlns: Strophe.NS.CAPS,\n                hash: HASH,\n                node: this.node,\n                ver: this.version\n            }\n        });\n    }\n\n    /**\n     * Handles this.version changes.\n     */\n    _notifyVersionChanged() {\n        // update the version for all rooms\n        this.rooms.forEach(room => this._fixChatRoomPresenceMap(room));\n    }\n\n    /**\n     * Generates the value for the \"ver\" attribute.\n     */\n    _generateVersion() {\n        this.version\n            = generateSha(this.disco._identities, this.disco._features);\n\n        this._notifyVersionChanged();\n    }\n}\n","import { getLogger } from '@jitsi/logger';\n\nimport Listenable from '../util/Listenable';\n\nexport const NETWORK_INFO_EVENT = 'NETWORK_INFO_CHANGED';\n\nconst logger = getLogger(__filename);\n\n/**\n * Module provides information about the current status of the internet\n * connection. Lib-jitsi-meet doesn't have any logic for detecting internet\n * online/offline, but rather it relies on the information supplied by the app\n * that uses it. By default the online state is assumed and the lib acts as if\n * it was connected. See {@link JitsiMeetJS.setNetworkInfo}.\n */\nexport class NetworkInfo extends Listenable {\n    /**\n     * Creates new {@link NetworkInfo} instance.\n     */\n    constructor() {\n        super();\n        this._current = {\n            isOnline: true\n        };\n    }\n\n    /**\n     * Updates the network info state.\n     * @param {boolean} isOnline - {@code true} if internet is online or {@code false} otherwise.\n     */\n    updateNetworkInfo({ isOnline }) {\n        logger.debug('updateNetworkInfo', { isOnline });\n        this._current = {\n            isOnline: isOnline === true\n        };\n        this.eventEmitter.emit(NETWORK_INFO_EVENT, this._current);\n    }\n\n    /**\n     * Returns the online/offline internet status. By default the value is {@code true} and changes only if\n     * the lib's user wires the state through {@link JitsiMeetJS.setNetworkInfo} like the jitsi-meet does. Because of\n     * that any logic should still assume that the internet may be offline and should handle the failure gracefully.\n     * It's only a good hint in the other way around: to pause internet operations until it comes back online.\n     * @returns {boolean}\n     */\n    isOnline() {\n        return this._current.isOnline === true;\n    }\n}\n\nconst networkInfo = new NetworkInfo();\n\nexport default networkInfo;\n","import { getLogger } from '@jitsi/logger';\n\nimport {\n    default as NetworkInfo,\n    NETWORK_INFO_EVENT\n} from '../connectivity/NetworkInfo';\nimport { getJitterDelay } from '../util/Retry';\n\nconst logger = getLogger(__filename);\n\n/**\n * The class contains the logic for triggering connection resume via XEP-0198 stream management.\n * It does two things, the first one is it tracks the internet online/offline status and it makes sure that\n * the reconnect is attempted only while online. The seconds thing is that it tracks the retry attempts and extends\n * the retry interval using the full jitter pattern.\n */\nexport default class ResumeTask {\n    /**\n     * Initializes new {@code RetryTask}.\n     * @param {Strophe.Connection} stropheConnection - The Strophe connection instance.\n     */\n    constructor(stropheConnection) {\n        this._stropheConn = stropheConnection;\n\n        /**\n         * The counter increased before each resume retry attempt, used to calculate exponential backoff.\n         * @type {number}\n         * @private\n         */\n        this._resumeRetryN = 0;\n\n        this._retryDelay = undefined;\n    }\n\n    /**\n     * @returns {number|undefined} - How much the app will wait before trying to resume the XMPP connection. When\n     * 'undefined' it means that no resume task was not scheduled.\n     */\n    get retryDelay() {\n        return this._retryDelay;\n    }\n\n    /**\n     * Called by {@link XmppConnection} when the connection drops and it's a signal it wants to schedule a reconnect.\n     *\n     * @returns {void}\n     */\n    schedule() {\n        this._cancelResume();\n\n        this._resumeRetryN += 1;\n\n        this._networkOnlineListener\n            = NetworkInfo.addEventListener(\n                NETWORK_INFO_EVENT,\n                ({ isOnline }) => {\n                    if (isOnline) {\n                        this._scheduleResume();\n                    } else {\n                        this._cancelResume();\n                    }\n                });\n\n        NetworkInfo.isOnline() && this._scheduleResume();\n    }\n\n    /**\n     * Schedules a delayed timeout which will execute the resume action.\n     * @private\n     * @returns {void}\n     */\n    _scheduleResume() {\n        if (this._resumeTimeout) {\n\n            // NO-OP\n            return;\n        }\n\n        // The retry delay will be:\n        //   1st retry: 1.5s - 3s\n        //   2nd retry: 3s - 9s\n        //   3rd and next retry: 4.5s - 27s\n        this._resumeRetryN = Math.min(3, this._resumeRetryN);\n        this._retryDelay = getJitterDelay(\n            /* retry */ this._resumeRetryN,\n            /* minDelay */ this._resumeRetryN * 1500,\n            3);\n\n        logger.info(`Will try to resume the XMPP connection in ${this.retryDelay}ms`);\n\n        this._resumeTimeout = setTimeout(() => this._resumeConnection(), this.retryDelay);\n    }\n\n    /**\n     * Cancels the delayed resume task.\n     *\n     * @private\n     * @returns {void}\n     */\n    _cancelResume() {\n        if (this._resumeTimeout) {\n            logger.info('Canceling connection resume task');\n            clearTimeout(this._resumeTimeout);\n            this._resumeTimeout = undefined;\n            this._retryDelay = undefined;\n        }\n    }\n\n    /**\n     * Resumes the XMPP connection using the stream management plugin.\n     *\n     * @private\n     * @returns {void}\n     */\n    _resumeConnection() {\n        const { streamManagement } = this._stropheConn;\n        const resumeToken = streamManagement.getResumeToken();\n\n        // Things may have changed since when the task was scheduled\n        if (!resumeToken) {\n            return;\n        }\n\n        logger.info('Trying to resume the XMPP connection');\n\n        const url = new URL(this._stropheConn.service);\n        let { search } = url;\n        const pattern = /(previd=)([\\w-]+)/;\n        const oldToken = search.match(pattern);\n\n        // Replace previd if the previd value has changed.\n        if (oldToken && oldToken.indexOf(resumeToken) === -1) {\n            search = search.replace(pattern, `$1${resumeToken}`);\n\n        // Append previd if it doesn't exist.\n        } else if (!oldToken) {\n            search += search.indexOf('?') === -1 ? `?previd=${resumeToken}` : `&previd=${resumeToken}`;\n        }\n\n        url.search = search;\n\n        this._stropheConn.service = url.toString();\n\n        streamManagement.resume();\n    }\n\n    /**\n     * Cancels the retry task. It's called by {@link XmppConnection} when it's no longer interested in reconnecting for\n     * example when the disconnect method is called.\n     *\n     * @returns {void}\n     */\n    cancel() {\n        this._cancelResume();\n        this._resumeRetryN = 0;\n        if (this._networkOnlineListener) {\n            this._networkOnlineListener();\n            this._networkOnlineListener = null;\n        }\n    }\n}\n","/**\n* Gets next timeout using the full jitter pattern.\n*\n* NOTE that there are no checks for argument correctness, so either do the math or use defaults.\n*\n* @param {number} retry - The retry number.\n* @param {number} minDelay - The minimal delay in milliseconds.\n* @param {number} base - The exponent base.\n* @returns {number} - The amount of waiting before trying another time given in milliseconds.\n* @private\n*/\nexport function getJitterDelay(retry, minDelay = 500, base = 2) {\n    return Math.floor((Math.random() * ((Math.pow(base, retry) * 1000) - minDelay)) + minDelay);\n}\n","/**\n * Attaches to the {@link Strophe.Connection.rawInput} which is called whenever any data is received from the server.\n */\nexport default class LastRequestTracker {\n    /**\n     * Initializes new instance.\n     */\n    constructor() {\n        this._lastSuccess = null;\n        this._lastFailedMessage = null;\n    }\n\n    /**\n     * Starts tracking requests on the given connection.\n     *\n     * @param {XmppConnection} xmppConnection - The XMPP connection which manages the given {@code stropheConnection}.\n     * @param {Object} stropheConnection - Strophe connection instance.\n     */\n    startTracking(xmppConnection, stropheConnection) {\n        const originalRawInput = stropheConnection.rawInput;\n\n        stropheConnection.rawInput = (...args) => {\n            const rawMessage = args[0];\n\n            if (rawMessage.includes('failure')) {\n                this._lastFailedMessage = rawMessage;\n            }\n\n            // It's okay to use rawInput callback only once the connection has been established, otherwise it will\n            // treat 'item-not-found' or other connection error on websocket reconnect as successful stanza received.\n            if (xmppConnection.connected) {\n                this._lastSuccess = Date.now();\n            }\n            originalRawInput.apply(stropheConnection, args);\n        };\n    }\n\n    /**\n     * Returns the last raw failed incoming message on the xmpp connection.\n     *\n     * @returns {string|null}\n     */\n    getLastFailedMessage() {\n        return this._lastFailedMessage;\n    }\n\n    /**\n     * Returns how many milliseconds have passed since the last successful BOSH request.\n     *\n     * @returns {number|null}\n     */\n    getTimeSinceLastSuccess() {\n        return this._lastSuccess\n            ? Date.now() - this._lastSuccess\n            : null;\n    }\n}\n","import Listenable from '../util/Listenable';\n\n/**\n * Creates ConnectionPlugin class that extends the passed class.\n * @param {Class} base the definition of the class that will be extended by\n * ConnectionPlugin\n */\nfunction getConnectionPluginDefinition(base = class {}) {\n    /**\n     * Base class for strophe connection plugins.\n     */\n    return class extends base {\n        /**\n         *\n         */\n        constructor(...args) {\n            super(...args);\n            this.connection = null;\n        }\n\n        /**\n         *\n         * @param connection\n         */\n        init(connection) {\n            this.connection = connection;\n        }\n    };\n}\n\n/**\n * ConnectionPlugin class.\n */\nexport default getConnectionPluginDefinition();\n\n/**\n * ConnectionPlugin class that extends Listenable.\n */\nexport const ConnectionPluginListenable\n    = getConnectionPluginDefinition(Listenable);\n","import { getLogger } from '@jitsi/logger';\nimport { $iq, Strophe } from 'strophe.js';\n\nimport GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';\n\nimport ConnectionPlugin from './ConnectionPlugin';\n\n\nconst logger = getLogger(__filename);\n\n/**\n * Default ping every 10 sec\n */\nconst PING_DEFAULT_INTERVAL = 10000;\n\n/**\n * Default ping timeout error after 5 sec of waiting.\n */\nconst PING_DEFAULT_TIMEOUT = 5000;\n\n/**\n * Default value for how many ping failures will be tolerated before the WebSocket connection is killed.\n * The worst case scenario in case of ping timing out without a response is (25 seconds at the time of this writing):\n * PING_THRESHOLD * PING_INTERVAL + PING_TIMEOUT\n */\nconst PING_DEFAULT_THRESHOLD = 2;\n\n/**\n * XEP-0199 ping plugin.\n *\n * Registers \"urn:xmpp:ping\" namespace under Strophe.NS.PING.\n */\nexport default class PingConnectionPlugin extends ConnectionPlugin {\n    /**\n     * Constructs new object\n     * @param {Object} options\n     * @param {Function} options.onPingThresholdExceeded - Callback called when ping fails too many times (controlled\n     * by the {@link PING_THRESHOLD} constant).\n     * @param {Function} options._getTimeSinceLastServerResponse - A function to obtain the last seen\n     * response from the server.\n     * @param {Object} options.pingOptions - The ping options if any.\n     * @constructor\n     */\n    constructor({ getTimeSinceLastServerResponse, onPingThresholdExceeded, pingOptions = {} }) {\n        super();\n        this.failedPings = 0;\n        this._onPingThresholdExceeded = onPingThresholdExceeded;\n        this._getTimeSinceLastServerResponse = getTimeSinceLastServerResponse;\n\n        this.pingInterval = typeof pingOptions.interval === 'number' ? pingOptions.interval : PING_DEFAULT_INTERVAL;\n        this.pingTimeout = typeof pingOptions.timeout === 'number' ? pingOptions.timeout : PING_DEFAULT_TIMEOUT;\n        this.pingThreshold = typeof pingOptions.threshold === 'number'\n            ? pingOptions.threshold : PING_DEFAULT_THRESHOLD;\n\n        // The number of timestamps of send pings to keep.\n        // The current value is 2 minutes.\n        this.pingTimestampsToKeep = Math.round(120000 / this.pingInterval);\n        this.pingExecIntervals = new Array(this.pingTimestampsToKeep);\n    }\n\n    /**\n     * Initializes the plugin. Method called by Strophe.\n     * @param connection Strophe connection instance.\n     */\n    init(connection) {\n        super.init(connection);\n        Strophe.addNamespace('PING', 'urn:xmpp:ping');\n    }\n\n    /* eslint-disable max-params */\n\n    /**\n     * Sends \"ping\" to given <tt>jid</tt>\n     * @param jid the JID to which ping request will be sent.\n     * @param success callback called on success.\n     * @param error callback called on error.\n     * @param timeout ms how long are we going to wait for the response. On\n     * timeout <tt>error<//t> callback is called with undefined error argument.\n     */\n    ping(jid, success, error, timeout) {\n        this._addPingExecutionTimestamp();\n\n        const iq = $iq({\n            type: 'get',\n            to: jid\n        });\n\n        iq.c('ping', { xmlns: Strophe.NS.PING });\n        this.connection.sendIQ2(iq, { timeout })\n            .then(success, error);\n    }\n\n    /* eslint-enable max-params */\n\n    /**\n     * Starts to send ping in given interval to specified remote JID.\n     * This plugin supports only one such task and <tt>stopInterval</tt>\n     * must be called before starting a new one.\n     * @param remoteJid remote JID to which ping requests will be sent to.\n     */\n    startInterval(remoteJid) {\n        clearInterval(this.intervalId);\n        this.intervalId = window.setInterval(() => {\n\n            // when there were some server responses in the interval since the last time we checked (_lastServerCheck)\n            // let's skip the ping\n\n            const now = Date.now();\n\n            if (this._getTimeSinceLastServerResponse() < now - this._lastServerCheck) {\n                // do this just to keep in sync the intervals so we can detect suspended device\n                this._addPingExecutionTimestamp();\n\n                this._lastServerCheck = now;\n                this.failedPings = 0;\n\n                return;\n            }\n\n            this.ping(remoteJid, () => {\n                // server response is measured on raw input and ping response time is measured after all the xmpp\n                // processing is done in js, so there can be some misalignment when we do the check above.\n                // That's why we store the last time we got the response\n                this._lastServerCheck = this._getTimeSinceLastServerResponse() + Date.now();\n\n                this.failedPings = 0;\n            }, error => {\n                this.failedPings += 1;\n                const errmsg = `Ping ${error ? 'error' : 'timeout'}`;\n\n                if (this.failedPings >= this.pingThreshold) {\n                    GlobalOnErrorHandler.callErrorHandler(new Error(errmsg));\n                    logger.error(errmsg, error);\n                    this._onPingThresholdExceeded && this._onPingThresholdExceeded();\n                } else {\n                    logger.warn(errmsg, error);\n                }\n            }, this.pingTimeout);\n        }, this.pingInterval);\n        logger.info(`XMPP pings will be sent every ${this.pingInterval} ms`);\n    }\n\n    /**\n     * Stops current \"ping\"  interval task.\n     */\n    stopInterval() {\n        if (this.intervalId) {\n            window.clearInterval(this.intervalId);\n            this.intervalId = null;\n            this.failedPings = 0;\n            logger.info('Ping interval cleared');\n        }\n    }\n\n    /**\n     * Adds the current time to the array of send ping timestamps.\n     * @private\n     */\n    _addPingExecutionTimestamp() {\n        this.pingExecIntervals.push(new Date().getTime());\n\n        // keep array length to PING_TIMESTAMPS_TO_KEEP\n        if (this.pingExecIntervals.length > this.pingTimestampsToKeep) {\n            this.pingExecIntervals.shift();\n        }\n    }\n\n    /**\n     * Returns the maximum time between the recent sent pings, if there is a\n     * big value it means the computer was inactive for some time(suspended).\n     * Checks the maximum gap between sending pings, considering and the\n     * current time. Trying to detect computer inactivity (sleep).\n     *\n     * @returns {int} the time ping was suspended, if it was not 0 is returned.\n     */\n    getPingSuspendTime() {\n        const pingIntervals = this.pingExecIntervals.slice();\n\n        // we need current time, as if ping was sent now\n        // if computer sleeps we will get correct interval after next\n        // scheduled ping, bet we sometimes need that interval before waiting\n        // for the next ping, on closing the connection on error.\n        pingIntervals.push(new Date().getTime());\n\n        let maxInterval = 0;\n        let previousTS = pingIntervals[0];\n\n        pingIntervals.forEach(e => {\n            const currentInterval = e - previousTS;\n\n            if (currentInterval > maxInterval) {\n                maxInterval = currentInterval;\n            }\n\n            previousTS = e;\n        });\n\n        // remove the interval between the ping sent\n        // this way in normal execution there is no suspend and the return\n        // will be 0 or close to 0.\n        maxInterval -= this.pingInterval;\n\n        // make sure we do not return less than 0\n        return Math.max(maxInterval, 0);\n    }\n}\n","import { getLogger } from '@jitsi/logger';\nimport { $pres, Strophe } from 'strophe.js';\nimport 'strophejs-plugin-stream-management';\n\nimport Listenable from '../util/Listenable';\n\nimport ResumeTask from './ResumeTask';\nimport LastSuccessTracker from './StropheLastSuccess';\nimport PingConnectionPlugin from './strophe.ping';\n\nconst logger = getLogger(__filename);\n\n/**\n * The lib-jitsi-meet layer for {@link Strophe.Connection}.\n */\nexport default class XmppConnection extends Listenable {\n    /**\n     * The list of {@link XmppConnection} events.\n     *\n     * @returns {Object}\n     */\n    static get Events() {\n        return {\n            CONN_STATUS_CHANGED: 'CONN_STATUS_CHANGED',\n            CONN_SHARD_CHANGED: 'CONN_SHARD_CHANGED'\n        };\n    }\n\n    /**\n     * The list of Xmpp connection statuses.\n     *\n     * @returns {Strophe.Status}\n     */\n    static get Status() {\n        return Strophe.Status;\n    }\n\n    /**\n     * Initializes new connection instance.\n     *\n     * @param {Object} options\n     * @param {String} options.serviceUrl - The BOSH or WebSocket service URL.\n     * @param {String} options.shard - The BOSH or WebSocket is connecting to this shard.\n     * Useful for detecting when shard changes.\n     * @param {String} [options.enableWebsocketResume=true] - True/false to control the stream resumption functionality.\n     * It will enable automatically by default if supported by the XMPP server.\n     * @param {Number} [options.websocketKeepAlive=60000] - The websocket keep alive interval.\n     * It's the interval + a up to a minute of jitter. Pass -1 to disable.\n     * The keep alive is HTTP GET request to {@link options.serviceUrl} or to {@link options.websocketKeepAliveUrl}.\n     * @param {Number} [options.websocketKeepAliveUrl] - The websocket keep alive url to use if any,\n     * if missing the serviceUrl url will be used.\n     * @param {Object} [options.xmppPing] - The xmpp ping settings.\n     */\n    constructor({ enableWebsocketResume, websocketKeepAlive, websocketKeepAliveUrl, serviceUrl, shard, xmppPing }) {\n        super();\n        this._options = {\n            enableWebsocketResume: typeof enableWebsocketResume === 'undefined' ? true : enableWebsocketResume,\n            pingOptions: xmppPing,\n            shard,\n            websocketKeepAlive: typeof websocketKeepAlive === 'undefined' ? 60 * 1000 : Number(websocketKeepAlive),\n            websocketKeepAliveUrl\n        };\n\n        this._stropheConn = new Strophe.Connection(serviceUrl);\n        this._usesWebsocket = serviceUrl.startsWith('ws:') || serviceUrl.startsWith('wss:');\n\n        // The default maxRetries is 5, which is too long.\n        this._stropheConn.maxRetries = 3;\n\n        this._rawInputTracker = new LastSuccessTracker();\n        this._rawInputTracker.startTracking(this, this._stropheConn);\n\n        this._resumeTask = new ResumeTask(this._stropheConn);\n\n        /**\n         * @typedef DeferredSendIQ Object\n         * @property {Element} iq - The IQ to send.\n         * @property {function} resolve - The resolve method of the deferred Promise.\n         * @property {function} reject - The reject method of the deferred Promise.\n         * @property {number} timeout - The ID of the timeout task that needs to be cleared, before sending the IQ.\n         */\n        /**\n         * Deferred IQs to be sent upon reconnect.\n         * @type {Array<DeferredSendIQ>}\n         * @private\n         */\n        this._deferredIQs = [];\n\n        // Ping plugin is mandatory for the Websocket mode to work correctly. It's used to detect when the connection\n        // is broken (WebSocket/TCP connection not closed gracefully).\n        this.addConnectionPlugin(\n            'ping',\n            new PingConnectionPlugin({\n                getTimeSinceLastServerResponse: () => this.getTimeSinceLastSuccess(),\n                onPingThresholdExceeded: () => this._onPingErrorThresholdExceeded(),\n                pingOptions: xmppPing\n            }));\n\n        // tracks whether this is the initial connection or a reconnect\n        this._oneSuccessfulConnect = false;\n    }\n\n    /**\n     * A getter for the connected state.\n     *\n     * @returns {boolean}\n     */\n    get connected() {\n        const websocket = this._stropheConn && this._stropheConn._proto && this._stropheConn._proto.socket;\n\n        return (this._status === Strophe.Status.CONNECTED || this._status === Strophe.Status.ATTACHED)\n            && (!this.isUsingWebSocket || (websocket && websocket.readyState === WebSocket.OPEN));\n    }\n\n    /**\n     * Retrieves the feature discovery plugin instance.\n     *\n     * @returns {Strophe.Connection.disco}\n     */\n    get disco() {\n        return this._stropheConn.disco;\n    }\n\n    /**\n     * A getter for the disconnecting state.\n     *\n     * @returns {boolean}\n     */\n    get disconnecting() {\n        return this._stropheConn.disconnecting === true;\n    }\n\n    /**\n     * A getter for the domain.\n     *\n     * @returns {string|null}\n     */\n    get domain() {\n        return this._stropheConn.domain;\n    }\n\n    /**\n     * Tells if Websocket is used as the transport for the current XMPP connection. Returns true for Websocket or false\n     * for BOSH.\n     * @returns {boolean}\n     */\n    get isUsingWebSocket() {\n        return this._usesWebsocket;\n    }\n\n    /**\n     * A getter for the JID.\n     *\n     * @returns {string|null}\n     */\n    get jid() {\n        return this._stropheConn.jid;\n    }\n\n    /**\n     * Returns headers for the last BOSH response received.\n     *\n     * @returns {string}\n     */\n    get lastResponseHeaders() {\n        return this._stropheConn._proto && this._stropheConn._proto.lastResponseHeaders;\n    }\n\n    /**\n     * A getter for the logger plugin instance.\n     *\n     * @returns {*}\n     */\n    get logger() {\n        return this._stropheConn.logger;\n    }\n\n    /**\n     * A getter for the connection options.\n     *\n     * @returns {*}\n     */\n    get options() {\n        return this._stropheConn.options;\n    }\n\n    /**\n     * A getter for the domain to be used for ping.\n     */\n    get pingDomain() {\n        return this._options.pingOptions?.domain || this.domain;\n    }\n\n    /**\n     * A getter for the service URL.\n     *\n     * @returns {string}\n     */\n    get service() {\n        return this._stropheConn.service;\n    }\n\n    /**\n     * Sets new value for shard.\n     * @param value the new shard value.\n     */\n    set shard(value) {\n        this._options.shard = value;\n\n        // shard setting changed so let's schedule a new keep-alive check if connected\n        if (this._oneSuccessfulConnect) {\n            this._maybeStartWSKeepAlive();\n        }\n    }\n\n    /**\n     * Returns the current connection status.\n     *\n     * @returns {Strophe.Status}\n     */\n    get status() {\n        return this._status;\n    }\n\n    /**\n     * Adds a connection plugin to this instance.\n     *\n     * @param {string} name - The name of the plugin or rather a key under which it will be stored on this connection\n     * instance.\n     * @param {ConnectionPluginListenable} plugin - The plugin to add.\n     */\n    addConnectionPlugin(name, plugin) {\n        this[name] = plugin;\n        plugin.init(this);\n    }\n\n    /**\n     * See {@link Strophe.Connection.addHandler}\n     *\n     * @returns {void}\n     */\n    addHandler(...args) {\n        this._stropheConn.addHandler(...args);\n    }\n\n    /* eslint-disable max-params */\n    /**\n     * Wraps {@link Strophe.Connection.attach} method in order to intercept the connection status updates.\n     * See {@link Strophe.Connection.attach} for the params description.\n     *\n     * @returns {void}\n     */\n    attach(jid, sid, rid, callback, ...args) {\n        this._stropheConn.attach(jid, sid, rid, this._stropheConnectionCb.bind(this, callback), ...args);\n    }\n\n    /**\n     * Wraps Strophe.Connection.connect method in order to intercept the connection status updates.\n     * See {@link Strophe.Connection.connect} for the params description.\n     *\n     * @returns {void}\n     */\n    connect(jid, pass, callback, ...args) {\n        this._stropheConn.connect(jid, pass, this._stropheConnectionCb.bind(this, callback), ...args);\n    }\n\n    /* eslint-enable max-params */\n\n    /**\n     * Handles {@link Strophe.Status} updates for the current connection.\n     *\n     * @param {function} targetCallback - The callback passed by the {@link XmppConnection} consumer to one of\n     * the connect methods.\n     * @param {Strophe.Status} status - The new connection status.\n     * @param {*} args - The rest of the arguments passed by Strophe.\n     * @private\n     */\n    _stropheConnectionCb(targetCallback, status, ...args) {\n        this._status = status;\n\n        let blockCallback = false;\n\n        if (status === Strophe.Status.CONNECTED || status === Strophe.Status.ATTACHED) {\n            this._maybeEnableStreamResume();\n\n            // after connecting - immediately check whether shard changed,\n            // we need this only when using websockets as bosh checks headers from every response\n            if (this._usesWebsocket && this._oneSuccessfulConnect) {\n                this._keepAliveAndCheckShard();\n            }\n            this._oneSuccessfulConnect = true;\n\n            this._maybeStartWSKeepAlive();\n            this._processDeferredIQs();\n            this._resumeTask.cancel();\n            this.ping.startInterval(this._options.pingOptions?.domain || this.domain);\n        } else if (status === Strophe.Status.DISCONNECTED) {\n            this.ping.stopInterval();\n\n            // FIXME add RECONNECTING state instead of blocking the DISCONNECTED update\n            blockCallback = this._tryResumingConnection();\n            if (!blockCallback) {\n                clearTimeout(this._wsKeepAlive);\n            }\n        }\n\n        if (!blockCallback) {\n            targetCallback(status, ...args);\n            this.eventEmitter.emit(XmppConnection.Events.CONN_STATUS_CHANGED, status);\n        }\n    }\n\n    /**\n     * Clears the list of IQs and rejects deferred Promises with an error.\n     *\n     * @private\n     */\n    _clearDeferredIQs() {\n        for (const deferred of this._deferredIQs) {\n            deferred.reject(new Error('disconnect'));\n        }\n        this._deferredIQs = [];\n    }\n\n    /**\n     * The method is meant to be used for testing. It's a shortcut for closing the WebSocket.\n     *\n     * @returns {void}\n     */\n    closeWebsocket() {\n        if (this._stropheConn && this._stropheConn._proto) {\n            this._stropheConn._proto._closeSocket();\n            this._stropheConn._proto._onClose(null);\n        }\n    }\n\n    /**\n     * See {@link Strophe.Connection.disconnect}.\n     *\n     * @returns {void}\n     */\n    disconnect(...args) {\n        this._resumeTask.cancel();\n        clearTimeout(this._wsKeepAlive);\n        this._clearDeferredIQs();\n        this._stropheConn.disconnect(...args);\n    }\n\n    /**\n     * See {@link Strophe.Connection.flush}.\n     *\n     * @returns {void}\n     */\n    flush(...args) {\n        this._stropheConn.flush(...args);\n    }\n\n    /**\n     * See {@link LastRequestTracker.getTimeSinceLastSuccess}.\n     *\n     * @returns {number|null}\n     */\n    getTimeSinceLastSuccess() {\n        return this._rawInputTracker.getTimeSinceLastSuccess();\n    }\n\n    /**\n     * See {@link LastRequestTracker.getLastFailedMessage}.\n     *\n     * @returns {string|null}\n     */\n    getLastFailedMessage() {\n        return this._rawInputTracker.getLastFailedMessage();\n    }\n\n    /**\n     * Requests a resume token from the server if enabled and all requirements are met.\n     *\n     * @private\n     */\n    _maybeEnableStreamResume() {\n        if (!this._options.enableWebsocketResume) {\n\n            return;\n        }\n\n        const { streamManagement } = this._stropheConn;\n\n        if (!this.isUsingWebSocket) {\n            logger.warn('Stream resume enabled, but WebSockets are not enabled');\n        } else if (!streamManagement) {\n            logger.warn('Stream resume enabled, but Strophe streamManagement plugin is not installed');\n        } else if (!streamManagement.isSupported()) {\n            logger.warn('Stream resume enabled, but XEP-0198 is not supported by the server');\n        } else if (!streamManagement.getResumeToken()) {\n            logger.info('Enabling XEP-0198 stream management');\n            streamManagement.enable(/* resume */ true);\n        }\n    }\n\n    /**\n     * Starts the Websocket keep alive if enabled.\n     *\n     * @private\n     * @returns {void}\n     */\n    _maybeStartWSKeepAlive() {\n        const { websocketKeepAlive } = this._options;\n\n        if (this._usesWebsocket && websocketKeepAlive > 0) {\n            this._wsKeepAlive || logger.info(`WebSocket keep alive interval: ${websocketKeepAlive}ms`);\n            clearTimeout(this._wsKeepAlive);\n\n            const intervalWithJitter = /* base */ websocketKeepAlive + /* jitter */ (Math.random() * 60 * 1000);\n\n            logger.debug(`Scheduling next WebSocket keep-alive in ${intervalWithJitter}ms`);\n\n            this._wsKeepAlive = setTimeout(\n                () => this._keepAliveAndCheckShard()\n                    .then(() => this._maybeStartWSKeepAlive()),\n                intervalWithJitter);\n        }\n    }\n\n    /**\n     * Do a http GET to the shard and if shard change will throw an event.\n     *\n     * @private\n     * @returns {Promise}\n     */\n    _keepAliveAndCheckShard() {\n        const { shard, websocketKeepAliveUrl } = this._options;\n        const url = websocketKeepAliveUrl ? websocketKeepAliveUrl\n            : this.service.replace('wss://', 'https://').replace('ws://', 'http://');\n\n        return fetch(url)\n            .then(response => {\n\n                // skips header checking if there is no info in options\n                if (!shard) {\n                    return;\n                }\n\n                const responseShard = response.headers.get('x-jitsi-shard');\n\n                if (responseShard !== shard) {\n                    logger.error(\n                        `Detected that shard changed from ${shard} to ${responseShard}`);\n                    this.eventEmitter.emit(XmppConnection.Events.CONN_SHARD_CHANGED);\n                }\n            })\n            .catch(error => {\n                logger.error(`Websocket Keep alive failed for url: ${url}`, { error });\n            });\n    }\n\n    /**\n     * Goes over the list of {@link DeferredSendIQ} tasks and sends them.\n     *\n     * @private\n     * @returns {void}\n     */\n    _processDeferredIQs() {\n        for (const deferred of this._deferredIQs) {\n            if (deferred.iq) {\n                clearTimeout(deferred.timeout);\n\n                const timeLeft = Date.now() - deferred.start;\n\n                this.sendIQ(\n                    deferred.iq,\n                    result => deferred.resolve(result),\n                    error => deferred.reject(error),\n                    timeLeft);\n            }\n        }\n\n        this._deferredIQs = [];\n    }\n\n    /**\n     * Send a stanza. This function is called to push data onto the send queue to go out over the wire.\n     *\n     * @param {Element|Strophe.Builder} stanza - The stanza to send.\n     * @returns {void}\n     */\n    send(stanza) {\n        if (!this.connected) {\n            throw new Error('Not connected');\n        }\n        this._stropheConn.send(stanza);\n    }\n\n    /**\n     * Helper function to send IQ stanzas.\n     *\n     * @param {Element} elem - The stanza to send.\n     * @param {Function} callback - The callback function for a successful request.\n     * @param {Function} errback - The callback function for a failed or timed out request.  On timeout, the stanza will\n     * be null.\n     * @param {number} timeout - The time specified in milliseconds for a timeout to occur.\n     * @returns {number} - The id used to send the IQ.\n     */\n    sendIQ(elem, callback, errback, timeout) {\n        if (!this.connected) {\n            errback('Not connected');\n\n            return;\n        }\n\n        return this._stropheConn.sendIQ(elem, callback, errback, timeout);\n    }\n\n    /**\n     * Sends an IQ immediately if connected or puts it on the send queue otherwise(in contrary to other send methods\n     * which would fail immediately if disconnected).\n     *\n     * @param {Element} iq - The IQ to send.\n     * @param {number} timeout - How long to wait for the response. The time when the connection is reconnecting is\n     * included, which means that the IQ may never be sent and still fail with a timeout.\n     */\n    sendIQ2(iq, { timeout }) {\n        return new Promise((resolve, reject) => {\n            if (this.connected) {\n                this.sendIQ(\n                    iq,\n                    result => resolve(result),\n                    error => reject(error),\n                    timeout);\n            } else {\n                const deferred = {\n                    iq,\n                    resolve,\n                    reject,\n                    start: Date.now(),\n                    timeout: setTimeout(() => {\n                        // clears the IQ on timeout and invalidates the deferred task\n                        deferred.iq = undefined;\n\n                        // Strophe calls with undefined on timeout\n                        reject(undefined);\n                    }, timeout)\n                };\n\n                this._deferredIQs.push(deferred);\n            }\n        });\n    }\n\n    /**\n     * Called by the ping plugin when ping fails too many times.\n     *\n     * @returns {void}\n     */\n    _onPingErrorThresholdExceeded() {\n        if (this.isUsingWebSocket) {\n            logger.warn('Ping error threshold exceeded - killing the WebSocket');\n            this.closeWebsocket();\n        }\n    }\n\n    /**\n     *  Helper function to send presence stanzas. The main benefit is for sending presence stanzas for which you expect\n     *  a responding presence stanza with the same id (for example when leaving a chat room).\n     *\n     * @param {Element} elem - The stanza to send.\n     * @param {Function} callback - The callback function for a successful request.\n     * @param {Function} errback - The callback function for a failed or timed out request. On timeout, the stanza will\n     * be null.\n     * @param {number} timeout - The time specified in milliseconds for a timeout to occur.\n     * @returns {number} - The id used to send the presence.\n     */\n    sendPresence(elem, callback, errback, timeout) {\n        if (!this.connected) {\n            errback('Not connected');\n\n            return;\n        }\n        this._stropheConn.sendPresence(elem, callback, errback, timeout);\n    }\n\n    /**\n     * The method gracefully closes the BOSH connection by using 'navigator.sendBeacon'.\n     *\n     * @returns {boolean} - true if the beacon was sent.\n     */\n    sendUnavailableBeacon() {\n        if (!navigator.sendBeacon || this._stropheConn.disconnecting || !this._stropheConn.connected) {\n            return false;\n        }\n\n        this._stropheConn._changeConnectStatus(Strophe.Status.DISCONNECTING);\n        this._stropheConn.disconnecting = true;\n\n        const body = this._stropheConn._proto._buildBody()\n            .attrs({\n                type: 'terminate'\n            });\n        const pres = $pres({\n            xmlns: Strophe.NS.CLIENT,\n            type: 'unavailable'\n        });\n\n        body.cnode(pres.tree());\n\n        const res = navigator.sendBeacon(\n            this.service.indexOf('https://') === -1 ? `https:${this.service}` : this.service,\n            Strophe.serialize(body.tree()));\n\n        logger.info(`Successfully send unavailable beacon ${res}`);\n\n        this._stropheConn._proto._abortAllRequests();\n        this._stropheConn._doDisconnect();\n\n        return true;\n    }\n\n    /**\n     * Tries to use stream management plugin to resume dropped XMPP connection. The streamManagement plugin clears\n     * the resume token if any connection error occurs which would put it in unrecoverable state, so as long as\n     * the token is present it means the connection can be resumed.\n     *\n     * @private\n     * @returns {boolean}\n     */\n    _tryResumingConnection() {\n        const { streamManagement } = this._stropheConn;\n        const resumeToken = streamManagement && streamManagement.getResumeToken();\n\n        if (resumeToken) {\n            this._resumeTask.schedule();\n\n            return true;\n        }\n\n        return false;\n    }\n}\n","export enum JitsiTranscriptionStatus {\n    /**\n     * The transcription is on.\n     */\n    ON = 'on',\n\n    /**\n     * The transcription is off.\n     */\n    OFF = 'off'\n}\n\n// exported for backward compatibility\nexport const ON = JitsiTranscriptionStatus.ON;\nexport const OFF = JitsiTranscriptionStatus.OFF;\n","import { getLogger } from '@jitsi/logger';\nimport { $msg } from 'strophe.js';\n\nimport { MediaType } from '../../service/RTC/MediaType';\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\n\nconst logger = getLogger(__filename);\n\n/**\n * The AVModeration logic.\n */\nexport default class AVModeration {\n\n    /**\n     * Constructs AV moderation room.\n     *\n     * @param {ChatRoom} room the main room.\n     */\n    constructor(room) {\n        this._xmpp = room.xmpp;\n\n        this._mainRoom = room;\n\n        this._moderationEnabledByType = {\n            [MediaType.AUDIO]: false,\n            [MediaType.VIDEO]: false\n        };\n\n        this._whitelistAudio = [];\n        this._whitelistVideo = [];\n\n        this._onMessage = this._onMessage.bind(this);\n        this._xmpp.addListener(XMPPEvents.AV_MODERATION_RECEIVED, this._onMessage);\n    }\n\n    /**\n     * Stops listening for events.\n     */\n    dispose() {\n        this._xmpp.removeListener(XMPPEvents.AV_MODERATION_RECEIVED, this._onMessage);\n    }\n\n    /**\n     * Whether AV moderation is supported on backend.\n     *\n     * @returns {boolean} whether AV moderation is supported on backend.\n     */\n    isSupported() {\n        return Boolean(this._xmpp.avModerationComponentAddress);\n    }\n\n    /**\n     * Enables or disables AV Moderation by sending a msg with command to the component.\n     */\n    enable(state, mediaType) {\n        if (!this.isSupported() || !this._mainRoom.isModerator()) {\n            logger.error(`Cannot enable:${state} AV moderation supported:${this.isSupported()},\n                moderator:${this._mainRoom.isModerator()}`);\n\n            return;\n        }\n\n        if (state === this._moderationEnabledByType[mediaType]) {\n            logger.warn(`Moderation already in state:${state} for mediaType:${mediaType}`);\n\n            return;\n        }\n\n        // send the enable/disable message\n        const msg = $msg({ to: this._xmpp.avModerationComponentAddress });\n\n        msg.c('av_moderation', {\n            enable: state,\n            mediaType\n        }).up();\n\n        this._xmpp.connection.send(msg);\n    }\n\n    /**\n     * Approves that a participant can unmute by sending a msg with its jid to the component.\n     */\n    approve(mediaType, jid) {\n        if (!this.isSupported() || !this._mainRoom.isModerator()) {\n            logger.error(`Cannot approve in AV moderation supported:${this.isSupported()},\n                moderator:${this._mainRoom.isModerator()}`);\n\n            return;\n        }\n\n        // send a message to whitelist the jid and approve it to unmute\n        const msg = $msg({ to: this._xmpp.avModerationComponentAddress });\n\n        msg.c('av_moderation', {\n            mediaType,\n            jidToWhitelist: jid }).up();\n\n        this._xmpp.connection.send(msg);\n    }\n\n    /**\n     * Rejects that a participant can unmute by sending a msg with its jid to the component.\n     */\n    reject(mediaType, jid) {\n        if (!this.isSupported() || !this._mainRoom.isModerator()) {\n            logger.error(`Cannot reject in AV moderation supported:${this.isSupported()},\n                moderator:${this._mainRoom.isModerator()}`);\n\n            return;\n        }\n\n        // send a message to remove from whitelist the jid and reject it to unmute\n        const msg = $msg({ to: this._xmpp.avModerationComponentAddress });\n\n        msg.c('av_moderation', {\n            mediaType,\n            jidToBlacklist: jid\n        }).up();\n\n        this._xmpp.connection.send(msg);\n    }\n\n    /**\n     * Receives av_moderation parsed messages as json.\n     * @param obj the parsed json content of the message to process.\n     * @private\n     */\n    _onMessage(obj) {\n        const { removed, mediaType: media, enabled, approved, actor, whitelists: newWhitelists } = obj;\n\n        if (newWhitelists) {\n            const oldList = media === MediaType.AUDIO\n                ? this._whitelistAudio\n                : this._whitelistVideo;\n            const newList = Array.isArray(newWhitelists[media]) ? newWhitelists[media] : [];\n\n            if (removed) {\n                oldList.filter(x => !newList.includes(x))\n                    .forEach(jid => this._xmpp.eventEmitter\n                        .emit(XMPPEvents.AV_MODERATION_PARTICIPANT_REJECTED, media, jid));\n            } else {\n                newList.filter(x => !oldList.includes(x))\n                    .forEach(jid => this._xmpp.eventEmitter\n                        .emit(XMPPEvents.AV_MODERATION_PARTICIPANT_APPROVED, media, jid));\n            }\n\n            if (media === MediaType.AUDIO) {\n                this._whitelistAudio = newList;\n            } else {\n                this._whitelistVideo = newList;\n            }\n        } else if (enabled !== undefined && this._moderationEnabledByType[media] !== enabled) {\n            this._moderationEnabledByType[media] = enabled;\n\n            this._xmpp.eventEmitter.emit(XMPPEvents.AV_MODERATION_CHANGED, enabled, media, actor);\n        } else if (removed) {\n            this._xmpp.eventEmitter.emit(XMPPEvents.AV_MODERATION_REJECTED, media);\n        } else if (approved) {\n            this._xmpp.eventEmitter.emit(XMPPEvents.AV_MODERATION_APPROVED, media);\n        }\n    }\n}\n","import { getLogger } from '@jitsi/logger';\nimport { $msg } from 'strophe.js';\n\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\n\nconst FEATURE_KEY = 'features/breakout-rooms';\nconst BREAKOUT_ROOM_ACTIONS = {\n    ADD: `${FEATURE_KEY}/add`,\n    REMOVE: `${FEATURE_KEY}/remove`,\n    MOVE_TO_ROOM: `${FEATURE_KEY}/move-to-room`\n};\nconst BREAKOUT_ROOM_EVENTS = {\n    MOVE_TO_ROOM: `${FEATURE_KEY}/move-to-room`,\n    UPDATE: `${FEATURE_KEY}/update`\n};\n\nconst logger = getLogger(__filename);\n\n/**\n * Helper class for handling breakout rooms.\n */\nexport default class BreakoutRooms {\n\n    /**\n     * Constructs lobby room.\n     *\n     * @param {ChatRoom} room the room we are in.\n     */\n    constructor(room) {\n        this.room = room;\n\n        this._handleMessages = this._handleMessages.bind(this);\n        this.room.xmpp.addListener(XMPPEvents.BREAKOUT_ROOMS_EVENT, this._handleMessages);\n\n        this._rooms = {};\n    }\n\n    /**\n     * Stops listening for events.\n     */\n    dispose() {\n        this.room.xmpp.removeListener(XMPPEvents.BREAKOUT_ROOMS_EVENT, this._handleMessages);\n    }\n\n    /**\n     * Creates a breakout room with the given subject.\n     *\n     * @param {string} subject - A subject for the breakout room.\n     */\n    createBreakoutRoom(subject) {\n        if (!this.isSupported() || !this.room.isModerator()) {\n            logger.error(`Cannot create breakout room - supported:${this.isSupported()},\n                moderator:${this.room.isModerator()}`);\n\n            return;\n        }\n\n        const message = {\n            type: BREAKOUT_ROOM_ACTIONS.ADD,\n            subject\n        };\n\n        this._sendMessage(message);\n    }\n\n    /**\n     * Removes a breakout room.\n     *\n     * @param {string} breakoutRoomJid - JID of the room to be removed.\n     */\n    removeBreakoutRoom(breakoutRoomJid) {\n        if (!this.isSupported() || !this.room.isModerator()) {\n            logger.error(`Cannot remove breakout room - supported:${this.isSupported()},\n                moderator:${this.room.isModerator()}`);\n\n            return;\n        }\n\n        const message = {\n            type: BREAKOUT_ROOM_ACTIONS.REMOVE,\n            breakoutRoomJid\n        };\n\n        this._sendMessage(message);\n    }\n\n    /**\n     * Sends the given participant to the given room.\n     *\n     * @param {string} participantJid - JID of the participant to be sent to a room.\n     * @param {string} roomJid - JID of the target room.\n     */\n    sendParticipantToRoom(participantJid, roomJid) {\n        if (!this.isSupported() || !this.room.isModerator()) {\n            logger.error(`Cannot send participant to room - supported:${this.isSupported()},\n                moderator:${this.room.isModerator()}`);\n\n            return;\n        }\n\n        const message = {\n            type: BREAKOUT_ROOM_ACTIONS.MOVE_TO_ROOM,\n            participantJid,\n            roomJid\n        };\n\n        this._sendMessage(message);\n    }\n\n    /**\n     * Whether Breakout Rooms support is enabled in the backend or not.\n     */\n    isSupported() {\n        return Boolean(this.getComponentAddress());\n    }\n\n    /**\n     * Gets the address of the Breakout Rooms XMPP component.\n     *\n     * @returns The address of the component.\n     */\n    getComponentAddress() {\n        return this.room.xmpp.breakoutRoomsComponentAddress;\n    }\n\n    /**\n     * Stores if the current room is a breakout room.\n     *\n     * @param {boolean} isBreakoutRoom - Whether this room is a breakout room.\n     */\n    _setIsBreakoutRoom(isBreakoutRoom) {\n        this._isBreakoutRoom = isBreakoutRoom;\n    }\n\n    /**\n     * Checks whether this room is a breakout room.\n     *\n     * @returns True if the room is a breakout room, false otherwise.\n     */\n    isBreakoutRoom() {\n        return this._isBreakoutRoom;\n    }\n\n    /**\n     * Sets the main room JID associated with this breakout room. Only applies when\n     * in a breakout room.\n     *\n     * @param {string} jid - The main room JID.\n     */\n    _setMainRoomJid(jid) {\n        this._mainRoomJid = jid;\n    }\n\n    /**\n     * Gets the main room's JID associated with this breakout room.\n     *\n     * @returns The main room JID.\n     */\n    getMainRoomJid() {\n        return this._mainRoomJid;\n    }\n\n    /**\n     * Handles a message for managing breakout rooms.\n     *\n     * @param {object} payload - Arbitrary data.\n     */\n    _handleMessages(payload) {\n        switch (payload.event) {\n        case BREAKOUT_ROOM_EVENTS.MOVE_TO_ROOM:\n            this.room.eventEmitter.emit(XMPPEvents.BREAKOUT_ROOMS_MOVE_TO_ROOM, payload.roomJid);\n            break;\n        case BREAKOUT_ROOM_EVENTS.UPDATE: {\n            this._rooms = payload.rooms;\n            this.room.eventEmitter.emit(XMPPEvents.BREAKOUT_ROOMS_UPDATED, payload);\n            break;\n        }\n        }\n    }\n\n    /**\n     * Helper to send a breakout rooms message to the component.\n     *\n     * @param {Object} message - Command that needs to be sent.\n     */\n    _sendMessage(message) {\n        const msg = $msg({ to: this.getComponentAddress() });\n\n        msg.c('breakout_rooms', message).up();\n\n        this.room.xmpp.connection.send(msg);\n    }\n}\n","import { getLogger } from '@jitsi/logger';\nimport { $msg, Strophe } from 'strophe.js';\n\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\n\nconst logger = getLogger(__filename);\n\n/**\n * The command type for updating a lobby participant's e-mail address.\n *\n * @type {string}\n */\nconst EMAIL_COMMAND = 'email';\n\n/**\n * The Lobby room implementation. Setting a room to members only, joining the lobby room\n * approving or denying access to participants from the lobby room.\n */\nexport default class Lobby {\n\n    /**\n     * Constructs lobby room.\n     *\n     * @param {ChatRoom} room the main room.\n     */\n    constructor(room) {\n        this.xmpp = room.xmpp;\n        this.mainRoom = room;\n\n        const maybeJoinLobbyRoom = this._maybeJoinLobbyRoom.bind(this);\n\n        this.mainRoom.addEventListener(\n            XMPPEvents.LOCAL_ROLE_CHANGED,\n            maybeJoinLobbyRoom);\n\n        this.mainRoom.addEventListener(\n            XMPPEvents.MUC_MEMBERS_ONLY_CHANGED,\n            maybeJoinLobbyRoom);\n\n        this.mainRoom.addEventListener(\n            XMPPEvents.ROOM_CONNECT_MEMBERS_ONLY_ERROR,\n            jid => {\n                this.lobbyRoomJid = jid;\n            });\n    }\n\n    /**\n     * Whether lobby is supported on backend.\n     *\n     * @returns {boolean} whether lobby is supported on backend.\n     */\n    isSupported() {\n        return this.xmpp.lobbySupported;\n    }\n\n    /**\n     * Enables lobby by setting the main room to be members only and joins the lobby chat room.\n     *\n     * @returns {Promise}\n     */\n    enable() {\n        if (!this.isSupported()) {\n            return Promise.reject(new Error('Lobby not supported!'));\n        }\n\n        return new Promise((resolve, reject) => {\n            this.mainRoom.setMembersOnly(true, resolve, reject);\n        });\n    }\n\n    /**\n     * Disable lobby by setting the main room to be non members only and levaes the lobby chat room if joined.\n     *\n     * @returns {void}\n     */\n    disable() {\n        if (!this.isSupported() || !this.mainRoom.isModerator()\n                || !this.lobbyRoom || !this.mainRoom.membersOnlyEnabled) {\n            return;\n        }\n\n        this.mainRoom.setMembersOnly(false);\n    }\n\n    /**\n     * Broadcast a message to all participants in the lobby room\n     * @param {Object} message The message to send\n     *\n     * @returns {void}\n     */\n    sendMessage(message) {\n        if (this.lobbyRoom) {\n            this.lobbyRoom.sendMessage(JSON.stringify(message), 'json-message');\n        }\n    }\n\n    /**\n     * Sends a private message to a participant in a lobby room.\n     * @param {string} id The message to send\n     * @param {Object} message The message to send\n     *\n     * @returns {void}\n     */\n    sendPrivateMessage(id, message) {\n        if (this.lobbyRoom) {\n            this.lobbyRoom.sendPrivateMessage(id, JSON.stringify(message), 'json-message');\n        }\n    }\n\n    /**\n     * Gets the local id for a participant in a lobby room.\n     * This is used for lobby room private chat messages.\n     *\n     * @returns {string}\n     */\n    getLocalId() {\n        if (this.lobbyRoom) {\n            return Strophe.getResourceFromJid(this.lobbyRoom.myroomjid);\n        }\n    }\n\n    /**\n     * Adds a message listener to the lobby room.\n     * @param {Function} listener The listener function,\n     * called when a new message is received in the lobby room.\n     *\n     * @returns {Function} Handler returned to be able to remove it later.\n     */\n    addMessageListener(listener) {\n        if (this.lobbyRoom) {\n            const handler = (participantId, message) => {\n                listener(message, Strophe.getResourceFromJid(participantId));\n            };\n\n            this.lobbyRoom.on(XMPPEvents.JSON_MESSAGE_RECEIVED, handler);\n\n            return handler;\n        }\n    }\n\n    /**\n     * Remove a message handler from the lobby room.\n     * @param {Function} handler The handler function to remove.\n     *\n     * @returns {void}\n     */\n    removeMessageHandler(handler) {\n        if (this.lobbyRoom) {\n            this.lobbyRoom.off(XMPPEvents.JSON_MESSAGE_RECEIVED, handler);\n        }\n    }\n\n    /**\n     * Leaves the lobby room.\n     *\n     * @returns {Promise}\n     */\n    leave() {\n        if (this.lobbyRoom) {\n            return this.lobbyRoom.leave()\n                .then(() => {\n                    this.lobbyRoom = undefined;\n                    logger.info('Lobby room left!');\n                })\n                .catch(() => {}); // eslint-disable-line no-empty-function\n        }\n\n        return Promise.reject(\n                new Error('The lobby has already been left'));\n    }\n\n    /**\n     * We had received a jid for the lobby room.\n     *\n     * @param jid the lobby room jid to join.\n     */\n    setLobbyRoomJid(jid) {\n        this.lobbyRoomJid = jid;\n    }\n\n    /**\n     * Checks the state of mainRoom, lobbyRoom and current user role to decide whether to join lobby room.\n     * @private\n     */\n    _maybeJoinLobbyRoom() {\n        if (!this.isSupported()) {\n            return;\n        }\n\n        const isModerator = this.mainRoom.joined && this.mainRoom.isModerator();\n\n        if (isModerator && this.mainRoom.membersOnlyEnabled && !this.lobbyRoom) {\n            // join the lobby\n            this.join()\n                .then(() => logger.info('Joined lobby room'))\n                .catch(e => logger.error('Failed joining lobby', e));\n        }\n    }\n\n    /**\n     * Joins a lobby room setting display name and eventually avatar(using the email provided).\n     *\n     * @param {string} username is required.\n     * @param {string} email is optional.\n     * @returns {Promise} resolves once we join the room.\n     */\n    join(displayName, email) {\n        const isModerator = this.mainRoom.joined && this.mainRoom.isModerator();\n\n        if (!this.lobbyRoomJid) {\n            return Promise.reject(new Error('Missing lobbyRoomJid, cannot join lobby room.'));\n        }\n\n        const roomName = Strophe.getNodeFromJid(this.lobbyRoomJid);\n        const customDomain = Strophe.getDomainFromJid(this.lobbyRoomJid);\n\n        this.lobbyRoom = this.xmpp.createRoom(\n            roomName, {\n                customDomain,\n                disableDiscoInfo: true,\n                disableFocus: true,\n                enableLobby: false\n            }\n        );\n\n        if (displayName) {\n            // remove previously set nickname\n            this.lobbyRoom.addOrReplaceInPresence('nick', {\n                attributes: { xmlns: 'http://jabber.org/protocol/nick' },\n                value: displayName\n            });\n        }\n\n        if (isModerator) {\n            this.lobbyRoom.addPresenceListener(EMAIL_COMMAND, (node, from) => {\n                this.mainRoom.eventEmitter.emit(XMPPEvents.MUC_LOBBY_MEMBER_UPDATED, from, { email: node.value });\n            });\n            this.lobbyRoom.addEventListener(\n                XMPPEvents.MUC_MEMBER_JOINED,\n                // eslint-disable-next-line max-params\n                (from, nick, role, isHiddenDomain, statsID, status, identity, botType, jid) => {\n                    // we need to ignore joins on lobby for participants that are already in the main room\n                    if (Object.values(this.mainRoom.members).find(m => m.jid === jid)) {\n                        return;\n                    }\n\n                    // Check if the user is a member if any breakout room.\n                    for (const room of Object.values(this.mainRoom.getBreakoutRooms()._rooms)) {\n                        if (Object.values(room.participants).find(p => p.jid === jid)) {\n                            return;\n                        }\n                    }\n\n                    // we emit the new event on the main room so we can propagate\n                    // events to the conference\n                    this.mainRoom.eventEmitter.emit(\n                        XMPPEvents.MUC_LOBBY_MEMBER_JOINED,\n                        Strophe.getResourceFromJid(from),\n                        nick,\n                        identity ? identity.avatar : undefined\n                    );\n                });\n            this.lobbyRoom.addEventListener(\n                XMPPEvents.MUC_MEMBER_LEFT, from => {\n                    // we emit the new event on the main room so we can propagate\n                    // events to the conference\n                    this.mainRoom.eventEmitter.emit(\n                        XMPPEvents.MUC_LOBBY_MEMBER_LEFT,\n                        Strophe.getResourceFromJid(from)\n                    );\n                });\n            this.lobbyRoom.addEventListener(\n                XMPPEvents.MUC_DESTROYED,\n                () => {\n                    // let's make sure we emit that all lobby users had left\n                    Object.keys(this.lobbyRoom.members)\n                        .forEach(j => this.mainRoom.eventEmitter.emit(\n                            XMPPEvents.MUC_LOBBY_MEMBER_LEFT, Strophe.getResourceFromJid(j)));\n\n                    this.lobbyRoom.clean();\n\n                    this.lobbyRoom = undefined;\n                    logger.info('Lobby room left(destroyed)!');\n                });\n        } else {\n            // this should only be handled by those waiting in lobby\n            this.lobbyRoom.addEventListener(XMPPEvents.KICKED, isSelfPresence => {\n                if (isSelfPresence) {\n                    this.mainRoom.eventEmitter.emit(XMPPEvents.MUC_DENIED_ACCESS);\n\n                    this.lobbyRoom.clean();\n\n                    return;\n                }\n            });\n\n            // As there is still reference of the main room\n            // the invite will be detected and addressed to its eventEmitter, even though we are not in it\n            // the invite message should be received directly to the xmpp conn in general\n            this.mainRoom.addEventListener(\n                XMPPEvents.INVITE_MESSAGE_RECEIVED,\n                (roomJid, from, txt, invitePassword) => {\n                    logger.debug(`Received approval to join ${roomJid} ${from} ${txt}`);\n                    if (roomJid === this.mainRoom.roomjid) {\n                        // we are now allowed, so let's join\n                        this.mainRoom.join(invitePassword);\n                    }\n                });\n            this.lobbyRoom.addEventListener(\n                XMPPEvents.MUC_DESTROYED,\n                (reason, jid) => {\n                    // we are receiving the jid of the main room\n                    // means we are invited to join, maybe lobby was disabled\n                    if (jid) {\n                        this.mainRoom.join();\n\n                        return;\n                    }\n\n                    this.lobbyRoom.clean();\n\n                    this.mainRoom.eventEmitter.emit(XMPPEvents.MUC_DESTROYED, reason);\n                });\n\n            // If participant retries joining shared password while waiting in the lobby\n            // and succeeds make sure we leave lobby\n            this.mainRoom.addEventListener(\n                XMPPEvents.MUC_JOINED,\n                () => {\n                    this.leave();\n                });\n        }\n\n        return new Promise((resolve, reject) => {\n            this.lobbyRoom.addEventListener(XMPPEvents.MUC_JOINED, () => {\n                resolve();\n\n                // send our email, as we do not handle this on initial presence we need a second one\n                if (email && !isModerator) {\n                    this.lobbyRoom.addOrReplaceInPresence(EMAIL_COMMAND, { value: email })\n                        && this.lobbyRoom.sendPresence();\n                }\n            });\n            this.lobbyRoom.addEventListener(XMPPEvents.ROOM_JOIN_ERROR, reject);\n            this.lobbyRoom.addEventListener(XMPPEvents.ROOM_CONNECT_NOT_ALLOWED_ERROR, reject);\n            this.lobbyRoom.addEventListener(XMPPEvents.ROOM_CONNECT_ERROR, reject);\n\n            this.lobbyRoom.join();\n        });\n\n    }\n\n    /**\n     * Should be possible only for moderators.\n     * @param id\n     */\n    denyAccess(id) {\n        if (!this.isSupported() || !this.mainRoom.isModerator()) {\n            return;\n        }\n\n        const jid = Object.keys(this.lobbyRoom.members)\n            .find(j => Strophe.getResourceFromJid(j) === id);\n\n        if (jid) {\n            this.lobbyRoom.kick(jid);\n        } else {\n            logger.error(`Not found member for ${id} in lobby room.`);\n        }\n    }\n\n    /**\n     * Should be possible only for moderators.\n     * @param id\n     */\n    approveAccess(id) {\n        if (!this.isSupported() || !this.mainRoom.isModerator()) {\n            return;\n        }\n\n        // Get the main room JID. If we are in a breakout room we'll use the main\n        // room's lobby.\n        let mainRoomJid = this.mainRoom.roomjid;\n\n        if (this.mainRoom.getBreakoutRooms().isBreakoutRoom()) {\n            mainRoomJid = this.mainRoom.getBreakoutRooms().getMainRoomJid();\n        }\n\n        const memberRoomJid = Object.keys(this.lobbyRoom.members)\n            .find(j => Strophe.getResourceFromJid(j) === id);\n\n        if (memberRoomJid) {\n            const jid = this.lobbyRoom.members[memberRoomJid].jid;\n            const msgToSend\n                = $msg({ to: mainRoomJid })\n                    .c('x', { xmlns: 'http://jabber.org/protocol/muc#user' })\n                    .c('invite', { to: jid });\n\n            this.xmpp.connection.sendIQ(msgToSend,\n                () => { }, // eslint-disable-line no-empty-function\n                e => {\n                    logger.error(`Error sending invite for ${jid}`, e);\n                });\n        } else {\n            logger.error(`Not found member for ${memberRoomJid} in lobby room.`);\n        }\n    }\n}\n","import { jitsiLocalStorage } from '@jitsi/js-utils';\nimport { getLogger } from '@jitsi/logger';\n\nconst logger = getLogger(__filename);\n\nimport UsernameGenerator from '../util/UsernameGenerator';\n\nlet _callStatsUserName;\n\nlet _machineId;\n\n/**\n *\n */\nexport default {\n\n    /**\n     * The storage used to store the settings.\n     */\n    _storage: jitsiLocalStorage,\n\n    /**\n     * Initializes the Settings class.\n     *\n     * @param {Storage|undefined} externalStorage - Object that implements the Storage interface. This object will be\n     * used for storing data instead of jitsiLocalStorage if specified.\n     */\n    init(externalStorage) {\n        this._storage = externalStorage || jitsiLocalStorage;\n    },\n\n    /**\n     * Returns fake username for callstats\n     * @returns {string} fake username for callstats\n     */\n    get callStatsUserName() {\n        if (!_callStatsUserName) {\n            _callStatsUserName = this._storage.getItem('callStatsUserName');\n            if (!_callStatsUserName) {\n                _callStatsUserName = generateCallStatsUserName();\n                this._storage.setItem('callStatsUserName', _callStatsUserName);\n            }\n        }\n\n        return _callStatsUserName;\n    },\n\n    /**\n     * Returns current machine id.\n     * @returns {string} machine id\n     */\n    get machineId() {\n        if (!_machineId) {\n            const amDid = this._storage.getItem('billingId');\n\n            _machineId = amDid || this._storage.getItem('jitsiMeetId');\n\n            if (amDid) {\n                this._storage.setItem('jitsiMeetId', amDid);\n            } else if (!_machineId) {\n                _machineId = generateJitsiMeetId();\n                this._storage.setItem('jitsiMeetId', _machineId);\n            }\n        }\n\n        return _machineId;\n    },\n\n    /**\n     * Returns current session id.\n     * @returns {string} current session id\n     */\n    get sessionId() {\n        // We may update sessionId in localStorage from another JitsiConference\n        // instance and that's why we should always re-read it.\n        return this._storage.getItem('sessionId');\n    },\n\n    /**\n     * Save current session id.\n     * @param {string} sessionId session id\n     */\n    set sessionId(sessionId) {\n        if (sessionId) {\n            this._storage.setItem('sessionId', sessionId);\n        } else {\n            this._storage.removeItem('sessionId');\n        }\n    }\n};\n\n/**\n * Generate fake username for callstats.\n * @returns {string} fake random username\n */\nfunction generateCallStatsUserName() {\n    const username = UsernameGenerator.generateUsername();\n\n    logger.log('generated callstats uid', username);\n\n    return username;\n}\n\n/**\n * Generate unique id.\n * @returns {string} random unique id\n */\nfunction generateJitsiMeetId() {\n    const jitsiMeetId = generateUniqueId();\n\n    logger.log('generated id', jitsiMeetId);\n\n    return jitsiMeetId;\n}\n\n/**\n *\n */\nfunction generateUniqueId() {\n    return _p8() + _p8() + _p8() + _p8();\n}\n\n/**\n *\n */\nfunction _p8() {\n    return `${Math.random().toString(16)}000000000`.substr(2, 8);\n}\n","import { getLogger } from '@jitsi/logger';\nimport $ from 'jquery';\nimport { $iq, Strophe } from 'strophe.js';\n\nimport Settings from '../settings/Settings';\n\nconst AuthenticationEvents\n    = require('../../service/authentication/AuthenticationEvents');\nconst { XMPPEvents } = require('../../service/xmpp/XMPPEvents');\nconst GlobalOnErrorHandler = require('../util/GlobalOnErrorHandler');\n\nconst logger = getLogger(__filename);\n\n/**\n *\n * @param step\n */\nfunction createExpBackoffTimer(step) {\n    let count = 1;\n\n    return function(reset) {\n        // Reset call\n        if (reset) {\n            count = 1;\n\n            return;\n        }\n\n        // Calculate next timeout\n        const timeout = Math.pow(2, count - 1);\n\n        count += 1;\n\n        return timeout * step;\n    };\n}\n\n/* eslint-disable max-params */\n\n/**\n *\n * @param roomName\n * @param xmpp\n * @param emitter\n * @param options\n */\nexport default function Moderator(roomName, xmpp, emitter, options) {\n    this.roomName = roomName;\n    this.xmppService = xmpp;\n    this.getNextTimeout = createExpBackoffTimer(1000);\n    this.getNextErrorTimeout = createExpBackoffTimer(1000);\n\n    // External authentication stuff\n    this.externalAuthEnabled = false;\n    this.options = options;\n\n    // Whether SIP gateway (jigasi) support is enabled. This is set\n    // based on conference properties received in presence.\n    this.sipGatewayEnabled = false;\n\n    this.eventEmitter = emitter;\n\n    this.connection = this.xmppService.connection;\n\n    // FIXME: Message listener that talks to POPUP window\n    /**\n     *\n     * @param event\n     */\n    function listener(event) {\n        if (event.data && event.data.sessionId) {\n            if (event.origin !== window.location.origin) {\n                logger.warn(\n                    `Ignoring sessionId from different origin: ${\n                        event.origin}`);\n\n                return;\n            }\n            Settings.sessionId = event.data.sessionId;\n\n            // After popup is closed we will authenticate\n        }\n    }\n\n    // Register\n    if (window.addEventListener) {\n        window.addEventListener('message', listener, false);\n    } else {\n        window.attachEvent('onmessage', listener);\n    }\n}\n\n/* eslint-enable max-params */\n\nModerator.prototype.isExternalAuthEnabled = function() {\n    return this.externalAuthEnabled;\n};\n\nModerator.prototype.isSipGatewayEnabled = function() {\n    return this.sipGatewayEnabled;\n};\n\nModerator.prototype.onMucMemberLeft = function(jid) {\n    const resource = Strophe.getResourceFromJid(jid);\n\n    if (resource === 'focus') {\n        logger.info(\n            'Focus has left the room - leaving conference');\n        this.eventEmitter.emit(XMPPEvents.FOCUS_LEFT);\n    }\n};\n\nModerator.prototype.setFocusUserJid = function(focusJid) {\n    if (!this.focusUserJid) {\n        this.focusUserJid = focusJid;\n        logger.info(`Focus jid set to:  ${this.focusUserJid}`);\n    }\n};\n\nModerator.prototype.getFocusUserJid = function() {\n    return this.focusUserJid;\n};\n\nModerator.prototype.getFocusComponent = function() {\n    // Get focus component address\n    let focusComponent = this.options.connection.hosts.focus;\n\n    // If not specified use default:  'focus.domain'\n\n    if (!focusComponent) {\n        focusComponent = `focus.${this.options.connection.hosts.domain}`;\n    }\n\n    return focusComponent;\n};\n\nModerator.prototype.createConferenceIq = function() {\n    // Generate create conference IQ\n    const elem = $iq({ to: this.getFocusComponent(),\n        type: 'set' });\n\n    // Session Id used for authentication\n    const { sessionId } = Settings;\n    const machineUID = Settings.machineId;\n    const config = this.options.conference;\n\n    logger.info(`Session ID: ${sessionId} machine UID: ${machineUID}`);\n\n    elem.c('conference', {\n        xmlns: 'http://jitsi.org/protocol/focus',\n        room: this.roomName,\n        'machine-uid': machineUID\n    });\n\n    if (sessionId) {\n        elem.attrs({ 'session-id': sessionId });\n    }\n\n    elem.c(\n        'property', {\n            name: 'disableRtx',\n            value: Boolean(config.disableRtx)\n        }).up();\n\n    if (config.audioPacketDelay !== undefined) {\n        elem.c(\n            'property', {\n                name: 'audioPacketDelay',\n                value: config.audioPacketDelay\n            }).up();\n    }\n    if (config.startBitrate) {\n        elem.c(\n            'property', {\n                name: 'startBitrate',\n                value: config.startBitrate\n            }).up();\n    }\n    if (config.minBitrate) {\n        elem.c(\n            'property', {\n                name: 'minBitrate',\n                value: config.minBitrate\n            }).up();\n    }\n\n    if (this.options.conference.startAudioMuted !== undefined) {\n        elem.c(\n            'property', {\n                name: 'startAudioMuted',\n                value: this.options.conference.startAudioMuted\n            }).up();\n    }\n    if (this.options.conference.startVideoMuted !== undefined) {\n        elem.c(\n            'property', {\n                name: 'startVideoMuted',\n                value: this.options.conference.startVideoMuted\n            }).up();\n    }\n\n    // this flag determines whether the bridge will include this call in its\n    // rtcstats reporting or not. If the site admin hasn't set the flag in\n    // config.js, then the client defaults to false (see\n    // react/features/rtcstats/functions.js in jitsi-meet). The server-side\n    // components default to true to match the pre-existing behavior so we only\n    // signal if false.\n    const rtcstatsEnabled = this.options.conference?.analytics?.rtcstatsEnabled ?? false;\n\n    if (!rtcstatsEnabled) {\n        elem.c(\n            'property', {\n                name: 'rtcstatsEnabled',\n                value: rtcstatsEnabled\n            }).up();\n    }\n\n    const { callStatsID, callStatsSecret, disableThirdPartyRequests, enableCallStats } = this.options.conference;\n    const callstatsDisabled = !callStatsID || !callStatsSecret || !enableCallStats\n\n        // Even though AppID and AppSecret may be specified, the integration\n        // of callstats.io may be disabled because of globally-disallowed\n        // requests to any third parties.\n        || disableThirdPartyRequests === true;\n\n    // since the default is true across all the server-side components, only signal if false.\n    if (callstatsDisabled) {\n        elem.c(\n            'property', {\n                name: 'callstatsEnabled',\n                value: !callstatsDisabled\n            }).up();\n    }\n    elem.up();\n\n    return elem;\n};\n\n\nModerator.prototype.parseSessionId = function(resultIq) {\n    // eslint-disable-next-line newline-per-chained-call\n    const sessionId = $(resultIq).find('conference').attr('session-id');\n\n    if (sessionId) {\n        logger.info(`Received sessionId:  ${sessionId}`);\n        Settings.sessionId = sessionId;\n    }\n};\n\nModerator.prototype.parseConfigOptions = function(resultIq) {\n    // eslint-disable-next-line newline-per-chained-call\n    this.setFocusUserJid($(resultIq).find('conference').attr('focusjid'));\n\n    const authenticationEnabled\n        = $(resultIq).find(\n            '>conference>property'\n            + '[name=\\'authentication\\'][value=\\'true\\']').length > 0;\n\n    logger.info(`Authentication enabled: ${authenticationEnabled}`);\n\n    this.externalAuthEnabled = $(resultIq).find(\n        '>conference>property'\n            + '[name=\\'externalAuth\\'][value=\\'true\\']').length > 0;\n\n    logger.info(\n        `External authentication enabled: ${this.externalAuthEnabled}`);\n\n    if (!this.externalAuthEnabled) {\n        // We expect to receive sessionId in 'internal' authentication mode\n        this.parseSessionId(resultIq);\n    }\n\n    // eslint-disable-next-line newline-per-chained-call\n    const authIdentity = $(resultIq).find('>conference').attr('identity');\n\n    this.eventEmitter.emit(AuthenticationEvents.IDENTITY_UPDATED,\n        authenticationEnabled, authIdentity);\n\n    // Check if jicofo has jigasi support enabled.\n    if ($(resultIq).find(\n        '>conference>property'\n        + '[name=\\'sipGatewayEnabled\\'][value=\\'true\\']').length) {\n        this.sipGatewayEnabled = true;\n    }\n\n    logger.info(`Sip gateway enabled:  ${this.sipGatewayEnabled}`);\n};\n\n// FIXME We need to show the fact that we're waiting for the focus to the user\n// (or that the focus is not available)\n/**\n * Allocates the conference focus.\n *\n * @param {Function} callback - the function to be called back upon the\n * successful allocation of the conference focus\n * @returns {Promise} - Resolved when Jicofo allows to join the room. It's never\n * rejected and it'll keep on pinging Jicofo forever.\n */\nModerator.prototype.allocateConferenceFocus = function() {\n    return new Promise(resolve => {\n        // Try to use focus user JID from the config\n        this.setFocusUserJid(this.options.connection.focusUserJid);\n\n        // Send create conference IQ\n        this.connection.sendIQ(\n            this.createConferenceIq(),\n            result => this._allocateConferenceFocusSuccess(result, resolve),\n            error => this._allocateConferenceFocusError(error, resolve));\n\n        // XXX We're pressed for time here because we're beginning a complex\n        // and/or lengthy conference-establishment process which supposedly\n        // involves multiple RTTs. We don't have the time to wait for Strophe to\n        // decide to send our IQ.\n        this.connection.flush();\n    });\n};\n\n/**\n * Invoked by {@link #allocateConferenceFocus} upon its request receiving an\n * error result.\n *\n * @param error - the error result of the request that\n * {@link #allocateConferenceFocus} sent\n * @param {Function} callback - the function to be called back upon the\n * successful allocation of the conference focus\n */\nModerator.prototype._allocateConferenceFocusError = function(error, callback) {\n    // If the session is invalid, remove and try again without session ID to get\n    // a new one\n    const invalidSession\n        = $(error).find('>error>session-invalid').length\n            || $(error).find('>error>not-acceptable').length;\n\n    if (invalidSession) {\n        logger.info('Session expired! - removing');\n        Settings.sessionId = undefined;\n    }\n    if ($(error).find('>error>graceful-shutdown').length) {\n        this.eventEmitter.emit(XMPPEvents.GRACEFUL_SHUTDOWN);\n\n        return;\n    }\n\n    // Check for error returned by the reservation system\n    const reservationErr = $(error).find('>error>reservation-error');\n\n    if (reservationErr.length) {\n        // Trigger error event\n        const errorCode = reservationErr.attr('error-code');\n        const errorTextNode = $(error).find('>error>text');\n        let errorMsg;\n\n        if (errorTextNode) {\n            errorMsg = errorTextNode.text();\n        }\n        this.eventEmitter.emit(\n            XMPPEvents.RESERVATION_ERROR,\n            errorCode,\n            errorMsg);\n\n        return;\n    }\n\n    // Not authorized to create new room\n    if ($(error).find('>error>not-authorized').length) {\n        logger.warn('Unauthorized to start the conference', error);\n        const toDomain = Strophe.getDomainFromJid(error.getAttribute('to'));\n\n        if (toDomain !== this.options.connection.hosts.anonymousdomain) {\n            // FIXME \"is external\" should come either from the focus or\n            // config.js\n            this.externalAuthEnabled = true;\n        }\n        this.eventEmitter.emit(XMPPEvents.AUTHENTICATION_REQUIRED);\n\n        return;\n    }\n    const waitMs = this.getNextErrorTimeout();\n    const errmsg = `Focus error, retry after ${waitMs}`;\n\n    GlobalOnErrorHandler.callErrorHandler(new Error(errmsg));\n    logger.error(errmsg, error);\n\n    // Show message\n    const focusComponent = this.getFocusComponent();\n    const retrySec = waitMs / 1000;\n\n    // FIXME: message is duplicated ? Do not show in case of session invalid\n    // which means just a retry\n\n    if (!invalidSession) {\n        this.eventEmitter.emit(\n            XMPPEvents.FOCUS_DISCONNECTED,\n            focusComponent,\n            retrySec);\n    }\n\n    // Reset response timeout\n    this.getNextTimeout(true);\n    window.setTimeout(\n        () => this.allocateConferenceFocus().then(callback),\n        waitMs);\n};\n\n/**\n * Invoked by {@link #allocateConferenceFocus} upon its request receiving a\n * success (i.e. non-error) result.\n *\n * @param result - the success (i.e. non-error) result of the request that\n * {@link #allocateConferenceFocus} sent\n * @param {Function} callback - the function to be called back upon the\n * successful allocation of the conference focus\n */\nModerator.prototype._allocateConferenceFocusSuccess = function(\n        result,\n        callback) {\n    // Setup config options\n    this.parseConfigOptions(result);\n\n    // Reset the error timeout (because we haven't failed here).\n    this.getNextErrorTimeout(true);\n\n    // eslint-disable-next-line newline-per-chained-call\n    if ($(result).find('conference').attr('ready') === 'true') {\n        // Reset the non-error timeout (because we've succeeded here).\n        this.getNextTimeout(true);\n\n        // Exec callback\n        callback();\n    } else {\n        const waitMs = this.getNextTimeout();\n\n        logger.info(`Waiting for the focus... ${waitMs}`);\n        window.setTimeout(\n            () => this.allocateConferenceFocus().then(callback),\n            waitMs);\n    }\n};\n\nModerator.prototype.authenticate = function() {\n    return new Promise((resolve, reject) => {\n        this.connection.sendIQ(\n            this.createConferenceIq(),\n            result => {\n                this.parseSessionId(result);\n                resolve();\n            },\n            errorIq => reject({\n                error: $(errorIq).find('iq>error :first')\n                    .prop('tagName'),\n                message: $(errorIq).find('iq>error>text')\n                    .text()\n            })\n        );\n    });\n};\n\nModerator.prototype.getLoginUrl = function(urlCallback, failureCallback) {\n    this._getLoginUrl(/* popup */ false, urlCallback, failureCallback);\n};\n\n/**\n *\n * @param {boolean} popup false for {@link Moderator#getLoginUrl} or true for\n * {@link Moderator#getPopupLoginUrl}\n * @param urlCb\n * @param failureCb\n */\nModerator.prototype._getLoginUrl = function(popup, urlCb, failureCb) {\n    const iq = $iq({ to: this.getFocusComponent(),\n        type: 'get' });\n    const attrs = {\n        xmlns: 'http://jitsi.org/protocol/focus',\n        room: this.roomName,\n        'machine-uid': Settings.machineId\n    };\n    let str = 'auth url'; // for logger\n\n    if (popup) {\n        attrs.popup = true;\n        str = `POPUP ${str}`;\n    }\n    iq.c('login-url', attrs);\n\n    /**\n     * Implements a failure callback which reports an error message and an error\n     * through (1) GlobalOnErrorHandler, (2) logger, and (3) failureCb.\n     *\n     * @param {string} errmsg the error messsage to report\n     * @param {*} error the error to report (in addition to errmsg)\n     */\n    function reportError(errmsg, err) {\n        GlobalOnErrorHandler.callErrorHandler(new Error(errmsg));\n        logger.error(errmsg, err);\n        failureCb(err);\n    }\n    this.connection.sendIQ(\n        iq,\n        result => {\n            // eslint-disable-next-line newline-per-chained-call\n            let url = $(result).find('login-url').attr('url');\n\n            url = decodeURIComponent(url);\n            if (url) {\n                logger.info(`Got ${str}: ${url}`);\n                urlCb(url);\n            } else {\n                reportError(`Failed to get ${str} from the focus`, result);\n            }\n        },\n        reportError.bind(undefined, `Get ${str} error`)\n    );\n};\n\nModerator.prototype.getPopupLoginUrl = function(urlCallback, failureCallback) {\n    this._getLoginUrl(/* popup */ true, urlCallback, failureCallback);\n};\n\nModerator.prototype.logout = function(callback) {\n    const iq = $iq({ to: this.getFocusComponent(),\n        type: 'set' });\n    const { sessionId } = Settings;\n\n    if (!sessionId) {\n        callback();\n\n        return;\n    }\n    iq.c('logout', {\n        xmlns: 'http://jitsi.org/protocol/focus',\n        'session-id': sessionId\n    });\n    this.connection.sendIQ(\n        iq,\n        result => {\n            // eslint-disable-next-line newline-per-chained-call\n            let logoutUrl = $(result).find('logout').attr('logout-url');\n\n            if (logoutUrl) {\n                logoutUrl = decodeURIComponent(logoutUrl);\n            }\n            logger.info(`Log out OK, url: ${logoutUrl}`, result);\n            Settings.sessionId = undefined;\n            callback(logoutUrl);\n        },\n        error => {\n            const errmsg = 'Logout error';\n\n            GlobalOnErrorHandler.callErrorHandler(new Error(errmsg));\n            logger.error(errmsg, error);\n        }\n    );\n};\n","import { getLogger } from '@jitsi/logger';\nimport $ from 'jquery';\nimport isEqual from 'lodash.isequal';\nimport { $iq, $msg, $pres, Strophe } from 'strophe.js';\n\nimport * as JitsiTranscriptionStatus from '../../JitsiTranscriptionStatus';\nimport { MediaType } from '../../service/RTC/MediaType';\nimport { VideoType } from '../../service/RTC/VideoType';\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\nimport GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';\nimport Listenable from '../util/Listenable';\n\nimport AVModeration from './AVModeration';\nimport BreakoutRooms from './BreakoutRooms';\nimport Lobby from './Lobby';\nimport XmppConnection from './XmppConnection';\nimport Moderator from './moderator';\n\nconst logger = getLogger(__filename);\n\nexport const parser = {\n    packet2JSON(xmlElement, nodes) {\n        for (const child of Array.from(xmlElement.children)) {\n            const node = {\n                attributes: {},\n                children: [],\n                tagName: child.tagName\n            };\n\n            for (const attr of Array.from(child.attributes)) {\n                node.attributes[attr.name] = attr.value;\n            }\n            const text = Strophe.getText(child);\n\n            if (text) {\n                // Using Strophe.getText will do work for traversing all direct\n                // child text nodes but returns an escaped value, which is not\n                // desirable at this point.\n                node.value = Strophe.xmlunescape(text);\n            }\n            nodes.push(node);\n            this.packet2JSON(child, node.children);\n        }\n    },\n    json2packet(nodes, packet) {\n        for (let i = 0; i < nodes.length; i++) {\n            const node = nodes[i];\n\n            if (node) {\n                packet.c(node.tagName, node.attributes);\n                if (node.value) {\n                    packet.t(node.value);\n                }\n                if (node.children) {\n                    this.json2packet(node.children, packet);\n                }\n                packet.up();\n            }\n        }\n\n        // packet.up();\n    }\n};\n\n/**\n * Returns array of JS objects from the presence JSON associated with the passed\n / nodeName\n * @param pres the presence JSON\n * @param nodeName the name of the node (videomuted, audiomuted, etc)\n */\nexport function filterNodeFromPresenceJSON(pres, nodeName) {\n    const res = [];\n\n    for (let i = 0; i < pres.length; i++) {\n        if (pres[i].tagName === nodeName) {\n            res.push(pres[i]);\n        }\n    }\n\n    return res;\n}\n\n// XXX As ChatRoom constructs XMPP stanzas and Strophe is build around the idea\n// of chaining function calls, allow long function call chains.\n/* eslint-disable newline-per-chained-call */\n\n/**\n * Array of affiliations that are allowed in members only room.\n * @type {string[]}\n */\nconst MEMBERS_AFFILIATIONS = [ 'owner', 'admin', 'member' ];\n\n/**\n *\n */\nexport default class ChatRoom extends Listenable {\n\n    /* eslint-disable max-params */\n\n    /**\n     *\n     * @param {XmppConnection} connection - The XMPP connection instance.\n     * @param jid\n     * @param password\n     * @param XMPP\n     * @param options\n     * @param {boolean} options.disableFocus - when set to {@code false} will\n     * not invite Jicofo into the room.\n     * @param {boolean} options.disableDiscoInfo - when set to {@code false} will skip disco info.\n     * This is intended to be used only for lobby rooms.\n     * @param {boolean} options.enableLobby - when set to {@code false} will skip creating lobby room.\n     * @param {boolean} options.hiddenFromRecorderFeatureEnabled - when set to {@code true} we will check identity tag\n     * for node presence.\n     */\n    constructor(connection, jid, password, XMPP, options) {\n        super();\n        this.xmpp = XMPP;\n        this.connection = connection;\n        this.roomjid = Strophe.getBareJidFromJid(jid);\n        this.myroomjid = jid;\n        this.password = password;\n        this.replaceParticipant = false;\n        logger.info(`Joined MUC as ${this.myroomjid}`);\n        this.members = {};\n        this.presMap = {};\n        this.presHandlers = {};\n        this._removeConnListeners = [];\n        this.joined = false;\n        this.inProgressEmitted = false;\n        this.role = null;\n        this.focusMucJid = null;\n        this.noBridgeAvailable = false;\n        this.options = options || {};\n        this.moderator\n            = new Moderator(this.roomjid, this.xmpp, this.eventEmitter, {\n                connection: this.xmpp.options,\n                conference: this.options\n            });\n        if (typeof this.options.enableLobby === 'undefined' || this.options.enableLobby) {\n            this.lobby = new Lobby(this);\n        }\n        this.avModeration = new AVModeration(this);\n        this.breakoutRooms = new BreakoutRooms(this);\n        this.initPresenceMap(options);\n        this.lastPresences = {};\n        this.phoneNumber = null;\n        this.phonePin = null;\n        this.connectionTimes = {};\n        this.participantPropertyListener = null;\n\n        this.locked = false;\n        this.transcriptionStatus = JitsiTranscriptionStatus.OFF;\n    }\n\n    /* eslint-enable max-params */\n\n    /**\n     *\n     */\n    initPresenceMap(options = {}) {\n        this.presMap.to = this.myroomjid;\n        this.presMap.xns = 'http://jabber.org/protocol/muc';\n        this.presMap.nodes = [];\n\n        if (options.statsId) {\n            this.presMap.nodes.push({\n                'tagName': 'stats-id',\n                'value': options.statsId\n            });\n        }\n\n        this.presenceUpdateTime = Date.now();\n    }\n\n    /**\n     * Joins the chat room.\n     * @param {string} password - Password to unlock room on joining.\n     * @returns {Promise} - resolved when join completes. At the time of this\n     * writing it's never rejected.\n     */\n    join(password, replaceParticipant) {\n        this.password = password;\n        this.replaceParticipant = replaceParticipant;\n\n        return new Promise(resolve => {\n            this.options.disableFocus\n                && logger.info(`Conference focus disabled for ${this.roomjid}`);\n\n            const preJoin\n                = this.options.disableFocus\n                    ? Promise.resolve()\n                    : this.moderator.allocateConferenceFocus();\n\n            preJoin.then(() => {\n                this.sendPresence(true);\n                this._removeConnListeners.push(\n                    this.connection.addEventListener(\n                        XmppConnection.Events.CONN_STATUS_CHANGED,\n                        this.onConnStatusChanged.bind(this))\n                );\n                resolve();\n            });\n        });\n    }\n\n    /**\n     *\n     * @param fromJoin - Whether this is initial presence to join the room.\n     */\n    sendPresence(fromJoin) {\n        const to = this.presMap.to;\n\n        if (!this.connection || !this.connection.connected || !to || (!this.joined && !fromJoin)) {\n            // Too early to send presence - not initialized\n            return;\n        }\n\n        const pres = $pres({ to });\n\n        // xep-0045 defines: \"including in the initial presence stanza an empty\n        // <x/> element qualified by the 'http://jabber.org/protocol/muc'\n        // namespace\" and subsequent presences should not include that or it can\n        // be considered as joining, and server can send us the message history\n        // for the room on every presence\n        if (fromJoin) {\n            if (this.replaceParticipant) {\n                pres.c('flip_device').up();\n            }\n\n            pres.c('x', { xmlns: this.presMap.xns });\n\n            if (this.password) {\n                pres.c('password').t(this.password).up();\n            }\n            if (this.options.billingId) {\n                pres.c('billingid').t(this.options.billingId).up();\n            }\n\n            pres.up();\n        }\n\n        parser.json2packet(this.presMap.nodes, pres);\n\n        // we store time we last synced presence state\n        this.presenceSyncTime = Date.now();\n\n        this.connection.send(pres);\n        if (fromJoin) {\n            // XXX We're pressed for time here because we're beginning a complex\n            // and/or lengthy conference-establishment process which supposedly\n            // involves multiple RTTs. We don't have the time to wait for\n            // Strophe to decide to send our IQ.\n            this.connection.flush();\n        }\n    }\n\n    /**\n     * Sends the presence unavailable, signaling the server\n     * we want to leave the room.\n     */\n    doLeave() {\n        logger.log('do leave', this.myroomjid);\n        const pres = $pres({ to: this.myroomjid,\n            type: 'unavailable' });\n\n        this.presMap.length = 0;\n\n        // XXX Strophe is asynchronously sending by default. Unfortunately, that\n        // means that there may not be enough time to send the unavailable\n        // presence. Switching Strophe to synchronous sending is not much of an\n        // option because it may lead to a noticeable delay in navigating away\n        // from the current location. As a compromise, we will try to increase\n        // the chances of sending the unavailable presence within the short time\n        // span that we have upon unloading by invoking flush() on the\n        // connection. We flush() once before sending/queuing the unavailable\n        // presence in order to attemtp to have the unavailable presence at the\n        // top of the send queue. We flush() once more after sending/queuing the\n        // unavailable presence in order to attempt to have it sent as soon as\n        // possible.\n        // FIXME do not use Strophe.Connection in the ChatRoom directly\n        !this.connection.isUsingWebSocket && this.connection.flush();\n        this.connection.send(pres);\n        this.connection.flush();\n    }\n\n    /**\n     *\n     */\n    discoRoomInfo() {\n        // https://xmpp.org/extensions/xep-0045.html#disco-roominfo\n\n        const getInfo\n            = $iq({\n                type: 'get',\n                to: this.roomjid\n            })\n                .c('query', { xmlns: Strophe.NS.DISCO_INFO });\n\n        this.connection.sendIQ(getInfo, result => {\n            const locked\n                = $(result).find('>query>feature[var=\"muc_passwordprotected\"]')\n                    .length\n                    === 1;\n\n            if (locked !== this.locked) {\n                this.eventEmitter.emit(XMPPEvents.MUC_LOCK_CHANGED, locked);\n                this.locked = locked;\n            }\n\n            const meetingIdValEl\n                = $(result).find('>query>x[type=\"result\"]>field[var=\"muc#roominfo_meetingId\"]>value');\n\n            if (meetingIdValEl.length) {\n                this.setMeetingId(meetingIdValEl.text());\n            } else {\n                logger.warn('No meeting ID from backend');\n            }\n\n            const membersOnly = $(result).find('>query>feature[var=\"muc_membersonly\"]').length === 1;\n\n            const lobbyRoomField\n                = $(result).find('>query>x[type=\"result\"]>field[var=\"muc#roominfo_lobbyroom\"]>value');\n\n            if (this.lobby) {\n                this.lobby.setLobbyRoomJid(lobbyRoomField && lobbyRoomField.length ? lobbyRoomField.text() : undefined);\n            }\n\n            const isBreakoutField\n                = $(result).find('>query>x[type=\"result\"]>field[var=\"muc#roominfo_isbreakout\"]>value');\n            const isBreakoutRoom = Boolean(isBreakoutField?.text());\n\n            this.breakoutRooms._setIsBreakoutRoom(isBreakoutRoom);\n\n            const breakoutMainRoomField\n                = $(result).find('>query>x[type=\"result\"]>field[var=\"muc#roominfo_breakout_main_room\"]>value');\n\n            if (breakoutMainRoomField?.length) {\n                this.breakoutRooms._setMainRoomJid(breakoutMainRoomField.text());\n            }\n\n            if (membersOnly !== this.membersOnlyEnabled) {\n                this.membersOnlyEnabled = membersOnly;\n                this.eventEmitter.emit(XMPPEvents.MUC_MEMBERS_ONLY_CHANGED, membersOnly);\n            }\n\n        }, error => {\n            GlobalOnErrorHandler.callErrorHandler(error);\n            logger.error('Error getting room info: ', error);\n        });\n    }\n\n    /**\n     * Sets the meeting unique Id (received from the backend).\n     *\n     * @param {string} meetingId - The new meetings id.\n     * @returns {void}\n     */\n    setMeetingId(meetingId) {\n        if (this.meetingId !== meetingId) {\n            if (this.meetingId) {\n                logger.warn(`Meeting Id changed from:${this.meetingId} to:${meetingId}`);\n            }\n            this.meetingId = meetingId;\n            this.eventEmitter.emit(XMPPEvents.MEETING_ID_SET, meetingId);\n        }\n    }\n\n    /**\n     *\n     */\n    createNonAnonymousRoom() {\n        // http://xmpp.org/extensions/xep-0045.html#createroom-reserved\n\n        if (this.options.disableDiscoInfo) {\n            return;\n        }\n\n        const getForm = $iq({ type: 'get',\n            to: this.roomjid })\n            .c('query', { xmlns: 'http://jabber.org/protocol/muc#owner' })\n            .c('x', { xmlns: 'jabber:x:data',\n                type: 'submit' });\n\n        this.connection.sendIQ(getForm, form => {\n            if (!$(form).find(\n                    '>query>x[xmlns=\"jabber:x:data\"]'\n                    + '>field[var=\"muc#roomconfig_whois\"]').length) {\n                const errmsg = 'non-anonymous rooms not supported';\n\n                GlobalOnErrorHandler.callErrorHandler(new Error(errmsg));\n                logger.error(errmsg);\n\n                return;\n            }\n\n            const formSubmit = $iq({ to: this.roomjid,\n                type: 'set' })\n                .c('query', { xmlns: 'http://jabber.org/protocol/muc#owner' });\n\n            formSubmit.c('x', { xmlns: 'jabber:x:data',\n                type: 'submit' });\n\n            formSubmit.c('field', { 'var': 'FORM_TYPE' })\n                .c('value')\n                .t('http://jabber.org/protocol/muc#roomconfig').up().up();\n\n            formSubmit.c('field', { 'var': 'muc#roomconfig_whois' })\n                .c('value').t('anyone').up().up();\n\n            this.connection.sendIQ(formSubmit);\n\n        }, error => {\n            GlobalOnErrorHandler.callErrorHandler(error);\n            logger.error('Error getting room configuration form: ', error);\n        });\n    }\n\n    /**\n     * Handles Xmpp Connection status updates.\n     *\n     * @param {Strophe.Status} status - The Strophe connection status.\n     */\n    onConnStatusChanged(status) {\n        // Send cached presence when the XMPP connection is re-established.\n        if (status === XmppConnection.Status.CONNECTED) {\n            this.sendPresence();\n        }\n    }\n\n    /**\n     *\n     * @param pres\n     */\n    onPresence(pres) {\n        const from = pres.getAttribute('from');\n        const member = {};\n        const statusEl = pres.getElementsByTagName('status')[0];\n\n        if (statusEl) {\n            member.status = statusEl.textContent || '';\n        }\n        let hasStatusUpdate = false;\n        let hasVersionUpdate = false;\n        const xElement\n            = pres.getElementsByTagNameNS(\n                'http://jabber.org/protocol/muc#user', 'x')[0];\n        const mucUserItem\n            = xElement && xElement.getElementsByTagName('item')[0];\n\n        member.isReplaceParticipant\n            = pres.getElementsByTagName('flip_device').length;\n\n        member.affiliation\n            = mucUserItem && mucUserItem.getAttribute('affiliation');\n        member.role = mucUserItem && mucUserItem.getAttribute('role');\n\n        // Focus recognition\n        const jid = mucUserItem && mucUserItem.getAttribute('jid');\n\n        member.jid = jid;\n        member.isFocus\n            = jid && jid.indexOf(`${this.moderator.getFocusUserJid()}/`) === 0;\n        member.isHiddenDomain\n            = jid && jid.indexOf('@') > 0\n                && this.options.hiddenDomain\n                    === jid.substring(jid.indexOf('@') + 1, jid.indexOf('/'));\n\n        this.eventEmitter.emit(XMPPEvents.PRESENCE_RECEIVED, {\n            fromHiddenDomain: member.isHiddenDomain,\n            presence: pres\n        });\n\n        const xEl = pres.querySelector('x');\n\n        if (xEl) {\n            xEl.remove();\n        }\n\n        const nodes = [];\n\n        parser.packet2JSON(pres, nodes);\n        this.lastPresences[from] = nodes;\n\n        // process nodes to extract data needed for MUC_JOINED and\n        // MUC_MEMBER_JOINED events\n        const extractIdentityInformation = node => {\n            const identity = {};\n            const userInfo = node.children.find(c => c.tagName === 'user');\n\n            if (userInfo) {\n                identity.user = {};\n                const tags = [ 'id', 'name', 'avatar' ];\n\n                if (this.options.hiddenFromRecorderFeatureEnabled) {\n                    tags.push('hidden-from-recorder');\n                }\n\n                for (const tag of tags) {\n                    const child\n                        = userInfo.children.find(c => c.tagName === tag);\n\n                    if (child) {\n                        identity.user[tag] = child.value;\n                    }\n                }\n            }\n            const groupInfo = node.children.find(c => c.tagName === 'group');\n\n            if (groupInfo) {\n                identity.group = groupInfo.value;\n            }\n\n            return identity;\n        };\n\n        for (let i = 0; i < nodes.length; i++) {\n            const node = nodes[i];\n\n            switch (node.tagName) {\n            case 'bot': {\n                const { attributes } = node;\n\n                if (!attributes) {\n                    break;\n                }\n                const { type } = attributes;\n\n                member.botType = type;\n                break;\n            }\n            case 'nick':\n                member.nick = node.value;\n                break;\n            case 'userId':\n                member.id = node.value;\n                break;\n            case 'stats-id':\n                member.statsID = node.value;\n                break;\n            case 'identity':\n                member.identity = extractIdentityInformation(node);\n                break;\n            case 'features': {\n                member.features = this._extractFeatures(node);\n                break;\n            }\n            case 'stat': {\n                const { attributes } = node;\n\n                if (!attributes) {\n                    break;\n                }\n                const { name } = attributes;\n\n                if (name === 'version') {\n                    member.version = attributes.value;\n                }\n                break;\n            }\n            }\n        }\n\n        if (!this.joined && !this.inProgressEmitted) {\n            const now = this.connectionTimes['muc.join.started'] = window.performance.now();\n\n            logger.log('(TIME) MUC join started:\\t', now);\n\n            this.eventEmitter.emit(XMPPEvents.MUC_JOIN_IN_PROGRESS);\n            this.inProgressEmitted = true;\n        }\n\n        if (from === this.myroomjid) {\n            const newRole\n                = member.affiliation === 'owner' ? member.role : 'none';\n\n            if (this.role !== newRole) {\n                this.role = newRole;\n                this.eventEmitter.emit(\n                    XMPPEvents.LOCAL_ROLE_CHANGED,\n                    this.role);\n            }\n            if (!this.joined) {\n                this.joined = true;\n                const now = this.connectionTimes['muc.joined']\n                    = window.performance.now();\n\n                logger.log('(TIME) MUC joined:\\t', now);\n\n                // set correct initial state of locked\n                if (this.password) {\n                    this.locked = true;\n                }\n\n                // Re-send presence in case any presence updates were added,\n                // but blocked from sending, during the join process.\n                // send the presence only if there was a modification after we had synced it\n                if (this.presenceUpdateTime >= this.presenceSyncTime) {\n                    this.sendPresence();\n                }\n\n                this.eventEmitter.emit(XMPPEvents.MUC_JOINED);\n\n                // Now let's check the disco-info to retrieve the\n                // meeting Id if any\n                !this.options.disableDiscoInfo && this.discoRoomInfo();\n            }\n        } else if (jid === undefined) {\n            logger.info('Ignoring member with undefined JID');\n        } else if (this.members[from] === undefined) {\n            // new participant\n            this.members[from] = member;\n            logger.log('entered', from, member);\n            hasStatusUpdate = member.status !== undefined;\n            hasVersionUpdate = member.version !== undefined;\n            if (member.isFocus) {\n                this._initFocus(from, member.features);\n            } else {\n                // identity is being added to member joined, so external\n                // services can be notified for that (currently identity is\n                // not used inside library)\n                this.eventEmitter.emit(\n                    XMPPEvents.MUC_MEMBER_JOINED,\n                    from,\n                    member.nick,\n                    member.role,\n                    member.isHiddenDomain,\n                    member.statsID,\n                    member.status,\n                    member.identity,\n                    member.botType,\n                    member.jid,\n                    member.features,\n                    member.isReplaceParticipant);\n\n                // we are reporting the status with the join\n                // so we do not want a second event about status update\n                hasStatusUpdate = false;\n            }\n        } else {\n            // Presence update for existing participant\n            // Watch role change:\n            const memberOfThis = this.members[from];\n\n            if (memberOfThis.role !== member.role) {\n                memberOfThis.role = member.role;\n                this.eventEmitter.emit(\n                    XMPPEvents.MUC_ROLE_CHANGED, from, member.role);\n            }\n\n            // affiliation changed\n            if (memberOfThis.affiliation !== member.affiliation) {\n                memberOfThis.affiliation = member.affiliation;\n            }\n\n            // fire event that botType had changed\n            if (memberOfThis.botType !== member.botType) {\n                memberOfThis.botType = member.botType;\n                this.eventEmitter.emit(\n                    XMPPEvents.MUC_MEMBER_BOT_TYPE_CHANGED,\n                    from,\n                    member.botType);\n            }\n\n            if (member.isFocus) {\n                // From time to time first few presences of the focus are not\n                // containing it's jid. That way we can mark later the focus\n                // member instead of not marking it at all and not starting the\n                // conference.\n                // FIXME: Maybe there is a better way to handle this issue. It\n                // seems there is some period of time in prosody that the\n                // configuration form is received but not applied. And if any\n                // participant joins during that period of time the first\n                // presence from the focus won't contain\n                // <item jid=\"focus...\" />.\n                // By default we are disabling the waiting for form submission in order to use the room\n                // and we had enabled by default that jids are public in the room ,\n                // so this case should not happen, if public jid is turned off we will receive the jid\n                // when we become moderator in the room\n                memberOfThis.isFocus = true;\n                this._initFocus(from, member.features);\n            }\n\n            // store the new display name\n            if (member.displayName) {\n                memberOfThis.displayName = member.displayName;\n            }\n\n            // update stored status message to be able to detect changes\n            if (memberOfThis.status !== member.status) {\n                hasStatusUpdate = true;\n                memberOfThis.status = member.status;\n            }\n\n            if (memberOfThis.version !== member.version) {\n                hasVersionUpdate = true;\n                memberOfThis.version = member.version;\n            }\n\n            if (!isEqual(memberOfThis.features, member.features)) {\n                memberOfThis.features = member.features;\n                this.eventEmitter.emit(XMPPEvents.PARTICIPANT_FEATURES_CHANGED, from, member.features);\n            }\n        }\n\n        // after we had fired member or room joined events, lets fire events\n        // for the rest info we got in presence\n        for (let i = 0; i < nodes.length; i++) {\n            const node = nodes[i];\n\n            switch (node.tagName) {\n            case 'nick':\n                if (!member.isFocus) {\n                    const displayName\n                        = this.xmpp.options.displayJids\n                            ? Strophe.getResourceFromJid(from)\n                            : member.nick;\n\n                    this.eventEmitter.emit(\n                        XMPPEvents.DISPLAY_NAME_CHANGED,\n                        from,\n                        displayName);\n                }\n                break;\n            case 'bridgeNotAvailable':\n                if (member.isFocus && !this.noBridgeAvailable) {\n                    this.noBridgeAvailable = true;\n                    this.eventEmitter.emit(XMPPEvents.BRIDGE_DOWN);\n                }\n                break;\n            case 'conference-properties':\n                if (member.isFocus) {\n                    const properties = {};\n\n                    for (let j = 0; j < node.children.length; j++) {\n                        const { attributes } = node.children[j];\n\n                        if (attributes && attributes.key) {\n                            properties[attributes.key] = attributes.value;\n                        }\n                    }\n\n                    this.eventEmitter.emit(XMPPEvents.CONFERENCE_PROPERTIES_CHANGED, properties);\n\n                    // Log if Jicofo supports restart by terminate only once. This conference property does not change\n                    // during the call.\n                    if (typeof this.restartByTerminateSupported === 'undefined') {\n                        this.restartByTerminateSupported = properties['support-terminate-restart'] === 'true';\n                        logger.info(`Jicofo supports restart by terminate: ${this.supportsRestartByTerminate()}`);\n                    }\n                }\n                break;\n            case 'transcription-status': {\n                const { attributes } = node;\n\n                if (!attributes) {\n                    break;\n                }\n\n                const { status } = attributes;\n\n                if (status && status !== this.transcriptionStatus) {\n                    this.transcriptionStatus = status;\n                    this.eventEmitter.emit(\n                        XMPPEvents.TRANSCRIPTION_STATUS_CHANGED,\n                        status\n                    );\n                }\n\n\n                break;\n            }\n            case 'call-control': {\n                const att = node.attributes;\n\n                if (!att) {\n                    break;\n                }\n                this.phoneNumber = att.phone || null;\n                this.phonePin = att.pin || null;\n                this.eventEmitter.emit(XMPPEvents.PHONE_NUMBER_CHANGED);\n                break;\n            }\n            default:\n                this.processNode(node, from);\n            }\n        }\n\n        // Trigger status message update if necessary\n        if (hasStatusUpdate) {\n            this.eventEmitter.emit(\n                XMPPEvents.PRESENCE_STATUS,\n                from,\n                member.status);\n        }\n\n        if (hasVersionUpdate) {\n            logger.info(`Received version for ${jid}: ${member.version}`);\n        }\n    }\n\n    /**\n     * Extracts the features from the presence.\n     * @param node the node to process.\n     * @return features the Set of features where extracted data is added.\n     * @private\n     */\n    _extractFeatures(node) {\n        const features = new Set();\n\n        for (let j = 0; j < node.children.length; j++) {\n            const { attributes } = node.children[j];\n\n            if (attributes && attributes.var) {\n                features.add(attributes.var);\n            }\n        }\n\n        return features;\n    }\n\n    /**\n     * Initialize some properties when the focus participant is verified.\n     * @param from jid of the focus\n     * @param features the features reported in jicofo presence\n     */\n    _initFocus(from, features) {\n        this.focusMucJid = from;\n        this.focusFeatures = features;\n    }\n\n    /**\n     * Sets the special listener to be used for \"command\"s whose name starts\n     * with \"jitsi_participant_\".\n     */\n    setParticipantPropertyListener(listener) {\n        this.participantPropertyListener = listener;\n    }\n\n    /**\n     * Checks if Jicofo supports restarting Jingle session after 'session-terminate'.\n     * @returns {boolean}\n     */\n    supportsRestartByTerminate() {\n        return this.restartByTerminateSupported;\n    }\n\n    /**\n     *\n     * @param node\n     * @param from\n     */\n    processNode(node, from) {\n        // make sure we catch all errors coming from any handler\n        // otherwise we can remove the presence handler from strophe\n        try {\n            let tagHandlers = this.presHandlers[node.tagName];\n\n            if (node.tagName.startsWith('jitsi_participant_')) {\n                tagHandlers = [ this.participantPropertyListener ];\n            }\n\n            if (tagHandlers) {\n                tagHandlers.forEach(handler => {\n                    handler(node, Strophe.getResourceFromJid(from), from);\n                });\n            }\n        } catch (e) {\n            GlobalOnErrorHandler.callErrorHandler(e);\n            logger.error(`Error processing:${node.tagName} node.`, e);\n        }\n    }\n\n    /**\n     * Send text message to the other participants in the conference\n     * @param message\n     * @param elementName\n     */\n    sendMessage(message, elementName) {\n        const msg = $msg({ to: this.roomjid,\n            type: 'groupchat' });\n\n        // We are adding the message in a packet extension. If this element\n        // is different from 'body', we add a custom namespace.\n        // e.g. for 'json-message' extension of message stanza.\n        if (elementName === 'body') {\n            msg.c(elementName, {}, message);\n        } else {\n            msg.c(elementName, { xmlns: 'http://jitsi.org/jitmeet' }, message);\n        }\n\n        this.connection.send(msg);\n        this.eventEmitter.emit(XMPPEvents.SENDING_CHAT_MESSAGE, message);\n    }\n\n    /* eslint-disable max-params */\n    /**\n     * Send private text message to another participant of the conference\n     * @param id id/muc resource of the receiver\n     * @param message\n     * @param elementName\n     */\n    sendPrivateMessage(id, message, elementName) {\n        const msg = $msg({ to: `${this.roomjid}/${id}`,\n            type: 'chat' });\n\n        // We are adding the message in packet. If this element is different\n        // from 'body', we add our custom namespace for the same.\n        // e.g. for 'json-message' message extension.\n        if (elementName === 'body') {\n            msg.c(elementName, message).up();\n        } else {\n            msg.c(elementName, { xmlns: 'http://jitsi.org/jitmeet' }, message)\n                .up();\n        }\n\n        this.connection.send(msg);\n        this.eventEmitter.emit(\n            XMPPEvents.SENDING_PRIVATE_CHAT_MESSAGE, message);\n    }\n    /* eslint-enable max-params */\n\n    /**\n     *\n     * @param subject\n     */\n    setSubject(subject) {\n        const msg = $msg({ to: this.roomjid,\n            type: 'groupchat' });\n\n        msg.c('subject', subject);\n        this.connection.send(msg);\n    }\n\n    /**\n     * Called when participant leaves.\n     * @param jid the jid of the participant that leaves\n     * @param skipEvents optional params to skip any events, including check\n     * whether this is the focus that left\n     */\n    onParticipantLeft(jid, skipEvents) {\n        delete this.lastPresences[jid];\n\n        if (skipEvents) {\n            return;\n        }\n\n        this.eventEmitter.emit(XMPPEvents.MUC_MEMBER_LEFT, jid);\n\n        this.moderator.onMucMemberLeft(jid);\n    }\n\n    /**\n     *\n     * @param pres\n     * @param from\n     */\n    onPresenceUnavailable(pres, from) {\n        // ignore presence\n        if ($(pres).find('>ignore[xmlns=\"http://jitsi.org/jitmeet/\"]').length) {\n            return true;\n        }\n\n        // room destroyed ?\n        const destroySelect = $(pres).find('>x[xmlns=\"http://jabber.org/protocol/muc#user\"]>destroy');\n\n        if (destroySelect.length) {\n            let reason;\n            const reasonSelect\n                = $(pres).find(\n                    '>x[xmlns=\"http://jabber.org/protocol/muc#user\"]'\n                        + '>destroy>reason');\n\n            if (reasonSelect.length) {\n                reason = reasonSelect.text();\n            }\n\n            this.eventEmitter.emit(XMPPEvents.MUC_DESTROYED, reason, destroySelect.attr('jid'));\n            this.connection.emuc.doLeave(this.roomjid);\n\n            return true;\n        }\n\n        // Status code 110 indicates that this notification is \"self-presence\".\n        const isSelfPresence\n            = $(pres)\n                .find(\n                    '>x[xmlns=\"http://jabber.org/protocol/muc#user\"]>'\n                        + 'status[code=\"110\"]')\n                .length;\n        const isKick\n            = $(pres)\n                .find(\n                    '>x[xmlns=\"http://jabber.org/protocol/muc#user\"]'\n                        + '>status[code=\"307\"]')\n                .length;\n        const membersKeys = Object.keys(this.members);\n        const isReplaceParticipant = $(pres).find('flip_device').length;\n\n        if (isKick) {\n            const actorSelect\n                = $(pres)\n                .find('>x[xmlns=\"http://jabber.org/protocol/muc#user\"]>item>actor');\n            let actorNick;\n\n            if (actorSelect.length) {\n                actorNick = actorSelect.attr('nick');\n            }\n\n            let reason;\n            const reasonSelect\n                = $(pres).find(\n                '>x[xmlns=\"http://jabber.org/protocol/muc#user\"]'\n                + '>item>reason');\n\n            if (reasonSelect.length) {\n                reason = reasonSelect.text();\n            }\n\n            // we first fire the kicked so we can show the participant\n            // who kicked, before notifying that participant left\n            // we fire kicked for us and for any participant kicked\n            this.eventEmitter.emit(\n                XMPPEvents.KICKED,\n                isSelfPresence,\n                actorNick,\n                Strophe.getResourceFromJid(from),\n                reason,\n                isReplaceParticipant);\n        }\n\n        if (isSelfPresence) {\n            // If the status code is 110 this means we're leaving and we would\n            // like to remove everyone else from our view, so we trigger the\n            // event.\n            membersKeys.forEach(jid => {\n                const member = this.members[jid];\n\n                delete this.members[jid];\n                this.onParticipantLeft(jid, member.isFocus);\n            });\n            this.connection.emuc.doLeave(this.roomjid);\n\n            // we fire muc_left only if this is not a kick,\n            // kick has both statuses 110 and 307.\n            if (!isKick) {\n                this.eventEmitter.emit(XMPPEvents.MUC_LEFT);\n            }\n        } else {\n            delete this.members[from];\n            this.onParticipantLeft(from, false);\n        }\n    }\n\n    /**\n     *\n     * @param msg\n     * @param from\n     */\n    onMessage(msg, from) {\n        const type = msg.getAttribute('type');\n\n        if (type === 'error') {\n            const settingsErrorMsg = $(msg).find('>settings-error>text').text();\n\n            if (settingsErrorMsg.length) {\n                this.eventEmitter.emit(XMPPEvents.SETTINGS_ERROR_RECEIVED, settingsErrorMsg);\n\n                return true;\n            }\n            const errorMsg = $(msg).find('>error>text').text();\n\n            this.eventEmitter.emit(XMPPEvents.CHAT_ERROR_RECEIVED, errorMsg);\n\n            return true;\n        }\n\n        const txt = $(msg).find('>body').text();\n        const subject = $(msg).find('>subject');\n\n        if (subject.length) {\n            const subjectText = subject.text();\n\n            if (subjectText || subjectText === '') {\n                this.eventEmitter.emit(XMPPEvents.SUBJECT_CHANGED, subjectText);\n                logger.log(`Subject is changed to ${subjectText}`);\n            }\n        }\n\n        // xep-0203 delay\n        let stamp = $(msg).find('>delay').attr('stamp');\n\n        if (!stamp) {\n            // or xep-0091 delay, UTC timestamp\n            stamp = $(msg).find('>[xmlns=\"jabber:x:delay\"]').attr('stamp');\n\n            if (stamp) {\n                // the format is CCYYMMDDThh:mm:ss\n                const dateParts\n                    = stamp.match(/(\\d{4})(\\d{2})(\\d{2}T\\d{2}:\\d{2}:\\d{2})/);\n\n                stamp = `${dateParts[1]}-${dateParts[2]}-${dateParts[3]}Z`;\n            }\n        }\n\n        if (from === this.roomjid) {\n            let invite;\n\n            if ($(msg).find('>x[xmlns=\"http://jabber.org/protocol/muc#user\"]>status[code=\"104\"]').length) {\n                this.discoRoomInfo();\n            } else if ((invite = $(msg).find('>x[xmlns=\"http://jabber.org/protocol/muc#user\"]>invite'))\n                        && invite.length) {\n                const passwordSelect = $(msg).find('>x[xmlns=\"http://jabber.org/protocol/muc#user\"]>password');\n                let password;\n\n                if (passwordSelect && passwordSelect.length) {\n                    password = passwordSelect.text();\n                }\n\n                this.eventEmitter.emit(XMPPEvents.INVITE_MESSAGE_RECEIVED,\n                    from, invite.attr('from'), txt, password);\n            }\n        }\n\n        const jsonMessage = $(msg).find('>json-message').text();\n\n        if (jsonMessage) {\n            const parsedJson = this.xmpp.tryParseJSONAndVerify(jsonMessage);\n\n            // We emit this event if the message is a valid json, and is not\n            // delivered after a delay, i.e. stamp is undefined.\n            // e.g. - subtitles should not be displayed if delayed.\n            if (parsedJson && stamp === undefined) {\n                this.eventEmitter.emit(XMPPEvents.JSON_MESSAGE_RECEIVED,\n                    from, parsedJson);\n\n                return;\n            }\n        }\n\n        if (txt) {\n            if (type === 'chat') {\n                this.eventEmitter.emit(XMPPEvents.PRIVATE_MESSAGE_RECEIVED,\n                        from, txt, this.myroomjid, stamp);\n            } else if (type === 'groupchat') {\n                this.eventEmitter.emit(XMPPEvents.MESSAGE_RECEIVED,\n                        from, txt, this.myroomjid, stamp);\n            }\n        }\n    }\n\n    /**\n     *\n     * @param pres\n     * @param from\n     */\n    onPresenceError(pres, from) {\n        if ($(pres)\n                .find(\n                    '>error[type=\"auth\"]'\n                        + '>not-authorized['\n                        + 'xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"]')\n                .length) {\n            logger.log('on password required', from);\n            this.eventEmitter.emit(XMPPEvents.PASSWORD_REQUIRED);\n        } else if ($(pres)\n                .find(\n                    '>error[type=\"cancel\"]'\n                        + '>not-allowed['\n                        + 'xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"]')\n                .length) {\n            const toDomain = Strophe.getDomainFromJid(pres.getAttribute('to'));\n\n            if (toDomain === this.xmpp.options.hosts.anonymousdomain) {\n                // enter the room by replying with 'not-authorized'. This would\n                // result in reconnection from authorized domain.\n                // We're either missing Jicofo/Prosody config for anonymous\n                // domains or something is wrong.\n                this.eventEmitter.emit(XMPPEvents.ROOM_JOIN_ERROR);\n\n            } else {\n                logger.warn('onPresError ', pres);\n                this.eventEmitter.emit(\n                    XMPPEvents.ROOM_CONNECT_NOT_ALLOWED_ERROR);\n            }\n        } else if ($(pres).find('>error>service-unavailable').length) {\n            logger.warn('Maximum users limit for the room has been reached',\n                pres);\n            this.eventEmitter.emit(XMPPEvents.ROOM_MAX_USERS_ERROR);\n            this.connection.emuc.doLeave(this.roomjid);\n        } else if ($(pres)\n            .find(\n                '>error[type=\"auth\"]'\n                + '>registration-required['\n                + 'xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"]').length) {\n\n            // let's extract the lobby jid from the custom field\n            const lobbyRoomNode = $(pres).find('>error[type=\"auth\"]>lobbyroom');\n            let lobbyRoomJid;\n\n            if (lobbyRoomNode.length) {\n                lobbyRoomJid = lobbyRoomNode.text();\n            } else {\n                // let's fallback to old location of lobbyroom node, TODO: to be removed in the future once\n                // everything is updated\n                const lobbyRoomOldNode = $(pres).find('>lobbyroom');\n\n                if (lobbyRoomOldNode.length) {\n                    lobbyRoomJid = lobbyRoomOldNode.text();\n                }\n            }\n\n            this.eventEmitter.emit(XMPPEvents.ROOM_CONNECT_MEMBERS_ONLY_ERROR, lobbyRoomJid);\n        } else {\n            logger.warn('onPresError ', pres);\n            this.eventEmitter.emit(XMPPEvents.ROOM_CONNECT_ERROR);\n        }\n    }\n\n    /**\n     *\n     * @param jid\n     * @param affiliation\n     */\n    setAffiliation(jid, affiliation) {\n        const grantIQ = $iq({\n            to: this.roomjid,\n            type: 'set'\n        })\n        .c('query', { xmlns: 'http://jabber.org/protocol/muc#admin' })\n        .c('item', {\n            affiliation,\n            nick: Strophe.getResourceFromJid(jid)\n        })\n        .c('reason').t(`Your affiliation has been changed to '${affiliation}'.`)\n        .up().up().up();\n\n        this.connection.sendIQ(\n            grantIQ,\n            result => logger.log('Set affiliation of participant with jid: ', jid, 'to', affiliation, result),\n            error => logger.log('Set affiliation of participant error: ', error));\n    }\n\n    /**\n     *\n     * @param jid\n     * @param reason\n     */\n    kick(jid, reason = 'You have been kicked.') {\n        const kickIQ = $iq({ to: this.roomjid,\n            type: 'set' })\n            .c('query', { xmlns: 'http://jabber.org/protocol/muc#admin' })\n            .c('item', { nick: Strophe.getResourceFromJid(jid),\n                role: 'none' })\n            .c('reason').t(reason).up().up().up();\n\n        this.connection.sendIQ(\n            kickIQ,\n            result => logger.log('Kick participant with jid: ', jid, result),\n            error => logger.log('Kick participant error: ', error));\n    }\n\n    /* eslint-disable max-params */\n\n    /**\n     *\n     * @param key\n     * @param onSuccess\n     * @param onError\n     * @param onNotSupported\n     */\n    lockRoom(key, onSuccess, onError, onNotSupported) {\n        // http://xmpp.org/extensions/xep-0045.html#roomconfig\n        this.connection.sendIQ(\n            $iq({\n                to: this.roomjid,\n                type: 'get'\n            })\n                .c('query', { xmlns: 'http://jabber.org/protocol/muc#owner' }),\n            res => {\n                if ($(res)\n                        .find(\n                            '>query>x[xmlns=\"jabber:x:data\"]'\n                                + '>field[var=\"muc#roomconfig_roomsecret\"]')\n                        .length) {\n                    const formsubmit\n                        = $iq({\n                            to: this.roomjid,\n                            type: 'set'\n                        })\n                            .c('query', {\n                                xmlns: 'http://jabber.org/protocol/muc#owner'\n                            });\n\n                    formsubmit.c('x', {\n                        xmlns: 'jabber:x:data',\n                        type: 'submit'\n                    });\n                    formsubmit\n                        .c('field', { 'var': 'FORM_TYPE' })\n                        .c('value')\n                        .t('http://jabber.org/protocol/muc#roomconfig')\n                        .up()\n                        .up();\n                    formsubmit\n                        .c('field', { 'var': 'muc#roomconfig_roomsecret' })\n                        .c('value')\n                        .t(key)\n                        .up()\n                        .up();\n                    formsubmit\n                        .c('field',\n                             { 'var': 'muc#roomconfig_passwordprotectedroom' })\n                        .c('value')\n                        .t(key === null || key.length === 0 ? '0' : '1')\n                        .up()\n                        .up();\n\n                    // if members only enabled\n                    if (this.membersOnlyEnabled) {\n                        formsubmit\n                            .c('field', { 'var': 'muc#roomconfig_membersonly' })\n                            .c('value')\n                            .t('true')\n                            .up()\n                            .up();\n                    }\n\n                    // Fixes a bug in prosody 0.9.+\n                    // https://prosody.im/issues/issue/373\n                    formsubmit\n                        .c('field', { 'var': 'muc#roomconfig_whois' })\n                        .c('value')\n                        .t('anyone')\n                        .up()\n                        .up();\n\n                    this.connection.sendIQ(\n                        formsubmit,\n                        () => {\n\n                            // we set the password in chat room so we can use it\n                            // later when dialing out\n                            this.password = key;\n                            onSuccess();\n                        },\n                        onError);\n                } else {\n                    onNotSupported();\n                }\n            },\n            onError);\n    }\n\n    /* eslint-enable max-params */\n\n    /**\n     * Turns off or on the members only config for the main room.\n     *\n     * @param {boolean} enabled - Whether to turn it on or off.\n     * @param onSuccess - optional callback.\n     * @param onError - optional callback.\n     */\n    setMembersOnly(enabled, onSuccess, onError) {\n        if (enabled && Object.values(this.members).filter(m => !m.isFocus).length) {\n            // first grant membership to all that are in the room\n            // currently there is a bug in prosody where it handles only the first item\n            // that's why we will send iq per member\n            Object.values(this.members).forEach(m => {\n                if (m.jid && !MEMBERS_AFFILIATIONS.includes(m.affiliation)) {\n                    this.xmpp.connection.sendIQ(\n                        $iq({\n                            to: this.roomjid,\n                            type: 'set' })\n                        .c('query', {\n                            xmlns: 'http://jabber.org/protocol/muc#admin' })\n                        .c('item', {\n                            'affiliation': 'member',\n                            'jid': m.jid\n                        }).up().up());\n                }\n            });\n        }\n\n        const errorCallback = onError ? onError : () => {}; // eslint-disable-line no-empty-function\n\n        this.xmpp.connection.sendIQ(\n            $iq({\n                to: this.roomjid,\n                type: 'get'\n            }).c('query', { xmlns: 'http://jabber.org/protocol/muc#owner' }),\n            res => {\n                if ($(res).find('>query>x[xmlns=\"jabber:x:data\"]>field[var=\"muc#roomconfig_membersonly\"]').length) {\n                    const formToSubmit\n                        = $iq({\n                            to: this.roomjid,\n                            type: 'set'\n                        }).c('query', { xmlns: 'http://jabber.org/protocol/muc#owner' });\n\n                    formToSubmit.c('x', {\n                        xmlns: 'jabber:x:data',\n                        type: 'submit'\n                    });\n                    formToSubmit\n                        .c('field', { 'var': 'FORM_TYPE' })\n                        .c('value')\n                        .t('http://jabber.org/protocol/muc#roomconfig')\n                        .up()\n                        .up();\n                    formToSubmit\n                        .c('field', { 'var': 'muc#roomconfig_membersonly' })\n                        .c('value')\n                        .t(enabled ? 'true' : 'false')\n                        .up()\n                        .up();\n\n                    // if room is locked from other participant or we are locking it\n                    if (this.locked) {\n                        formToSubmit\n                            .c('field',\n                                { 'var': 'muc#roomconfig_passwordprotectedroom' })\n                            .c('value')\n                            .t('1')\n                            .up()\n                            .up();\n                    }\n\n                    this.xmpp.connection.sendIQ(formToSubmit, onSuccess, errorCallback);\n                } else {\n                    errorCallback(new Error('Setting members only room not supported!'));\n                }\n            },\n            errorCallback);\n    }\n\n    /**\n     * Adds the key to the presence map, overriding any previous value.\n     * This method is used by jibri.\n     *\n     * @param key The key to add or replace.\n     * @param values The new values.\n     * @returns {boolean|null} <tt>true</tt> if the operation succeeded or <tt>false</tt> when no add or replce was\n     * performed as the value was already there.\n     * @deprecated Use 'addOrReplaceInPresence' instead. TODO: remove it from here and jibri.\n     */\n    addToPresence(key, values) {\n        return this.addOrReplaceInPresence(key, values);\n    }\n\n    /**\n     * Adds the key to the presence map, overriding any previous value.\n     * @param key The key to add or replace.\n     * @param values The new values.\n     * @returns {boolean|null} <tt>true</tt> if the operation succeeded or <tt>false</tt> when no add or replace was\n     * performed as the value was already there.\n     */\n    addOrReplaceInPresence(key, values) {\n        values.tagName = key;\n\n        const matchingNodes = this.presMap.nodes.filter(node => key === node.tagName);\n\n        // if we have found just one, let's check is it the same\n        if (matchingNodes.length === 1 && isEqual(matchingNodes[0], values)) {\n            return false;\n        }\n\n        this.removeFromPresence(key);\n        this.presMap.nodes.push(values);\n        this.presenceUpdateTime = Date.now();\n\n        return true;\n    }\n\n    /**\n     * Retrieves a value from the presence map.\n     *\n     * @param {string} key - The key to find the value for.\n     * @returns {Object?}\n     */\n    getFromPresence(key) {\n        return this.presMap.nodes.find(node => key === node.tagName);\n    }\n\n    /**\n     * Removes a key from the presence map.\n     * @param key\n     */\n    removeFromPresence(key) {\n        const nodes = this.presMap.nodes.filter(node => key !== node.tagName);\n\n        this.presMap.nodes = nodes;\n        this.presenceUpdateTime = Date.now();\n    }\n\n    /**\n     *\n     * @param name\n     * @param handler\n     */\n    addPresenceListener(name, handler) {\n        if (typeof handler !== 'function') {\n            throw new Error('\"handler\" is not a function');\n        }\n        let tagHandlers = this.presHandlers[name];\n\n        if (!tagHandlers) {\n            this.presHandlers[name] = tagHandlers = [];\n        }\n        if (tagHandlers.indexOf(handler) === -1) {\n            tagHandlers.push(handler);\n        } else {\n            logger.warn(\n                `Trying to add the same handler more than once for: ${name}`);\n        }\n    }\n\n    /**\n     *\n     * @param name\n     * @param handler\n     */\n    removePresenceListener(name, handler) {\n        const tagHandlers = this.presHandlers[name];\n        const handlerIdx = tagHandlers ? tagHandlers.indexOf(handler) : -1;\n\n        // eslint-disable-next-line no-negated-condition\n        if (handlerIdx !== -1) {\n            tagHandlers.splice(handlerIdx, 1);\n        } else {\n            logger.warn(`Handler for: ${name} was not registered`);\n        }\n    }\n\n    /**\n     * Checks if the user identified by given <tt>mucJid</tt> is the conference\n     * focus.\n     * @param mucJid the full MUC address of the user to be checked.\n     * @returns {boolean|null} <tt>true</tt> if MUC user is the conference focus\n     * or <tt>false</tt> if is not. When given <tt>mucJid</tt> does not exist in\n     * the MUC then <tt>null</tt> is returned.\n     */\n    isFocus(mucJid) {\n        const member = this.members[mucJid];\n\n        if (member) {\n            return member.isFocus;\n        }\n\n        return null;\n    }\n\n    /**\n     *\n     */\n    isModerator() {\n        return this.role === 'moderator';\n    }\n\n    /**\n     *\n     * @param peerJid\n     */\n    getMemberRole(peerJid) {\n        if (this.members[peerJid]) {\n            return this.members[peerJid].role;\n        }\n\n        return null;\n    }\n\n    /**\n     *\n     * @param mute\n     */\n    addAudioInfoToPresence(mute) {\n        const audioMutedTagName = 'audiomuted';\n\n        // we skip adding it as muted is default value\n        if (mute && !this.getFromPresence(audioMutedTagName)) {\n            return false;\n        }\n\n        return this.addOrReplaceInPresence(\n            audioMutedTagName,\n            {\n                value: mute.toString()\n            });\n    }\n\n    /**\n     *\n     * @param mute\n     */\n    addVideoInfoToPresence(mute) {\n        const videoMutedTagName = 'videomuted';\n\n        // we skip adding it as muted is default value\n        if (mute && !this.getFromPresence(videoMutedTagName)) {\n            return false;\n        }\n\n        return this.addOrReplaceInPresence(\n            videoMutedTagName,\n            {\n                value: mute.toString()\n            });\n    }\n\n    /**\n     * Obtains the info about given media advertised in the MUC presence of\n     * the participant identified by the given endpoint JID.\n     * @param {string} endpointId the endpoint ID mapped to the participant\n     * which corresponds to MUC nickname.\n     * @param {MediaType} mediaType the type of the media for which presence\n     * info will be obtained.\n     * @return {PeerMediaInfo} presenceInfo an object with media presence\n     * info or <tt>null</tt> either if there is no presence available or if\n     * the media type given is invalid.\n     */\n    getMediaPresenceInfo(endpointId, mediaType) {\n        // Will figure out current muted status by looking up owner's presence\n        const pres = this.lastPresences[`${this.roomjid}/${endpointId}`];\n\n        if (!pres) {\n            // No presence available\n            return null;\n        }\n        const data = {\n            muted: true, // muted by default\n            videoType: VideoType.CAMERA // 'camera' by default\n        };\n        let mutedNode = null;\n\n        if (mediaType === MediaType.AUDIO) {\n            mutedNode = filterNodeFromPresenceJSON(pres, 'audiomuted');\n        } else if (mediaType === MediaType.VIDEO) {\n            mutedNode = filterNodeFromPresenceJSON(pres, 'videomuted');\n            const codecTypeNode = filterNodeFromPresenceJSON(pres, 'jitsi_participant_codecType');\n            const videoTypeNode = filterNodeFromPresenceJSON(pres, 'videoType');\n\n            if (videoTypeNode.length > 0) {\n                data.videoType = videoTypeNode[0].value;\n            }\n            if (codecTypeNode.length > 0) {\n                data.codecType = codecTypeNode[0].value;\n            }\n        } else {\n            logger.error(`Unsupported media type: ${mediaType}`);\n\n            return null;\n        }\n\n        if (mutedNode.length > 0) {\n            data.muted = mutedNode[0].value === 'true';\n        }\n\n        return data;\n    }\n\n    /**\n     * Returns the last presence advertised by a MUC member.\n     * @param {string} mucNick\n     * @returns {*}\n     */\n    getLastPresence(mucNick) {\n        return this.lastPresences[`${this.roomjid}/${mucNick}`];\n    }\n\n    /**\n     * Returns true if the SIP calls are supported and false otherwise\n     */\n    isSIPCallingSupported() {\n        if (this.moderator) {\n            return this.moderator.isSipGatewayEnabled();\n        }\n\n        return false;\n    }\n\n    /**\n     * Dials a number.\n     * @param number the number\n     */\n    dial(number) {\n        return this.connection.rayo.dial(number, 'fromnumber',\n            Strophe.getBareJidFromJid(this.myroomjid), this.password,\n            this.focusMucJid);\n    }\n\n    /**\n     * Hangup an existing call\n     */\n    hangup() {\n        return this.connection.rayo.hangup();\n    }\n\n    /**\n     *\n     * @returns {Lobby}\n     */\n    getLobby() {\n        return this.lobby;\n    }\n\n    /**\n     * @returns {AVModeration}\n     */\n    getAVModeration() {\n        return this.avModeration;\n    }\n\n    /**\n     * @returns {BreakoutRooms}\n     */\n    getBreakoutRooms() {\n        return this.breakoutRooms;\n    }\n\n    /**\n     * Returns the phone number for joining the conference.\n     */\n    getPhoneNumber() {\n        return this.phoneNumber;\n    }\n\n    /**\n     * Returns the pin for joining the conference with phone.\n     */\n    getPhonePin() {\n        return this.phonePin;\n    }\n\n    /**\n     * Returns the meeting unique ID if any came from backend.\n     *\n     * @returns {string} - The meeting ID.\n     */\n    getMeetingId() {\n        return this.meetingId;\n    }\n\n    /**\n     * Mutes remote participant.\n     * @param jid of the participant\n     * @param mute\n     * @param mediaType\n     */\n    muteParticipant(jid, mute, mediaType) {\n        logger.info('set mute', mute, jid);\n        const iqToFocus = $iq(\n            { to: this.focusMucJid,\n                type: 'set' })\n            .c('mute', {\n                xmlns: `http://jitsi.org/jitmeet/${mediaType}`,\n                jid\n            })\n            .t(mute.toString())\n            .up();\n\n        this.connection.sendIQ(\n            iqToFocus,\n            result => logger.log('set mute', result),\n            error => logger.log('set mute error', error));\n    }\n\n    /**\n     * TODO: Document\n     * @param iq\n     */\n    onMute(iq) {\n        const from = iq.getAttribute('from');\n\n        if (from !== this.focusMucJid) {\n            logger.warn('Ignored mute from non focus peer');\n\n            return;\n        }\n        const mute = $(iq).find('mute');\n\n        if (mute.length && mute.text() === 'true') {\n            this.eventEmitter.emit(XMPPEvents.AUDIO_MUTED_BY_FOCUS, mute.attr('actor'));\n        } else {\n            // XXX Why do we support anything but muting? Why do we encode the\n            // value in the text of the element? Why do we use a separate XML\n            // namespace?\n            logger.warn('Ignoring a mute request which does not explicitly '\n                + 'specify a positive mute command.');\n        }\n    }\n\n    /**\n     * TODO: Document\n     * @param iq\n     */\n    onMuteVideo(iq) {\n        const from = iq.getAttribute('from');\n\n        if (from !== this.focusMucJid) {\n            logger.warn('Ignored mute from non focus peer');\n\n            return;\n        }\n        const mute = $(iq).find('mute');\n\n        if (mute.length && mute.text() === 'true') {\n            this.eventEmitter.emit(XMPPEvents.VIDEO_MUTED_BY_FOCUS, mute.attr('actor'));\n        } else {\n            // XXX Why do we support anything but muting? Why do we encode the\n            // value in the text of the element? Why do we use a separate XML\n            // namespace?\n            logger.warn('Ignoring a mute request which does not explicitly '\n                + 'specify a positive mute command.');\n        }\n    }\n\n    /**\n     * Clean any listeners or resources, executed on leaving.\n     */\n    clean() {\n        this._removeConnListeners.forEach(remove => remove());\n        this._removeConnListeners = [];\n\n        this.joined = false;\n        this.inProgressEmitted = false;\n    }\n\n    /**\n     * Leaves the room. Closes the jingle session.\n     * @returns {Promise} which is resolved if XMPPEvents.MUC_LEFT is received\n     * less than 5s after sending presence unavailable. Otherwise the promise is\n     * rejected.\n     */\n    leave() {\n        this.avModeration.dispose();\n        this.breakoutRooms.dispose();\n\n        const promises = [];\n\n        this.lobby?.lobbyRoom && promises.push(this.lobby.leave());\n\n        promises.push(new Promise((resolve, reject) => {\n            let timeout = -1;\n\n            const onMucLeft = (doReject = false) => {\n                this.eventEmitter.removeListener(XMPPEvents.MUC_LEFT, onMucLeft);\n                clearTimeout(timeout);\n                if (doReject) {\n                    // The timeout expired. Make sure we clean the EMUC state.\n                    this.connection.emuc.doLeave(this.roomjid);\n                    reject(new Error('The timeout for the confirmation about leaving the room expired.'));\n                } else {\n                    resolve();\n                }\n            };\n\n            timeout = setTimeout(() => onMucLeft(true), 5000);\n\n            this.clean();\n            this.eventEmitter.on(XMPPEvents.MUC_LEFT, onMucLeft);\n            this.doLeave();\n        }));\n\n        return Promise.allSettled(promises);\n    }\n}\n\n/* eslint-enable newline-per-chained-call */\n","import { getLogger } from '@jitsi/logger';\nimport $ from 'jquery';\nimport { Strophe } from 'strophe.js';\n\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\n\nimport ChatRoom from './ChatRoom';\nimport { ConnectionPluginListenable } from './ConnectionPlugin';\n\nconst logger = getLogger(__filename);\n\n/**\n * MUC connection plugin.\n */\nexport default class MucConnectionPlugin extends ConnectionPluginListenable {\n    /**\n     *\n     * @param xmpp\n     */\n    constructor(xmpp) {\n        super();\n        this.xmpp = xmpp;\n        this.rooms = {};\n    }\n\n    /**\n     *\n     * @param connection\n     */\n    init(connection) {\n        super.init(connection);\n\n        // add handlers (just once)\n        this.connection.addHandler(this.onPresence.bind(this), null,\n            'presence', null, null, null, null);\n        this.connection.addHandler(this.onPresenceUnavailable.bind(this),\n            null, 'presence', 'unavailable', null);\n        this.connection.addHandler(this.onPresenceError.bind(this), null,\n            'presence', 'error', null);\n        this.connection.addHandler(this.onMessage.bind(this), null,\n            'message', null, null);\n        this.connection.addHandler(this.onMute.bind(this),\n            'http://jitsi.org/jitmeet/audio', 'iq', 'set', null, null);\n        this.connection.addHandler(this.onMuteVideo.bind(this),\n            'http://jitsi.org/jitmeet/video', 'iq', 'set', null, null);\n    }\n\n    /**\n     *\n     * @param jid\n     * @param password\n     * @param options\n     */\n    createRoom(jid, password, options) {\n        const roomJid = Strophe.getBareJidFromJid(jid);\n\n        if (this.isRoomCreated(roomJid)) {\n            const errmsg = 'You are already in the room!';\n\n            logger.error(errmsg);\n            throw new Error(errmsg);\n        }\n        this.rooms[roomJid] = new ChatRoom(this.connection, jid,\n            password, this.xmpp, options);\n        this.eventEmitter.emit(\n            XMPPEvents.EMUC_ROOM_ADDED, this.rooms[roomJid]);\n\n        return this.rooms[roomJid];\n    }\n\n    /**\n     *  Check if a room with the passed JID is already created.\n     *\n     * @param {string} roomJid - The JID of the room.\n     * @returns {boolean}\n     */\n    isRoomCreated(roomJid) {\n        return roomJid in this.rooms;\n    }\n\n    /**\n     *\n     * @param jid\n     */\n    doLeave(jid) {\n        this.eventEmitter.emit(\n            XMPPEvents.EMUC_ROOM_REMOVED, this.rooms[jid]);\n        delete this.rooms[jid];\n    }\n\n    /**\n     *\n     * @param pres\n     */\n    onPresence(pres) {\n        const from = pres.getAttribute('from');\n\n        // What is this for? A workaround for something?\n        if (pres.getAttribute('type')) {\n            return true;\n        }\n\n        const room = this.rooms[Strophe.getBareJidFromJid(from)];\n\n        if (!room) {\n            return true;\n        }\n\n        // Parse status.\n        if ($(pres).find('>x[xmlns=\"http://jabber.org/protocol/muc#user\"]'\n            + '>status[code=\"201\"]').length) {\n            room.createNonAnonymousRoom();\n        }\n\n        room.onPresence(pres);\n\n        return true;\n    }\n\n    /**\n     *\n     * @param pres\n     */\n    onPresenceUnavailable(pres) {\n        const from = pres.getAttribute('from');\n        const room = this.rooms[Strophe.getBareJidFromJid(from)];\n\n        if (!room) {\n            return true;\n        }\n\n        room.onPresenceUnavailable(pres, from);\n\n        return true;\n    }\n\n    /**\n     *\n     * @param pres\n     */\n    onPresenceError(pres) {\n        const from = pres.getAttribute('from');\n        const room = this.rooms[Strophe.getBareJidFromJid(from)];\n\n        if (!room) {\n            return true;\n        }\n\n        room.onPresenceError(pres, from);\n\n        return true;\n    }\n\n    /**\n     *\n     * @param msg\n     */\n    onMessage(msg) {\n        // FIXME: this is a hack. but jingle on muc makes nickchanges hard\n        const from = msg.getAttribute('from');\n        const room = this.rooms[Strophe.getBareJidFromJid(from)];\n\n        if (!room) {\n            return true;\n        }\n\n        room.onMessage(msg, from);\n\n        return true;\n    }\n\n    /**\n     * TODO: Document\n     * @param iq\n     */\n    onMute(iq) {\n        const from = iq.getAttribute('from');\n        const room = this.rooms[Strophe.getBareJidFromJid(from)];\n\n        // Returning false would result in the listener being deregistered by Strophe\n        if (!room) {\n            return true;\n        }\n\n        room.onMute(iq);\n\n        return true;\n    }\n\n    /**\n     * TODO: Document\n     * @param iq\n     */\n    onMuteVideo(iq) {\n        const from = iq.getAttribute('from');\n        const room = this.rooms[Strophe.getBareJidFromJid(from)];\n\n        // Returning false would result in the listener being deregistered by Strophe\n        if (!room) {\n            return true;\n        }\n\n        room.onMuteVideo(iq);\n\n        return true;\n    }\n}\n","import { getLogger } from '@jitsi/logger';\n\nconst logger = getLogger('FeatureFlags');\n\n/**\n * A global module for accessing information about different feature flags state.\n */\nclass FeatureFlags {\n    /**\n     * Configures the module.\n     *\n     * @param {boolean} flags.sourceNameSignaling - Enables source names in the signaling.\n     */\n    init(flags) {\n        this._sourceNameSignaling = Boolean(flags.sourceNameSignaling);\n        this._sendMultipleVideoStreams = Boolean(flags.sendMultipleVideoStreams);\n\n        logger.info(`Source name signaling: ${this._sourceNameSignaling},`\n            + ` Send multiple video streams: ${this._sendMultipleVideoStreams}`);\n    }\n\n    /**\n     * Checks if multiple local video streams support is enabled.\n     *\n     * @returns {boolean}\n     */\n    isMultiStreamSupportEnabled() {\n        return this._sourceNameSignaling && this._sendMultipleVideoStreams;\n    }\n\n    /**\n     * Checks if the source name signaling is enabled.\n     *\n     * @returns {boolean}\n     */\n    isSourceNameSignalingEnabled() {\n        return this._sourceNameSignaling;\n    }\n}\n\nexport default new FeatureFlags();\n","import { getLogger } from '@jitsi/logger';\nimport $ from 'jquery';\nimport { $build } from 'strophe.js';\n\nimport { MediaType } from '../../service/RTC/MediaType';\nimport FeatureFlags from '../flags/FeatureFlags';\n\nconst logger = getLogger(__filename);\n\n/**\n * Creates a \"source\" XML element for the source described in compact JSON format in [sourceCompactJson].\n * @param {*} owner the endpoint ID of the owner of the source.\n * @param {*} sourceCompactJson the compact JSON representation of the source.\n * @returns the created \"source\" XML element.\n */\nfunction _createSourceExtension(owner, sourceCompactJson) {\n    const node = $build('source', {\n        xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0',\n        ssrc: sourceCompactJson.s,\n        name: FeatureFlags.isSourceNameSignalingEnabled() ? sourceCompactJson.n : undefined\n    });\n\n    if (sourceCompactJson.m) {\n        node.c('parameter', {\n            name: 'msid',\n            value: sourceCompactJson.m\n        }).up();\n    }\n    node.c('ssrc-info', {\n        xmlns: 'http://jitsi.org/jitmeet',\n        owner\n    }).up();\n\n    return node.node;\n}\n\n/**\n * Creates an \"ssrc-group\" XML element for the SSRC group described in compact JSON format in [ssrcGroupCompactJson].\n * @param {*} ssrcGroupCompactJson the compact JSON representation of the SSRC group.\n * @returns the created \"ssrc-group\" element.\n */\nfunction _createSsrcGroupExtension(ssrcGroupCompactJson) {\n    const node = $build('ssrc-group', {\n        xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0',\n        semantics: _getSemantics(ssrcGroupCompactJson[0])\n    });\n\n    for (let i = 1; i < ssrcGroupCompactJson.length; i++) {\n        node.c('source', {\n            xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0',\n            ssrc: ssrcGroupCompactJson[i]\n        }).up();\n    }\n\n    return node.node;\n}\n\n/**\n * Finds in a Jingle IQ the RTP description element with the given media type. If one does not exists, create it (as\n *  well as the required  \"content\" parent element) and adds it to the IQ.\n * @param {*} iq\n * @param {*} mediaType The media type, \"audio\" or \"video\".\n * @returns the RTP description element with the given media type.\n */\nfunction _getOrCreateRtpDescription(iq, mediaType) {\n    const jingle = $(iq).find('jingle')[0];\n    let content = $(jingle).find(`content[name=\"${mediaType}\"]`);\n    let description;\n\n    if (content.length) {\n        content = content[0];\n    } else {\n        // I'm not suree if \"creator\" and \"senders\" are required.\n        content = $build('content', {\n            name: mediaType\n        }).node;\n        jingle.appendChild(content);\n    }\n\n    description = $(content).find('description');\n\n    if (description.length) {\n        description = description[0];\n    } else {\n        description = $build('description', {\n            xmlns: 'urn:xmpp:jingle:apps:rtp:1',\n            media: mediaType\n        }).node;\n        content.appendChild(description);\n    }\n\n    return description;\n}\n\n/**\n * Converts the short string representing SSRC group semantics in compact JSON format to the standard representation\n * (i.e. convert \"f\" to \"FID\" and \"s\" to \"SIM\").\n * @param {*} str the compact JSON format representation of an SSRC group's semantics.\n * @returns the SSRC group semantics corresponding to [str].\n */\nfunction _getSemantics(str) {\n    if (str === 'f') {\n        return 'FID';\n    } else if (str === 's') {\n        return 'SIM';\n    }\n\n    return null;\n}\n\n/**\n * Reads a JSON-encoded message (from a \"json-message\" element) and extracts source descriptions. Adds the extracted\n * source descriptions to the given Jingle IQ in the standard Jingle format.\n *\n * Encoding sources in this compact JSON format instead of standard Jingle was introduced in order to reduce the\n * network traffic and load on the XMPP server. The format is described in Jicofo [TODO: insert link].\n *\n * @param {*} iq the IQ to which source descriptions will be added.\n * @param {*} jsonMessageXml The XML node for the \"json-message\" element.\n * @returns {Map<string, Array<string>} The audio and video ssrcs extracted from the JSON-encoded message with remote\n * endpoint id as the key.\n */\nexport function expandSourcesFromJson(iq, jsonMessageXml) {\n    let json;\n\n    try {\n        json = JSON.parse(jsonMessageXml.textContent);\n    } catch (error) {\n        logger.error(`json-message XML contained invalid JSON, ignoring: ${jsonMessageXml.textContent}`);\n\n        return null;\n    }\n\n    if (!json?.sources) {\n        // It might be a message of a different type, no need to log.\n        return null;\n    }\n\n    // This is where we'll add \"source\" and \"ssrc-group\" elements. Create them elements if they don't exist.\n    const audioRtpDescription = _getOrCreateRtpDescription(iq, MediaType.AUDIO);\n    const videoRtpDescription = _getOrCreateRtpDescription(iq, MediaType.VIDEO);\n    const ssrcMap = new Map();\n\n    for (const owner in json.sources) {\n        if (json.sources.hasOwnProperty(owner)) {\n            const ssrcs = [];\n            const ownerSources = json.sources[owner];\n\n            // The video sources, video ssrc-groups, audio sources and audio ssrc-groups are encoded in that order in\n            // the elements of the array.\n            const videoSources = ownerSources?.length && ownerSources[0];\n            const videoSsrcGroups = ownerSources?.length > 1 && ownerSources[1];\n            const audioSources = ownerSources?.length > 2 && ownerSources[2];\n            const audioSsrcGroups = ownerSources?.length > 3 && ownerSources[3];\n\n            if (videoSources?.length) {\n                for (let i = 0; i < videoSources.length; i++) {\n                    videoRtpDescription.appendChild(_createSourceExtension(owner, videoSources[i]));\n                    ssrcs.push(videoSources[i]?.s);\n                }\n            }\n\n            if (videoSsrcGroups?.length) {\n                for (let i = 0; i < videoSsrcGroups.length; i++) {\n                    videoRtpDescription.appendChild(_createSsrcGroupExtension(videoSsrcGroups[i]));\n                }\n            }\n            if (audioSources?.length) {\n                for (let i = 0; i < audioSources.length; i++) {\n                    audioRtpDescription.appendChild(_createSourceExtension(owner, audioSources[i]));\n                    ssrcs.push(audioSources[i]?.s);\n                }\n            }\n\n            if (audioSsrcGroups?.length) {\n                for (let i = 0; i < audioSsrcGroups.length; i++) {\n                    audioRtpDescription.appendChild(_createSsrcGroupExtension(audioSsrcGroups[i]));\n                }\n            }\n            ssrcMap.set(owner, ssrcs);\n        }\n    }\n\n    return ssrcMap;\n}\n","/**\n * Enumeration of the codec mime types\n * @type {{H264: string, OPUS: string, ULPFEC: string, VP8: string, VP9: string}}\n */\nexport const CodecMimeType = {\n    /**\n     * The h264 codec mime type.\n     */\n    H264: 'h264',\n\n    /**\n     * The opus codec mime type.\n     */\n    OPUS: 'opus',\n\n    /**\n     * The ulpfec codec mime type.\n     */\n    ULPFEC: 'ulpfec',\n\n    /**\n     * The vp8 codec mime type.\n     */\n    VP8: 'vp8',\n\n    /**\n     * The vp9 codec mime type.\n     */\n    VP9: 'vp9'\n\n};\n\nexport default CodecMimeType;\n","/**\n * Enumeration of the media direction types.\n * @type {{INACTIVE: string, RECVONLY: string, SENDONLY: string, SENDRECV: string}}\n */\nexport const MediaDirection = {\n    /**\n     * Media is send and receive is suspended.\n     */\n    INACTIVE: 'inactive',\n\n    /**\n     * Media is only received from remote peer.\n     */\n    RECVONLY: 'recvonly',\n\n    /**\n     * Media is only sent to the remote peer.\n     */\n    SENDONLY: 'sendonly',\n\n    /**\n     * Media is sent and received.\n     */\n    SENDRECV: 'sendrecv'\n};\n\nexport default MediaDirection;\n","\nimport JitsiTrackError from '../../JitsiTrackError';\nimport * as JitsiTrackErrors from '../../JitsiTrackErrors';\nimport browser from '../browser';\n\nconst logger = require('@jitsi/logger').getLogger(__filename);\n\n/**\n * The default frame rate for Screen Sharing.\n */\nexport const SS_DEFAULT_FRAME_RATE = 5;\n\n/**\n * Handles obtaining a stream from a screen capture on different browsers.\n */\nconst ScreenObtainer = {\n    /**\n     * If not <tt>null</tt> it means that the initialization process is still in\n     * progress. It is used to make desktop stream request wait and continue\n     * after it's done.\n     * {@type Promise|null}\n     */\n\n    obtainStream: null,\n\n    /**\n     * Initializes the function used to obtain a screen capture\n     * (this.obtainStream).\n     *\n     * @param {object} options\n     */\n    init(options = {}) {\n        this.options = options;\n        this.obtainStream = this._createObtainStreamMethod();\n\n        if (!this.obtainStream) {\n            logger.info('Desktop sharing disabled');\n        }\n    },\n\n    /**\n     * Returns a method which will be used to obtain the screen sharing stream\n     * (based on the browser type).\n     *\n     * @returns {Function}\n     * @private\n     */\n    _createObtainStreamMethod() {\n        if (browser.isNWJS()) {\n            return (onSuccess, onFailure) => {\n                window.JitsiMeetNW.obtainDesktopStream(\n                    onSuccess,\n                    (error, constraints) => {\n                        let jitsiError;\n\n                        // FIXME:\n                        // This is very very dirty fix for recognising that the\n                        // user have clicked the cancel button from the Desktop\n                        // sharing pick window. The proper solution would be to\n                        // detect this in the NWJS application by checking the\n                        // streamId === \"\". Even better solution would be to\n                        // stop calling GUM from the NWJS app and just pass the\n                        // streamId to lib-jitsi-meet. This way the desktop\n                        // sharing implementation for NWJS and chrome extension\n                        // will be the same and lib-jitsi-meet will be able to\n                        // control the constraints, check the streamId, etc.\n                        //\n                        // I cannot find documentation about \"InvalidStateError\"\n                        // but this is what we are receiving from GUM when the\n                        // streamId for the desktop sharing is \"\".\n\n                        if (error && error.name === 'InvalidStateError') {\n                            jitsiError = new JitsiTrackError(\n                                JitsiTrackErrors.SCREENSHARING_USER_CANCELED\n                            );\n                        } else {\n                            jitsiError = new JitsiTrackError(\n                                error, constraints, [ 'desktop' ]);\n                        }\n                        (typeof onFailure === 'function')\n                            && onFailure(jitsiError);\n                    });\n            };\n        } else if (browser.isElectron()) {\n            return this.obtainScreenOnElectron;\n        } else if (browser.isReactNative() && browser.supportsGetDisplayMedia()) {\n            return this.obtainScreenFromGetDisplayMediaRN;\n        } else if (browser.supportsGetDisplayMedia()) {\n            return this.obtainScreenFromGetDisplayMedia;\n        }\n        logger.log('Screen sharing not supported on ', browser.getName());\n\n        return null;\n    },\n\n    /**\n     * Gets the appropriate constraints for audio sharing.\n     *\n     * @returns {Object|boolean}\n     */\n    _getAudioConstraints() {\n        const { audioQuality } = this.options;\n        const audio = audioQuality?.stereo ? {\n            autoGainControl: false,\n            channelCount: 2,\n            echoCancellation: false,\n            noiseSuppression: false\n        } : true;\n\n        return audio;\n    },\n\n    /**\n     * Checks whether obtaining a screen capture is supported in the current\n     * environment.\n     * @returns {boolean}\n     */\n    isSupported() {\n        return this.obtainStream !== null;\n    },\n\n    /**\n     * Obtains a screen capture stream on Electron.\n     *\n     * @param onSuccess - Success callback.\n     * @param onFailure - Failure callback.\n     */\n    obtainScreenOnElectron(onSuccess, onFailure) {\n        if (window.JitsiMeetScreenObtainer && window.JitsiMeetScreenObtainer.openDesktopPicker) {\n            const { desktopSharingFrameRate, desktopSharingSources } = this.options;\n\n            window.JitsiMeetScreenObtainer.openDesktopPicker(\n                {\n                    desktopSharingSources: desktopSharingSources || [ 'screen', 'window' ]\n                },\n                (streamId, streamType, screenShareAudio = false) => {\n                    if (streamId) {\n                        let audioConstraints = false;\n\n                        if (screenShareAudio) {\n                            audioConstraints = {};\n                            const optionalConstraints = this._getAudioConstraints();\n\n                            if (typeof optionalConstraints !== 'boolean') {\n                                audioConstraints = {\n                                    optional: optionalConstraints\n                                };\n                            }\n\n                            // Audio screen sharing for electron only works for screen type devices.\n                            // i.e. when the user shares the whole desktop.\n                            // Note. The documentation specifies that chromeMediaSourceId should not be present\n                            // which, in the case a users has multiple monitors, leads to them being shared all\n                            // at once. However we tested with chromeMediaSourceId present and it seems to be\n                            // working properly.\n                            if (streamType === 'screen') {\n                                audioConstraints.mandatory = {\n                                    chromeMediaSource: 'desktop'\n                                };\n                            }\n                        }\n\n                        const constraints = {\n                            audio: audioConstraints,\n                            video: {\n                                mandatory: {\n                                    chromeMediaSource: 'desktop',\n                                    chromeMediaSourceId: streamId,\n                                    minFrameRate: desktopSharingFrameRate?.min ?? SS_DEFAULT_FRAME_RATE,\n                                    maxFrameRate: desktopSharingFrameRate?.max ?? SS_DEFAULT_FRAME_RATE,\n                                    maxWidth: window.screen.width,\n                                    maxHeight: window.screen.height\n                                }\n                            }\n                        };\n\n                        // We have to use the old API on Electron to get a desktop stream.\n                        navigator.mediaDevices.getUserMedia(constraints)\n                            .then(stream => onSuccess({\n                                stream,\n                                sourceId: streamId,\n                                sourceType: streamType\n                            }), onFailure);\n                    } else {\n                        // As noted in Chrome Desktop Capture API:\n                        // If user didn't select any source (i.e. canceled the prompt)\n                        // then the callback is called with an empty streamId.\n                        onFailure(new JitsiTrackError(JitsiTrackErrors.SCREENSHARING_USER_CANCELED));\n                    }\n                },\n                err => onFailure(new JitsiTrackError(\n                    JitsiTrackErrors.ELECTRON_DESKTOP_PICKER_ERROR,\n                    err\n                ))\n            );\n        } else {\n            onFailure(new JitsiTrackError(JitsiTrackErrors.ELECTRON_DESKTOP_PICKER_NOT_FOUND));\n        }\n    },\n\n    /**\n     * Obtains a screen capture stream using getDisplayMedia.\n     *\n     * @param callback - The success callback.\n     * @param errorCallback - The error callback.\n     */\n    obtainScreenFromGetDisplayMedia(callback, errorCallback) {\n        let getDisplayMedia;\n\n        if (navigator.getDisplayMedia) {\n            getDisplayMedia = navigator.getDisplayMedia.bind(navigator);\n        } else {\n            // eslint-disable-next-line max-len\n            getDisplayMedia = navigator.mediaDevices.getDisplayMedia.bind(navigator.mediaDevices);\n        }\n\n        const { desktopSharingFrameRate } = this.options;\n        const video = typeof desktopSharingFrameRate === 'object' ? { frameRate: desktopSharingFrameRate } : true;\n        const audio = this._getAudioConstraints();\n\n        // At the time of this writing 'min' constraint for fps is not supported by getDisplayMedia.\n        video.frameRate && delete video.frameRate.min;\n\n        const constraints = {\n            video,\n            audio,\n            cursor: 'always'\n        };\n\n        logger.info('Using getDisplayMedia for screen sharing', constraints);\n\n        getDisplayMedia(constraints)\n            .then(stream => {\n                callback({\n                    stream,\n                    sourceId: stream.id\n                });\n            })\n            .catch(error => {\n                const errorDetails = {\n                    errorName: error && error.name,\n                    errorMsg: error && error.message,\n                    errorStack: error && error.stack\n                };\n\n                logger.error('getDisplayMedia error', constraints, errorDetails);\n\n                if (errorDetails.errorMsg && errorDetails.errorMsg.indexOf('denied by system') !== -1) {\n                    // On Chrome this is the only thing different between error returned when user cancels\n                    // and when no permission was given on the OS level.\n                    errorCallback(new JitsiTrackError(JitsiTrackErrors.PERMISSION_DENIED));\n\n                    return;\n                }\n\n                errorCallback(new JitsiTrackError(JitsiTrackErrors.SCREENSHARING_USER_CANCELED));\n            });\n    },\n\n    /**\n     * Obtains a screen capture stream using getDisplayMedia.\n     *\n     * @param callback - The success callback.\n     * @param errorCallback - The error callback.\n     */\n    obtainScreenFromGetDisplayMediaRN(callback, errorCallback) {\n        logger.info('Using getDisplayMedia for screen sharing');\n\n        navigator.mediaDevices.getDisplayMedia({ video: true })\n            .then(stream => {\n                callback({\n                    stream,\n                    sourceId: stream.id });\n            })\n            .catch(() => {\n                errorCallback(new JitsiTrackError(JitsiTrackErrors\n                    .SCREENSHARING_USER_CANCELED));\n            });\n    },\n\n    /**\n     * Sets the max frame rate to be used for a desktop track capture.\n     *\n     * @param {number} maxFps capture frame rate to be used for desktop tracks.\n     * @returns {void}\n     */\n    setDesktopSharingFrameRate(maxFps) {\n        logger.info(`Setting the desktop capture rate to ${maxFps}`);\n\n        this.options.desktopSharingFrameRate = {\n            min: SS_DEFAULT_FRAME_RATE,\n            max: maxFps\n        };\n    }\n};\n\nexport default ScreenObtainer;\n","import { getLogger } from '@jitsi/logger';\nconst logger = getLogger(__filename);\n\nimport CodecMimeType from '../../service/RTC/CodecMimeType';\nimport MediaDirection from '../../service/RTC/MediaDirection';\nimport browser from '../browser';\nimport RandomUtil from '../util/RandomUtil';\n\nconst SDPUtil = {\n    filterSpecialChars(text) {\n        // XXX Neither one of the falsy values (e.g. null, undefined, false,\n        // \"\", etc.) \"contain\" special chars.\n        // eslint-disable-next-line no-useless-escape\n        return text ? text.replace(/[\\\\\\/\\{,\\}\\+]/g, '') : text;\n    },\n    iceparams(mediadesc, sessiondesc) {\n        let data = null;\n        let pwd, ufrag;\n\n        if ((ufrag = SDPUtil.findLine(mediadesc, 'a=ice-ufrag:', sessiondesc))\n                && (pwd\n                    = SDPUtil.findLine(\n                        mediadesc,\n                        'a=ice-pwd:',\n                        sessiondesc))) {\n            data = {\n                ufrag: SDPUtil.parseICEUfrag(ufrag),\n                pwd: SDPUtil.parseICEPwd(pwd)\n            };\n        }\n\n        return data;\n    },\n    parseICEUfrag(line) {\n        return line.substring(12);\n    },\n    buildICEUfrag(frag) {\n        return `a=ice-ufrag:${frag}`;\n    },\n    parseICEPwd(line) {\n        return line.substring(10);\n    },\n    buildICEPwd(pwd) {\n        return `a=ice-pwd:${pwd}`;\n    },\n    parseMID(line) {\n        return line.substring(6);\n    },\n\n    /**\n     * Finds the MSID attribute in the given array of SSRC attribute lines and returns the value.\n     *\n     * @param {string[]} ssrcLines - an array of lines similar to 'a:213123 msid:stream-id track-id'.\n     * @returns {undefined|string}\n     */\n    parseMSIDAttribute(ssrcLines) {\n        const msidLine = ssrcLines.find(line => line.indexOf(' msid:') > 0);\n\n        if (!msidLine) {\n            return undefined;\n        }\n\n        const v = msidLine.substring(msidLine.indexOf(' msid:') + 6 /* the length of ' msid:' */);\n\n        return SDPUtil.filterSpecialChars(v);\n    },\n    parseMLine(line) {\n        const data = {};\n        const parts = line.substring(2).split(' ');\n\n        data.media = parts.shift();\n        data.port = parts.shift();\n        data.proto = parts.shift();\n        if (parts[parts.length - 1] === '') { // trailing whitespace\n            parts.pop();\n        }\n        data.fmt = parts;\n\n        return data;\n    },\n    buildMLine(mline) {\n        return (\n            `m=${mline.media} ${mline.port} ${mline.proto} ${\n                mline.fmt.join(' ')}`);\n    },\n    parseRTPMap(line) {\n        const data = {};\n        let parts = line.substring(9).split(' ');\n\n        data.id = parts.shift();\n        parts = parts[0].split('/');\n        data.name = parts.shift();\n        data.clockrate = parts.shift();\n        data.channels = parts.length ? parts.shift() : '1';\n\n        return data;\n    },\n\n    /**\n     * Parses SDP line \"a=sctpmap:...\" and extracts SCTP port from it.\n     * @param line eg. \"a=sctpmap:5000 webrtc-datachannel\"\n     * @returns [SCTP port number, protocol, streams]\n     */\n    parseSCTPMap(line) {\n        const parts = line.substring(10).split(' ');\n        const sctpPort = parts[0];\n        const protocol = parts[1];\n\n        // Stream count is optional\n        const streamCount = parts.length > 2 ? parts[2] : null;\n\n\n        return [ sctpPort, protocol, streamCount ];// SCTP port\n    },\n    parseSCTPPort(line) {\n        return line.substring(12);\n    },\n    buildRTPMap(el) {\n        let line\n            = `a=rtpmap:${el.getAttribute('id')} ${el.getAttribute('name')}/${\n                el.getAttribute('clockrate')}`;\n\n        if (el.getAttribute('channels')\n            && el.getAttribute('channels') !== '1') {\n            line += `/${el.getAttribute('channels')}`;\n        }\n\n        return line;\n    },\n    parseCrypto(line) {\n        const data = {};\n        const parts = line.substring(9).split(' ');\n\n        data.tag = parts.shift();\n        data['crypto-suite'] = parts.shift();\n        data['key-params'] = parts.shift();\n        if (parts.length) {\n            data['session-params'] = parts.join(' ');\n        }\n\n        return data;\n    },\n    parseFingerprint(line) { // RFC 4572\n        const data = {};\n        const parts = line.substring(14).split(' ');\n\n        data.hash = parts.shift();\n        data.fingerprint = parts.shift();\n\n        // TODO assert that fingerprint satisfies 2UHEX *(\":\" 2UHEX) ?\n        return data;\n    },\n    parseFmtp(line) {\n        const data = [];\n        let parts = line.split(' ');\n\n        parts.shift();\n        parts = parts.join(' ').split(';');\n        for (let i = 0; i < parts.length; i++) {\n            let key = parts[i].split('=')[0];\n\n            while (key.length && key[0] === ' ') {\n                key = key.substring(1);\n            }\n            const value = parts[i].split('=')[1];\n\n            if (key && value) {\n                data.push({ name: key,\n                    value });\n            } else if (key) {\n                // rfc 4733 (DTMF) style stuff\n                data.push({ name: '',\n                    value: key });\n            }\n        }\n\n        return data;\n    },\n    parseICECandidate(line) {\n        const candidate = {};\n        const elems = line.split(' ');\n\n        candidate.foundation = elems[0].substring(12);\n        candidate.component = elems[1];\n        candidate.protocol = elems[2].toLowerCase();\n        candidate.priority = elems[3];\n        candidate.ip = elems[4];\n        candidate.port = elems[5];\n\n        // elems[6] => \"typ\"\n        candidate.type = elems[7];\n        candidate.generation = 0; // default value, may be overwritten below\n        for (let i = 8; i < elems.length; i += 2) {\n            switch (elems[i]) {\n            case 'raddr':\n                candidate['rel-addr'] = elems[i + 1];\n                break;\n            case 'rport':\n                candidate['rel-port'] = elems[i + 1];\n                break;\n            case 'generation':\n                candidate.generation = elems[i + 1];\n                break;\n            case 'tcptype':\n                candidate.tcptype = elems[i + 1];\n                break;\n            default: // TODO\n                logger.debug(\n                    `parseICECandidate not translating \"${\n                        elems[i]}\" = \"${elems[i + 1]}\"`);\n            }\n        }\n        candidate.network = '1';\n\n        // not applicable to SDP -- FIXME: should be unique, not just random\n        // eslint-disable-next-line newline-per-chained-call\n        candidate.id = Math.random().toString(36).substr(2, 10);\n\n        return candidate;\n    },\n    buildICECandidate(cand) {\n        let line = [\n            `a=candidate:${cand.foundation}`,\n            cand.component,\n            cand.protocol,\n            cand.priority,\n            cand.ip,\n            cand.port,\n            'typ',\n            cand.type\n        ].join(' ');\n\n        line += ' ';\n        switch (cand.type) {\n        case 'srflx':\n        case 'prflx':\n        case 'relay':\n            if (cand.hasOwnAttribute('rel-addr')\n                    && cand.hasOwnAttribute('rel-port')) {\n                line += 'raddr';\n                line += ' ';\n                line += cand['rel-addr'];\n                line += ' ';\n                line += 'rport';\n                line += ' ';\n                line += cand['rel-port'];\n                line += ' ';\n            }\n            break;\n        }\n        if (cand.hasOwnAttribute('tcptype')) {\n            line += 'tcptype';\n            line += ' ';\n            line += cand.tcptype;\n            line += ' ';\n        }\n        line += 'generation';\n        line += ' ';\n        line += cand.hasOwnAttribute('generation') ? cand.generation : '0';\n\n        return line;\n    },\n    parseSSRC(desc) {\n        // proprietary mapping of a=ssrc lines\n        // TODO: see \"Jingle RTP Source Description\" by Juberti and P. Thatcher\n        // on google docs and parse according to that\n        const data = new Map();\n        const lines = desc.split('\\r\\n');\n\n        for (let i = 0; i < lines.length; i++) {\n            if (lines[i].substring(0, 7) === 'a=ssrc:') {\n                // FIXME: Use regex to smartly find the ssrc.\n                const ssrc = lines[i].split('a=ssrc:')[1].split(' ')[0];\n\n                if (!data.get(ssrc)) {\n                    data.set(ssrc, []);\n                }\n\n                data.get(ssrc).push(lines[i]);\n            }\n        }\n\n        return data;\n    },\n\n    /**\n     * Gets the source name out of the name attribute \"a=ssrc:254321 name:name1\".\n     *\n     * @param {string[]} ssrcLines\n     * @returns {string | undefined}\n     */\n    parseSourceNameLine(ssrcLines) {\n        const sourceNameLine = ssrcLines.find(ssrcSdpLine => ssrcSdpLine.indexOf(' name:') > 0);\n\n        // Everything past the \"name:\" part\n        return sourceNameLine?.substring(sourceNameLine.indexOf(' name:') + 6);\n    },\n    parseRTCPFB(line) {\n        const parts = line.substr(10).split(' ');\n        const data = {};\n\n        data.pt = parts.shift();\n        data.type = parts.shift();\n        data.params = parts;\n\n        return data;\n    },\n    parseExtmap(line) {\n        const parts = line.substr(9).split(' ');\n        const data = {};\n\n        data.value = parts.shift();\n        if (data.value.indexOf('/') === -1) {\n            data.direction = 'both';\n        } else {\n            data.direction = data.value.substr(data.value.indexOf('/') + 1);\n            data.value = data.value.substr(0, data.value.indexOf('/'));\n        }\n        data.uri = parts.shift();\n        data.params = parts;\n\n        return data;\n    },\n    findLine(haystack, needle, sessionpart) {\n        let lines = haystack.split('\\r\\n');\n\n        for (let i = 0; i < lines.length; i++) {\n            if (lines[i].substring(0, needle.length) === needle) {\n                return lines[i];\n            }\n        }\n        if (!sessionpart) {\n            return false;\n        }\n\n        // search session part\n        lines = sessionpart.split('\\r\\n');\n        for (let j = 0; j < lines.length; j++) {\n            if (lines[j].substring(0, needle.length) === needle) {\n                return lines[j];\n            }\n        }\n\n        return false;\n    },\n    findLines(haystack, needle, sessionpart) {\n        let lines = haystack.split('\\r\\n');\n        const needles = [];\n\n        for (let i = 0; i < lines.length; i++) {\n            if (lines[i].substring(0, needle.length) === needle) {\n                needles.push(lines[i]);\n            }\n        }\n        if (needles.length || !sessionpart) {\n            return needles;\n        }\n\n        // search session part\n        lines = sessionpart.split('\\r\\n');\n        for (let j = 0; j < lines.length; j++) {\n            if (lines[j].substring(0, needle.length) === needle) {\n                needles.push(lines[j]);\n            }\n        }\n\n        return needles;\n    },\n    candidateToJingle(line) {\n        // a=candidate:2979166662 1 udp 2113937151 192.168.2.100 57698 typ host\n        // generation 0\n        //      <candidate component=... foundation=... generation=... id=...\n        // ip=... network=... port=... priority=... protocol=... type=.../>\n        if (line.indexOf('candidate:') === 0) {\n            // eslint-disable-next-line no-param-reassign\n            line = `a=${line}`;\n        } else if (line.substring(0, 12) !== 'a=candidate:') {\n            logger.warn(\n                'parseCandidate called with a line that is not a candidate'\n                    + ' line');\n            logger.warn(line);\n\n            return null;\n        }\n        if (line.substring(line.length - 2) === '\\r\\n') { // chomp it\n            // eslint-disable-next-line no-param-reassign\n            line = line.substring(0, line.length - 2);\n        }\n        const candidate = {};\n        const elems = line.split(' ');\n\n        if (elems[6] !== 'typ') {\n            logger.warn('did not find typ in the right place');\n            logger.warn(line);\n\n            return null;\n        }\n        candidate.foundation = elems[0].substring(12);\n        candidate.component = elems[1];\n        candidate.protocol = elems[2].toLowerCase();\n        candidate.priority = elems[3];\n        candidate.ip = elems[4];\n        candidate.port = elems[5];\n\n        // elems[6] => \"typ\"\n        candidate.type = elems[7];\n\n        candidate.generation = '0'; // default, may be overwritten below\n        for (let i = 8; i < elems.length; i += 2) {\n            switch (elems[i]) {\n            case 'raddr':\n                candidate['rel-addr'] = elems[i + 1];\n                break;\n            case 'rport':\n                candidate['rel-port'] = elems[i + 1];\n                break;\n            case 'generation':\n                candidate.generation = elems[i + 1];\n                break;\n            case 'tcptype':\n                candidate.tcptype = elems[i + 1];\n                break;\n            default: // TODO\n                logger.debug(`not translating \"${elems[i]}\" = \"${elems[i + 1]}\"`);\n            }\n        }\n        candidate.network = '1';\n\n        // not applicable to SDP -- FIXME: should be unique, not just random\n        // eslint-disable-next-line newline-per-chained-call\n        candidate.id = Math.random().toString(36).substr(2, 10);\n\n        return candidate;\n    },\n    candidateFromJingle(cand) {\n        let line = 'a=candidate:';\n\n        line += cand.getAttribute('foundation');\n        line += ' ';\n        line += cand.getAttribute('component');\n        line += ' ';\n\n        let protocol = cand.getAttribute('protocol');\n\n        // use tcp candidates for FF\n\n        if (browser.isFirefox() && protocol.toLowerCase() === 'ssltcp') {\n            protocol = 'tcp';\n        }\n\n        line += protocol; // .toUpperCase(); // chrome M23 doesn't like this\n        line += ' ';\n        line += cand.getAttribute('priority');\n        line += ' ';\n        line += cand.getAttribute('ip');\n        line += ' ';\n        line += cand.getAttribute('port');\n        line += ' ';\n        line += 'typ';\n        line += ` ${cand.getAttribute('type')}`;\n        line += ' ';\n        switch (cand.getAttribute('type')) {\n        case 'srflx':\n        case 'prflx':\n        case 'relay':\n            if (cand.getAttribute('rel-addr')\n                    && cand.getAttribute('rel-port')) {\n                line += 'raddr';\n                line += ' ';\n                line += cand.getAttribute('rel-addr');\n                line += ' ';\n                line += 'rport';\n                line += ' ';\n                line += cand.getAttribute('rel-port');\n                line += ' ';\n            }\n            break;\n        }\n        if (protocol.toLowerCase() === 'tcp') {\n            line += 'tcptype';\n            line += ' ';\n            line += cand.getAttribute('tcptype');\n            line += ' ';\n        }\n        line += 'generation';\n        line += ' ';\n        line += cand.getAttribute('generation') || '0';\n\n        return `${line}\\r\\n`;\n    },\n\n    /**\n     * Parse the 'most' primary video ssrc from the given m line\n     * @param {object} mLine object as parsed from transform.parse\n     * @return {number} the primary video ssrc from the given m line\n     */\n    parsePrimaryVideoSsrc(videoMLine) {\n        const numSsrcs = videoMLine.ssrcs\n            .map(ssrcInfo => ssrcInfo.id)\n            .filter((ssrc, index, array) => array.indexOf(ssrc) === index)\n            .length;\n        const numGroups\n            = (videoMLine.ssrcGroups && videoMLine.ssrcGroups.length) || 0;\n\n        if (numSsrcs > 1 && numGroups === 0) {\n            // Ambiguous, can't figure out the primary\n            return;\n        }\n        let primarySsrc = null;\n\n        if (numSsrcs === 1) {\n            primarySsrc = videoMLine.ssrcs[0].id;\n        } else if (numSsrcs === 2) {\n            // Can figure it out if there's an FID group\n            const fidGroup\n                = videoMLine.ssrcGroups.find(\n                    group => group.semantics === 'FID');\n\n            if (fidGroup) {\n                primarySsrc = fidGroup.ssrcs.split(' ')[0];\n            }\n        } else if (numSsrcs >= 3) {\n            // Can figure it out if there's a sim group\n            const simGroup\n                = videoMLine.ssrcGroups.find(\n                    group => group.semantics === 'SIM');\n\n            if (simGroup) {\n                primarySsrc = simGroup.ssrcs.split(' ')[0];\n            }\n        }\n\n        return primarySsrc;\n    },\n\n    /**\n     * Generate an ssrc\n     * @returns {number} an ssrc\n     */\n    generateSsrc() {\n        return RandomUtil.randomInt(1, 0xffffffff);\n    },\n\n    /**\n     * Get an attribute for the given ssrc with the given attributeName\n     *  from the given mline\n     * @param {object} mLine an mLine object as parsed from transform.parse\n     * @param {number} ssrc the ssrc for which an attribute is desired\n     * @param {string} attributeName the name of the desired attribute\n     * @returns {string} the value corresponding to the given ssrc\n     *  and attributeName\n     */\n    getSsrcAttribute(mLine, ssrc, attributeName) {\n        for (let i = 0; i < mLine.ssrcs.length; ++i) {\n            const ssrcLine = mLine.ssrcs[i];\n\n            if (ssrcLine.id === ssrc\n                && ssrcLine.attribute === attributeName) {\n                return ssrcLine.value;\n            }\n        }\n    },\n\n    /**\n     * Parses the ssrcs from the group sdp line and\n     *  returns them as a list of numbers\n     * @param {object} the ssrcGroup object as parsed from\n     *  sdp-transform\n     * @returns {list<number>} a list of the ssrcs in the group\n     *  parsed as numbers\n     */\n    parseGroupSsrcs(ssrcGroup) {\n        return ssrcGroup\n            .ssrcs\n            .split(' ')\n            .map(ssrcStr => parseInt(ssrcStr, 10));\n    },\n\n    /**\n     * Get the mline of the given type from the given sdp\n     * @param {object} sdp sdp as parsed from transform.parse\n     * @param {string} type the type of the desired mline (e.g. \"video\")\n     * @returns {object} a media object\n     */\n    getMedia(sdp, type) {\n        return sdp.media.find(m => m.type === type);\n    },\n\n    /**\n     * Extracts the ICE username fragment from an SDP string.\n     * @param {string} sdp the SDP in raw text format\n     */\n    getUfrag(sdp) {\n        const ufragLines\n            = sdp.split('\\n').filter(line => line.startsWith('a=ice-ufrag:'));\n\n        if (ufragLines.length > 0) {\n            return ufragLines[0].substr('a=ice-ufrag:'.length);\n        }\n    },\n\n    /**\n     * Sets the given codecName as the preferred codec by moving it to the beginning\n     * of the payload types list (modifies the given mline in place). All instances\n     * of the codec are moved up.\n     * @param {object} mLine the mline object from an sdp as parsed by transform.parse\n     * @param {string} codecName the name of the preferred codec\n     */\n    preferCodec(mline, codecName) {\n        if (!mline || !codecName) {\n            return;\n        }\n\n        const matchingPayloadTypes = mline.rtp\n            .filter(rtp => rtp.codec && rtp.codec.toLowerCase() === codecName.toLowerCase())\n            .map(rtp => rtp.payload);\n\n        if (matchingPayloadTypes) {\n            // Call toString() on payloads to get around an issue within SDPTransform that sets\n            // payloads as a number, instead of a string, when there is only one payload.\n            const payloadTypes\n                = mline.payloads\n                .toString()\n                .split(' ')\n                .map(p => parseInt(p, 10));\n\n            for (const pt of matchingPayloadTypes.reverse()) {\n                const payloadIndex = payloadTypes.indexOf(pt);\n\n                payloadTypes.splice(payloadIndex, 1);\n                payloadTypes.unshift(pt);\n            }\n            mline.payloads = payloadTypes.join(' ');\n        }\n    },\n\n    /**\n     * Strips the given codec from the given mline. All related RTX payload\n     * types are also stripped. If the resulting mline would have no codecs,\n     * it's disabled.\n     *\n     * @param {object} mLine the mline object from an sdp as parsed by transform.parse.\n     * @param {string} codecName the name of the codec which will be stripped.\n     * @param {boolean} highProfile determines if only the high profile H264 codec needs to be\n     * stripped from the sdp when the passed codecName is H264.\n     */\n    stripCodec(mLine, codecName, highProfile = false) {\n        if (!mLine || !codecName) {\n            return;\n        }\n\n        const h264Pts = [];\n        let removePts = [];\n        const stripH264HighCodec = codecName.toLowerCase() === CodecMimeType.H264 && highProfile;\n\n        for (const rtp of mLine.rtp) {\n            if (rtp.codec\n                && rtp.codec.toLowerCase() === codecName.toLowerCase()) {\n                if (stripH264HighCodec) {\n                    h264Pts.push(rtp.payload);\n                } else {\n                    removePts.push(rtp.payload);\n                }\n            }\n        }\n\n        // high profile H264 codecs have 64 as the first two bytes of the profile-level-id.\n        if (stripH264HighCodec) {\n            removePts = mLine.fmtp\n                .filter(item => h264Pts.indexOf(item.payload) > -1 && item.config.includes('profile-level-id=64'))\n                .map(item => item.payload);\n        }\n\n        if (removePts.length > 0) {\n            // We also need to remove the payload types that are related to RTX\n            // for the codecs we want to disable.\n            const rtxApts = removePts.map(item => `apt=${item}`);\n            const rtxPts = mLine.fmtp.filter(\n                item => rtxApts.indexOf(item.config) !== -1);\n\n            removePts.push(...rtxPts.map(item => item.payload));\n\n            // Call toString() on payloads to get around an issue within\n            // SDPTransform that sets payloads as a number, instead of a string,\n            // when there is only one payload.\n            const allPts = mLine.payloads\n                .toString()\n                .split(' ')\n                .map(Number);\n            const keepPts = allPts.filter(pt => removePts.indexOf(pt) === -1);\n\n            if (keepPts.length === 0) {\n                // There are no other codecs, disable the stream.\n                mLine.port = 0;\n                mLine.direction = MediaDirection.INACTIVE;\n                mLine.payloads = '*';\n            } else {\n                mLine.payloads = keepPts.join(' ');\n            }\n\n            mLine.rtp = mLine.rtp.filter(\n                item => keepPts.indexOf(item.payload) !== -1);\n            mLine.fmtp = mLine.fmtp.filter(\n                item => keepPts.indexOf(item.payload) !== -1);\n            if (mLine.rtcpFb) {\n                mLine.rtcpFb = mLine.rtcpFb.filter(\n                    item => keepPts.indexOf(item.payload) !== -1);\n            }\n        }\n    }\n};\n\nexport default SDPUtil;\n","import $ from 'jquery';\n\nimport clonedeep from 'lodash.clonedeep';\nimport transform from 'sdp-transform';\n\nimport MediaDirection from '../../service/RTC/MediaDirection';\nimport browser from '../browser';\nimport FeatureFlags from '../flags/FeatureFlags';\n\nimport SDPUtil from './SDPUtil';\n\n/**\n *\n * @param sdp\n */\nexport default function SDP(sdp) {\n    const media = sdp.split('\\r\\nm=');\n\n    for (let i = 1, length = media.length; i < length; i++) {\n        let mediaI = `m=${media[i]}`;\n\n        if (i !== length - 1) {\n            mediaI += '\\r\\n';\n        }\n        media[i] = mediaI;\n    }\n    const session = `${media.shift()}\\r\\n`;\n\n    this.media = media;\n    this.raw = session + media.join('');\n    this.session = session;\n}\n\n/**\n * A flag will make {@link transportToJingle} and {@link jingle2media} replace\n * ICE candidates IPs with invalid value of '1.1.1.1' which will cause ICE\n * failure. The flag is used in the automated testing.\n * @type {boolean}\n */\nSDP.prototype.failICE = false;\n\n/**\n * Whether or not to remove TCP ice candidates when translating from/to jingle.\n * @type {boolean}\n */\nSDP.prototype.removeTcpCandidates = false;\n\n/**\n * Whether or not to remove UDP ice candidates when translating from/to jingle.\n * @type {boolean}\n */\nSDP.prototype.removeUdpCandidates = false;\n\n/**\n * Adds a new m-line to the description so that a new local source can then be attached to the transceiver that gets\n * added after a reneogtiation cycle.\n *\n * @param {MediaType} mediaType media type of the new source that is being added.\n */\nSDP.prototype.addMlineForNewLocalSource = function(mediaType) {\n    const mid = this.media.length;\n    const sdp = transform.parse(this.raw);\n    const mline = clonedeep(sdp.media.find(m => m.type === mediaType));\n\n    // Edit media direction, mid and remove the existing ssrc lines in the m-line.\n    mline.mid = mid;\n    mline.direction = MediaDirection.RECVONLY;\n\n    // Remove the ssrcs and source groups.\n    mline.msid = undefined;\n    mline.ssrcs = undefined;\n    mline.ssrcGroups = undefined;\n\n    sdp.media = sdp.media.concat(mline);\n\n    // We regenerate the BUNDLE group (since we added a new m-line)\n    sdp.groups.forEach(group => {\n        if (group.type === 'BUNDLE') {\n            const mids = group.mids.split(' ');\n\n            mids.push(mid);\n            group.mids = mids.join(' ');\n        }\n    });\n    this.raw = transform.write(sdp);\n};\n\n/**\n * Returns map of MediaChannel mapped per channel idx.\n */\nSDP.prototype.getMediaSsrcMap = function() {\n    const mediaSSRCs = {};\n\n    for (let mediaindex = 0; mediaindex < this.media.length; mediaindex++) {\n        const mid\n            = SDPUtil.parseMID(\n                SDPUtil.findLine(this.media[mediaindex], 'a=mid:'));\n        const media = {\n            mediaindex,\n            mid,\n            ssrcs: {},\n            ssrcGroups: []\n        };\n\n        mediaSSRCs[mediaindex] = media;\n\n        SDPUtil.findLines(this.media[mediaindex], 'a=ssrc:').forEach(line => {\n            const linessrc = line.substring(7).split(' ')[0];\n\n            // allocate new ChannelSsrc\n\n            if (!media.ssrcs[linessrc]) {\n                media.ssrcs[linessrc] = {\n                    ssrc: linessrc,\n                    lines: []\n                };\n            }\n            media.ssrcs[linessrc].lines.push(line);\n        });\n        SDPUtil.findLines(this.media[mediaindex], 'a=ssrc-group:').forEach(line => {\n            const idx = line.indexOf(' ');\n            const semantics = line.substr(0, idx).substr(13);\n            const ssrcs = line.substr(14 + semantics.length).split(' ');\n\n            if (ssrcs.length) {\n                media.ssrcGroups.push({\n                    semantics,\n                    ssrcs\n                });\n            }\n        });\n    }\n\n    return mediaSSRCs;\n};\n\n/**\n * Returns <tt>true</tt> if this SDP contains given SSRC.\n * @param ssrc the ssrc to check.\n * @returns {boolean} <tt>true</tt> if this SDP contains given SSRC.\n */\nSDP.prototype.containsSSRC = function(ssrc) {\n    // FIXME this code is really strange - improve it if you can\n    const medias = this.getMediaSsrcMap();\n    let result = false;\n\n    Object.keys(medias).forEach(mediaindex => {\n        if (result) {\n            return;\n        }\n        if (medias[mediaindex].ssrcs[ssrc]) {\n            result = true;\n        }\n    });\n\n    return result;\n};\n\n// add content's to a jingle element\nSDP.prototype.toJingle = function(elem, thecreator) {\n    // https://xmpp.org/extensions/xep-0338.html\n    SDPUtil.findLines(this.session, 'a=group:').forEach(line => {\n        const parts = line.split(' ');\n        const semantics = parts.shift().substr(8);\n\n        elem.c('group', { xmlns: 'urn:xmpp:jingle:apps:grouping:0',\n            semantics });\n        for (let j = 0; j < parts.length; j++) {\n            elem.c('content', { name: parts[j] }).up();\n        }\n        elem.up();\n    });\n\n    for (let i = 0; i < this.media.length; i++) {\n        const mline = SDPUtil.parseMLine(this.media[i].split('\\r\\n')[0]);\n\n        if (!(mline.media === 'audio'\n              || mline.media === 'video'\n              || mline.media === 'application')) {\n            continue; // eslint-disable-line no-continue\n        }\n\n        let ssrc;\n        const assrcline = SDPUtil.findLine(this.media[i], 'a=ssrc:');\n\n        if (assrcline) {\n            ssrc = assrcline.substring(7).split(' ')[0]; // take the first\n        } else {\n            ssrc = false;\n        }\n\n        elem.c('content', { creator: thecreator,\n            name: mline.media });\n        const amidline = SDPUtil.findLine(this.media[i], 'a=mid:');\n\n        if (amidline) {\n            // prefer identifier from a=mid if present\n            const mid = SDPUtil.parseMID(amidline);\n\n            elem.attrs({ name: mid });\n        }\n\n        if (mline.media === 'audio' || mline.media === 'video') {\n            elem.c('description',\n                { xmlns: 'urn:xmpp:jingle:apps:rtp:1',\n                    media: mline.media });\n            if (ssrc) {\n                elem.attrs({ ssrc });\n            }\n            for (let j = 0; j < mline.fmt.length; j++) {\n                const rtpmap\n                    = SDPUtil.findLine(\n                        this.media[i],\n                        `a=rtpmap:${mline.fmt[j]}`);\n\n                elem.c('payload-type', SDPUtil.parseRTPMap(rtpmap));\n\n                // put any 'a=fmtp:' + mline.fmt[j] lines into <param name=foo\n                // value=bar/>\n                const afmtpline\n                    = SDPUtil.findLine(\n                        this.media[i],\n                        `a=fmtp:${mline.fmt[j]}`);\n\n                if (afmtpline) {\n                    const fmtpParameters = SDPUtil.parseFmtp(afmtpline);\n\n                    // eslint-disable-next-line max-depth\n                    for (let k = 0; k < fmtpParameters.length; k++) {\n                        elem.c('parameter', fmtpParameters[k]).up();\n                    }\n                }\n\n                // XEP-0293 -- map a=rtcp-fb\n                this.rtcpFbToJingle(i, elem, mline.fmt[j]);\n\n                elem.up();\n            }\n\n            if (ssrc) {\n                const ssrcMap = SDPUtil.parseSSRC(this.media[i]);\n\n                for (const [ availableSsrc, ssrcParameters ] of ssrcMap) {\n                    const sourceName = SDPUtil.parseSourceNameLine(ssrcParameters);\n\n                    elem.c('source', {\n                        ssrc: availableSsrc,\n                        name: FeatureFlags.isSourceNameSignalingEnabled() ? sourceName : undefined,\n                        xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0'\n                    });\n\n                    const msid = SDPUtil.parseMSIDAttribute(ssrcParameters);\n\n                    // eslint-disable-next-line max-depth\n                    if (msid) {\n                        elem.c('parameter');\n                        elem.attrs({ name: 'msid' });\n                        elem.attrs({ value: msid });\n                        elem.up();\n                    }\n\n                    elem.up();\n                }\n\n                // XEP-0339 handle ssrc-group attributes\n                const ssrcGroupLines\n                    = SDPUtil.findLines(this.media[i], 'a=ssrc-group:');\n\n                ssrcGroupLines.forEach(line => {\n                    const idx = line.indexOf(' ');\n                    const semantics = line.substr(0, idx).substr(13);\n                    const ssrcs = line.substr(14 + semantics.length).split(' ');\n\n                    if (ssrcs.length) {\n                        elem.c('ssrc-group', { semantics,\n                            xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });\n                        ssrcs.forEach(s => elem.c('source', { ssrc: s }).up());\n                        elem.up();\n                    }\n                });\n            }\n\n            const ridLines = SDPUtil.findLines(this.media[i], 'a=rid:');\n\n            if (ridLines.length && browser.usesRidsForSimulcast()) {\n                // Map a line which looks like \"a=rid:2 send\" to just\n                // the rid (\"2\")\n                const rids = ridLines\n                    .map(ridLine => ridLine.split(':')[1])\n                    .map(ridInfo => ridInfo.split(' ')[0]);\n\n                rids.forEach(rid => {\n                    elem.c('source', {\n                        rid,\n                        xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0'\n                    });\n                    elem.up();\n                });\n                const unifiedSimulcast\n                    = SDPUtil.findLine(this.media[i], 'a=simulcast:');\n\n                if (unifiedSimulcast) {\n                    elem.c('rid-group', {\n                        semantics: 'SIM',\n                        xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0'\n                    });\n                    rids.forEach(rid => {\n                        elem.c('source', { rid }).up();\n                    });\n                    elem.up();\n                }\n            }\n\n            if (SDPUtil.findLine(this.media[i], 'a=rtcp-mux')) {\n                elem.c('rtcp-mux').up();\n            }\n\n            // XEP-0293 -- map a=rtcp-fb:*\n            this.rtcpFbToJingle(i, elem, '*');\n\n            // XEP-0294\n            const extmapLines = SDPUtil.findLines(this.media[i], 'a=extmap:');\n\n            for (let j = 0; j < extmapLines.length; j++) {\n                const extmap = SDPUtil.parseExtmap(extmapLines[j]);\n\n                elem.c('rtp-hdrext', {\n                    xmlns: 'urn:xmpp:jingle:apps:rtp:rtp-hdrext:0',\n                    uri: extmap.uri,\n                    id: extmap.value\n                });\n\n                // eslint-disable-next-line max-depth\n                if (extmap.hasOwnProperty('direction')) {\n\n                    // eslint-disable-next-line max-depth\n                    switch (extmap.direction) {\n                    case MediaDirection.SENDONLY:\n                        elem.attrs({ senders: 'responder' });\n                        break;\n                    case MediaDirection.RECVONLY:\n                        elem.attrs({ senders: 'initiator' });\n                        break;\n                    case MediaDirection.SENDRECV:\n                        elem.attrs({ senders: 'both' });\n                        break;\n                    case MediaDirection.INACTIVE:\n                        elem.attrs({ senders: 'none' });\n                        break;\n                    }\n                }\n\n                // TODO: handle params\n                elem.up();\n            }\n            elem.up(); // end of description\n        }\n\n        // map ice-ufrag/pwd, dtls fingerprint, candidates\n        this.transportToJingle(i, elem);\n\n        const m = this.media[i];\n\n        if (SDPUtil.findLine(m, `a=${MediaDirection.SENDRECV}`, this.session)) {\n            elem.attrs({ senders: 'both' });\n        } else if (SDPUtil.findLine(m, `a=${MediaDirection.SENDONLY}`, this.session)) {\n            elem.attrs({ senders: 'initiator' });\n        } else if (SDPUtil.findLine(m, `a=${MediaDirection.RECVONLY}`, this.session)) {\n            elem.attrs({ senders: 'responder' });\n        } else if (SDPUtil.findLine(m, `a=${MediaDirection.INACTIVE}`, this.session)) {\n            elem.attrs({ senders: 'none' });\n        }\n\n        // Reject an m-line only when port is 0 and a=bundle-only is not present in the section.\n        // The port is automatically set to 0 when bundle-only is used.\n        if (mline.port === '0' && !SDPUtil.findLine(m, 'a=bundle-only', this.session)) {\n            // estos hack to reject an m-line\n            elem.attrs({ senders: 'rejected' });\n        }\n        elem.up(); // end of content\n    }\n    elem.up();\n\n    return elem;\n};\n\nSDP.prototype.transportToJingle = function(mediaindex, elem) {\n    elem.c('transport');\n\n    // XEP-0343 DTLS/SCTP\n    const sctpport\n        = SDPUtil.findLine(this.media[mediaindex], 'a=sctp-port:', this.session);\n    const sctpmap\n        = SDPUtil.findLine(this.media[mediaindex], 'a=sctpmap:', this.session);\n\n    if (sctpport) {\n        const sctpAttrs = SDPUtil.parseSCTPPort(sctpport);\n\n        elem.c('sctpmap', {\n            xmlns: 'urn:xmpp:jingle:transports:dtls-sctp:1',\n            number: sctpAttrs, /* SCTP port */\n            protocol: 'webrtc-datachannel' /* protocol */\n        });\n\n        // The parser currently requires streams to be present\n        elem.attrs({ streams: 0 });\n        elem.up();\n    } else if (sctpmap) {\n        const sctpAttrs = SDPUtil.parseSCTPMap(sctpmap);\n\n        elem.c('sctpmap', {\n            xmlns: 'urn:xmpp:jingle:transports:dtls-sctp:1',\n            number: sctpAttrs[0], /* SCTP port */\n            protocol: sctpAttrs[1] /* protocol */\n        });\n\n        // Optional stream count attribute\n        if (sctpAttrs.length > 2) {\n            elem.attrs({ streams: sctpAttrs[2] });\n        } else {\n            elem.attrs({ streams: 0 });\n        }\n        elem.up();\n    }\n\n    // XEP-0320\n    const fingerprints\n        = SDPUtil.findLines(\n            this.media[mediaindex],\n            'a=fingerprint:',\n            this.session);\n\n    fingerprints.forEach(line => {\n        const fingerprint = SDPUtil.parseFingerprint(line);\n\n        fingerprint.xmlns = 'urn:xmpp:jingle:apps:dtls:0';\n        elem.c('fingerprint').t(fingerprint.fingerprint);\n        delete fingerprint.fingerprint;\n\n        const setupLine\n            = SDPUtil.findLine(\n                this.media[mediaindex],\n                'a=setup:',\n                this.session);\n\n        if (setupLine) {\n            fingerprint.setup = setupLine.substr(8);\n        }\n        elem.attrs(fingerprint);\n        elem.up(); // end of fingerprint\n    });\n    const iceParameters = SDPUtil.iceparams(this.media[mediaindex], this.session);\n\n    if (iceParameters) {\n        iceParameters.xmlns = 'urn:xmpp:jingle:transports:ice-udp:1';\n        elem.attrs(iceParameters);\n\n        // XEP-0176\n        const candidateLines\n            = SDPUtil.findLines(\n                this.media[mediaindex],\n                'a=candidate:',\n                this.session);\n\n        candidateLines.forEach(line => { // add any a=candidate lines\n            const candidate = SDPUtil.candidateToJingle(line);\n\n            if (this.failICE) {\n                candidate.ip = '1.1.1.1';\n            }\n            const protocol\n                = candidate && typeof candidate.protocol === 'string'\n                    ? candidate.protocol.toLowerCase()\n                    : '';\n\n            if ((this.removeTcpCandidates\n                    && (protocol === 'tcp' || protocol === 'ssltcp'))\n                || (this.removeUdpCandidates && protocol === 'udp')) {\n                return;\n            }\n            elem.c('candidate', candidate).up();\n        });\n    }\n    elem.up(); // end of transport\n};\n\n// XEP-0293\nSDP.prototype.rtcpFbToJingle = function(mediaindex, elem, payloadtype) {\n    const lines\n        = SDPUtil.findLines(\n            this.media[mediaindex],\n            `a=rtcp-fb:${payloadtype}`);\n\n    lines.forEach(line => {\n        const feedback = SDPUtil.parseRTCPFB(line);\n\n        if (feedback.type === 'trr-int') {\n            elem.c('rtcp-fb-trr-int', {\n                xmlns: 'urn:xmpp:jingle:apps:rtp:rtcp-fb:0',\n                value: feedback.params[0]\n            });\n            elem.up();\n        } else {\n            elem.c('rtcp-fb', {\n                xmlns: 'urn:xmpp:jingle:apps:rtp:rtcp-fb:0',\n                type: feedback.type\n            });\n            if (feedback.params.length > 0) {\n                elem.attrs({ 'subtype': feedback.params[0] });\n            }\n            elem.up();\n        }\n    });\n};\n\nSDP.prototype.rtcpFbFromJingle = function(elem, payloadtype) { // XEP-0293\n    let sdp = '';\n    const feedbackElementTrrInt\n        = elem.find(\n            '>rtcp-fb-trr-int[xmlns=\"urn:xmpp:jingle:apps:rtp:rtcp-fb:0\"]');\n\n    if (feedbackElementTrrInt.length) {\n        sdp += 'a=rtcp-fb:* trr-int ';\n        if (feedbackElementTrrInt.attr('value')) {\n            sdp += feedbackElementTrrInt.attr('value');\n        } else {\n            sdp += '0';\n        }\n        sdp += '\\r\\n';\n    }\n\n    const feedbackElements = elem.find('>rtcp-fb[xmlns=\"urn:xmpp:jingle:apps:rtp:rtcp-fb:0\"]');\n\n    feedbackElements.each((_, fb) => {\n        sdp += `a=rtcp-fb:${payloadtype} ${fb.getAttribute('type')}`;\n        if (fb.hasAttribute('subtype')) {\n            sdp += ` ${fb.getAttribute('subtype')}`;\n        }\n        sdp += '\\r\\n';\n    });\n\n    return sdp;\n};\n\n// construct an SDP from a jingle stanza\nSDP.prototype.fromJingle = function(jingle) {\n    const sessionId = Date.now();\n\n    // Use a unique session id for every TPC.\n    this.raw = 'v=0\\r\\n'\n        + `o=- ${sessionId} 2 IN IP4 0.0.0.0\\r\\n`\n        + 's=-\\r\\n'\n        + 't=0 0\\r\\n';\n\n    // http://tools.ietf.org/html/draft-ietf-mmusic-sdp-bundle-negotiation-04\n    // #section-8\n    const groups\n        = $(jingle).find('>group[xmlns=\"urn:xmpp:jingle:apps:grouping:0\"]');\n\n    if (groups.length) {\n        groups.each((idx, group) => {\n            const contents\n                = $(group)\n                    .find('>content')\n                    .map((_, content) => content.getAttribute('name'))\n                    .get();\n\n            if (contents.length > 0) {\n                this.raw\n                    += `a=group:${\n                        group.getAttribute('semantics')\n                            || group.getAttribute('type')} ${\n                        contents.join(' ')}\\r\\n`;\n            }\n        });\n    }\n\n    this.session = this.raw;\n    jingle.find('>content').each((_, content) => {\n        const m = this.jingle2media($(content));\n\n        this.media.push(m);\n    });\n\n    // reconstruct msid-semantic -- apparently not necessary\n    /*\n     var msid = SDPUtil.parseSSRC(this.raw);\n     if (msid.hasOwnProperty('mslabel')) {\n     this.session += \"a=msid-semantic: WMS \" + msid.mslabel + \"\\r\\n\";\n     }\n     */\n\n    this.raw = this.session + this.media.join('');\n};\n\n// translate a jingle content element into an an SDP media part\nSDP.prototype.jingle2media = function(content) {\n    const desc = content.find('>description');\n    const transport = content.find('>transport[xmlns=\"urn:xmpp:jingle:transports:ice-udp:1\"]');\n    let sdp = '';\n    const sctp = transport.find(\n        '>sctpmap[xmlns=\"urn:xmpp:jingle:transports:dtls-sctp:1\"]');\n\n    const media = { media: desc.attr('media') };\n\n    media.port = '9';\n    if (content.attr('senders') === 'rejected') {\n        // estos hack to reject an m-line.\n        media.port = '0';\n    }\n    if (transport.find('>fingerprint[xmlns=\"urn:xmpp:jingle:apps:dtls:0\"]').length) {\n        media.proto = sctp.length ? 'UDP/DTLS/SCTP' : 'UDP/TLS/RTP/SAVPF';\n    } else {\n        media.proto = 'UDP/TLS/RTP/SAVPF';\n    }\n    if (sctp.length) {\n        sdp += `m=application ${media.port} UDP/DTLS/SCTP webrtc-datachannel\\r\\n`;\n        sdp += `a=sctp-port:${sctp.attr('number')}\\r\\n`;\n        sdp += 'a=max-message-size:262144\\r\\n';\n    } else {\n        media.fmt\n            = desc\n                .find('>payload-type')\n                .map((_, payloadType) => payloadType.getAttribute('id'))\n                .get();\n        sdp += `${SDPUtil.buildMLine(media)}\\r\\n`;\n    }\n\n    sdp += 'c=IN IP4 0.0.0.0\\r\\n';\n    if (!sctp.length) {\n        sdp += 'a=rtcp:1 IN IP4 0.0.0.0\\r\\n';\n    }\n\n    // XEP-0176 ICE parameters\n    if (transport.length) {\n        if (transport.attr('ufrag')) {\n            sdp += `${SDPUtil.buildICEUfrag(transport.attr('ufrag'))}\\r\\n`;\n        }\n        if (transport.attr('pwd')) {\n            sdp += `${SDPUtil.buildICEPwd(transport.attr('pwd'))}\\r\\n`;\n        }\n        transport.find('>fingerprint[xmlns=\"urn:xmpp:jingle:apps:dtls:0\"]').each((_, fingerprint) => {\n            sdp += `a=fingerprint:${fingerprint.getAttribute('hash')}`;\n            sdp += ` ${$(fingerprint).text()}`;\n            sdp += '\\r\\n';\n            if (fingerprint.hasAttribute('setup')) {\n                sdp += `a=setup:${fingerprint.getAttribute('setup')}\\r\\n`;\n            }\n        });\n    }\n\n    // XEP-0176 ICE candidates\n    transport.find('>candidate')\n        .each((_, candidate) => {\n            let protocol = candidate.getAttribute('protocol');\n\n            protocol\n                = typeof protocol === 'string' ? protocol.toLowerCase() : '';\n\n            if ((this.removeTcpCandidates\n                    && (protocol === 'tcp' || protocol === 'ssltcp'))\n                || (this.removeUdpCandidates && protocol === 'udp')) {\n                return;\n            } else if (this.failICE) {\n                candidate.setAttribute('ip', '1.1.1.1');\n            }\n\n            sdp += SDPUtil.candidateFromJingle(candidate);\n        });\n\n    switch (content.attr('senders')) {\n    case 'initiator':\n        sdp += `a=${MediaDirection.SENDONLY}\\r\\n`;\n        break;\n    case 'responder':\n        sdp += `a=${MediaDirection.RECVONLY}\\r\\n`;\n        break;\n    case 'none':\n        sdp += `a=${MediaDirection.INACTIVE}\\r\\n`;\n        break;\n    case 'both':\n        sdp += `a=${MediaDirection.SENDRECV}\\r\\n`;\n        break;\n    }\n    sdp += `a=mid:${content.attr('name')}\\r\\n`;\n\n    // <description><rtcp-mux/></description>\n    // see http://code.google.com/p/libjingle/issues/detail?id=309 -- no spec\n    // though\n    // and http://mail.jabber.org/pipermail/jingle/2011-December/001761.html\n    if (desc.find('>rtcp-mux').length) {\n        sdp += 'a=rtcp-mux\\r\\n';\n    }\n\n    desc.find('>payload-type').each((_, payloadType) => {\n        sdp += `${SDPUtil.buildRTPMap(payloadType)}\\r\\n`;\n        if ($(payloadType).find('>parameter').length) {\n            sdp += `a=fmtp:${payloadType.getAttribute('id')} `;\n            sdp\n                += $(payloadType)\n                    .find('>parameter')\n                    .map((__, parameter) => {\n                        const name = parameter.getAttribute('name');\n\n                        return (\n                            (name ? `${name}=` : '')\n                                + parameter.getAttribute('value'));\n                    })\n                    .get()\n                    .join('; ');\n            sdp += '\\r\\n';\n        }\n\n        // xep-0293\n        sdp += this.rtcpFbFromJingle($(payloadType), payloadType.getAttribute('id'));\n    });\n\n    // xep-0293\n    sdp += this.rtcpFbFromJingle(desc, '*');\n\n    // xep-0294\n    desc\n        .find('>rtp-hdrext[xmlns=\"urn:xmpp:jingle:apps:rtp:rtp-hdrext:0\"]')\n        .each((_, hdrExt) => {\n            sdp\n                += `a=extmap:${hdrExt.getAttribute('id')} ${\n                    hdrExt.getAttribute('uri')}\\r\\n`;\n        });\n\n    // XEP-0339 handle ssrc-group attributes\n    desc\n        .find('>ssrc-group[xmlns=\"urn:xmpp:jingle:apps:rtp:ssma:0\"]')\n        .each((_, ssrcGroup) => {\n            const semantics = ssrcGroup.getAttribute('semantics');\n            const ssrcs\n                = $(ssrcGroup)\n                    .find('>source')\n                    .map((__, source) => source.getAttribute('ssrc'))\n                    .get();\n\n            if (ssrcs.length) {\n                sdp += `a=ssrc-group:${semantics} ${ssrcs.join(' ')}\\r\\n`;\n            }\n        });\n\n    // XEP-0339 handle source attributes\n    let userSources = '';\n    let nonUserSources = '';\n\n    desc\n        .find('>source[xmlns=\"urn:xmpp:jingle:apps:rtp:ssma:0\"]')\n        .each((_, source) => {\n            const ssrc = source.getAttribute('ssrc');\n            let isUserSource = true;\n            let sourceStr = '';\n\n            $(source)\n                .find('>parameter')\n                .each((__, parameter) => {\n                    const name = parameter.getAttribute('name');\n                    let value = parameter.getAttribute('value');\n\n                    value = SDPUtil.filterSpecialChars(value);\n                    sourceStr += `a=ssrc:${ssrc} ${name}`;\n\n                    if (value && value.length) {\n                        sourceStr += `:${value}`;\n                    }\n\n                    sourceStr += '\\r\\n';\n\n                    if (value?.includes('mixedmslabel')) {\n                        isUserSource = false;\n                    }\n                });\n\n            if (isUserSource) {\n                userSources += sourceStr;\n            } else {\n                nonUserSources += sourceStr;\n            }\n        });\n\n    // The sdp-interop package is relying the mixedmslabel m line to be the first one in order to set the direction\n    // to sendrecv.\n    sdp += nonUserSources + userSources;\n\n    return sdp;\n};\n","import FeatureFlags from '../flags/FeatureFlags';\n\nimport SDPUtil from './SDPUtil';\n\n// this could be useful in Array.prototype.\n/**\n *\n * @param array1\n * @param array2\n */\nfunction arrayEquals(array1, array2) {\n    // if the other array is a falsy value, return\n    if (!array2) {\n        return false;\n    }\n\n    // compare lengths - can save a lot of time\n    if (array1.length !== array2.length) {\n        return false;\n    }\n\n    for (let i = 0, l = array1.length; i < l; i++) {\n        // Check if we have nested arrays\n        if (array1[i] instanceof Array && array2[i] instanceof Array) {\n            // recurse into the nested arrays\n            if (!array1[i].equals(array2[i])) {\n                return false;\n            }\n        } else if (array1[i] !== array2[i]) {\n            // Warning - two different object instances will never be\n            // equal: {x:20} != {x:20}\n            return false;\n        }\n    }\n\n    return true;\n}\n\n/**\n *\n * @param mySDP\n * @param otherSDP\n */\nexport default function SDPDiffer(mySDP, otherSDP) {\n    this.mySDP = mySDP;\n    this.otherSDP = otherSDP;\n    if (!mySDP) {\n        throw new Error('\"mySDP\" is undefined!');\n    } else if (!otherSDP) {\n        throw new Error('\"otherSDP\" is undefined!');\n    }\n}\n\n/**\n * Returns map of MediaChannel that contains media contained in\n * 'mySDP', but not contained in 'otherSdp'. Mapped by channel idx.\n */\nSDPDiffer.prototype.getNewMedia = function() {\n\n    const myMedias = this.mySDP.getMediaSsrcMap();\n    const othersMedias = this.otherSDP.getMediaSsrcMap();\n    const newMedia = {};\n\n    Object.keys(othersMedias).forEach(othersMediaIdx => {\n        const myMedia = myMedias[othersMediaIdx];\n        const othersMedia = othersMedias[othersMediaIdx];\n\n        if (!myMedia && othersMedia) {\n            // Add whole channel\n            newMedia[othersMediaIdx] = othersMedia;\n\n            return;\n        }\n\n        // Look for new ssrcs across the channel\n        Object.keys(othersMedia.ssrcs).forEach(ssrc => {\n            if (Object.keys(myMedia.ssrcs).indexOf(ssrc) === -1) {\n                // Allocate channel if we've found ssrc that doesn't exist in\n                // our channel\n                if (!newMedia[othersMediaIdx]) {\n                    newMedia[othersMediaIdx] = {\n                        mediaindex: othersMedia.mediaindex,\n                        mid: othersMedia.mid,\n                        ssrcs: {},\n                        ssrcGroups: []\n                    };\n                }\n                newMedia[othersMediaIdx].ssrcs[ssrc] = othersMedia.ssrcs[ssrc];\n            } else if (othersMedia.ssrcs[ssrc].lines\n                        && myMedia.ssrcs[ssrc].lines) {\n                // we want to detect just changes in adding/removing msid\n                const myContainMsid = myMedia.ssrcs[ssrc].lines.find(\n                    line => line.indexOf('msid') !== -1) !== undefined;\n                const newContainMsid = othersMedia.ssrcs[ssrc].lines.find(\n                    line => line.indexOf('msid') !== -1) !== undefined;\n\n                if (myContainMsid !== newContainMsid) {\n                    if (!newMedia[othersMediaIdx]) {\n                        newMedia[othersMediaIdx] = {\n                            mediaindex: othersMedia.mediaindex,\n                            mid: othersMedia.mid,\n                            ssrcs: {},\n                            ssrcGroups: []\n                        };\n                    }\n                    newMedia[othersMediaIdx].ssrcs[ssrc]\n                        = othersMedia.ssrcs[ssrc];\n                }\n            }\n        });\n\n        // Look for new ssrc groups across the channels\n        othersMedia.ssrcGroups.forEach(otherSsrcGroup => {\n\n            // try to match the other ssrc-group with an ssrc-group of ours\n            let matched = false;\n\n            for (let i = 0; i < myMedia.ssrcGroups.length; i++) {\n                const mySsrcGroup = myMedia.ssrcGroups[i];\n\n                if (otherSsrcGroup.semantics === mySsrcGroup.semantics\n                    && arrayEquals(otherSsrcGroup.ssrcs, mySsrcGroup.ssrcs)) {\n\n                    matched = true;\n                    break;\n                }\n            }\n\n            if (!matched) {\n                // Allocate channel if we've found an ssrc-group that doesn't\n                // exist in our channel\n\n                if (!newMedia[othersMediaIdx]) {\n                    newMedia[othersMediaIdx] = {\n                        mediaindex: othersMedia.mediaindex,\n                        mid: othersMedia.mid,\n                        ssrcs: {},\n                        ssrcGroups: []\n                    };\n                }\n                newMedia[othersMediaIdx].ssrcGroups.push(otherSsrcGroup);\n            }\n        });\n    });\n\n    return newMedia;\n};\n\n/**\n * TODO: document!\n */\nSDPDiffer.prototype.toJingle = function(modify) {\n    const sdpMediaSsrcs = this.getNewMedia();\n\n    let modified = false;\n\n    Object.keys(sdpMediaSsrcs).forEach(mediaindex => {\n        modified = true;\n        const media = sdpMediaSsrcs[mediaindex];\n\n        modify.c('content', { name: media.mid });\n\n        modify.c('description',\n            { xmlns: 'urn:xmpp:jingle:apps:rtp:1',\n                media: media.mid });\n\n        // FIXME: not completely sure this operates on blocks and / or handles\n        // different ssrcs correctly\n        // generate sources from lines\n        Object.keys(media.ssrcs).forEach(ssrcNum => {\n            const mediaSsrc = media.ssrcs[ssrcNum];\n            const ssrcLines = mediaSsrc.lines;\n            const sourceName = SDPUtil.parseSourceNameLine(ssrcLines);\n\n            modify.c('source', { xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });\n            modify.attrs({\n                name: FeatureFlags.isSourceNameSignalingEnabled() ? sourceName : undefined,\n                ssrc: mediaSsrc.ssrc\n            });\n\n            // Only MSID attribute is sent\n            const msid = SDPUtil.parseMSIDAttribute(ssrcLines);\n\n            if (msid) {\n                modify.c('parameter');\n                modify.attrs({ name: 'msid' });\n                modify.attrs({ value: msid });\n                modify.up();\n            }\n\n            modify.up(); // end of source\n        });\n\n        // generate source groups from lines\n        media.ssrcGroups.forEach(ssrcGroup => {\n            if (ssrcGroup.ssrcs.length) {\n\n                modify.c('ssrc-group', {\n                    semantics: ssrcGroup.semantics,\n                    xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0'\n                });\n\n                ssrcGroup.ssrcs.forEach(ssrc => {\n                    modify.c('source', { ssrc })\n                        .up(); // end of source\n                });\n                modify.up(); // end of ssrc-group\n            }\n        });\n\n        modify.up(); // end of description\n        modify.up(); // end of content\n    });\n\n    return modified;\n};\n","/**\n * Creates a continuation function with some arguments already applied.\n *\n * Useful as a shorthand when combined with other control flow functions. Any\n * arguments passed to the returned function are added to the arguments\n * originally passed to apply.\n *\n * @name apply\n * @static\n * @memberOf module:Utils\n * @method\n * @category Util\n * @param {Function} fn - The function you want to eventually apply all\n * arguments to. Invokes with (arguments...).\n * @param {...*} arguments... - Any number of arguments to automatically apply\n * when the continuation is called.\n * @returns {Function} the partially-applied function\n * @example\n *\n * // using apply\n * async.parallel([\n *     async.apply(fs.writeFile, 'testfile1', 'test1'),\n *     async.apply(fs.writeFile, 'testfile2', 'test2')\n * ]);\n *\n *\n * // the same process without using apply\n * async.parallel([\n *     function(callback) {\n *         fs.writeFile('testfile1', 'test1', callback);\n *     },\n *     function(callback) {\n *         fs.writeFile('testfile2', 'test2', callback);\n *     }\n * ]);\n *\n * // It's possible to pass any number of additional arguments when calling the\n * // continuation:\n *\n * node> var fn = async.apply(sys.puts, 'one');\n * node> fn('two', 'three');\n * one\n * two\n * three\n */\nfunction apply(fn, ...args) {\n    return (...callArgs) => fn(...args,...callArgs);\n}\n\nfunction initialParams (fn) {\n    return function (...args/*, callback*/) {\n        var callback = args.pop();\n        return fn.call(this, args, callback);\n    };\n}\n\n/* istanbul ignore file */\n\nvar hasQueueMicrotask = typeof queueMicrotask === 'function' && queueMicrotask;\nvar hasSetImmediate = typeof setImmediate === 'function' && setImmediate;\nvar hasNextTick = typeof process === 'object' && typeof process.nextTick === 'function';\n\nfunction fallback(fn) {\n    setTimeout(fn, 0);\n}\n\nfunction wrap(defer) {\n    return (fn, ...args) => defer(() => fn(...args));\n}\n\nvar _defer;\n\nif (hasQueueMicrotask) {\n    _defer = queueMicrotask;\n} else if (hasSetImmediate) {\n    _defer = setImmediate;\n} else if (hasNextTick) {\n    _defer = process.nextTick;\n} else {\n    _defer = fallback;\n}\n\nvar setImmediate$1 = wrap(_defer);\n\n/**\n * Take a sync function and make it async, passing its return value to a\n * callback. This is useful for plugging sync functions into a waterfall,\n * series, or other async functions. Any arguments passed to the generated\n * function will be passed to the wrapped function (except for the final\n * callback argument). Errors thrown will be passed to the callback.\n *\n * If the function passed to `asyncify` returns a Promise, that promises's\n * resolved/rejected state will be used to call the callback, rather than simply\n * the synchronous return value.\n *\n * This also means you can asyncify ES2017 `async` functions.\n *\n * @name asyncify\n * @static\n * @memberOf module:Utils\n * @method\n * @alias wrapSync\n * @category Util\n * @param {Function} func - The synchronous function, or Promise-returning\n * function to convert to an {@link AsyncFunction}.\n * @returns {AsyncFunction} An asynchronous wrapper of the `func`. To be\n * invoked with `(args..., callback)`.\n * @example\n *\n * // passing a regular synchronous function\n * async.waterfall([\n *     async.apply(fs.readFile, filename, \"utf8\"),\n *     async.asyncify(JSON.parse),\n *     function (data, next) {\n *         // data is the result of parsing the text.\n *         // If there was a parsing error, it would have been caught.\n *     }\n * ], callback);\n *\n * // passing a function returning a promise\n * async.waterfall([\n *     async.apply(fs.readFile, filename, \"utf8\"),\n *     async.asyncify(function (contents) {\n *         return db.model.create(contents);\n *     }),\n *     function (model, next) {\n *         // `model` is the instantiated model object.\n *         // If there was an error, this function would be skipped.\n *     }\n * ], callback);\n *\n * // es2017 example, though `asyncify` is not needed if your JS environment\n * // supports async functions out of the box\n * var q = async.queue(async.asyncify(async function(file) {\n *     var intermediateStep = await processFile(file);\n *     return await somePromise(intermediateStep)\n * }));\n *\n * q.push(files);\n */\nfunction asyncify(func) {\n    if (isAsync(func)) {\n        return function (...args/*, callback*/) {\n            const callback = args.pop();\n            const promise = func.apply(this, args);\n            return handlePromise(promise, callback)\n        }\n    }\n\n    return initialParams(function (args, callback) {\n        var result;\n        try {\n            result = func.apply(this, args);\n        } catch (e) {\n            return callback(e);\n        }\n        // if result is Promise object\n        if (result && typeof result.then === 'function') {\n            return handlePromise(result, callback)\n        } else {\n            callback(null, result);\n        }\n    });\n}\n\nfunction handlePromise(promise, callback) {\n    return promise.then(value => {\n        invokeCallback(callback, null, value);\n    }, err => {\n        invokeCallback(callback, err && err.message ? err : new Error(err));\n    });\n}\n\nfunction invokeCallback(callback, error, value) {\n    try {\n        callback(error, value);\n    } catch (err) {\n        setImmediate$1(e => { throw e }, err);\n    }\n}\n\nfunction isAsync(fn) {\n    return fn[Symbol.toStringTag] === 'AsyncFunction';\n}\n\nfunction isAsyncGenerator(fn) {\n    return fn[Symbol.toStringTag] === 'AsyncGenerator';\n}\n\nfunction isAsyncIterable(obj) {\n    return typeof obj[Symbol.asyncIterator] === 'function';\n}\n\nfunction wrapAsync(asyncFn) {\n    if (typeof asyncFn !== 'function') throw new Error('expected a function')\n    return isAsync(asyncFn) ? asyncify(asyncFn) : asyncFn;\n}\n\n// conditionally promisify a function.\n// only return a promise if a callback is omitted\nfunction awaitify (asyncFn, arity = asyncFn.length) {\n    if (!arity) throw new Error('arity is undefined')\n    function awaitable (...args) {\n        if (typeof args[arity - 1] === 'function') {\n            return asyncFn.apply(this, args)\n        }\n\n        return new Promise((resolve, reject) => {\n            args[arity - 1] = (err, ...cbArgs) => {\n                if (err) return reject(err)\n                resolve(cbArgs.length > 1 ? cbArgs : cbArgs[0]);\n            };\n            asyncFn.apply(this, args);\n        })\n    }\n\n    return awaitable\n}\n\nfunction applyEach (eachfn) {\n    return function applyEach(fns, ...callArgs) {\n        const go = awaitify(function (callback) {\n            var that = this;\n            return eachfn(fns, (fn, cb) => {\n                wrapAsync(fn).apply(that, callArgs.concat(cb));\n            }, callback);\n        });\n        return go;\n    };\n}\n\nfunction _asyncMap(eachfn, arr, iteratee, callback) {\n    arr = arr || [];\n    var results = [];\n    var counter = 0;\n    var _iteratee = wrapAsync(iteratee);\n\n    return eachfn(arr, (value, _, iterCb) => {\n        var index = counter++;\n        _iteratee(value, (err, v) => {\n            results[index] = v;\n            iterCb(err);\n        });\n    }, err => {\n        callback(err, results);\n    });\n}\n\nfunction isArrayLike(value) {\n    return value &&\n        typeof value.length === 'number' &&\n        value.length >= 0 &&\n        value.length % 1 === 0;\n}\n\n// A temporary value used to identify if the loop should be broken.\n// See #1064, #1293\nconst breakLoop = {};\n\nfunction once(fn) {\n    function wrapper (...args) {\n        if (fn === null) return;\n        var callFn = fn;\n        fn = null;\n        callFn.apply(this, args);\n    }\n    Object.assign(wrapper, fn);\n    return wrapper\n}\n\nfunction getIterator (coll) {\n    return coll[Symbol.iterator] && coll[Symbol.iterator]();\n}\n\nfunction createArrayIterator(coll) {\n    var i = -1;\n    var len = coll.length;\n    return function next() {\n        return ++i < len ? {value: coll[i], key: i} : null;\n    }\n}\n\nfunction createES2015Iterator(iterator) {\n    var i = -1;\n    return function next() {\n        var item = iterator.next();\n        if (item.done)\n            return null;\n        i++;\n        return {value: item.value, key: i};\n    }\n}\n\nfunction createObjectIterator(obj) {\n    var okeys = obj ? Object.keys(obj) : [];\n    var i = -1;\n    var len = okeys.length;\n    return function next() {\n        var key = okeys[++i];\n        if (key === '__proto__') {\n            return next();\n        }\n        return i < len ? {value: obj[key], key} : null;\n    };\n}\n\nfunction createIterator(coll) {\n    if (isArrayLike(coll)) {\n        return createArrayIterator(coll);\n    }\n\n    var iterator = getIterator(coll);\n    return iterator ? createES2015Iterator(iterator) : createObjectIterator(coll);\n}\n\nfunction onlyOnce(fn) {\n    return function (...args) {\n        if (fn === null) throw new Error(\"Callback was already called.\");\n        var callFn = fn;\n        fn = null;\n        callFn.apply(this, args);\n    };\n}\n\n// for async generators\nfunction asyncEachOfLimit(generator, limit, iteratee, callback) {\n    let done = false;\n    let canceled = false;\n    let awaiting = false;\n    let running = 0;\n    let idx = 0;\n\n    function replenish() {\n        //console.log('replenish')\n        if (running >= limit || awaiting || done) return\n        //console.log('replenish awaiting')\n        awaiting = true;\n        generator.next().then(({value, done: iterDone}) => {\n            //console.log('got value', value)\n            if (canceled || done) return\n            awaiting = false;\n            if (iterDone) {\n                done = true;\n                if (running <= 0) {\n                    //console.log('done nextCb')\n                    callback(null);\n                }\n                return;\n            }\n            running++;\n            iteratee(value, idx, iterateeCallback);\n            idx++;\n            replenish();\n        }).catch(handleError);\n    }\n\n    function iterateeCallback(err, result) {\n        //console.log('iterateeCallback')\n        running -= 1;\n        if (canceled) return\n        if (err) return handleError(err)\n\n        if (err === false) {\n            done = true;\n            canceled = true;\n            return\n        }\n\n        if (result === breakLoop || (done && running <= 0)) {\n            done = true;\n            //console.log('done iterCb')\n            return callback(null);\n        }\n        replenish();\n    }\n\n    function handleError(err) {\n        if (canceled) return\n        awaiting = false;\n        done = true;\n        callback(err);\n    }\n\n    replenish();\n}\n\nvar eachOfLimit = (limit) => {\n    return (obj, iteratee, callback) => {\n        callback = once(callback);\n        if (limit <= 0) {\n            throw new RangeError('concurrency limit cannot be less than 1')\n        }\n        if (!obj) {\n            return callback(null);\n        }\n        if (isAsyncGenerator(obj)) {\n            return asyncEachOfLimit(obj, limit, iteratee, callback)\n        }\n        if (isAsyncIterable(obj)) {\n            return asyncEachOfLimit(obj[Symbol.asyncIterator](), limit, iteratee, callback)\n        }\n        var nextElem = createIterator(obj);\n        var done = false;\n        var canceled = false;\n        var running = 0;\n        var looping = false;\n\n        function iterateeCallback(err, value) {\n            if (canceled) return\n            running -= 1;\n            if (err) {\n                done = true;\n                callback(err);\n            }\n            else if (err === false) {\n                done = true;\n                canceled = true;\n            }\n            else if (value === breakLoop || (done && running <= 0)) {\n                done = true;\n                return callback(null);\n            }\n            else if (!looping) {\n                replenish();\n            }\n        }\n\n        function replenish () {\n            looping = true;\n            while (running < limit && !done) {\n                var elem = nextElem();\n                if (elem === null) {\n                    done = true;\n                    if (running <= 0) {\n                        callback(null);\n                    }\n                    return;\n                }\n                running += 1;\n                iteratee(elem.value, elem.key, onlyOnce(iterateeCallback));\n            }\n            looping = false;\n        }\n\n        replenish();\n    };\n};\n\n/**\n * The same as [`eachOf`]{@link module:Collections.eachOf} but runs a maximum of `limit` async operations at a\n * time.\n *\n * @name eachOfLimit\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.eachOf]{@link module:Collections.eachOf}\n * @alias forEachOfLimit\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {AsyncFunction} iteratee - An async function to apply to each\n * item in `coll`. The `key` is the item's key, or index in the case of an\n * array.\n * Invoked with (item, key, callback).\n * @param {Function} [callback] - A callback which is called when all\n * `iteratee` functions have finished, or an error occurs. Invoked with (err).\n * @returns {Promise} a promise, if a callback is omitted\n */\nfunction eachOfLimit$1(coll, limit, iteratee, callback) {\n    return eachOfLimit(limit)(coll, wrapAsync(iteratee), callback);\n}\n\nvar eachOfLimit$2 = awaitify(eachOfLimit$1, 4);\n\n// eachOf implementation optimized for array-likes\nfunction eachOfArrayLike(coll, iteratee, callback) {\n    callback = once(callback);\n    var index = 0,\n        completed = 0,\n        {length} = coll,\n        canceled = false;\n    if (length === 0) {\n        callback(null);\n    }\n\n    function iteratorCallback(err, value) {\n        if (err === false) {\n            canceled = true;\n        }\n        if (canceled === true) return\n        if (err) {\n            callback(err);\n        } else if ((++completed === length) || value === breakLoop) {\n            callback(null);\n        }\n    }\n\n    for (; index < length; index++) {\n        iteratee(coll[index], index, onlyOnce(iteratorCallback));\n    }\n}\n\n// a generic version of eachOf which can handle array, object, and iterator cases.\nfunction eachOfGeneric (coll, iteratee, callback) {\n    return eachOfLimit$2(coll, Infinity, iteratee, callback);\n}\n\n/**\n * Like [`each`]{@link module:Collections.each}, except that it passes the key (or index) as the second argument\n * to the iteratee.\n *\n * @name eachOf\n * @static\n * @memberOf module:Collections\n * @method\n * @alias forEachOf\n * @category Collection\n * @see [async.each]{@link module:Collections.each}\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - A function to apply to each\n * item in `coll`.\n * The `key` is the item's key, or index in the case of an array.\n * Invoked with (item, key, callback).\n * @param {Function} [callback] - A callback which is called when all\n * `iteratee` functions have finished, or an error occurs. Invoked with (err).\n * @returns {Promise} a promise, if a callback is omitted\n * @example\n *\n * // dev.json is a file containing a valid json object config for dev environment\n * // dev.json is a file containing a valid json object config for test environment\n * // prod.json is a file containing a valid json object config for prod environment\n * // invalid.json is a file with a malformed json object\n *\n * let configs = {}; //global variable\n * let validConfigFileMap = {dev: 'dev.json', test: 'test.json', prod: 'prod.json'};\n * let invalidConfigFileMap = {dev: 'dev.json', test: 'test.json', invalid: 'invalid.json'};\n *\n * // asynchronous function that reads a json file and parses the contents as json object\n * function parseFile(file, key, callback) {\n *     fs.readFile(file, \"utf8\", function(err, data) {\n *         if (err) return calback(err);\n *         try {\n *             configs[key] = JSON.parse(data);\n *         } catch (e) {\n *             return callback(e);\n *         }\n *         callback();\n *     });\n * }\n *\n * // Using callbacks\n * async.forEachOf(validConfigFileMap, parseFile, function (err) {\n *     if (err) {\n *         console.error(err);\n *     } else {\n *         console.log(configs);\n *         // configs is now a map of JSON data, e.g.\n *         // { dev: //parsed dev.json, test: //parsed test.json, prod: //parsed prod.json}\n *     }\n * });\n *\n * //Error handing\n * async.forEachOf(invalidConfigFileMap, parseFile, function (err) {\n *     if (err) {\n *         console.error(err);\n *         // JSON parse error exception\n *     } else {\n *         console.log(configs);\n *     }\n * });\n *\n * // Using Promises\n * async.forEachOf(validConfigFileMap, parseFile)\n * .then( () => {\n *     console.log(configs);\n *     // configs is now a map of JSON data, e.g.\n *     // { dev: //parsed dev.json, test: //parsed test.json, prod: //parsed prod.json}\n * }).catch( err => {\n *     console.error(err);\n * });\n *\n * //Error handing\n * async.forEachOf(invalidConfigFileMap, parseFile)\n * .then( () => {\n *     console.log(configs);\n * }).catch( err => {\n *     console.error(err);\n *     // JSON parse error exception\n * });\n *\n * // Using async/await\n * async () => {\n *     try {\n *         let result = await async.forEachOf(validConfigFileMap, parseFile);\n *         console.log(configs);\n *         // configs is now a map of JSON data, e.g.\n *         // { dev: //parsed dev.json, test: //parsed test.json, prod: //parsed prod.json}\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n * //Error handing\n * async () => {\n *     try {\n *         let result = await async.forEachOf(invalidConfigFileMap, parseFile);\n *         console.log(configs);\n *     }\n *     catch (err) {\n *         console.log(err);\n *         // JSON parse error exception\n *     }\n * }\n *\n */\nfunction eachOf(coll, iteratee, callback) {\n    var eachOfImplementation = isArrayLike(coll) ? eachOfArrayLike : eachOfGeneric;\n    return eachOfImplementation(coll, wrapAsync(iteratee), callback);\n}\n\nvar eachOf$1 = awaitify(eachOf, 3);\n\n/**\n * Produces a new collection of values by mapping each value in `coll` through\n * the `iteratee` function. The `iteratee` is called with an item from `coll`\n * and a callback for when it has finished processing. Each of these callbacks\n * takes 2 arguments: an `error`, and the transformed item from `coll`. If\n * `iteratee` passes an error to its callback, the main `callback` (for the\n * `map` function) is immediately called with the error.\n *\n * Note, that since this function applies the `iteratee` to each item in\n * parallel, there is no guarantee that the `iteratee` functions will complete\n * in order. However, the results array will be in the same order as the\n * original `coll`.\n *\n * If `map` is passed an Object, the results will be an Array.  The results\n * will roughly be in the order of the original Objects' keys (but this can\n * vary across JavaScript engines).\n *\n * @name map\n * @static\n * @memberOf module:Collections\n * @method\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async function to apply to each item in\n * `coll`.\n * The iteratee should complete with the transformed item.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called when all `iteratee`\n * functions have finished, or an error occurs. Results is an Array of the\n * transformed items from the `coll`. Invoked with (err, results).\n * @returns {Promise} a promise, if no callback is passed\n * @example\n *\n * // file1.txt is a file that is 1000 bytes in size\n * // file2.txt is a file that is 2000 bytes in size\n * // file3.txt is a file that is 3000 bytes in size\n * // file4.txt does not exist\n *\n * const fileList = ['file1.txt','file2.txt','file3.txt'];\n * const withMissingFileList = ['file1.txt','file2.txt','file4.txt'];\n *\n * // asynchronous function that returns the file size in bytes\n * function getFileSizeInBytes(file, callback) {\n *     fs.stat(file, function(err, stat) {\n *         if (err) {\n *             return callback(err);\n *         }\n *         callback(null, stat.size);\n *     });\n * }\n *\n * // Using callbacks\n * async.map(fileList, getFileSizeInBytes, function(err, results) {\n *     if (err) {\n *         console.log(err);\n *     } else {\n *         console.log(results);\n *         // results is now an array of the file size in bytes for each file, e.g.\n *         // [ 1000, 2000, 3000]\n *     }\n * });\n *\n * // Error Handling\n * async.map(withMissingFileList, getFileSizeInBytes, function(err, results) {\n *     if (err) {\n *         console.log(err);\n *         // [ Error: ENOENT: no such file or directory ]\n *     } else {\n *         console.log(results);\n *     }\n * });\n *\n * // Using Promises\n * async.map(fileList, getFileSizeInBytes)\n * .then( results => {\n *     console.log(results);\n *     // results is now an array of the file size in bytes for each file, e.g.\n *     // [ 1000, 2000, 3000]\n * }).catch( err => {\n *     console.log(err);\n * });\n *\n * // Error Handling\n * async.map(withMissingFileList, getFileSizeInBytes)\n * .then( results => {\n *     console.log(results);\n * }).catch( err => {\n *     console.log(err);\n *     // [ Error: ENOENT: no such file or directory ]\n * });\n *\n * // Using async/await\n * async () => {\n *     try {\n *         let results = await async.map(fileList, getFileSizeInBytes);\n *         console.log(results);\n *         // results is now an array of the file size in bytes for each file, e.g.\n *         // [ 1000, 2000, 3000]\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n * // Error Handling\n * async () => {\n *     try {\n *         let results = await async.map(withMissingFileList, getFileSizeInBytes);\n *         console.log(results);\n *     }\n *     catch (err) {\n *         console.log(err);\n *         // [ Error: ENOENT: no such file or directory ]\n *     }\n * }\n *\n */\nfunction map (coll, iteratee, callback) {\n    return _asyncMap(eachOf$1, coll, iteratee, callback)\n}\nvar map$1 = awaitify(map, 3);\n\n/**\n * Applies the provided arguments to each function in the array, calling\n * `callback` after all functions have completed. If you only provide the first\n * argument, `fns`, then it will return a function which lets you pass in the\n * arguments as if it were a single function call. If more arguments are\n * provided, `callback` is required while `args` is still optional. The results\n * for each of the applied async functions are passed to the final callback\n * as an array.\n *\n * @name applyEach\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @param {Array|Iterable|AsyncIterable|Object} fns - A collection of {@link AsyncFunction}s\n * to all call with the same arguments\n * @param {...*} [args] - any number of separate arguments to pass to the\n * function.\n * @param {Function} [callback] - the final argument should be the callback,\n * called when all functions have completed processing.\n * @returns {AsyncFunction} - Returns a function that takes no args other than\n * an optional callback, that is the result of applying the `args` to each\n * of the functions.\n * @example\n *\n * const appliedFn = async.applyEach([enableSearch, updateSchema], 'bucket')\n *\n * appliedFn((err, results) => {\n *     // results[0] is the results for `enableSearch`\n *     // results[1] is the results for `updateSchema`\n * });\n *\n * // partial application example:\n * async.each(\n *     buckets,\n *     async (bucket) => async.applyEach([enableSearch, updateSchema], bucket)(),\n *     callback\n * );\n */\nvar applyEach$1 = applyEach(map$1);\n\n/**\n * The same as [`eachOf`]{@link module:Collections.eachOf} but runs only a single async operation at a time.\n *\n * @name eachOfSeries\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.eachOf]{@link module:Collections.eachOf}\n * @alias forEachOfSeries\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async function to apply to each item in\n * `coll`.\n * Invoked with (item, key, callback).\n * @param {Function} [callback] - A callback which is called when all `iteratee`\n * functions have finished, or an error occurs. Invoked with (err).\n * @returns {Promise} a promise, if a callback is omitted\n */\nfunction eachOfSeries(coll, iteratee, callback) {\n    return eachOfLimit$2(coll, 1, iteratee, callback)\n}\nvar eachOfSeries$1 = awaitify(eachOfSeries, 3);\n\n/**\n * The same as [`map`]{@link module:Collections.map} but runs only a single async operation at a time.\n *\n * @name mapSeries\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.map]{@link module:Collections.map}\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async function to apply to each item in\n * `coll`.\n * The iteratee should complete with the transformed item.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called when all `iteratee`\n * functions have finished, or an error occurs. Results is an array of the\n * transformed items from the `coll`. Invoked with (err, results).\n * @returns {Promise} a promise, if no callback is passed\n */\nfunction mapSeries (coll, iteratee, callback) {\n    return _asyncMap(eachOfSeries$1, coll, iteratee, callback)\n}\nvar mapSeries$1 = awaitify(mapSeries, 3);\n\n/**\n * The same as [`applyEach`]{@link module:ControlFlow.applyEach} but runs only a single async operation at a time.\n *\n * @name applyEachSeries\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.applyEach]{@link module:ControlFlow.applyEach}\n * @category Control Flow\n * @param {Array|Iterable|AsyncIterable|Object} fns - A collection of {@link AsyncFunction}s to all\n * call with the same arguments\n * @param {...*} [args] - any number of separate arguments to pass to the\n * function.\n * @param {Function} [callback] - the final argument should be the callback,\n * called when all functions have completed processing.\n * @returns {AsyncFunction} - A function, that when called, is the result of\n * appling the `args` to the list of functions.  It takes no args, other than\n * a callback.\n */\nvar applyEachSeries = applyEach(mapSeries$1);\n\nconst PROMISE_SYMBOL = Symbol('promiseCallback');\n\nfunction promiseCallback () {\n    let resolve, reject;\n    function callback (err, ...args) {\n        if (err) return reject(err)\n        resolve(args.length > 1 ? args : args[0]);\n    }\n\n    callback[PROMISE_SYMBOL] = new Promise((res, rej) => {\n        resolve = res,\n        reject = rej;\n    });\n\n    return callback\n}\n\n/**\n * Determines the best order for running the {@link AsyncFunction}s in `tasks`, based on\n * their requirements. Each function can optionally depend on other functions\n * being completed first, and each function is run as soon as its requirements\n * are satisfied.\n *\n * If any of the {@link AsyncFunction}s pass an error to their callback, the `auto` sequence\n * will stop. Further tasks will not execute (so any other functions depending\n * on it will not run), and the main `callback` is immediately called with the\n * error.\n *\n * {@link AsyncFunction}s also receive an object containing the results of functions which\n * have completed so far as the first argument, if they have dependencies. If a\n * task function has no dependencies, it will only be passed a callback.\n *\n * @name auto\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @param {Object} tasks - An object. Each of its properties is either a\n * function or an array of requirements, with the {@link AsyncFunction} itself the last item\n * in the array. The object's key of a property serves as the name of the task\n * defined by that property, i.e. can be used when specifying requirements for\n * other tasks. The function receives one or two arguments:\n * * a `results` object, containing the results of the previously executed\n *   functions, only passed if the task has any dependencies,\n * * a `callback(err, result)` function, which must be called when finished,\n *   passing an `error` (which can be `null`) and the result of the function's\n *   execution.\n * @param {number} [concurrency=Infinity] - An optional `integer` for\n * determining the maximum number of tasks that can be run in parallel. By\n * default, as many as possible.\n * @param {Function} [callback] - An optional callback which is called when all\n * the tasks have been completed. It receives the `err` argument if any `tasks`\n * pass an error to their callback. Results are always returned; however, if an\n * error occurs, no further `tasks` will be performed, and the results object\n * will only contain partial results. Invoked with (err, results).\n * @returns {Promise} a promise, if a callback is not passed\n * @example\n *\n * //Using Callbacks\n * async.auto({\n *     get_data: function(callback) {\n *         // async code to get some data\n *         callback(null, 'data', 'converted to array');\n *     },\n *     make_folder: function(callback) {\n *         // async code to create a directory to store a file in\n *         // this is run at the same time as getting the data\n *         callback(null, 'folder');\n *     },\n *     write_file: ['get_data', 'make_folder', function(results, callback) {\n *         // once there is some data and the directory exists,\n *         // write the data to a file in the directory\n *         callback(null, 'filename');\n *     }],\n *     email_link: ['write_file', function(results, callback) {\n *         // once the file is written let's email a link to it...\n *         callback(null, {'file':results.write_file, 'email':'user@example.com'});\n *     }]\n * }, function(err, results) {\n *     if (err) {\n *         console.log('err = ', err);\n *     }\n *     console.log('results = ', results);\n *     // results = {\n *     //     get_data: ['data', 'converted to array']\n *     //     make_folder; 'folder',\n *     //     write_file: 'filename'\n *     //     email_link: { file: 'filename', email: 'user@example.com' }\n *     // }\n * });\n *\n * //Using Promises\n * async.auto({\n *     get_data: function(callback) {\n *         console.log('in get_data');\n *         // async code to get some data\n *         callback(null, 'data', 'converted to array');\n *     },\n *     make_folder: function(callback) {\n *         console.log('in make_folder');\n *         // async code to create a directory to store a file in\n *         // this is run at the same time as getting the data\n *         callback(null, 'folder');\n *     },\n *     write_file: ['get_data', 'make_folder', function(results, callback) {\n *         // once there is some data and the directory exists,\n *         // write the data to a file in the directory\n *         callback(null, 'filename');\n *     }],\n *     email_link: ['write_file', function(results, callback) {\n *         // once the file is written let's email a link to it...\n *         callback(null, {'file':results.write_file, 'email':'user@example.com'});\n *     }]\n * }).then(results => {\n *     console.log('results = ', results);\n *     // results = {\n *     //     get_data: ['data', 'converted to array']\n *     //     make_folder; 'folder',\n *     //     write_file: 'filename'\n *     //     email_link: { file: 'filename', email: 'user@example.com' }\n *     // }\n * }).catch(err => {\n *     console.log('err = ', err);\n * });\n *\n * //Using async/await\n * async () => {\n *     try {\n *         let results = await async.auto({\n *             get_data: function(callback) {\n *                 // async code to get some data\n *                 callback(null, 'data', 'converted to array');\n *             },\n *             make_folder: function(callback) {\n *                 // async code to create a directory to store a file in\n *                 // this is run at the same time as getting the data\n *                 callback(null, 'folder');\n *             },\n *             write_file: ['get_data', 'make_folder', function(results, callback) {\n *                 // once there is some data and the directory exists,\n *                 // write the data to a file in the directory\n *                 callback(null, 'filename');\n *             }],\n *             email_link: ['write_file', function(results, callback) {\n *                 // once the file is written let's email a link to it...\n *                 callback(null, {'file':results.write_file, 'email':'user@example.com'});\n *             }]\n *         });\n *         console.log('results = ', results);\n *         // results = {\n *         //     get_data: ['data', 'converted to array']\n *         //     make_folder; 'folder',\n *         //     write_file: 'filename'\n *         //     email_link: { file: 'filename', email: 'user@example.com' }\n *         // }\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n */\nfunction auto(tasks, concurrency, callback) {\n    if (typeof concurrency !== 'number') {\n        // concurrency is optional, shift the args.\n        callback = concurrency;\n        concurrency = null;\n    }\n    callback = once(callback || promiseCallback());\n    var numTasks = Object.keys(tasks).length;\n    if (!numTasks) {\n        return callback(null);\n    }\n    if (!concurrency) {\n        concurrency = numTasks;\n    }\n\n    var results = {};\n    var runningTasks = 0;\n    var canceled = false;\n    var hasError = false;\n\n    var listeners = Object.create(null);\n\n    var readyTasks = [];\n\n    // for cycle detection:\n    var readyToCheck = []; // tasks that have been identified as reachable\n    // without the possibility of returning to an ancestor task\n    var uncheckedDependencies = {};\n\n    Object.keys(tasks).forEach(key => {\n        var task = tasks[key];\n        if (!Array.isArray(task)) {\n            // no dependencies\n            enqueueTask(key, [task]);\n            readyToCheck.push(key);\n            return;\n        }\n\n        var dependencies = task.slice(0, task.length - 1);\n        var remainingDependencies = dependencies.length;\n        if (remainingDependencies === 0) {\n            enqueueTask(key, task);\n            readyToCheck.push(key);\n            return;\n        }\n        uncheckedDependencies[key] = remainingDependencies;\n\n        dependencies.forEach(dependencyName => {\n            if (!tasks[dependencyName]) {\n                throw new Error('async.auto task `' + key +\n                    '` has a non-existent dependency `' +\n                    dependencyName + '` in ' +\n                    dependencies.join(', '));\n            }\n            addListener(dependencyName, () => {\n                remainingDependencies--;\n                if (remainingDependencies === 0) {\n                    enqueueTask(key, task);\n                }\n            });\n        });\n    });\n\n    checkForDeadlocks();\n    processQueue();\n\n    function enqueueTask(key, task) {\n        readyTasks.push(() => runTask(key, task));\n    }\n\n    function processQueue() {\n        if (canceled) return\n        if (readyTasks.length === 0 && runningTasks === 0) {\n            return callback(null, results);\n        }\n        while(readyTasks.length && runningTasks < concurrency) {\n            var run = readyTasks.shift();\n            run();\n        }\n\n    }\n\n    function addListener(taskName, fn) {\n        var taskListeners = listeners[taskName];\n        if (!taskListeners) {\n            taskListeners = listeners[taskName] = [];\n        }\n\n        taskListeners.push(fn);\n    }\n\n    function taskComplete(taskName) {\n        var taskListeners = listeners[taskName] || [];\n        taskListeners.forEach(fn => fn());\n        processQueue();\n    }\n\n\n    function runTask(key, task) {\n        if (hasError) return;\n\n        var taskCallback = onlyOnce((err, ...result) => {\n            runningTasks--;\n            if (err === false) {\n                canceled = true;\n                return\n            }\n            if (result.length < 2) {\n                [result] = result;\n            }\n            if (err) {\n                var safeResults = {};\n                Object.keys(results).forEach(rkey => {\n                    safeResults[rkey] = results[rkey];\n                });\n                safeResults[key] = result;\n                hasError = true;\n                listeners = Object.create(null);\n                if (canceled) return\n                callback(err, safeResults);\n            } else {\n                results[key] = result;\n                taskComplete(key);\n            }\n        });\n\n        runningTasks++;\n        var taskFn = wrapAsync(task[task.length - 1]);\n        if (task.length > 1) {\n            taskFn(results, taskCallback);\n        } else {\n            taskFn(taskCallback);\n        }\n    }\n\n    function checkForDeadlocks() {\n        // Kahn's algorithm\n        // https://en.wikipedia.org/wiki/Topological_sorting#Kahn.27s_algorithm\n        // http://connalle.blogspot.com/2013/10/topological-sortingkahn-algorithm.html\n        var currentTask;\n        var counter = 0;\n        while (readyToCheck.length) {\n            currentTask = readyToCheck.pop();\n            counter++;\n            getDependents(currentTask).forEach(dependent => {\n                if (--uncheckedDependencies[dependent] === 0) {\n                    readyToCheck.push(dependent);\n                }\n            });\n        }\n\n        if (counter !== numTasks) {\n            throw new Error(\n                'async.auto cannot execute tasks due to a recursive dependency'\n            );\n        }\n    }\n\n    function getDependents(taskName) {\n        var result = [];\n        Object.keys(tasks).forEach(key => {\n            const task = tasks[key];\n            if (Array.isArray(task) && task.indexOf(taskName) >= 0) {\n                result.push(key);\n            }\n        });\n        return result;\n    }\n\n    return callback[PROMISE_SYMBOL]\n}\n\nvar FN_ARGS = /^(?:async\\s+)?(?:function)?\\s*\\w*\\s*\\(\\s*([^)]+)\\s*\\)(?:\\s*{)/;\nvar ARROW_FN_ARGS = /^(?:async\\s+)?\\(?\\s*([^)=]+)\\s*\\)?(?:\\s*=>)/;\nvar FN_ARG_SPLIT = /,/;\nvar FN_ARG = /(=.+)?(\\s*)$/;\n\nfunction stripComments(string) {\n    let stripped = '';\n    let index = 0;\n    let endBlockComment = string.indexOf('*/');\n    while (index < string.length) {\n        if (string[index] === '/' && string[index+1] === '/') {\n            // inline comment\n            let endIndex = string.indexOf('\\n', index);\n            index = (endIndex === -1) ? string.length : endIndex;\n        } else if ((endBlockComment !== -1) && (string[index] === '/') && (string[index+1] === '*')) {\n            // block comment\n            let endIndex = string.indexOf('*/', index);\n            if (endIndex !== -1) {\n                index = endIndex + 2;\n                endBlockComment = string.indexOf('*/', index);\n            } else {\n                stripped += string[index];\n                index++;\n            }\n        } else {\n            stripped += string[index];\n            index++;\n        }\n    }\n    return stripped;\n}\n\nfunction parseParams(func) {\n    const src = stripComments(func.toString());\n    let match = src.match(FN_ARGS);\n    if (!match) {\n        match = src.match(ARROW_FN_ARGS);\n    }\n    if (!match) throw new Error('could not parse args in autoInject\\nSource:\\n' + src)\n    let [, args] = match;\n    return args\n        .replace(/\\s/g, '')\n        .split(FN_ARG_SPLIT)\n        .map((arg) => arg.replace(FN_ARG, '').trim());\n}\n\n/**\n * A dependency-injected version of the [async.auto]{@link module:ControlFlow.auto} function. Dependent\n * tasks are specified as parameters to the function, after the usual callback\n * parameter, with the parameter names matching the names of the tasks it\n * depends on. This can provide even more readable task graphs which can be\n * easier to maintain.\n *\n * If a final callback is specified, the task results are similarly injected,\n * specified as named parameters after the initial error parameter.\n *\n * The autoInject function is purely syntactic sugar and its semantics are\n * otherwise equivalent to [async.auto]{@link module:ControlFlow.auto}.\n *\n * @name autoInject\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.auto]{@link module:ControlFlow.auto}\n * @category Control Flow\n * @param {Object} tasks - An object, each of whose properties is an {@link AsyncFunction} of\n * the form 'func([dependencies...], callback). The object's key of a property\n * serves as the name of the task defined by that property, i.e. can be used\n * when specifying requirements for other tasks.\n * * The `callback` parameter is a `callback(err, result)` which must be called\n *   when finished, passing an `error` (which can be `null`) and the result of\n *   the function's execution. The remaining parameters name other tasks on\n *   which the task is dependent, and the results from those tasks are the\n *   arguments of those parameters.\n * @param {Function} [callback] - An optional callback which is called when all\n * the tasks have been completed. It receives the `err` argument if any `tasks`\n * pass an error to their callback, and a `results` object with any completed\n * task results, similar to `auto`.\n * @returns {Promise} a promise, if no callback is passed\n * @example\n *\n * //  The example from `auto` can be rewritten as follows:\n * async.autoInject({\n *     get_data: function(callback) {\n *         // async code to get some data\n *         callback(null, 'data', 'converted to array');\n *     },\n *     make_folder: function(callback) {\n *         // async code to create a directory to store a file in\n *         // this is run at the same time as getting the data\n *         callback(null, 'folder');\n *     },\n *     write_file: function(get_data, make_folder, callback) {\n *         // once there is some data and the directory exists,\n *         // write the data to a file in the directory\n *         callback(null, 'filename');\n *     },\n *     email_link: function(write_file, callback) {\n *         // once the file is written let's email a link to it...\n *         // write_file contains the filename returned by write_file.\n *         callback(null, {'file':write_file, 'email':'user@example.com'});\n *     }\n * }, function(err, results) {\n *     console.log('err = ', err);\n *     console.log('email_link = ', results.email_link);\n * });\n *\n * // If you are using a JS minifier that mangles parameter names, `autoInject`\n * // will not work with plain functions, since the parameter names will be\n * // collapsed to a single letter identifier.  To work around this, you can\n * // explicitly specify the names of the parameters your task function needs\n * // in an array, similar to Angular.js dependency injection.\n *\n * // This still has an advantage over plain `auto`, since the results a task\n * // depends on are still spread into arguments.\n * async.autoInject({\n *     //...\n *     write_file: ['get_data', 'make_folder', function(get_data, make_folder, callback) {\n *         callback(null, 'filename');\n *     }],\n *     email_link: ['write_file', function(write_file, callback) {\n *         callback(null, {'file':write_file, 'email':'user@example.com'});\n *     }]\n *     //...\n * }, function(err, results) {\n *     console.log('err = ', err);\n *     console.log('email_link = ', results.email_link);\n * });\n */\nfunction autoInject(tasks, callback) {\n    var newTasks = {};\n\n    Object.keys(tasks).forEach(key => {\n        var taskFn = tasks[key];\n        var params;\n        var fnIsAsync = isAsync(taskFn);\n        var hasNoDeps =\n            (!fnIsAsync && taskFn.length === 1) ||\n            (fnIsAsync && taskFn.length === 0);\n\n        if (Array.isArray(taskFn)) {\n            params = [...taskFn];\n            taskFn = params.pop();\n\n            newTasks[key] = params.concat(params.length > 0 ? newTask : taskFn);\n        } else if (hasNoDeps) {\n            // no dependencies, use the function as-is\n            newTasks[key] = taskFn;\n        } else {\n            params = parseParams(taskFn);\n            if ((taskFn.length === 0 && !fnIsAsync) && params.length === 0) {\n                throw new Error(\"autoInject task functions require explicit parameters.\");\n            }\n\n            // remove callback param\n            if (!fnIsAsync) params.pop();\n\n            newTasks[key] = params.concat(newTask);\n        }\n\n        function newTask(results, taskCb) {\n            var newArgs = params.map(name => results[name]);\n            newArgs.push(taskCb);\n            wrapAsync(taskFn)(...newArgs);\n        }\n    });\n\n    return auto(newTasks, callback);\n}\n\n// Simple doubly linked list (https://en.wikipedia.org/wiki/Doubly_linked_list) implementation\n// used for queues. This implementation assumes that the node provided by the user can be modified\n// to adjust the next and last properties. We implement only the minimal functionality\n// for queue support.\nclass DLL {\n    constructor() {\n        this.head = this.tail = null;\n        this.length = 0;\n    }\n\n    removeLink(node) {\n        if (node.prev) node.prev.next = node.next;\n        else this.head = node.next;\n        if (node.next) node.next.prev = node.prev;\n        else this.tail = node.prev;\n\n        node.prev = node.next = null;\n        this.length -= 1;\n        return node;\n    }\n\n    empty () {\n        while(this.head) this.shift();\n        return this;\n    }\n\n    insertAfter(node, newNode) {\n        newNode.prev = node;\n        newNode.next = node.next;\n        if (node.next) node.next.prev = newNode;\n        else this.tail = newNode;\n        node.next = newNode;\n        this.length += 1;\n    }\n\n    insertBefore(node, newNode) {\n        newNode.prev = node.prev;\n        newNode.next = node;\n        if (node.prev) node.prev.next = newNode;\n        else this.head = newNode;\n        node.prev = newNode;\n        this.length += 1;\n    }\n\n    unshift(node) {\n        if (this.head) this.insertBefore(this.head, node);\n        else setInitial(this, node);\n    }\n\n    push(node) {\n        if (this.tail) this.insertAfter(this.tail, node);\n        else setInitial(this, node);\n    }\n\n    shift() {\n        return this.head && this.removeLink(this.head);\n    }\n\n    pop() {\n        return this.tail && this.removeLink(this.tail);\n    }\n\n    toArray() {\n        return [...this]\n    }\n\n    *[Symbol.iterator] () {\n        var cur = this.head;\n        while (cur) {\n            yield cur.data;\n            cur = cur.next;\n        }\n    }\n\n    remove (testFn) {\n        var curr = this.head;\n        while(curr) {\n            var {next} = curr;\n            if (testFn(curr)) {\n                this.removeLink(curr);\n            }\n            curr = next;\n        }\n        return this;\n    }\n}\n\nfunction setInitial(dll, node) {\n    dll.length = 1;\n    dll.head = dll.tail = node;\n}\n\nfunction queue(worker, concurrency, payload) {\n    if (concurrency == null) {\n        concurrency = 1;\n    }\n    else if(concurrency === 0) {\n        throw new RangeError('Concurrency must not be zero');\n    }\n\n    var _worker = wrapAsync(worker);\n    var numRunning = 0;\n    var workersList = [];\n    const events = {\n        error: [],\n        drain: [],\n        saturated: [],\n        unsaturated: [],\n        empty: []\n    };\n\n    function on (event, handler) {\n        events[event].push(handler);\n    }\n\n    function once (event, handler) {\n        const handleAndRemove = (...args) => {\n            off(event, handleAndRemove);\n            handler(...args);\n        };\n        events[event].push(handleAndRemove);\n    }\n\n    function off (event, handler) {\n        if (!event) return Object.keys(events).forEach(ev => events[ev] = [])\n        if (!handler) return events[event] = []\n        events[event] = events[event].filter(ev => ev !== handler);\n    }\n\n    function trigger (event, ...args) {\n        events[event].forEach(handler => handler(...args));\n    }\n\n    var processingScheduled = false;\n    function _insert(data, insertAtFront, rejectOnError, callback) {\n        if (callback != null && typeof callback !== 'function') {\n            throw new Error('task callback must be a function');\n        }\n        q.started = true;\n\n        var res, rej;\n        function promiseCallback (err, ...args) {\n            // we don't care about the error, let the global error handler\n            // deal with it\n            if (err) return rejectOnError ? rej(err) : res()\n            if (args.length <= 1) return res(args[0])\n            res(args);\n        }\n\n        var item = {\n            data,\n            callback: rejectOnError ?\n                promiseCallback :\n                (callback || promiseCallback)\n        };\n\n        if (insertAtFront) {\n            q._tasks.unshift(item);\n        } else {\n            q._tasks.push(item);\n        }\n\n        if (!processingScheduled) {\n            processingScheduled = true;\n            setImmediate$1(() => {\n                processingScheduled = false;\n                q.process();\n            });\n        }\n\n        if (rejectOnError || !callback) {\n            return new Promise((resolve, reject) => {\n                res = resolve;\n                rej = reject;\n            })\n        }\n    }\n\n    function _createCB(tasks) {\n        return function (err, ...args) {\n            numRunning -= 1;\n\n            for (var i = 0, l = tasks.length; i < l; i++) {\n                var task = tasks[i];\n\n                var index = workersList.indexOf(task);\n                if (index === 0) {\n                    workersList.shift();\n                } else if (index > 0) {\n                    workersList.splice(index, 1);\n                }\n\n                task.callback(err, ...args);\n\n                if (err != null) {\n                    trigger('error', err, task.data);\n                }\n            }\n\n            if (numRunning <= (q.concurrency - q.buffer) ) {\n                trigger('unsaturated');\n            }\n\n            if (q.idle()) {\n                trigger('drain');\n            }\n            q.process();\n        };\n    }\n\n    function _maybeDrain(data) {\n        if (data.length === 0 && q.idle()) {\n            // call drain immediately if there are no tasks\n            setImmediate$1(() => trigger('drain'));\n            return true\n        }\n        return false\n    }\n\n    const eventMethod = (name) => (handler) => {\n        if (!handler) {\n            return new Promise((resolve, reject) => {\n                once(name, (err, data) => {\n                    if (err) return reject(err)\n                    resolve(data);\n                });\n            })\n        }\n        off(name);\n        on(name, handler);\n\n    };\n\n    var isProcessing = false;\n    var q = {\n        _tasks: new DLL(),\n        *[Symbol.iterator] () {\n            yield* q._tasks[Symbol.iterator]();\n        },\n        concurrency,\n        payload,\n        buffer: concurrency / 4,\n        started: false,\n        paused: false,\n        push (data, callback) {\n            if (Array.isArray(data)) {\n                if (_maybeDrain(data)) return\n                return data.map(datum => _insert(datum, false, false, callback))\n            }\n            return _insert(data, false, false, callback);\n        },\n        pushAsync (data, callback) {\n            if (Array.isArray(data)) {\n                if (_maybeDrain(data)) return\n                return data.map(datum => _insert(datum, false, true, callback))\n            }\n            return _insert(data, false, true, callback);\n        },\n        kill () {\n            off();\n            q._tasks.empty();\n        },\n        unshift (data, callback) {\n            if (Array.isArray(data)) {\n                if (_maybeDrain(data)) return\n                return data.map(datum => _insert(datum, true, false, callback))\n            }\n            return _insert(data, true, false, callback);\n        },\n        unshiftAsync (data, callback) {\n            if (Array.isArray(data)) {\n                if (_maybeDrain(data)) return\n                return data.map(datum => _insert(datum, true, true, callback))\n            }\n            return _insert(data, true, true, callback);\n        },\n        remove (testFn) {\n            q._tasks.remove(testFn);\n        },\n        process () {\n            // Avoid trying to start too many processing operations. This can occur\n            // when callbacks resolve synchronously (#1267).\n            if (isProcessing) {\n                return;\n            }\n            isProcessing = true;\n            while(!q.paused && numRunning < q.concurrency && q._tasks.length){\n                var tasks = [], data = [];\n                var l = q._tasks.length;\n                if (q.payload) l = Math.min(l, q.payload);\n                for (var i = 0; i < l; i++) {\n                    var node = q._tasks.shift();\n                    tasks.push(node);\n                    workersList.push(node);\n                    data.push(node.data);\n                }\n\n                numRunning += 1;\n\n                if (q._tasks.length === 0) {\n                    trigger('empty');\n                }\n\n                if (numRunning === q.concurrency) {\n                    trigger('saturated');\n                }\n\n                var cb = onlyOnce(_createCB(tasks));\n                _worker(data, cb);\n            }\n            isProcessing = false;\n        },\n        length () {\n            return q._tasks.length;\n        },\n        running () {\n            return numRunning;\n        },\n        workersList () {\n            return workersList;\n        },\n        idle() {\n            return q._tasks.length + numRunning === 0;\n        },\n        pause () {\n            q.paused = true;\n        },\n        resume () {\n            if (q.paused === false) { return; }\n            q.paused = false;\n            setImmediate$1(q.process);\n        }\n    };\n    // define these as fixed properties, so people get useful errors when updating\n    Object.defineProperties(q, {\n        saturated: {\n            writable: false,\n            value: eventMethod('saturated')\n        },\n        unsaturated: {\n            writable: false,\n            value: eventMethod('unsaturated')\n        },\n        empty: {\n            writable: false,\n            value: eventMethod('empty')\n        },\n        drain: {\n            writable: false,\n            value: eventMethod('drain')\n        },\n        error: {\n            writable: false,\n            value: eventMethod('error')\n        },\n    });\n    return q;\n}\n\n/**\n * Creates a `cargo` object with the specified payload. Tasks added to the\n * cargo will be processed altogether (up to the `payload` limit). If the\n * `worker` is in progress, the task is queued until it becomes available. Once\n * the `worker` has completed some tasks, each callback of those tasks is\n * called. Check out [these](https://camo.githubusercontent.com/6bbd36f4cf5b35a0f11a96dcd2e97711ffc2fb37/68747470733a2f2f662e636c6f75642e6769746875622e636f6d2f6173736574732f313637363837312f36383130382f62626330636662302d356632392d313165322d393734662d3333393763363464633835382e676966) [animations](https://camo.githubusercontent.com/f4810e00e1c5f5f8addbe3e9f49064fd5d102699/68747470733a2f2f662e636c6f75642e6769746875622e636f6d2f6173736574732f313637363837312f36383130312f38346339323036362d356632392d313165322d383134662d3964336430323431336266642e676966)\n * for how `cargo` and `queue` work.\n *\n * While [`queue`]{@link module:ControlFlow.queue} passes only one task to one of a group of workers\n * at a time, cargo passes an array of tasks to a single worker, repeating\n * when the worker is finished.\n *\n * @name cargo\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.queue]{@link module:ControlFlow.queue}\n * @category Control Flow\n * @param {AsyncFunction} worker - An asynchronous function for processing an array\n * of queued tasks. Invoked with `(tasks, callback)`.\n * @param {number} [payload=Infinity] - An optional `integer` for determining\n * how many tasks should be processed per round; if omitted, the default is\n * unlimited.\n * @returns {module:ControlFlow.QueueObject} A cargo object to manage the tasks. Callbacks can\n * attached as certain properties to listen for specific events during the\n * lifecycle of the cargo and inner queue.\n * @example\n *\n * // create a cargo object with payload 2\n * var cargo = async.cargo(function(tasks, callback) {\n *     for (var i=0; i<tasks.length; i++) {\n *         console.log('hello ' + tasks[i].name);\n *     }\n *     callback();\n * }, 2);\n *\n * // add some items\n * cargo.push({name: 'foo'}, function(err) {\n *     console.log('finished processing foo');\n * });\n * cargo.push({name: 'bar'}, function(err) {\n *     console.log('finished processing bar');\n * });\n * await cargo.push({name: 'baz'});\n * console.log('finished processing baz');\n */\nfunction cargo(worker, payload) {\n    return queue(worker, 1, payload);\n}\n\n/**\n * Creates a `cargoQueue` object with the specified payload. Tasks added to the\n * cargoQueue will be processed together (up to the `payload` limit) in `concurrency` parallel workers.\n * If the all `workers` are in progress, the task is queued until one becomes available. Once\n * a `worker` has completed some tasks, each callback of those tasks is\n * called. Check out [these](https://camo.githubusercontent.com/6bbd36f4cf5b35a0f11a96dcd2e97711ffc2fb37/68747470733a2f2f662e636c6f75642e6769746875622e636f6d2f6173736574732f313637363837312f36383130382f62626330636662302d356632392d313165322d393734662d3333393763363464633835382e676966) [animations](https://camo.githubusercontent.com/f4810e00e1c5f5f8addbe3e9f49064fd5d102699/68747470733a2f2f662e636c6f75642e6769746875622e636f6d2f6173736574732f313637363837312f36383130312f38346339323036362d356632392d313165322d383134662d3964336430323431336266642e676966)\n * for how `cargo` and `queue` work.\n *\n * While [`queue`]{@link module:ControlFlow.queue} passes only one task to one of a group of workers\n * at a time, and [`cargo`]{@link module:ControlFlow.cargo} passes an array of tasks to a single worker,\n * the cargoQueue passes an array of tasks to multiple parallel workers.\n *\n * @name cargoQueue\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.queue]{@link module:ControlFlow.queue}\n * @see [async.cargo]{@link module:ControlFLow.cargo}\n * @category Control Flow\n * @param {AsyncFunction} worker - An asynchronous function for processing an array\n * of queued tasks. Invoked with `(tasks, callback)`.\n * @param {number} [concurrency=1] - An `integer` for determining how many\n * `worker` functions should be run in parallel.  If omitted, the concurrency\n * defaults to `1`.  If the concurrency is `0`, an error is thrown.\n * @param {number} [payload=Infinity] - An optional `integer` for determining\n * how many tasks should be processed per round; if omitted, the default is\n * unlimited.\n * @returns {module:ControlFlow.QueueObject} A cargoQueue object to manage the tasks. Callbacks can\n * attached as certain properties to listen for specific events during the\n * lifecycle of the cargoQueue and inner queue.\n * @example\n *\n * // create a cargoQueue object with payload 2 and concurrency 2\n * var cargoQueue = async.cargoQueue(function(tasks, callback) {\n *     for (var i=0; i<tasks.length; i++) {\n *         console.log('hello ' + tasks[i].name);\n *     }\n *     callback();\n * }, 2, 2);\n *\n * // add some items\n * cargoQueue.push({name: 'foo'}, function(err) {\n *     console.log('finished processing foo');\n * });\n * cargoQueue.push({name: 'bar'}, function(err) {\n *     console.log('finished processing bar');\n * });\n * cargoQueue.push({name: 'baz'}, function(err) {\n *     console.log('finished processing baz');\n * });\n * cargoQueue.push({name: 'boo'}, function(err) {\n *     console.log('finished processing boo');\n * });\n */\nfunction cargo$1(worker, concurrency, payload) {\n    return queue(worker, concurrency, payload);\n}\n\n/**\n * Reduces `coll` into a single value using an async `iteratee` to return each\n * successive step. `memo` is the initial state of the reduction. This function\n * only operates in series.\n *\n * For performance reasons, it may make sense to split a call to this function\n * into a parallel map, and then use the normal `Array.prototype.reduce` on the\n * results. This function is for situations where each step in the reduction\n * needs to be async; if you can get the data before reducing it, then it's\n * probably a good idea to do so.\n *\n * @name reduce\n * @static\n * @memberOf module:Collections\n * @method\n * @alias inject\n * @alias foldl\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {*} memo - The initial state of the reduction.\n * @param {AsyncFunction} iteratee - A function applied to each item in the\n * array to produce the next step in the reduction.\n * The `iteratee` should complete with the next state of the reduction.\n * If the iteratee completes with an error, the reduction is stopped and the\n * main `callback` is immediately called with the error.\n * Invoked with (memo, item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Result is the reduced value. Invoked with\n * (err, result).\n * @returns {Promise} a promise, if no callback is passed\n * @example\n *\n * // file1.txt is a file that is 1000 bytes in size\n * // file2.txt is a file that is 2000 bytes in size\n * // file3.txt is a file that is 3000 bytes in size\n * // file4.txt does not exist\n *\n * const fileList = ['file1.txt','file2.txt','file3.txt'];\n * const withMissingFileList = ['file1.txt','file2.txt','file3.txt', 'file4.txt'];\n *\n * // asynchronous function that computes the file size in bytes\n * // file size is added to the memoized value, then returned\n * function getFileSizeInBytes(memo, file, callback) {\n *     fs.stat(file, function(err, stat) {\n *         if (err) {\n *             return callback(err);\n *         }\n *         callback(null, memo + stat.size);\n *     });\n * }\n *\n * // Using callbacks\n * async.reduce(fileList, 0, getFileSizeInBytes, function(err, result) {\n *     if (err) {\n *         console.log(err);\n *     } else {\n *         console.log(result);\n *         // 6000\n *         // which is the sum of the file sizes of the three files\n *     }\n * });\n *\n * // Error Handling\n * async.reduce(withMissingFileList, 0, getFileSizeInBytes, function(err, result) {\n *     if (err) {\n *         console.log(err);\n *         // [ Error: ENOENT: no such file or directory ]\n *     } else {\n *         console.log(result);\n *     }\n * });\n *\n * // Using Promises\n * async.reduce(fileList, 0, getFileSizeInBytes)\n * .then( result => {\n *     console.log(result);\n *     // 6000\n *     // which is the sum of the file sizes of the three files\n * }).catch( err => {\n *     console.log(err);\n * });\n *\n * // Error Handling\n * async.reduce(withMissingFileList, 0, getFileSizeInBytes)\n * .then( result => {\n *     console.log(result);\n * }).catch( err => {\n *     console.log(err);\n *     // [ Error: ENOENT: no such file or directory ]\n * });\n *\n * // Using async/await\n * async () => {\n *     try {\n *         let result = await async.reduce(fileList, 0, getFileSizeInBytes);\n *         console.log(result);\n *         // 6000\n *         // which is the sum of the file sizes of the three files\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n * // Error Handling\n * async () => {\n *     try {\n *         let result = await async.reduce(withMissingFileList, 0, getFileSizeInBytes);\n *         console.log(result);\n *     }\n *     catch (err) {\n *         console.log(err);\n *         // [ Error: ENOENT: no such file or directory ]\n *     }\n * }\n *\n */\nfunction reduce(coll, memo, iteratee, callback) {\n    callback = once(callback);\n    var _iteratee = wrapAsync(iteratee);\n    return eachOfSeries$1(coll, (x, i, iterCb) => {\n        _iteratee(memo, x, (err, v) => {\n            memo = v;\n            iterCb(err);\n        });\n    }, err => callback(err, memo));\n}\nvar reduce$1 = awaitify(reduce, 4);\n\n/**\n * Version of the compose function that is more natural to read. Each function\n * consumes the return value of the previous function. It is the equivalent of\n * [compose]{@link module:ControlFlow.compose} with the arguments reversed.\n *\n * Each function is executed with the `this` binding of the composed function.\n *\n * @name seq\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.compose]{@link module:ControlFlow.compose}\n * @category Control Flow\n * @param {...AsyncFunction} functions - the asynchronous functions to compose\n * @returns {Function} a function that composes the `functions` in order\n * @example\n *\n * // Requires lodash (or underscore), express3 and dresende's orm2.\n * // Part of an app, that fetches cats of the logged user.\n * // This example uses `seq` function to avoid overnesting and error\n * // handling clutter.\n * app.get('/cats', function(request, response) {\n *     var User = request.models.User;\n *     async.seq(\n *         User.get.bind(User),  // 'User.get' has signature (id, callback(err, data))\n *         function(user, fn) {\n *             user.getCats(fn);      // 'getCats' has signature (callback(err, data))\n *         }\n *     )(req.session.user_id, function (err, cats) {\n *         if (err) {\n *             console.error(err);\n *             response.json({ status: 'error', message: err.message });\n *         } else {\n *             response.json({ status: 'ok', message: 'Cats found', data: cats });\n *         }\n *     });\n * });\n */\nfunction seq(...functions) {\n    var _functions = functions.map(wrapAsync);\n    return function (...args) {\n        var that = this;\n\n        var cb = args[args.length - 1];\n        if (typeof cb == 'function') {\n            args.pop();\n        } else {\n            cb = promiseCallback();\n        }\n\n        reduce$1(_functions, args, (newargs, fn, iterCb) => {\n            fn.apply(that, newargs.concat((err, ...nextargs) => {\n                iterCb(err, nextargs);\n            }));\n        },\n        (err, results) => cb(err, ...results));\n\n        return cb[PROMISE_SYMBOL]\n    };\n}\n\n/**\n * Creates a function which is a composition of the passed asynchronous\n * functions. Each function consumes the return value of the function that\n * follows. Composing functions `f()`, `g()`, and `h()` would produce the result\n * of `f(g(h()))`, only this version uses callbacks to obtain the return values.\n *\n * If the last argument to the composed function is not a function, a promise\n * is returned when you call it.\n *\n * Each function is executed with the `this` binding of the composed function.\n *\n * @name compose\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @param {...AsyncFunction} functions - the asynchronous functions to compose\n * @returns {Function} an asynchronous function that is the composed\n * asynchronous `functions`\n * @example\n *\n * function add1(n, callback) {\n *     setTimeout(function () {\n *         callback(null, n + 1);\n *     }, 10);\n * }\n *\n * function mul3(n, callback) {\n *     setTimeout(function () {\n *         callback(null, n * 3);\n *     }, 10);\n * }\n *\n * var add1mul3 = async.compose(mul3, add1);\n * add1mul3(4, function (err, result) {\n *     // result now equals 15\n * });\n */\nfunction compose(...args) {\n    return seq(...args.reverse());\n}\n\n/**\n * The same as [`map`]{@link module:Collections.map} but runs a maximum of `limit` async operations at a time.\n *\n * @name mapLimit\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.map]{@link module:Collections.map}\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {AsyncFunction} iteratee - An async function to apply to each item in\n * `coll`.\n * The iteratee should complete with the transformed item.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called when all `iteratee`\n * functions have finished, or an error occurs. Results is an array of the\n * transformed items from the `coll`. Invoked with (err, results).\n * @returns {Promise} a promise, if no callback is passed\n */\nfunction mapLimit (coll, limit, iteratee, callback) {\n    return _asyncMap(eachOfLimit(limit), coll, iteratee, callback)\n}\nvar mapLimit$1 = awaitify(mapLimit, 4);\n\n/**\n * The same as [`concat`]{@link module:Collections.concat} but runs a maximum of `limit` async operations at a time.\n *\n * @name concatLimit\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.concat]{@link module:Collections.concat}\n * @category Collection\n * @alias flatMapLimit\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {AsyncFunction} iteratee - A function to apply to each item in `coll`,\n * which should use an array as its result. Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished, or an error occurs. Results is an array\n * containing the concatenated results of the `iteratee` function. Invoked with\n * (err, results).\n * @returns A Promise, if no callback is passed\n */\nfunction concatLimit(coll, limit, iteratee, callback) {\n    var _iteratee = wrapAsync(iteratee);\n    return mapLimit$1(coll, limit, (val, iterCb) => {\n        _iteratee(val, (err, ...args) => {\n            if (err) return iterCb(err);\n            return iterCb(err, args);\n        });\n    }, (err, mapResults) => {\n        var result = [];\n        for (var i = 0; i < mapResults.length; i++) {\n            if (mapResults[i]) {\n                result = result.concat(...mapResults[i]);\n            }\n        }\n\n        return callback(err, result);\n    });\n}\nvar concatLimit$1 = awaitify(concatLimit, 4);\n\n/**\n * Applies `iteratee` to each item in `coll`, concatenating the results. Returns\n * the concatenated list. The `iteratee`s are called in parallel, and the\n * results are concatenated as they return. The results array will be returned in\n * the original order of `coll` passed to the `iteratee` function.\n *\n * @name concat\n * @static\n * @memberOf module:Collections\n * @method\n * @category Collection\n * @alias flatMap\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - A function to apply to each item in `coll`,\n * which should use an array as its result. Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished, or an error occurs. Results is an array\n * containing the concatenated results of the `iteratee` function. Invoked with\n * (err, results).\n * @returns A Promise, if no callback is passed\n * @example\n *\n * // dir1 is a directory that contains file1.txt, file2.txt\n * // dir2 is a directory that contains file3.txt, file4.txt\n * // dir3 is a directory that contains file5.txt\n * // dir4 does not exist\n *\n * let directoryList = ['dir1','dir2','dir3'];\n * let withMissingDirectoryList = ['dir1','dir2','dir3', 'dir4'];\n *\n * // Using callbacks\n * async.concat(directoryList, fs.readdir, function(err, results) {\n *    if (err) {\n *        console.log(err);\n *    } else {\n *        console.log(results);\n *        // [ 'file1.txt', 'file2.txt', 'file3.txt', 'file4.txt', file5.txt ]\n *    }\n * });\n *\n * // Error Handling\n * async.concat(withMissingDirectoryList, fs.readdir, function(err, results) {\n *    if (err) {\n *        console.log(err);\n *        // [ Error: ENOENT: no such file or directory ]\n *        // since dir4 does not exist\n *    } else {\n *        console.log(results);\n *    }\n * });\n *\n * // Using Promises\n * async.concat(directoryList, fs.readdir)\n * .then(results => {\n *     console.log(results);\n *     // [ 'file1.txt', 'file2.txt', 'file3.txt', 'file4.txt', file5.txt ]\n * }).catch(err => {\n *      console.log(err);\n * });\n *\n * // Error Handling\n * async.concat(withMissingDirectoryList, fs.readdir)\n * .then(results => {\n *     console.log(results);\n * }).catch(err => {\n *     console.log(err);\n *     // [ Error: ENOENT: no such file or directory ]\n *     // since dir4 does not exist\n * });\n *\n * // Using async/await\n * async () => {\n *     try {\n *         let results = await async.concat(directoryList, fs.readdir);\n *         console.log(results);\n *         // [ 'file1.txt', 'file2.txt', 'file3.txt', 'file4.txt', file5.txt ]\n *     } catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n * // Error Handling\n * async () => {\n *     try {\n *         let results = await async.concat(withMissingDirectoryList, fs.readdir);\n *         console.log(results);\n *     } catch (err) {\n *         console.log(err);\n *         // [ Error: ENOENT: no such file or directory ]\n *         // since dir4 does not exist\n *     }\n * }\n *\n */\nfunction concat(coll, iteratee, callback) {\n    return concatLimit$1(coll, Infinity, iteratee, callback)\n}\nvar concat$1 = awaitify(concat, 3);\n\n/**\n * The same as [`concat`]{@link module:Collections.concat} but runs only a single async operation at a time.\n *\n * @name concatSeries\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.concat]{@link module:Collections.concat}\n * @category Collection\n * @alias flatMapSeries\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - A function to apply to each item in `coll`.\n * The iteratee should complete with an array an array of results.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished, or an error occurs. Results is an array\n * containing the concatenated results of the `iteratee` function. Invoked with\n * (err, results).\n * @returns A Promise, if no callback is passed\n */\nfunction concatSeries(coll, iteratee, callback) {\n    return concatLimit$1(coll, 1, iteratee, callback)\n}\nvar concatSeries$1 = awaitify(concatSeries, 3);\n\n/**\n * Returns a function that when called, calls-back with the values provided.\n * Useful as the first function in a [`waterfall`]{@link module:ControlFlow.waterfall}, or for plugging values in to\n * [`auto`]{@link module:ControlFlow.auto}.\n *\n * @name constant\n * @static\n * @memberOf module:Utils\n * @method\n * @category Util\n * @param {...*} arguments... - Any number of arguments to automatically invoke\n * callback with.\n * @returns {AsyncFunction} Returns a function that when invoked, automatically\n * invokes the callback with the previous given arguments.\n * @example\n *\n * async.waterfall([\n *     async.constant(42),\n *     function (value, next) {\n *         // value === 42\n *     },\n *     //...\n * ], callback);\n *\n * async.waterfall([\n *     async.constant(filename, \"utf8\"),\n *     fs.readFile,\n *     function (fileData, next) {\n *         //...\n *     }\n *     //...\n * ], callback);\n *\n * async.auto({\n *     hostname: async.constant(\"https://server.net/\"),\n *     port: findFreePort,\n *     launchServer: [\"hostname\", \"port\", function (options, cb) {\n *         startServer(options, cb);\n *     }],\n *     //...\n * }, callback);\n */\nfunction constant(...args) {\n    return function (...ignoredArgs/*, callback*/) {\n        var callback = ignoredArgs.pop();\n        return callback(null, ...args);\n    };\n}\n\nfunction _createTester(check, getResult) {\n    return (eachfn, arr, _iteratee, cb) => {\n        var testPassed = false;\n        var testResult;\n        const iteratee = wrapAsync(_iteratee);\n        eachfn(arr, (value, _, callback) => {\n            iteratee(value, (err, result) => {\n                if (err || err === false) return callback(err);\n\n                if (check(result) && !testResult) {\n                    testPassed = true;\n                    testResult = getResult(true, value);\n                    return callback(null, breakLoop);\n                }\n                callback();\n            });\n        }, err => {\n            if (err) return cb(err);\n            cb(null, testPassed ? testResult : getResult(false));\n        });\n    };\n}\n\n/**\n * Returns the first value in `coll` that passes an async truth test. The\n * `iteratee` is applied in parallel, meaning the first iteratee to return\n * `true` will fire the detect `callback` with that result. That means the\n * result might not be the first item in the original `coll` (in terms of order)\n * that passes the test.\n\n * If order within the original `coll` is important, then look at\n * [`detectSeries`]{@link module:Collections.detectSeries}.\n *\n * @name detect\n * @static\n * @memberOf module:Collections\n * @method\n * @alias find\n * @category Collections\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - A truth test to apply to each item in `coll`.\n * The iteratee must complete with a boolean value as its result.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called as soon as any\n * iteratee returns `true`, or after all the `iteratee` functions have finished.\n * Result will be the first item in the array that passes the truth test\n * (iteratee) or the value `undefined` if none passed. Invoked with\n * (err, result).\n * @returns A Promise, if no callback is passed\n * @example\n *\n * // dir1 is a directory that contains file1.txt, file2.txt\n * // dir2 is a directory that contains file3.txt, file4.txt\n * // dir3 is a directory that contains file5.txt\n *\n * // asynchronous function that checks if a file exists\n * function fileExists(file, callback) {\n *    fs.access(file, fs.constants.F_OK, (err) => {\n *        callback(null, !err);\n *    });\n * }\n *\n * async.detect(['file3.txt','file2.txt','dir1/file1.txt'], fileExists,\n *    function(err, result) {\n *        console.log(result);\n *        // dir1/file1.txt\n *        // result now equals the first file in the list that exists\n *    }\n *);\n *\n * // Using Promises\n * async.detect(['file3.txt','file2.txt','dir1/file1.txt'], fileExists)\n * .then(result => {\n *     console.log(result);\n *     // dir1/file1.txt\n *     // result now equals the first file in the list that exists\n * }).catch(err => {\n *     console.log(err);\n * });\n *\n * // Using async/await\n * async () => {\n *     try {\n *         let result = await async.detect(['file3.txt','file2.txt','dir1/file1.txt'], fileExists);\n *         console.log(result);\n *         // dir1/file1.txt\n *         // result now equals the file in the list that exists\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n */\nfunction detect(coll, iteratee, callback) {\n    return _createTester(bool => bool, (res, item) => item)(eachOf$1, coll, iteratee, callback)\n}\nvar detect$1 = awaitify(detect, 3);\n\n/**\n * The same as [`detect`]{@link module:Collections.detect} but runs a maximum of `limit` async operations at a\n * time.\n *\n * @name detectLimit\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.detect]{@link module:Collections.detect}\n * @alias findLimit\n * @category Collections\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {AsyncFunction} iteratee - A truth test to apply to each item in `coll`.\n * The iteratee must complete with a boolean value as its result.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called as soon as any\n * iteratee returns `true`, or after all the `iteratee` functions have finished.\n * Result will be the first item in the array that passes the truth test\n * (iteratee) or the value `undefined` if none passed. Invoked with\n * (err, result).\n * @returns a Promise if no callback is passed\n */\nfunction detectLimit(coll, limit, iteratee, callback) {\n    return _createTester(bool => bool, (res, item) => item)(eachOfLimit(limit), coll, iteratee, callback)\n}\nvar detectLimit$1 = awaitify(detectLimit, 4);\n\n/**\n * The same as [`detect`]{@link module:Collections.detect} but runs only a single async operation at a time.\n *\n * @name detectSeries\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.detect]{@link module:Collections.detect}\n * @alias findSeries\n * @category Collections\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - A truth test to apply to each item in `coll`.\n * The iteratee must complete with a boolean value as its result.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called as soon as any\n * iteratee returns `true`, or after all the `iteratee` functions have finished.\n * Result will be the first item in the array that passes the truth test\n * (iteratee) or the value `undefined` if none passed. Invoked with\n * (err, result).\n * @returns a Promise if no callback is passed\n */\nfunction detectSeries(coll, iteratee, callback) {\n    return _createTester(bool => bool, (res, item) => item)(eachOfLimit(1), coll, iteratee, callback)\n}\n\nvar detectSeries$1 = awaitify(detectSeries, 3);\n\nfunction consoleFunc(name) {\n    return (fn, ...args) => wrapAsync(fn)(...args, (err, ...resultArgs) => {\n        /* istanbul ignore else */\n        if (typeof console === 'object') {\n            /* istanbul ignore else */\n            if (err) {\n                /* istanbul ignore else */\n                if (console.error) {\n                    console.error(err);\n                }\n            } else if (console[name]) { /* istanbul ignore else */\n                resultArgs.forEach(x => console[name](x));\n            }\n        }\n    })\n}\n\n/**\n * Logs the result of an [`async` function]{@link AsyncFunction} to the\n * `console` using `console.dir` to display the properties of the resulting object.\n * Only works in Node.js or in browsers that support `console.dir` and\n * `console.error` (such as FF and Chrome).\n * If multiple arguments are returned from the async function,\n * `console.dir` is called on each argument in order.\n *\n * @name dir\n * @static\n * @memberOf module:Utils\n * @method\n * @category Util\n * @param {AsyncFunction} function - The function you want to eventually apply\n * all arguments to.\n * @param {...*} arguments... - Any number of arguments to apply to the function.\n * @example\n *\n * // in a module\n * var hello = function(name, callback) {\n *     setTimeout(function() {\n *         callback(null, {hello: name});\n *     }, 1000);\n * };\n *\n * // in the node repl\n * node> async.dir(hello, 'world');\n * {hello: 'world'}\n */\nvar dir = consoleFunc('dir');\n\n/**\n * The post-check version of [`whilst`]{@link module:ControlFlow.whilst}. To reflect the difference in\n * the order of operations, the arguments `test` and `iteratee` are switched.\n *\n * `doWhilst` is to `whilst` as `do while` is to `while` in plain JavaScript.\n *\n * @name doWhilst\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.whilst]{@link module:ControlFlow.whilst}\n * @category Control Flow\n * @param {AsyncFunction} iteratee - A function which is called each time `test`\n * passes. Invoked with (callback).\n * @param {AsyncFunction} test - asynchronous truth test to perform after each\n * execution of `iteratee`. Invoked with (...args, callback), where `...args` are the\n * non-error args from the previous callback of `iteratee`.\n * @param {Function} [callback] - A callback which is called after the test\n * function has failed and repeated execution of `iteratee` has stopped.\n * `callback` will be passed an error and any arguments passed to the final\n * `iteratee`'s callback. Invoked with (err, [results]);\n * @returns {Promise} a promise, if no callback is passed\n */\nfunction doWhilst(iteratee, test, callback) {\n    callback = onlyOnce(callback);\n    var _fn = wrapAsync(iteratee);\n    var _test = wrapAsync(test);\n    var results;\n\n    function next(err, ...args) {\n        if (err) return callback(err);\n        if (err === false) return;\n        results = args;\n        _test(...args, check);\n    }\n\n    function check(err, truth) {\n        if (err) return callback(err);\n        if (err === false) return;\n        if (!truth) return callback(null, ...results);\n        _fn(next);\n    }\n\n    return check(null, true);\n}\n\nvar doWhilst$1 = awaitify(doWhilst, 3);\n\n/**\n * Like ['doWhilst']{@link module:ControlFlow.doWhilst}, except the `test` is inverted. Note the\n * argument ordering differs from `until`.\n *\n * @name doUntil\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.doWhilst]{@link module:ControlFlow.doWhilst}\n * @category Control Flow\n * @param {AsyncFunction} iteratee - An async function which is called each time\n * `test` fails. Invoked with (callback).\n * @param {AsyncFunction} test - asynchronous truth test to perform after each\n * execution of `iteratee`. Invoked with (...args, callback), where `...args` are the\n * non-error args from the previous callback of `iteratee`\n * @param {Function} [callback] - A callback which is called after the test\n * function has passed and repeated execution of `iteratee` has stopped. `callback`\n * will be passed an error and any arguments passed to the final `iteratee`'s\n * callback. Invoked with (err, [results]);\n * @returns {Promise} a promise, if no callback is passed\n */\nfunction doUntil(iteratee, test, callback) {\n    const _test = wrapAsync(test);\n    return doWhilst$1(iteratee, (...args) => {\n        const cb = args.pop();\n        _test(...args, (err, truth) => cb (err, !truth));\n    }, callback);\n}\n\nfunction _withoutIndex(iteratee) {\n    return (value, index, callback) => iteratee(value, callback);\n}\n\n/**\n * Applies the function `iteratee` to each item in `coll`, in parallel.\n * The `iteratee` is called with an item from the list, and a callback for when\n * it has finished. If the `iteratee` passes an error to its `callback`, the\n * main `callback` (for the `each` function) is immediately called with the\n * error.\n *\n * Note, that since this function applies `iteratee` to each item in parallel,\n * there is no guarantee that the iteratee functions will complete in order.\n *\n * @name each\n * @static\n * @memberOf module:Collections\n * @method\n * @alias forEach\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async function to apply to\n * each item in `coll`. Invoked with (item, callback).\n * The array index is not passed to the iteratee.\n * If you need the index, use `eachOf`.\n * @param {Function} [callback] - A callback which is called when all\n * `iteratee` functions have finished, or an error occurs. Invoked with (err).\n * @returns {Promise} a promise, if a callback is omitted\n * @example\n *\n * // dir1 is a directory that contains file1.txt, file2.txt\n * // dir2 is a directory that contains file3.txt, file4.txt\n * // dir3 is a directory that contains file5.txt\n * // dir4 does not exist\n *\n * const fileList = [ 'dir1/file2.txt', 'dir2/file3.txt', 'dir/file5.txt'];\n * const withMissingFileList = ['dir1/file1.txt', 'dir4/file2.txt'];\n *\n * // asynchronous function that deletes a file\n * const deleteFile = function(file, callback) {\n *     fs.unlink(file, callback);\n * };\n *\n * // Using callbacks\n * async.each(fileList, deleteFile, function(err) {\n *     if( err ) {\n *         console.log(err);\n *     } else {\n *         console.log('All files have been deleted successfully');\n *     }\n * });\n *\n * // Error Handling\n * async.each(withMissingFileList, deleteFile, function(err){\n *     console.log(err);\n *     // [ Error: ENOENT: no such file or directory ]\n *     // since dir4/file2.txt does not exist\n *     // dir1/file1.txt could have been deleted\n * });\n *\n * // Using Promises\n * async.each(fileList, deleteFile)\n * .then( () => {\n *     console.log('All files have been deleted successfully');\n * }).catch( err => {\n *     console.log(err);\n * });\n *\n * // Error Handling\n * async.each(fileList, deleteFile)\n * .then( () => {\n *     console.log('All files have been deleted successfully');\n * }).catch( err => {\n *     console.log(err);\n *     // [ Error: ENOENT: no such file or directory ]\n *     // since dir4/file2.txt does not exist\n *     // dir1/file1.txt could have been deleted\n * });\n *\n * // Using async/await\n * async () => {\n *     try {\n *         await async.each(files, deleteFile);\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n * // Error Handling\n * async () => {\n *     try {\n *         await async.each(withMissingFileList, deleteFile);\n *     }\n *     catch (err) {\n *         console.log(err);\n *         // [ Error: ENOENT: no such file or directory ]\n *         // since dir4/file2.txt does not exist\n *         // dir1/file1.txt could have been deleted\n *     }\n * }\n *\n */\nfunction eachLimit(coll, iteratee, callback) {\n    return eachOf$1(coll, _withoutIndex(wrapAsync(iteratee)), callback);\n}\n\nvar each = awaitify(eachLimit, 3);\n\n/**\n * The same as [`each`]{@link module:Collections.each} but runs a maximum of `limit` async operations at a time.\n *\n * @name eachLimit\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.each]{@link module:Collections.each}\n * @alias forEachLimit\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {AsyncFunction} iteratee - An async function to apply to each item in\n * `coll`.\n * The array index is not passed to the iteratee.\n * If you need the index, use `eachOfLimit`.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called when all\n * `iteratee` functions have finished, or an error occurs. Invoked with (err).\n * @returns {Promise} a promise, if a callback is omitted\n */\nfunction eachLimit$1(coll, limit, iteratee, callback) {\n    return eachOfLimit(limit)(coll, _withoutIndex(wrapAsync(iteratee)), callback);\n}\nvar eachLimit$2 = awaitify(eachLimit$1, 4);\n\n/**\n * The same as [`each`]{@link module:Collections.each} but runs only a single async operation at a time.\n *\n * Note, that unlike [`each`]{@link module:Collections.each}, this function applies iteratee to each item\n * in series and therefore the iteratee functions will complete in order.\n\n * @name eachSeries\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.each]{@link module:Collections.each}\n * @alias forEachSeries\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async function to apply to each\n * item in `coll`.\n * The array index is not passed to the iteratee.\n * If you need the index, use `eachOfSeries`.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called when all\n * `iteratee` functions have finished, or an error occurs. Invoked with (err).\n * @returns {Promise} a promise, if a callback is omitted\n */\nfunction eachSeries(coll, iteratee, callback) {\n    return eachLimit$2(coll, 1, iteratee, callback)\n}\nvar eachSeries$1 = awaitify(eachSeries, 3);\n\n/**\n * Wrap an async function and ensure it calls its callback on a later tick of\n * the event loop.  If the function already calls its callback on a next tick,\n * no extra deferral is added. This is useful for preventing stack overflows\n * (`RangeError: Maximum call stack size exceeded`) and generally keeping\n * [Zalgo](http://blog.izs.me/post/59142742143/designing-apis-for-asynchrony)\n * contained. ES2017 `async` functions are returned as-is -- they are immune\n * to Zalgo's corrupting influences, as they always resolve on a later tick.\n *\n * @name ensureAsync\n * @static\n * @memberOf module:Utils\n * @method\n * @category Util\n * @param {AsyncFunction} fn - an async function, one that expects a node-style\n * callback as its last argument.\n * @returns {AsyncFunction} Returns a wrapped function with the exact same call\n * signature as the function passed in.\n * @example\n *\n * function sometimesAsync(arg, callback) {\n *     if (cache[arg]) {\n *         return callback(null, cache[arg]); // this would be synchronous!!\n *     } else {\n *         doSomeIO(arg, callback); // this IO would be asynchronous\n *     }\n * }\n *\n * // this has a risk of stack overflows if many results are cached in a row\n * async.mapSeries(args, sometimesAsync, done);\n *\n * // this will defer sometimesAsync's callback if necessary,\n * // preventing stack overflows\n * async.mapSeries(args, async.ensureAsync(sometimesAsync), done);\n */\nfunction ensureAsync(fn) {\n    if (isAsync(fn)) return fn;\n    return function (...args/*, callback*/) {\n        var callback = args.pop();\n        var sync = true;\n        args.push((...innerArgs) => {\n            if (sync) {\n                setImmediate$1(() => callback(...innerArgs));\n            } else {\n                callback(...innerArgs);\n            }\n        });\n        fn.apply(this, args);\n        sync = false;\n    };\n}\n\n/**\n * Returns `true` if every element in `coll` satisfies an async test. If any\n * iteratee call returns `false`, the main `callback` is immediately called.\n *\n * @name every\n * @static\n * @memberOf module:Collections\n * @method\n * @alias all\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async truth test to apply to each item\n * in the collection in parallel.\n * The iteratee must complete with a boolean result value.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Result will be either `true` or `false`\n * depending on the values of the async tests. Invoked with (err, result).\n * @returns {Promise} a promise, if no callback provided\n * @example\n *\n * // dir1 is a directory that contains file1.txt, file2.txt\n * // dir2 is a directory that contains file3.txt, file4.txt\n * // dir3 is a directory that contains file5.txt\n * // dir4 does not exist\n *\n * const fileList = ['dir1/file1.txt','dir2/file3.txt','dir3/file5.txt'];\n * const withMissingFileList = ['file1.txt','file2.txt','file4.txt'];\n *\n * // asynchronous function that checks if a file exists\n * function fileExists(file, callback) {\n *    fs.access(file, fs.constants.F_OK, (err) => {\n *        callback(null, !err);\n *    });\n * }\n *\n * // Using callbacks\n * async.every(fileList, fileExists, function(err, result) {\n *     console.log(result);\n *     // true\n *     // result is true since every file exists\n * });\n *\n * async.every(withMissingFileList, fileExists, function(err, result) {\n *     console.log(result);\n *     // false\n *     // result is false since NOT every file exists\n * });\n *\n * // Using Promises\n * async.every(fileList, fileExists)\n * .then( result => {\n *     console.log(result);\n *     // true\n *     // result is true since every file exists\n * }).catch( err => {\n *     console.log(err);\n * });\n *\n * async.every(withMissingFileList, fileExists)\n * .then( result => {\n *     console.log(result);\n *     // false\n *     // result is false since NOT every file exists\n * }).catch( err => {\n *     console.log(err);\n * });\n *\n * // Using async/await\n * async () => {\n *     try {\n *         let result = await async.every(fileList, fileExists);\n *         console.log(result);\n *         // true\n *         // result is true since every file exists\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n * async () => {\n *     try {\n *         let result = await async.every(withMissingFileList, fileExists);\n *         console.log(result);\n *         // false\n *         // result is false since NOT every file exists\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n */\nfunction every(coll, iteratee, callback) {\n    return _createTester(bool => !bool, res => !res)(eachOf$1, coll, iteratee, callback)\n}\nvar every$1 = awaitify(every, 3);\n\n/**\n * The same as [`every`]{@link module:Collections.every} but runs a maximum of `limit` async operations at a time.\n *\n * @name everyLimit\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.every]{@link module:Collections.every}\n * @alias allLimit\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {AsyncFunction} iteratee - An async truth test to apply to each item\n * in the collection in parallel.\n * The iteratee must complete with a boolean result value.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Result will be either `true` or `false`\n * depending on the values of the async tests. Invoked with (err, result).\n * @returns {Promise} a promise, if no callback provided\n */\nfunction everyLimit(coll, limit, iteratee, callback) {\n    return _createTester(bool => !bool, res => !res)(eachOfLimit(limit), coll, iteratee, callback)\n}\nvar everyLimit$1 = awaitify(everyLimit, 4);\n\n/**\n * The same as [`every`]{@link module:Collections.every} but runs only a single async operation at a time.\n *\n * @name everySeries\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.every]{@link module:Collections.every}\n * @alias allSeries\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async truth test to apply to each item\n * in the collection in series.\n * The iteratee must complete with a boolean result value.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Result will be either `true` or `false`\n * depending on the values of the async tests. Invoked with (err, result).\n * @returns {Promise} a promise, if no callback provided\n */\nfunction everySeries(coll, iteratee, callback) {\n    return _createTester(bool => !bool, res => !res)(eachOfSeries$1, coll, iteratee, callback)\n}\nvar everySeries$1 = awaitify(everySeries, 3);\n\nfunction filterArray(eachfn, arr, iteratee, callback) {\n    var truthValues = new Array(arr.length);\n    eachfn(arr, (x, index, iterCb) => {\n        iteratee(x, (err, v) => {\n            truthValues[index] = !!v;\n            iterCb(err);\n        });\n    }, err => {\n        if (err) return callback(err);\n        var results = [];\n        for (var i = 0; i < arr.length; i++) {\n            if (truthValues[i]) results.push(arr[i]);\n        }\n        callback(null, results);\n    });\n}\n\nfunction filterGeneric(eachfn, coll, iteratee, callback) {\n    var results = [];\n    eachfn(coll, (x, index, iterCb) => {\n        iteratee(x, (err, v) => {\n            if (err) return iterCb(err);\n            if (v) {\n                results.push({index, value: x});\n            }\n            iterCb(err);\n        });\n    }, err => {\n        if (err) return callback(err);\n        callback(null, results\n            .sort((a, b) => a.index - b.index)\n            .map(v => v.value));\n    });\n}\n\nfunction _filter(eachfn, coll, iteratee, callback) {\n    var filter = isArrayLike(coll) ? filterArray : filterGeneric;\n    return filter(eachfn, coll, wrapAsync(iteratee), callback);\n}\n\n/**\n * Returns a new array of all the values in `coll` which pass an async truth\n * test. This operation is performed in parallel, but the results array will be\n * in the same order as the original.\n *\n * @name filter\n * @static\n * @memberOf module:Collections\n * @method\n * @alias select\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {Function} iteratee - A truth test to apply to each item in `coll`.\n * The `iteratee` is passed a `callback(err, truthValue)`, which must be called\n * with a boolean argument once it has completed. Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Invoked with (err, results).\n * @returns {Promise} a promise, if no callback provided\n * @example\n *\n * // dir1 is a directory that contains file1.txt, file2.txt\n * // dir2 is a directory that contains file3.txt, file4.txt\n * // dir3 is a directory that contains file5.txt\n *\n * const files = ['dir1/file1.txt','dir2/file3.txt','dir3/file6.txt'];\n *\n * // asynchronous function that checks if a file exists\n * function fileExists(file, callback) {\n *    fs.access(file, fs.constants.F_OK, (err) => {\n *        callback(null, !err);\n *    });\n * }\n *\n * // Using callbacks\n * async.filter(files, fileExists, function(err, results) {\n *    if(err) {\n *        console.log(err);\n *    } else {\n *        console.log(results);\n *        // [ 'dir1/file1.txt', 'dir2/file3.txt' ]\n *        // results is now an array of the existing files\n *    }\n * });\n *\n * // Using Promises\n * async.filter(files, fileExists)\n * .then(results => {\n *     console.log(results);\n *     // [ 'dir1/file1.txt', 'dir2/file3.txt' ]\n *     // results is now an array of the existing files\n * }).catch(err => {\n *     console.log(err);\n * });\n *\n * // Using async/await\n * async () => {\n *     try {\n *         let results = await async.filter(files, fileExists);\n *         console.log(results);\n *         // [ 'dir1/file1.txt', 'dir2/file3.txt' ]\n *         // results is now an array of the existing files\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n */\nfunction filter (coll, iteratee, callback) {\n    return _filter(eachOf$1, coll, iteratee, callback)\n}\nvar filter$1 = awaitify(filter, 3);\n\n/**\n * The same as [`filter`]{@link module:Collections.filter} but runs a maximum of `limit` async operations at a\n * time.\n *\n * @name filterLimit\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.filter]{@link module:Collections.filter}\n * @alias selectLimit\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {Function} iteratee - A truth test to apply to each item in `coll`.\n * The `iteratee` is passed a `callback(err, truthValue)`, which must be called\n * with a boolean argument once it has completed. Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Invoked with (err, results).\n * @returns {Promise} a promise, if no callback provided\n */\nfunction filterLimit (coll, limit, iteratee, callback) {\n    return _filter(eachOfLimit(limit), coll, iteratee, callback)\n}\nvar filterLimit$1 = awaitify(filterLimit, 4);\n\n/**\n * The same as [`filter`]{@link module:Collections.filter} but runs only a single async operation at a time.\n *\n * @name filterSeries\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.filter]{@link module:Collections.filter}\n * @alias selectSeries\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {Function} iteratee - A truth test to apply to each item in `coll`.\n * The `iteratee` is passed a `callback(err, truthValue)`, which must be called\n * with a boolean argument once it has completed. Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Invoked with (err, results)\n * @returns {Promise} a promise, if no callback provided\n */\nfunction filterSeries (coll, iteratee, callback) {\n    return _filter(eachOfSeries$1, coll, iteratee, callback)\n}\nvar filterSeries$1 = awaitify(filterSeries, 3);\n\n/**\n * Calls the asynchronous function `fn` with a callback parameter that allows it\n * to call itself again, in series, indefinitely.\n\n * If an error is passed to the callback then `errback` is called with the\n * error, and execution stops, otherwise it will never be called.\n *\n * @name forever\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @param {AsyncFunction} fn - an async function to call repeatedly.\n * Invoked with (next).\n * @param {Function} [errback] - when `fn` passes an error to it's callback,\n * this function will be called, and execution stops. Invoked with (err).\n * @returns {Promise} a promise that rejects if an error occurs and an errback\n * is not passed\n * @example\n *\n * async.forever(\n *     function(next) {\n *         // next is suitable for passing to things that need a callback(err [, whatever]);\n *         // it will result in this function being called again.\n *     },\n *     function(err) {\n *         // if next is called with a value in its first parameter, it will appear\n *         // in here as 'err', and execution will stop.\n *     }\n * );\n */\nfunction forever(fn, errback) {\n    var done = onlyOnce(errback);\n    var task = wrapAsync(ensureAsync(fn));\n\n    function next(err) {\n        if (err) return done(err);\n        if (err === false) return;\n        task(next);\n    }\n    return next();\n}\nvar forever$1 = awaitify(forever, 2);\n\n/**\n * The same as [`groupBy`]{@link module:Collections.groupBy} but runs a maximum of `limit` async operations at a time.\n *\n * @name groupByLimit\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.groupBy]{@link module:Collections.groupBy}\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {AsyncFunction} iteratee - An async function to apply to each item in\n * `coll`.\n * The iteratee should complete with a `key` to group the value under.\n * Invoked with (value, callback).\n * @param {Function} [callback] - A callback which is called when all `iteratee`\n * functions have finished, or an error occurs. Result is an `Object` whoses\n * properties are arrays of values which returned the corresponding key.\n * @returns {Promise} a promise, if no callback is passed\n */\nfunction groupByLimit(coll, limit, iteratee, callback) {\n    var _iteratee = wrapAsync(iteratee);\n    return mapLimit$1(coll, limit, (val, iterCb) => {\n        _iteratee(val, (err, key) => {\n            if (err) return iterCb(err);\n            return iterCb(err, {key, val});\n        });\n    }, (err, mapResults) => {\n        var result = {};\n        // from MDN, handle object having an `hasOwnProperty` prop\n        var {hasOwnProperty} = Object.prototype;\n\n        for (var i = 0; i < mapResults.length; i++) {\n            if (mapResults[i]) {\n                var {key} = mapResults[i];\n                var {val} = mapResults[i];\n\n                if (hasOwnProperty.call(result, key)) {\n                    result[key].push(val);\n                } else {\n                    result[key] = [val];\n                }\n            }\n        }\n\n        return callback(err, result);\n    });\n}\n\nvar groupByLimit$1 = awaitify(groupByLimit, 4);\n\n/**\n * Returns a new object, where each value corresponds to an array of items, from\n * `coll`, that returned the corresponding key. That is, the keys of the object\n * correspond to the values passed to the `iteratee` callback.\n *\n * Note: Since this function applies the `iteratee` to each item in parallel,\n * there is no guarantee that the `iteratee` functions will complete in order.\n * However, the values for each key in the `result` will be in the same order as\n * the original `coll`. For Objects, the values will roughly be in the order of\n * the original Objects' keys (but this can vary across JavaScript engines).\n *\n * @name groupBy\n * @static\n * @memberOf module:Collections\n * @method\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async function to apply to each item in\n * `coll`.\n * The iteratee should complete with a `key` to group the value under.\n * Invoked with (value, callback).\n * @param {Function} [callback] - A callback which is called when all `iteratee`\n * functions have finished, or an error occurs. Result is an `Object` whoses\n * properties are arrays of values which returned the corresponding key.\n * @returns {Promise} a promise, if no callback is passed\n * @example\n *\n * // dir1 is a directory that contains file1.txt, file2.txt\n * // dir2 is a directory that contains file3.txt, file4.txt\n * // dir3 is a directory that contains file5.txt\n * // dir4 does not exist\n *\n * const files = ['dir1/file1.txt','dir2','dir4']\n *\n * // asynchronous function that detects file type as none, file, or directory\n * function detectFile(file, callback) {\n *     fs.stat(file, function(err, stat) {\n *         if (err) {\n *             return callback(null, 'none');\n *         }\n *         callback(null, stat.isDirectory() ? 'directory' : 'file');\n *     });\n * }\n *\n * //Using callbacks\n * async.groupBy(files, detectFile, function(err, result) {\n *     if(err) {\n *         console.log(err);\n *     } else {\n *\t       console.log(result);\n *         // {\n *         //     file: [ 'dir1/file1.txt' ],\n *         //     none: [ 'dir4' ],\n *         //     directory: [ 'dir2']\n *         // }\n *         // result is object containing the files grouped by type\n *     }\n * });\n *\n * // Using Promises\n * async.groupBy(files, detectFile)\n * .then( result => {\n *     console.log(result);\n *     // {\n *     //     file: [ 'dir1/file1.txt' ],\n *     //     none: [ 'dir4' ],\n *     //     directory: [ 'dir2']\n *     // }\n *     // result is object containing the files grouped by type\n * }).catch( err => {\n *     console.log(err);\n * });\n *\n * // Using async/await\n * async () => {\n *     try {\n *         let result = await async.groupBy(files, detectFile);\n *         console.log(result);\n *         // {\n *         //     file: [ 'dir1/file1.txt' ],\n *         //     none: [ 'dir4' ],\n *         //     directory: [ 'dir2']\n *         // }\n *         // result is object containing the files grouped by type\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n */\nfunction groupBy (coll, iteratee, callback) {\n    return groupByLimit$1(coll, Infinity, iteratee, callback)\n}\n\n/**\n * The same as [`groupBy`]{@link module:Collections.groupBy} but runs only a single async operation at a time.\n *\n * @name groupBySeries\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.groupBy]{@link module:Collections.groupBy}\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async function to apply to each item in\n * `coll`.\n * The iteratee should complete with a `key` to group the value under.\n * Invoked with (value, callback).\n * @param {Function} [callback] - A callback which is called when all `iteratee`\n * functions have finished, or an error occurs. Result is an `Object` whose\n * properties are arrays of values which returned the corresponding key.\n * @returns {Promise} a promise, if no callback is passed\n */\nfunction groupBySeries (coll, iteratee, callback) {\n    return groupByLimit$1(coll, 1, iteratee, callback)\n}\n\n/**\n * Logs the result of an `async` function to the `console`. Only works in\n * Node.js or in browsers that support `console.log` and `console.error` (such\n * as FF and Chrome). If multiple arguments are returned from the async\n * function, `console.log` is called on each argument in order.\n *\n * @name log\n * @static\n * @memberOf module:Utils\n * @method\n * @category Util\n * @param {AsyncFunction} function - The function you want to eventually apply\n * all arguments to.\n * @param {...*} arguments... - Any number of arguments to apply to the function.\n * @example\n *\n * // in a module\n * var hello = function(name, callback) {\n *     setTimeout(function() {\n *         callback(null, 'hello ' + name);\n *     }, 1000);\n * };\n *\n * // in the node repl\n * node> async.log(hello, 'world');\n * 'hello world'\n */\nvar log = consoleFunc('log');\n\n/**\n * The same as [`mapValues`]{@link module:Collections.mapValues} but runs a maximum of `limit` async operations at a\n * time.\n *\n * @name mapValuesLimit\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.mapValues]{@link module:Collections.mapValues}\n * @category Collection\n * @param {Object} obj - A collection to iterate over.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {AsyncFunction} iteratee - A function to apply to each value and key\n * in `coll`.\n * The iteratee should complete with the transformed value as its result.\n * Invoked with (value, key, callback).\n * @param {Function} [callback] - A callback which is called when all `iteratee`\n * functions have finished, or an error occurs. `result` is a new object consisting\n * of each key from `obj`, with each transformed value on the right-hand side.\n * Invoked with (err, result).\n * @returns {Promise} a promise, if no callback is passed\n */\nfunction mapValuesLimit(obj, limit, iteratee, callback) {\n    callback = once(callback);\n    var newObj = {};\n    var _iteratee = wrapAsync(iteratee);\n    return eachOfLimit(limit)(obj, (val, key, next) => {\n        _iteratee(val, key, (err, result) => {\n            if (err) return next(err);\n            newObj[key] = result;\n            next(err);\n        });\n    }, err => callback(err, newObj));\n}\n\nvar mapValuesLimit$1 = awaitify(mapValuesLimit, 4);\n\n/**\n * A relative of [`map`]{@link module:Collections.map}, designed for use with objects.\n *\n * Produces a new Object by mapping each value of `obj` through the `iteratee`\n * function. The `iteratee` is called each `value` and `key` from `obj` and a\n * callback for when it has finished processing. Each of these callbacks takes\n * two arguments: an `error`, and the transformed item from `obj`. If `iteratee`\n * passes an error to its callback, the main `callback` (for the `mapValues`\n * function) is immediately called with the error.\n *\n * Note, the order of the keys in the result is not guaranteed.  The keys will\n * be roughly in the order they complete, (but this is very engine-specific)\n *\n * @name mapValues\n * @static\n * @memberOf module:Collections\n * @method\n * @category Collection\n * @param {Object} obj - A collection to iterate over.\n * @param {AsyncFunction} iteratee - A function to apply to each value and key\n * in `coll`.\n * The iteratee should complete with the transformed value as its result.\n * Invoked with (value, key, callback).\n * @param {Function} [callback] - A callback which is called when all `iteratee`\n * functions have finished, or an error occurs. `result` is a new object consisting\n * of each key from `obj`, with each transformed value on the right-hand side.\n * Invoked with (err, result).\n * @returns {Promise} a promise, if no callback is passed\n * @example\n *\n * // file1.txt is a file that is 1000 bytes in size\n * // file2.txt is a file that is 2000 bytes in size\n * // file3.txt is a file that is 3000 bytes in size\n * // file4.txt does not exist\n *\n * const fileMap = {\n *     f1: 'file1.txt',\n *     f2: 'file2.txt',\n *     f3: 'file3.txt'\n * };\n *\n * const withMissingFileMap = {\n *     f1: 'file1.txt',\n *     f2: 'file2.txt',\n *     f3: 'file4.txt'\n * };\n *\n * // asynchronous function that returns the file size in bytes\n * function getFileSizeInBytes(file, key, callback) {\n *     fs.stat(file, function(err, stat) {\n *         if (err) {\n *             return callback(err);\n *         }\n *         callback(null, stat.size);\n *     });\n * }\n *\n * // Using callbacks\n * async.mapValues(fileMap, getFileSizeInBytes, function(err, result) {\n *     if (err) {\n *         console.log(err);\n *     } else {\n *         console.log(result);\n *         // result is now a map of file size in bytes for each file, e.g.\n *         // {\n *         //     f1: 1000,\n *         //     f2: 2000,\n *         //     f3: 3000\n *         // }\n *     }\n * });\n *\n * // Error handling\n * async.mapValues(withMissingFileMap, getFileSizeInBytes, function(err, result) {\n *     if (err) {\n *         console.log(err);\n *         // [ Error: ENOENT: no such file or directory ]\n *     } else {\n *         console.log(result);\n *     }\n * });\n *\n * // Using Promises\n * async.mapValues(fileMap, getFileSizeInBytes)\n * .then( result => {\n *     console.log(result);\n *     // result is now a map of file size in bytes for each file, e.g.\n *     // {\n *     //     f1: 1000,\n *     //     f2: 2000,\n *     //     f3: 3000\n *     // }\n * }).catch (err => {\n *     console.log(err);\n * });\n *\n * // Error Handling\n * async.mapValues(withMissingFileMap, getFileSizeInBytes)\n * .then( result => {\n *     console.log(result);\n * }).catch (err => {\n *     console.log(err);\n *     // [ Error: ENOENT: no such file or directory ]\n * });\n *\n * // Using async/await\n * async () => {\n *     try {\n *         let result = await async.mapValues(fileMap, getFileSizeInBytes);\n *         console.log(result);\n *         // result is now a map of file size in bytes for each file, e.g.\n *         // {\n *         //     f1: 1000,\n *         //     f2: 2000,\n *         //     f3: 3000\n *         // }\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n * // Error Handling\n * async () => {\n *     try {\n *         let result = await async.mapValues(withMissingFileMap, getFileSizeInBytes);\n *         console.log(result);\n *     }\n *     catch (err) {\n *         console.log(err);\n *         // [ Error: ENOENT: no such file or directory ]\n *     }\n * }\n *\n */\nfunction mapValues(obj, iteratee, callback) {\n    return mapValuesLimit$1(obj, Infinity, iteratee, callback)\n}\n\n/**\n * The same as [`mapValues`]{@link module:Collections.mapValues} but runs only a single async operation at a time.\n *\n * @name mapValuesSeries\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.mapValues]{@link module:Collections.mapValues}\n * @category Collection\n * @param {Object} obj - A collection to iterate over.\n * @param {AsyncFunction} iteratee - A function to apply to each value and key\n * in `coll`.\n * The iteratee should complete with the transformed value as its result.\n * Invoked with (value, key, callback).\n * @param {Function} [callback] - A callback which is called when all `iteratee`\n * functions have finished, or an error occurs. `result` is a new object consisting\n * of each key from `obj`, with each transformed value on the right-hand side.\n * Invoked with (err, result).\n * @returns {Promise} a promise, if no callback is passed\n */\nfunction mapValuesSeries(obj, iteratee, callback) {\n    return mapValuesLimit$1(obj, 1, iteratee, callback)\n}\n\n/**\n * Caches the results of an async function. When creating a hash to store\n * function results against, the callback is omitted from the hash and an\n * optional hash function can be used.\n *\n * **Note: if the async function errs, the result will not be cached and\n * subsequent calls will call the wrapped function.**\n *\n * If no hash function is specified, the first argument is used as a hash key,\n * which may work reasonably if it is a string or a data type that converts to a\n * distinct string. Note that objects and arrays will not behave reasonably.\n * Neither will cases where the other arguments are significant. In such cases,\n * specify your own hash function.\n *\n * The cache of results is exposed as the `memo` property of the function\n * returned by `memoize`.\n *\n * @name memoize\n * @static\n * @memberOf module:Utils\n * @method\n * @category Util\n * @param {AsyncFunction} fn - The async function to proxy and cache results from.\n * @param {Function} hasher - An optional function for generating a custom hash\n * for storing results. It has all the arguments applied to it apart from the\n * callback, and must be synchronous.\n * @returns {AsyncFunction} a memoized version of `fn`\n * @example\n *\n * var slow_fn = function(name, callback) {\n *     // do something\n *     callback(null, result);\n * };\n * var fn = async.memoize(slow_fn);\n *\n * // fn can now be used as if it were slow_fn\n * fn('some name', function() {\n *     // callback\n * });\n */\nfunction memoize(fn, hasher = v => v) {\n    var memo = Object.create(null);\n    var queues = Object.create(null);\n    var _fn = wrapAsync(fn);\n    var memoized = initialParams((args, callback) => {\n        var key = hasher(...args);\n        if (key in memo) {\n            setImmediate$1(() => callback(null, ...memo[key]));\n        } else if (key in queues) {\n            queues[key].push(callback);\n        } else {\n            queues[key] = [callback];\n            _fn(...args, (err, ...resultArgs) => {\n                // #1465 don't memoize if an error occurred\n                if (!err) {\n                    memo[key] = resultArgs;\n                }\n                var q = queues[key];\n                delete queues[key];\n                for (var i = 0, l = q.length; i < l; i++) {\n                    q[i](err, ...resultArgs);\n                }\n            });\n        }\n    });\n    memoized.memo = memo;\n    memoized.unmemoized = fn;\n    return memoized;\n}\n\n/* istanbul ignore file */\n\n/**\n * Calls `callback` on a later loop around the event loop. In Node.js this just\n * calls `process.nextTick`.  In the browser it will use `setImmediate` if\n * available, otherwise `setTimeout(callback, 0)`, which means other higher\n * priority events may precede the execution of `callback`.\n *\n * This is used internally for browser-compatibility purposes.\n *\n * @name nextTick\n * @static\n * @memberOf module:Utils\n * @method\n * @see [async.setImmediate]{@link module:Utils.setImmediate}\n * @category Util\n * @param {Function} callback - The function to call on a later loop around\n * the event loop. Invoked with (args...).\n * @param {...*} args... - any number of additional arguments to pass to the\n * callback on the next tick.\n * @example\n *\n * var call_order = [];\n * async.nextTick(function() {\n *     call_order.push('two');\n *     // call_order now equals ['one','two']\n * });\n * call_order.push('one');\n *\n * async.setImmediate(function (a, b, c) {\n *     // a, b, and c equal 1, 2, and 3\n * }, 1, 2, 3);\n */\nvar _defer$1;\n\nif (hasNextTick) {\n    _defer$1 = process.nextTick;\n} else if (hasSetImmediate) {\n    _defer$1 = setImmediate;\n} else {\n    _defer$1 = fallback;\n}\n\nvar nextTick = wrap(_defer$1);\n\nvar _parallel = awaitify((eachfn, tasks, callback) => {\n    var results = isArrayLike(tasks) ? [] : {};\n\n    eachfn(tasks, (task, key, taskCb) => {\n        wrapAsync(task)((err, ...result) => {\n            if (result.length < 2) {\n                [result] = result;\n            }\n            results[key] = result;\n            taskCb(err);\n        });\n    }, err => callback(err, results));\n}, 3);\n\n/**\n * Run the `tasks` collection of functions in parallel, without waiting until\n * the previous function has completed. If any of the functions pass an error to\n * its callback, the main `callback` is immediately called with the value of the\n * error. Once the `tasks` have completed, the results are passed to the final\n * `callback` as an array.\n *\n * **Note:** `parallel` is about kicking-off I/O tasks in parallel, not about\n * parallel execution of code.  If your tasks do not use any timers or perform\n * any I/O, they will actually be executed in series.  Any synchronous setup\n * sections for each task will happen one after the other.  JavaScript remains\n * single-threaded.\n *\n * **Hint:** Use [`reflect`]{@link module:Utils.reflect} to continue the\n * execution of other tasks when a task fails.\n *\n * It is also possible to use an object instead of an array. Each property will\n * be run as a function and the results will be passed to the final `callback`\n * as an object instead of an array. This can be a more readable way of handling\n * results from {@link async.parallel}.\n *\n * @name parallel\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @param {Array|Iterable|AsyncIterable|Object} tasks - A collection of\n * [async functions]{@link AsyncFunction} to run.\n * Each async function can complete with any number of optional `result` values.\n * @param {Function} [callback] - An optional callback to run once all the\n * functions have completed successfully. This function gets a results array\n * (or object) containing all the result arguments passed to the task callbacks.\n * Invoked with (err, results).\n * @returns {Promise} a promise, if a callback is not passed\n *\n * @example\n *\n * //Using Callbacks\n * async.parallel([\n *     function(callback) {\n *         setTimeout(function() {\n *             callback(null, 'one');\n *         }, 200);\n *     },\n *     function(callback) {\n *         setTimeout(function() {\n *             callback(null, 'two');\n *         }, 100);\n *     }\n * ], function(err, results) {\n *     console.log(results);\n *     // results is equal to ['one','two'] even though\n *     // the second function had a shorter timeout.\n * });\n *\n * // an example using an object instead of an array\n * async.parallel({\n *     one: function(callback) {\n *         setTimeout(function() {\n *             callback(null, 1);\n *         }, 200);\n *     },\n *     two: function(callback) {\n *         setTimeout(function() {\n *             callback(null, 2);\n *         }, 100);\n *     }\n * }, function(err, results) {\n *     console.log(results);\n *     // results is equal to: { one: 1, two: 2 }\n * });\n *\n * //Using Promises\n * async.parallel([\n *     function(callback) {\n *         setTimeout(function() {\n *             callback(null, 'one');\n *         }, 200);\n *     },\n *     function(callback) {\n *         setTimeout(function() {\n *             callback(null, 'two');\n *         }, 100);\n *     }\n * ]).then(results => {\n *     console.log(results);\n *     // results is equal to ['one','two'] even though\n *     // the second function had a shorter timeout.\n * }).catch(err => {\n *     console.log(err);\n * });\n *\n * // an example using an object instead of an array\n * async.parallel({\n *     one: function(callback) {\n *         setTimeout(function() {\n *             callback(null, 1);\n *         }, 200);\n *     },\n *     two: function(callback) {\n *         setTimeout(function() {\n *             callback(null, 2);\n *         }, 100);\n *     }\n * }).then(results => {\n *     console.log(results);\n *     // results is equal to: { one: 1, two: 2 }\n * }).catch(err => {\n *     console.log(err);\n * });\n *\n * //Using async/await\n * async () => {\n *     try {\n *         let results = await async.parallel([\n *             function(callback) {\n *                 setTimeout(function() {\n *                     callback(null, 'one');\n *                 }, 200);\n *             },\n *             function(callback) {\n *                 setTimeout(function() {\n *                     callback(null, 'two');\n *                 }, 100);\n *             }\n *         ]);\n *         console.log(results);\n *         // results is equal to ['one','two'] even though\n *         // the second function had a shorter timeout.\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n * // an example using an object instead of an array\n * async () => {\n *     try {\n *         let results = await async.parallel({\n *             one: function(callback) {\n *                 setTimeout(function() {\n *                     callback(null, 1);\n *                 }, 200);\n *             },\n *            two: function(callback) {\n *                 setTimeout(function() {\n *                     callback(null, 2);\n *                 }, 100);\n *            }\n *         });\n *         console.log(results);\n *         // results is equal to: { one: 1, two: 2 }\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n */\nfunction parallel(tasks, callback) {\n    return _parallel(eachOf$1, tasks, callback);\n}\n\n/**\n * The same as [`parallel`]{@link module:ControlFlow.parallel} but runs a maximum of `limit` async operations at a\n * time.\n *\n * @name parallelLimit\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.parallel]{@link module:ControlFlow.parallel}\n * @category Control Flow\n * @param {Array|Iterable|AsyncIterable|Object} tasks - A collection of\n * [async functions]{@link AsyncFunction} to run.\n * Each async function can complete with any number of optional `result` values.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {Function} [callback] - An optional callback to run once all the\n * functions have completed successfully. This function gets a results array\n * (or object) containing all the result arguments passed to the task callbacks.\n * Invoked with (err, results).\n * @returns {Promise} a promise, if a callback is not passed\n */\nfunction parallelLimit(tasks, limit, callback) {\n    return _parallel(eachOfLimit(limit), tasks, callback);\n}\n\n/**\n * A queue of tasks for the worker function to complete.\n * @typedef {Iterable} QueueObject\n * @memberOf module:ControlFlow\n * @property {Function} length - a function returning the number of items\n * waiting to be processed. Invoke with `queue.length()`.\n * @property {boolean} started - a boolean indicating whether or not any\n * items have been pushed and processed by the queue.\n * @property {Function} running - a function returning the number of items\n * currently being processed. Invoke with `queue.running()`.\n * @property {Function} workersList - a function returning the array of items\n * currently being processed. Invoke with `queue.workersList()`.\n * @property {Function} idle - a function returning false if there are items\n * waiting or being processed, or true if not. Invoke with `queue.idle()`.\n * @property {number} concurrency - an integer for determining how many `worker`\n * functions should be run in parallel. This property can be changed after a\n * `queue` is created to alter the concurrency on-the-fly.\n * @property {number} payload - an integer that specifies how many items are\n * passed to the worker function at a time. only applies if this is a\n * [cargo]{@link module:ControlFlow.cargo} object\n * @property {AsyncFunction} push - add a new task to the `queue`. Calls `callback`\n * once the `worker` has finished processing the task. Instead of a single task,\n * a `tasks` array can be submitted. The respective callback is used for every\n * task in the list. Invoke with `queue.push(task, [callback])`,\n * @property {AsyncFunction} unshift - add a new task to the front of the `queue`.\n * Invoke with `queue.unshift(task, [callback])`.\n * @property {AsyncFunction} pushAsync - the same as `q.push`, except this returns\n * a promise that rejects if an error occurs.\n * @property {AsyncFunction} unshiftAsync - the same as `q.unshift`, except this returns\n * a promise that rejects if an error occurs.\n * @property {Function} remove - remove items from the queue that match a test\n * function.  The test function will be passed an object with a `data` property,\n * and a `priority` property, if this is a\n * [priorityQueue]{@link module:ControlFlow.priorityQueue} object.\n * Invoked with `queue.remove(testFn)`, where `testFn` is of the form\n * `function ({data, priority}) {}` and returns a Boolean.\n * @property {Function} saturated - a function that sets a callback that is\n * called when the number of running workers hits the `concurrency` limit, and\n * further tasks will be queued.  If the callback is omitted, `q.saturated()`\n * returns a promise for the next occurrence.\n * @property {Function} unsaturated - a function that sets a callback that is\n * called when the number of running workers is less than the `concurrency` &\n * `buffer` limits, and further tasks will not be queued. If the callback is\n * omitted, `q.unsaturated()` returns a promise for the next occurrence.\n * @property {number} buffer - A minimum threshold buffer in order to say that\n * the `queue` is `unsaturated`.\n * @property {Function} empty - a function that sets a callback that is called\n * when the last item from the `queue` is given to a `worker`. If the callback\n * is omitted, `q.empty()` returns a promise for the next occurrence.\n * @property {Function} drain - a function that sets a callback that is called\n * when the last item from the `queue` has returned from the `worker`. If the\n * callback is omitted, `q.drain()` returns a promise for the next occurrence.\n * @property {Function} error - a function that sets a callback that is called\n * when a task errors. Has the signature `function(error, task)`. If the\n * callback is omitted, `error()` returns a promise that rejects on the next\n * error.\n * @property {boolean} paused - a boolean for determining whether the queue is\n * in a paused state.\n * @property {Function} pause - a function that pauses the processing of tasks\n * until `resume()` is called. Invoke with `queue.pause()`.\n * @property {Function} resume - a function that resumes the processing of\n * queued tasks when the queue is paused. Invoke with `queue.resume()`.\n * @property {Function} kill - a function that removes the `drain` callback and\n * empties remaining tasks from the queue forcing it to go idle. No more tasks\n * should be pushed to the queue after calling this function. Invoke with `queue.kill()`.\n *\n * @example\n * const q = async.queue(worker, 2)\n * q.push(item1)\n * q.push(item2)\n * q.push(item3)\n * // queues are iterable, spread into an array to inspect\n * const items = [...q] // [item1, item2, item3]\n * // or use for of\n * for (let item of q) {\n *     console.log(item)\n * }\n *\n * q.drain(() => {\n *     console.log('all done')\n * })\n * // or\n * await q.drain()\n */\n\n/**\n * Creates a `queue` object with the specified `concurrency`. Tasks added to the\n * `queue` are processed in parallel (up to the `concurrency` limit). If all\n * `worker`s are in progress, the task is queued until one becomes available.\n * Once a `worker` completes a `task`, that `task`'s callback is called.\n *\n * @name queue\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @param {AsyncFunction} worker - An async function for processing a queued task.\n * If you want to handle errors from an individual task, pass a callback to\n * `q.push()`. Invoked with (task, callback).\n * @param {number} [concurrency=1] - An `integer` for determining how many\n * `worker` functions should be run in parallel.  If omitted, the concurrency\n * defaults to `1`.  If the concurrency is `0`, an error is thrown.\n * @returns {module:ControlFlow.QueueObject} A queue object to manage the tasks. Callbacks can be\n * attached as certain properties to listen for specific events during the\n * lifecycle of the queue.\n * @example\n *\n * // create a queue object with concurrency 2\n * var q = async.queue(function(task, callback) {\n *     console.log('hello ' + task.name);\n *     callback();\n * }, 2);\n *\n * // assign a callback\n * q.drain(function() {\n *     console.log('all items have been processed');\n * });\n * // or await the end\n * await q.drain()\n *\n * // assign an error callback\n * q.error(function(err, task) {\n *     console.error('task experienced an error');\n * });\n *\n * // add some items to the queue\n * q.push({name: 'foo'}, function(err) {\n *     console.log('finished processing foo');\n * });\n * // callback is optional\n * q.push({name: 'bar'});\n *\n * // add some items to the queue (batch-wise)\n * q.push([{name: 'baz'},{name: 'bay'},{name: 'bax'}], function(err) {\n *     console.log('finished processing item');\n * });\n *\n * // add some items to the front of the queue\n * q.unshift({name: 'bar'}, function (err) {\n *     console.log('finished processing bar');\n * });\n */\nfunction queue$1 (worker, concurrency) {\n    var _worker = wrapAsync(worker);\n    return queue((items, cb) => {\n        _worker(items[0], cb);\n    }, concurrency, 1);\n}\n\n// Binary min-heap implementation used for priority queue.\n// Implementation is stable, i.e. push time is considered for equal priorities\nclass Heap {\n    constructor() {\n        this.heap = [];\n        this.pushCount = Number.MIN_SAFE_INTEGER;\n    }\n\n    get length() {\n        return this.heap.length;\n    }\n\n    empty () {\n        this.heap = [];\n        return this;\n    }\n\n    percUp(index) {\n        let p;\n\n        while (index > 0 && smaller(this.heap[index], this.heap[p=parent(index)])) {\n            let t = this.heap[index];\n            this.heap[index] = this.heap[p];\n            this.heap[p] = t;\n\n            index = p;\n        }\n    }\n\n    percDown(index) {\n        let l;\n\n        while ((l=leftChi(index)) < this.heap.length) {\n            if (l+1 < this.heap.length && smaller(this.heap[l+1], this.heap[l])) {\n                l = l+1;\n            }\n\n            if (smaller(this.heap[index], this.heap[l])) {\n                break;\n            }\n\n            let t = this.heap[index];\n            this.heap[index] = this.heap[l];\n            this.heap[l] = t;\n\n            index = l;\n        }\n    }\n\n    push(node) {\n        node.pushCount = ++this.pushCount;\n        this.heap.push(node);\n        this.percUp(this.heap.length-1);\n    }\n\n    unshift(node) {\n        return this.heap.push(node);\n    }\n\n    shift() {\n        let [top] = this.heap;\n\n        this.heap[0] = this.heap[this.heap.length-1];\n        this.heap.pop();\n        this.percDown(0);\n\n        return top;\n    }\n\n    toArray() {\n        return [...this];\n    }\n\n    *[Symbol.iterator] () {\n        for (let i = 0; i < this.heap.length; i++) {\n            yield this.heap[i].data;\n        }\n    }\n\n    remove (testFn) {\n        let j = 0;\n        for (let i = 0; i < this.heap.length; i++) {\n            if (!testFn(this.heap[i])) {\n                this.heap[j] = this.heap[i];\n                j++;\n            }\n        }\n\n        this.heap.splice(j);\n\n        for (let i = parent(this.heap.length-1); i >= 0; i--) {\n            this.percDown(i);\n        }\n\n        return this;\n    }\n}\n\nfunction leftChi(i) {\n    return (i<<1)+1;\n}\n\nfunction parent(i) {\n    return ((i+1)>>1)-1;\n}\n\nfunction smaller(x, y) {\n    if (x.priority !== y.priority) {\n        return x.priority < y.priority;\n    }\n    else {\n        return x.pushCount < y.pushCount;\n    }\n}\n\n/**\n * The same as [async.queue]{@link module:ControlFlow.queue} only tasks are assigned a priority and\n * completed in ascending priority order.\n *\n * @name priorityQueue\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.queue]{@link module:ControlFlow.queue}\n * @category Control Flow\n * @param {AsyncFunction} worker - An async function for processing a queued task.\n * If you want to handle errors from an individual task, pass a callback to\n * `q.push()`.\n * Invoked with (task, callback).\n * @param {number} concurrency - An `integer` for determining how many `worker`\n * functions should be run in parallel.  If omitted, the concurrency defaults to\n * `1`.  If the concurrency is `0`, an error is thrown.\n * @returns {module:ControlFlow.QueueObject} A priorityQueue object to manage the tasks. There are two\n * differences between `queue` and `priorityQueue` objects:\n * * `push(task, priority, [callback])` - `priority` should be a number. If an\n *   array of `tasks` is given, all tasks will be assigned the same priority.\n * * The `unshift` method was removed.\n */\nfunction priorityQueue(worker, concurrency) {\n    // Start with a normal queue\n    var q = queue$1(worker, concurrency);\n    var processingScheduled = false;\n\n    q._tasks = new Heap();\n\n    // Override push to accept second parameter representing priority\n    q.push = function(data, priority = 0, callback = () => {}) {\n        if (typeof callback !== 'function') {\n            throw new Error('task callback must be a function');\n        }\n        q.started = true;\n        if (!Array.isArray(data)) {\n            data = [data];\n        }\n        if (data.length === 0 && q.idle()) {\n            // call drain immediately if there are no tasks\n            return setImmediate$1(() => q.drain());\n        }\n\n        for (var i = 0, l = data.length; i < l; i++) {\n            var item = {\n                data: data[i],\n                priority,\n                callback\n            };\n\n            q._tasks.push(item);\n        }\n\n        if (!processingScheduled) {\n            processingScheduled = true;\n            setImmediate$1(() => {\n                processingScheduled = false;\n                q.process();\n            });\n        }\n    };\n\n    // Remove unshift function\n    delete q.unshift;\n\n    return q;\n}\n\n/**\n * Runs the `tasks` array of functions in parallel, without waiting until the\n * previous function has completed. Once any of the `tasks` complete or pass an\n * error to its callback, the main `callback` is immediately called. It's\n * equivalent to `Promise.race()`.\n *\n * @name race\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @param {Array} tasks - An array containing [async functions]{@link AsyncFunction}\n * to run. Each function can complete with an optional `result` value.\n * @param {Function} callback - A callback to run once any of the functions have\n * completed. This function gets an error or result from the first function that\n * completed. Invoked with (err, result).\n * @returns undefined\n * @example\n *\n * async.race([\n *     function(callback) {\n *         setTimeout(function() {\n *             callback(null, 'one');\n *         }, 200);\n *     },\n *     function(callback) {\n *         setTimeout(function() {\n *             callback(null, 'two');\n *         }, 100);\n *     }\n * ],\n * // main callback\n * function(err, result) {\n *     // the result will be equal to 'two' as it finishes earlier\n * });\n */\nfunction race(tasks, callback) {\n    callback = once(callback);\n    if (!Array.isArray(tasks)) return callback(new TypeError('First argument to race must be an array of functions'));\n    if (!tasks.length) return callback();\n    for (var i = 0, l = tasks.length; i < l; i++) {\n        wrapAsync(tasks[i])(callback);\n    }\n}\n\nvar race$1 = awaitify(race, 2);\n\n/**\n * Same as [`reduce`]{@link module:Collections.reduce}, only operates on `array` in reverse order.\n *\n * @name reduceRight\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.reduce]{@link module:Collections.reduce}\n * @alias foldr\n * @category Collection\n * @param {Array} array - A collection to iterate over.\n * @param {*} memo - The initial state of the reduction.\n * @param {AsyncFunction} iteratee - A function applied to each item in the\n * array to produce the next step in the reduction.\n * The `iteratee` should complete with the next state of the reduction.\n * If the iteratee completes with an error, the reduction is stopped and the\n * main `callback` is immediately called with the error.\n * Invoked with (memo, item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Result is the reduced value. Invoked with\n * (err, result).\n * @returns {Promise} a promise, if no callback is passed\n */\nfunction reduceRight (array, memo, iteratee, callback) {\n    var reversed = [...array].reverse();\n    return reduce$1(reversed, memo, iteratee, callback);\n}\n\n/**\n * Wraps the async function in another function that always completes with a\n * result object, even when it errors.\n *\n * The result object has either the property `error` or `value`.\n *\n * @name reflect\n * @static\n * @memberOf module:Utils\n * @method\n * @category Util\n * @param {AsyncFunction} fn - The async function you want to wrap\n * @returns {Function} - A function that always passes null to it's callback as\n * the error. The second argument to the callback will be an `object` with\n * either an `error` or a `value` property.\n * @example\n *\n * async.parallel([\n *     async.reflect(function(callback) {\n *         // do some stuff ...\n *         callback(null, 'one');\n *     }),\n *     async.reflect(function(callback) {\n *         // do some more stuff but error ...\n *         callback('bad stuff happened');\n *     }),\n *     async.reflect(function(callback) {\n *         // do some more stuff ...\n *         callback(null, 'two');\n *     })\n * ],\n * // optional callback\n * function(err, results) {\n *     // values\n *     // results[0].value = 'one'\n *     // results[1].error = 'bad stuff happened'\n *     // results[2].value = 'two'\n * });\n */\nfunction reflect(fn) {\n    var _fn = wrapAsync(fn);\n    return initialParams(function reflectOn(args, reflectCallback) {\n        args.push((error, ...cbArgs) => {\n            let retVal = {};\n            if (error) {\n                retVal.error = error;\n            }\n            if (cbArgs.length > 0){\n                var value = cbArgs;\n                if (cbArgs.length <= 1) {\n                    [value] = cbArgs;\n                }\n                retVal.value = value;\n            }\n            reflectCallback(null, retVal);\n        });\n\n        return _fn.apply(this, args);\n    });\n}\n\n/**\n * A helper function that wraps an array or an object of functions with `reflect`.\n *\n * @name reflectAll\n * @static\n * @memberOf module:Utils\n * @method\n * @see [async.reflect]{@link module:Utils.reflect}\n * @category Util\n * @param {Array|Object|Iterable} tasks - The collection of\n * [async functions]{@link AsyncFunction} to wrap in `async.reflect`.\n * @returns {Array} Returns an array of async functions, each wrapped in\n * `async.reflect`\n * @example\n *\n * let tasks = [\n *     function(callback) {\n *         setTimeout(function() {\n *             callback(null, 'one');\n *         }, 200);\n *     },\n *     function(callback) {\n *         // do some more stuff but error ...\n *         callback(new Error('bad stuff happened'));\n *     },\n *     function(callback) {\n *         setTimeout(function() {\n *             callback(null, 'two');\n *         }, 100);\n *     }\n * ];\n *\n * async.parallel(async.reflectAll(tasks),\n * // optional callback\n * function(err, results) {\n *     // values\n *     // results[0].value = 'one'\n *     // results[1].error = Error('bad stuff happened')\n *     // results[2].value = 'two'\n * });\n *\n * // an example using an object instead of an array\n * let tasks = {\n *     one: function(callback) {\n *         setTimeout(function() {\n *             callback(null, 'one');\n *         }, 200);\n *     },\n *     two: function(callback) {\n *         callback('two');\n *     },\n *     three: function(callback) {\n *         setTimeout(function() {\n *             callback(null, 'three');\n *         }, 100);\n *     }\n * };\n *\n * async.parallel(async.reflectAll(tasks),\n * // optional callback\n * function(err, results) {\n *     // values\n *     // results.one.value = 'one'\n *     // results.two.error = 'two'\n *     // results.three.value = 'three'\n * });\n */\nfunction reflectAll(tasks) {\n    var results;\n    if (Array.isArray(tasks)) {\n        results = tasks.map(reflect);\n    } else {\n        results = {};\n        Object.keys(tasks).forEach(key => {\n            results[key] = reflect.call(this, tasks[key]);\n        });\n    }\n    return results;\n}\n\nfunction reject(eachfn, arr, _iteratee, callback) {\n    const iteratee = wrapAsync(_iteratee);\n    return _filter(eachfn, arr, (value, cb) => {\n        iteratee(value, (err, v) => {\n            cb(err, !v);\n        });\n    }, callback);\n}\n\n/**\n * The opposite of [`filter`]{@link module:Collections.filter}. Removes values that pass an `async` truth test.\n *\n * @name reject\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.filter]{@link module:Collections.filter}\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {Function} iteratee - An async truth test to apply to each item in\n * `coll`.\n * The should complete with a boolean value as its `result`.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Invoked with (err, results).\n * @returns {Promise} a promise, if no callback is passed\n * @example\n *\n * // dir1 is a directory that contains file1.txt, file2.txt\n * // dir2 is a directory that contains file3.txt, file4.txt\n * // dir3 is a directory that contains file5.txt\n *\n * const fileList = ['dir1/file1.txt','dir2/file3.txt','dir3/file6.txt'];\n *\n * // asynchronous function that checks if a file exists\n * function fileExists(file, callback) {\n *    fs.access(file, fs.constants.F_OK, (err) => {\n *        callback(null, !err);\n *    });\n * }\n *\n * // Using callbacks\n * async.reject(fileList, fileExists, function(err, results) {\n *    // [ 'dir3/file6.txt' ]\n *    // results now equals an array of the non-existing files\n * });\n *\n * // Using Promises\n * async.reject(fileList, fileExists)\n * .then( results => {\n *     console.log(results);\n *     // [ 'dir3/file6.txt' ]\n *     // results now equals an array of the non-existing files\n * }).catch( err => {\n *     console.log(err);\n * });\n *\n * // Using async/await\n * async () => {\n *     try {\n *         let results = await async.reject(fileList, fileExists);\n *         console.log(results);\n *         // [ 'dir3/file6.txt' ]\n *         // results now equals an array of the non-existing files\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n */\nfunction reject$1 (coll, iteratee, callback) {\n    return reject(eachOf$1, coll, iteratee, callback)\n}\nvar reject$2 = awaitify(reject$1, 3);\n\n/**\n * The same as [`reject`]{@link module:Collections.reject} but runs a maximum of `limit` async operations at a\n * time.\n *\n * @name rejectLimit\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.reject]{@link module:Collections.reject}\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {Function} iteratee - An async truth test to apply to each item in\n * `coll`.\n * The should complete with a boolean value as its `result`.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Invoked with (err, results).\n * @returns {Promise} a promise, if no callback is passed\n */\nfunction rejectLimit (coll, limit, iteratee, callback) {\n    return reject(eachOfLimit(limit), coll, iteratee, callback)\n}\nvar rejectLimit$1 = awaitify(rejectLimit, 4);\n\n/**\n * The same as [`reject`]{@link module:Collections.reject} but runs only a single async operation at a time.\n *\n * @name rejectSeries\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.reject]{@link module:Collections.reject}\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {Function} iteratee - An async truth test to apply to each item in\n * `coll`.\n * The should complete with a boolean value as its `result`.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Invoked with (err, results).\n * @returns {Promise} a promise, if no callback is passed\n */\nfunction rejectSeries (coll, iteratee, callback) {\n    return reject(eachOfSeries$1, coll, iteratee, callback)\n}\nvar rejectSeries$1 = awaitify(rejectSeries, 3);\n\nfunction constant$1(value) {\n    return function () {\n        return value;\n    }\n}\n\n/**\n * Attempts to get a successful response from `task` no more than `times` times\n * before returning an error. If the task is successful, the `callback` will be\n * passed the result of the successful task. If all attempts fail, the callback\n * will be passed the error and result (if any) of the final attempt.\n *\n * @name retry\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @see [async.retryable]{@link module:ControlFlow.retryable}\n * @param {Object|number} [opts = {times: 5, interval: 0}| 5] - Can be either an\n * object with `times` and `interval` or a number.\n * * `times` - The number of attempts to make before giving up.  The default\n *   is `5`.\n * * `interval` - The time to wait between retries, in milliseconds.  The\n *   default is `0`. The interval may also be specified as a function of the\n *   retry count (see example).\n * * `errorFilter` - An optional synchronous function that is invoked on\n *   erroneous result. If it returns `true` the retry attempts will continue;\n *   if the function returns `false` the retry flow is aborted with the current\n *   attempt's error and result being returned to the final callback.\n *   Invoked with (err).\n * * If `opts` is a number, the number specifies the number of times to retry,\n *   with the default interval of `0`.\n * @param {AsyncFunction} task - An async function to retry.\n * Invoked with (callback).\n * @param {Function} [callback] - An optional callback which is called when the\n * task has succeeded, or after the final failed attempt. It receives the `err`\n * and `result` arguments of the last attempt at completing the `task`. Invoked\n * with (err, results).\n * @returns {Promise} a promise if no callback provided\n *\n * @example\n *\n * // The `retry` function can be used as a stand-alone control flow by passing\n * // a callback, as shown below:\n *\n * // try calling apiMethod 3 times\n * async.retry(3, apiMethod, function(err, result) {\n *     // do something with the result\n * });\n *\n * // try calling apiMethod 3 times, waiting 200 ms between each retry\n * async.retry({times: 3, interval: 200}, apiMethod, function(err, result) {\n *     // do something with the result\n * });\n *\n * // try calling apiMethod 10 times with exponential backoff\n * // (i.e. intervals of 100, 200, 400, 800, 1600, ... milliseconds)\n * async.retry({\n *   times: 10,\n *   interval: function(retryCount) {\n *     return 50 * Math.pow(2, retryCount);\n *   }\n * }, apiMethod, function(err, result) {\n *     // do something with the result\n * });\n *\n * // try calling apiMethod the default 5 times no delay between each retry\n * async.retry(apiMethod, function(err, result) {\n *     // do something with the result\n * });\n *\n * // try calling apiMethod only when error condition satisfies, all other\n * // errors will abort the retry control flow and return to final callback\n * async.retry({\n *   errorFilter: function(err) {\n *     return err.message === 'Temporary error'; // only retry on a specific error\n *   }\n * }, apiMethod, function(err, result) {\n *     // do something with the result\n * });\n *\n * // to retry individual methods that are not as reliable within other\n * // control flow functions, use the `retryable` wrapper:\n * async.auto({\n *     users: api.getUsers.bind(api),\n *     payments: async.retryable(3, api.getPayments.bind(api))\n * }, function(err, results) {\n *     // do something with the results\n * });\n *\n */\nconst DEFAULT_TIMES = 5;\nconst DEFAULT_INTERVAL = 0;\n\nfunction retry(opts, task, callback) {\n    var options = {\n        times: DEFAULT_TIMES,\n        intervalFunc: constant$1(DEFAULT_INTERVAL)\n    };\n\n    if (arguments.length < 3 && typeof opts === 'function') {\n        callback = task || promiseCallback();\n        task = opts;\n    } else {\n        parseTimes(options, opts);\n        callback = callback || promiseCallback();\n    }\n\n    if (typeof task !== 'function') {\n        throw new Error(\"Invalid arguments for async.retry\");\n    }\n\n    var _task = wrapAsync(task);\n\n    var attempt = 1;\n    function retryAttempt() {\n        _task((err, ...args) => {\n            if (err === false) return\n            if (err && attempt++ < options.times &&\n                (typeof options.errorFilter != 'function' ||\n                    options.errorFilter(err))) {\n                setTimeout(retryAttempt, options.intervalFunc(attempt - 1));\n            } else {\n                callback(err, ...args);\n            }\n        });\n    }\n\n    retryAttempt();\n    return callback[PROMISE_SYMBOL]\n}\n\nfunction parseTimes(acc, t) {\n    if (typeof t === 'object') {\n        acc.times = +t.times || DEFAULT_TIMES;\n\n        acc.intervalFunc = typeof t.interval === 'function' ?\n            t.interval :\n            constant$1(+t.interval || DEFAULT_INTERVAL);\n\n        acc.errorFilter = t.errorFilter;\n    } else if (typeof t === 'number' || typeof t === 'string') {\n        acc.times = +t || DEFAULT_TIMES;\n    } else {\n        throw new Error(\"Invalid arguments for async.retry\");\n    }\n}\n\n/**\n * A close relative of [`retry`]{@link module:ControlFlow.retry}.  This method\n * wraps a task and makes it retryable, rather than immediately calling it\n * with retries.\n *\n * @name retryable\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.retry]{@link module:ControlFlow.retry}\n * @category Control Flow\n * @param {Object|number} [opts = {times: 5, interval: 0}| 5] - optional\n * options, exactly the same as from `retry`, except for a `opts.arity` that\n * is the arity of the `task` function, defaulting to `task.length`\n * @param {AsyncFunction} task - the asynchronous function to wrap.\n * This function will be passed any arguments passed to the returned wrapper.\n * Invoked with (...args, callback).\n * @returns {AsyncFunction} The wrapped function, which when invoked, will\n * retry on an error, based on the parameters specified in `opts`.\n * This function will accept the same parameters as `task`.\n * @example\n *\n * async.auto({\n *     dep1: async.retryable(3, getFromFlakyService),\n *     process: [\"dep1\", async.retryable(3, function (results, cb) {\n *         maybeProcessData(results.dep1, cb);\n *     })]\n * }, callback);\n */\nfunction retryable (opts, task) {\n    if (!task) {\n        task = opts;\n        opts = null;\n    }\n    let arity = (opts && opts.arity) || task.length;\n    if (isAsync(task)) {\n        arity += 1;\n    }\n    var _task = wrapAsync(task);\n    return initialParams((args, callback) => {\n        if (args.length < arity - 1 || callback == null) {\n            args.push(callback);\n            callback = promiseCallback();\n        }\n        function taskFn(cb) {\n            _task(...args, cb);\n        }\n\n        if (opts) retry(opts, taskFn, callback);\n        else retry(taskFn, callback);\n\n        return callback[PROMISE_SYMBOL]\n    });\n}\n\n/**\n * Run the functions in the `tasks` collection in series, each one running once\n * the previous function has completed. If any functions in the series pass an\n * error to its callback, no more functions are run, and `callback` is\n * immediately called with the value of the error. Otherwise, `callback`\n * receives an array of results when `tasks` have completed.\n *\n * It is also possible to use an object instead of an array. Each property will\n * be run as a function, and the results will be passed to the final `callback`\n * as an object instead of an array. This can be a more readable way of handling\n *  results from {@link async.series}.\n *\n * **Note** that while many implementations preserve the order of object\n * properties, the [ECMAScript Language Specification](http://www.ecma-international.org/ecma-262/5.1/#sec-8.6)\n * explicitly states that\n *\n * > The mechanics and order of enumerating the properties is not specified.\n *\n * So if you rely on the order in which your series of functions are executed,\n * and want this to work on all platforms, consider using an array.\n *\n * @name series\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @param {Array|Iterable|AsyncIterable|Object} tasks - A collection containing\n * [async functions]{@link AsyncFunction} to run in series.\n * Each function can complete with any number of optional `result` values.\n * @param {Function} [callback] - An optional callback to run once all the\n * functions have completed. This function gets a results array (or object)\n * containing all the result arguments passed to the `task` callbacks. Invoked\n * with (err, result).\n * @return {Promise} a promise, if no callback is passed\n * @example\n *\n * //Using Callbacks\n * async.series([\n *     function(callback) {\n *         setTimeout(function() {\n *             // do some async task\n *             callback(null, 'one');\n *         }, 200);\n *     },\n *     function(callback) {\n *         setTimeout(function() {\n *             // then do another async task\n *             callback(null, 'two');\n *         }, 100);\n *     }\n * ], function(err, results) {\n *     console.log(results);\n *     // results is equal to ['one','two']\n * });\n *\n * // an example using objects instead of arrays\n * async.series({\n *     one: function(callback) {\n *         setTimeout(function() {\n *             // do some async task\n *             callback(null, 1);\n *         }, 200);\n *     },\n *     two: function(callback) {\n *         setTimeout(function() {\n *             // then do another async task\n *             callback(null, 2);\n *         }, 100);\n *     }\n * }, function(err, results) {\n *     console.log(results);\n *     // results is equal to: { one: 1, two: 2 }\n * });\n *\n * //Using Promises\n * async.series([\n *     function(callback) {\n *         setTimeout(function() {\n *             callback(null, 'one');\n *         }, 200);\n *     },\n *     function(callback) {\n *         setTimeout(function() {\n *             callback(null, 'two');\n *         }, 100);\n *     }\n * ]).then(results => {\n *     console.log(results);\n *     // results is equal to ['one','two']\n * }).catch(err => {\n *     console.log(err);\n * });\n *\n * // an example using an object instead of an array\n * async.series({\n *     one: function(callback) {\n *         setTimeout(function() {\n *             // do some async task\n *             callback(null, 1);\n *         }, 200);\n *     },\n *     two: function(callback) {\n *         setTimeout(function() {\n *             // then do another async task\n *             callback(null, 2);\n *         }, 100);\n *     }\n * }).then(results => {\n *     console.log(results);\n *     // results is equal to: { one: 1, two: 2 }\n * }).catch(err => {\n *     console.log(err);\n * });\n *\n * //Using async/await\n * async () => {\n *     try {\n *         let results = await async.series([\n *             function(callback) {\n *                 setTimeout(function() {\n *                     // do some async task\n *                     callback(null, 'one');\n *                 }, 200);\n *             },\n *             function(callback) {\n *                 setTimeout(function() {\n *                     // then do another async task\n *                     callback(null, 'two');\n *                 }, 100);\n *             }\n *         ]);\n *         console.log(results);\n *         // results is equal to ['one','two']\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n * // an example using an object instead of an array\n * async () => {\n *     try {\n *         let results = await async.parallel({\n *             one: function(callback) {\n *                 setTimeout(function() {\n *                     // do some async task\n *                     callback(null, 1);\n *                 }, 200);\n *             },\n *            two: function(callback) {\n *                 setTimeout(function() {\n *                     // then do another async task\n *                     callback(null, 2);\n *                 }, 100);\n *            }\n *         });\n *         console.log(results);\n *         // results is equal to: { one: 1, two: 2 }\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n */\nfunction series(tasks, callback) {\n    return _parallel(eachOfSeries$1, tasks, callback);\n}\n\n/**\n * Returns `true` if at least one element in the `coll` satisfies an async test.\n * If any iteratee call returns `true`, the main `callback` is immediately\n * called.\n *\n * @name some\n * @static\n * @memberOf module:Collections\n * @method\n * @alias any\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async truth test to apply to each item\n * in the collections in parallel.\n * The iteratee should complete with a boolean `result` value.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called as soon as any\n * iteratee returns `true`, or after all the iteratee functions have finished.\n * Result will be either `true` or `false` depending on the values of the async\n * tests. Invoked with (err, result).\n * @returns {Promise} a promise, if no callback provided\n * @example\n *\n * // dir1 is a directory that contains file1.txt, file2.txt\n * // dir2 is a directory that contains file3.txt, file4.txt\n * // dir3 is a directory that contains file5.txt\n * // dir4 does not exist\n *\n * // asynchronous function that checks if a file exists\n * function fileExists(file, callback) {\n *    fs.access(file, fs.constants.F_OK, (err) => {\n *        callback(null, !err);\n *    });\n * }\n *\n * // Using callbacks\n * async.some(['dir1/missing.txt','dir2/missing.txt','dir3/file5.txt'], fileExists,\n *    function(err, result) {\n *        console.log(result);\n *        // true\n *        // result is true since some file in the list exists\n *    }\n *);\n *\n * async.some(['dir1/missing.txt','dir2/missing.txt','dir4/missing.txt'], fileExists,\n *    function(err, result) {\n *        console.log(result);\n *        // false\n *        // result is false since none of the files exists\n *    }\n *);\n *\n * // Using Promises\n * async.some(['dir1/missing.txt','dir2/missing.txt','dir3/file5.txt'], fileExists)\n * .then( result => {\n *     console.log(result);\n *     // true\n *     // result is true since some file in the list exists\n * }).catch( err => {\n *     console.log(err);\n * });\n *\n * async.some(['dir1/missing.txt','dir2/missing.txt','dir4/missing.txt'], fileExists)\n * .then( result => {\n *     console.log(result);\n *     // false\n *     // result is false since none of the files exists\n * }).catch( err => {\n *     console.log(err);\n * });\n *\n * // Using async/await\n * async () => {\n *     try {\n *         let result = await async.some(['dir1/missing.txt','dir2/missing.txt','dir3/file5.txt'], fileExists);\n *         console.log(result);\n *         // true\n *         // result is true since some file in the list exists\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n * async () => {\n *     try {\n *         let result = await async.some(['dir1/missing.txt','dir2/missing.txt','dir4/missing.txt'], fileExists);\n *         console.log(result);\n *         // false\n *         // result is false since none of the files exists\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n */\nfunction some(coll, iteratee, callback) {\n    return _createTester(Boolean, res => res)(eachOf$1, coll, iteratee, callback)\n}\nvar some$1 = awaitify(some, 3);\n\n/**\n * The same as [`some`]{@link module:Collections.some} but runs a maximum of `limit` async operations at a time.\n *\n * @name someLimit\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.some]{@link module:Collections.some}\n * @alias anyLimit\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {AsyncFunction} iteratee - An async truth test to apply to each item\n * in the collections in parallel.\n * The iteratee should complete with a boolean `result` value.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called as soon as any\n * iteratee returns `true`, or after all the iteratee functions have finished.\n * Result will be either `true` or `false` depending on the values of the async\n * tests. Invoked with (err, result).\n * @returns {Promise} a promise, if no callback provided\n */\nfunction someLimit(coll, limit, iteratee, callback) {\n    return _createTester(Boolean, res => res)(eachOfLimit(limit), coll, iteratee, callback)\n}\nvar someLimit$1 = awaitify(someLimit, 4);\n\n/**\n * The same as [`some`]{@link module:Collections.some} but runs only a single async operation at a time.\n *\n * @name someSeries\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.some]{@link module:Collections.some}\n * @alias anySeries\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async truth test to apply to each item\n * in the collections in series.\n * The iteratee should complete with a boolean `result` value.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called as soon as any\n * iteratee returns `true`, or after all the iteratee functions have finished.\n * Result will be either `true` or `false` depending on the values of the async\n * tests. Invoked with (err, result).\n * @returns {Promise} a promise, if no callback provided\n */\nfunction someSeries(coll, iteratee, callback) {\n    return _createTester(Boolean, res => res)(eachOfSeries$1, coll, iteratee, callback)\n}\nvar someSeries$1 = awaitify(someSeries, 3);\n\n/**\n * Sorts a list by the results of running each `coll` value through an async\n * `iteratee`.\n *\n * @name sortBy\n * @static\n * @memberOf module:Collections\n * @method\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async function to apply to each item in\n * `coll`.\n * The iteratee should complete with a value to use as the sort criteria as\n * its `result`.\n * Invoked with (item, callback).\n * @param {Function} callback - A callback which is called after all the\n * `iteratee` functions have finished, or an error occurs. Results is the items\n * from the original `coll` sorted by the values returned by the `iteratee`\n * calls. Invoked with (err, results).\n * @returns {Promise} a promise, if no callback passed\n * @example\n *\n * // bigfile.txt is a file that is 251100 bytes in size\n * // mediumfile.txt is a file that is 11000 bytes in size\n * // smallfile.txt is a file that is 121 bytes in size\n *\n * // asynchronous function that returns the file size in bytes\n * function getFileSizeInBytes(file, callback) {\n *     fs.stat(file, function(err, stat) {\n *         if (err) {\n *             return callback(err);\n *         }\n *         callback(null, stat.size);\n *     });\n * }\n *\n * // Using callbacks\n * async.sortBy(['mediumfile.txt','smallfile.txt','bigfile.txt'], getFileSizeInBytes,\n *     function(err, results) {\n *         if (err) {\n *             console.log(err);\n *         } else {\n *             console.log(results);\n *             // results is now the original array of files sorted by\n *             // file size (ascending by default), e.g.\n *             // [ 'smallfile.txt', 'mediumfile.txt', 'bigfile.txt']\n *         }\n *     }\n * );\n *\n * // By modifying the callback parameter the\n * // sorting order can be influenced:\n *\n * // ascending order\n * async.sortBy(['mediumfile.txt','smallfile.txt','bigfile.txt'], function(file, callback) {\n *     getFileSizeInBytes(file, function(getFileSizeErr, fileSize) {\n *         if (getFileSizeErr) return callback(getFileSizeErr);\n *         callback(null, fileSize);\n *     });\n * }, function(err, results) {\n *         if (err) {\n *             console.log(err);\n *         } else {\n *             console.log(results);\n *             // results is now the original array of files sorted by\n *             // file size (ascending by default), e.g.\n *             // [ 'smallfile.txt', 'mediumfile.txt', 'bigfile.txt']\n *         }\n *     }\n * );\n *\n * // descending order\n * async.sortBy(['bigfile.txt','mediumfile.txt','smallfile.txt'], function(file, callback) {\n *     getFileSizeInBytes(file, function(getFileSizeErr, fileSize) {\n *         if (getFileSizeErr) {\n *             return callback(getFileSizeErr);\n *         }\n *         callback(null, fileSize * -1);\n *     });\n * }, function(err, results) {\n *         if (err) {\n *             console.log(err);\n *         } else {\n *             console.log(results);\n *             // results is now the original array of files sorted by\n *             // file size (ascending by default), e.g.\n *             // [ 'bigfile.txt', 'mediumfile.txt', 'smallfile.txt']\n *         }\n *     }\n * );\n *\n * // Error handling\n * async.sortBy(['mediumfile.txt','smallfile.txt','missingfile.txt'], getFileSizeInBytes,\n *     function(err, results) {\n *         if (err) {\n *             console.log(err);\n *             // [ Error: ENOENT: no such file or directory ]\n *         } else {\n *             console.log(results);\n *         }\n *     }\n * );\n *\n * // Using Promises\n * async.sortBy(['mediumfile.txt','smallfile.txt','bigfile.txt'], getFileSizeInBytes)\n * .then( results => {\n *     console.log(results);\n *     // results is now the original array of files sorted by\n *     // file size (ascending by default), e.g.\n *     // [ 'smallfile.txt', 'mediumfile.txt', 'bigfile.txt']\n * }).catch( err => {\n *     console.log(err);\n * });\n *\n * // Error handling\n * async.sortBy(['mediumfile.txt','smallfile.txt','missingfile.txt'], getFileSizeInBytes)\n * .then( results => {\n *     console.log(results);\n * }).catch( err => {\n *     console.log(err);\n *     // [ Error: ENOENT: no such file or directory ]\n * });\n *\n * // Using async/await\n * (async () => {\n *     try {\n *         let results = await async.sortBy(['bigfile.txt','mediumfile.txt','smallfile.txt'], getFileSizeInBytes);\n *         console.log(results);\n *         // results is now the original array of files sorted by\n *         // file size (ascending by default), e.g.\n *         // [ 'smallfile.txt', 'mediumfile.txt', 'bigfile.txt']\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * })();\n *\n * // Error handling\n * async () => {\n *     try {\n *         let results = await async.sortBy(['missingfile.txt','mediumfile.txt','smallfile.txt'], getFileSizeInBytes);\n *         console.log(results);\n *     }\n *     catch (err) {\n *         console.log(err);\n *         // [ Error: ENOENT: no such file or directory ]\n *     }\n * }\n *\n */\nfunction sortBy (coll, iteratee, callback) {\n    var _iteratee = wrapAsync(iteratee);\n    return map$1(coll, (x, iterCb) => {\n        _iteratee(x, (err, criteria) => {\n            if (err) return iterCb(err);\n            iterCb(err, {value: x, criteria});\n        });\n    }, (err, results) => {\n        if (err) return callback(err);\n        callback(null, results.sort(comparator).map(v => v.value));\n    });\n\n    function comparator(left, right) {\n        var a = left.criteria, b = right.criteria;\n        return a < b ? -1 : a > b ? 1 : 0;\n    }\n}\nvar sortBy$1 = awaitify(sortBy, 3);\n\n/**\n * Sets a time limit on an asynchronous function. If the function does not call\n * its callback within the specified milliseconds, it will be called with a\n * timeout error. The code property for the error object will be `'ETIMEDOUT'`.\n *\n * @name timeout\n * @static\n * @memberOf module:Utils\n * @method\n * @category Util\n * @param {AsyncFunction} asyncFn - The async function to limit in time.\n * @param {number} milliseconds - The specified time limit.\n * @param {*} [info] - Any variable you want attached (`string`, `object`, etc)\n * to timeout Error for more information..\n * @returns {AsyncFunction} Returns a wrapped function that can be used with any\n * of the control flow functions.\n * Invoke this function with the same parameters as you would `asyncFunc`.\n * @example\n *\n * function myFunction(foo, callback) {\n *     doAsyncTask(foo, function(err, data) {\n *         // handle errors\n *         if (err) return callback(err);\n *\n *         // do some stuff ...\n *\n *         // return processed data\n *         return callback(null, data);\n *     });\n * }\n *\n * var wrapped = async.timeout(myFunction, 1000);\n *\n * // call `wrapped` as you would `myFunction`\n * wrapped({ bar: 'bar' }, function(err, data) {\n *     // if `myFunction` takes < 1000 ms to execute, `err`\n *     // and `data` will have their expected values\n *\n *     // else `err` will be an Error with the code 'ETIMEDOUT'\n * });\n */\nfunction timeout(asyncFn, milliseconds, info) {\n    var fn = wrapAsync(asyncFn);\n\n    return initialParams((args, callback) => {\n        var timedOut = false;\n        var timer;\n\n        function timeoutCallback() {\n            var name = asyncFn.name || 'anonymous';\n            var error  = new Error('Callback function \"' + name + '\" timed out.');\n            error.code = 'ETIMEDOUT';\n            if (info) {\n                error.info = info;\n            }\n            timedOut = true;\n            callback(error);\n        }\n\n        args.push((...cbArgs) => {\n            if (!timedOut) {\n                callback(...cbArgs);\n                clearTimeout(timer);\n            }\n        });\n\n        // setup timer and call original function\n        timer = setTimeout(timeoutCallback, milliseconds);\n        fn(...args);\n    });\n}\n\nfunction range(size) {\n    var result = Array(size);\n    while (size--) {\n        result[size] = size;\n    }\n    return result;\n}\n\n/**\n * The same as [times]{@link module:ControlFlow.times} but runs a maximum of `limit` async operations at a\n * time.\n *\n * @name timesLimit\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.times]{@link module:ControlFlow.times}\n * @category Control Flow\n * @param {number} count - The number of times to run the function.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {AsyncFunction} iteratee - The async function to call `n` times.\n * Invoked with the iteration index and a callback: (n, next).\n * @param {Function} callback - see [async.map]{@link module:Collections.map}.\n * @returns {Promise} a promise, if no callback is provided\n */\nfunction timesLimit(count, limit, iteratee, callback) {\n    var _iteratee = wrapAsync(iteratee);\n    return mapLimit$1(range(count), limit, _iteratee, callback);\n}\n\n/**\n * Calls the `iteratee` function `n` times, and accumulates results in the same\n * manner you would use with [map]{@link module:Collections.map}.\n *\n * @name times\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.map]{@link module:Collections.map}\n * @category Control Flow\n * @param {number} n - The number of times to run the function.\n * @param {AsyncFunction} iteratee - The async function to call `n` times.\n * Invoked with the iteration index and a callback: (n, next).\n * @param {Function} callback - see {@link module:Collections.map}.\n * @returns {Promise} a promise, if no callback is provided\n * @example\n *\n * // Pretend this is some complicated async factory\n * var createUser = function(id, callback) {\n *     callback(null, {\n *         id: 'user' + id\n *     });\n * };\n *\n * // generate 5 users\n * async.times(5, function(n, next) {\n *     createUser(n, function(err, user) {\n *         next(err, user);\n *     });\n * }, function(err, users) {\n *     // we should now have 5 users\n * });\n */\nfunction times (n, iteratee, callback) {\n    return timesLimit(n, Infinity, iteratee, callback)\n}\n\n/**\n * The same as [times]{@link module:ControlFlow.times} but runs only a single async operation at a time.\n *\n * @name timesSeries\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.times]{@link module:ControlFlow.times}\n * @category Control Flow\n * @param {number} n - The number of times to run the function.\n * @param {AsyncFunction} iteratee - The async function to call `n` times.\n * Invoked with the iteration index and a callback: (n, next).\n * @param {Function} callback - see {@link module:Collections.map}.\n * @returns {Promise} a promise, if no callback is provided\n */\nfunction timesSeries (n, iteratee, callback) {\n    return timesLimit(n, 1, iteratee, callback)\n}\n\n/**\n * A relative of `reduce`.  Takes an Object or Array, and iterates over each\n * element in parallel, each step potentially mutating an `accumulator` value.\n * The type of the accumulator defaults to the type of collection passed in.\n *\n * @name transform\n * @static\n * @memberOf module:Collections\n * @method\n * @category Collection\n * @param {Array|Iterable|AsyncIterable|Object} coll - A collection to iterate over.\n * @param {*} [accumulator] - The initial state of the transform.  If omitted,\n * it will default to an empty Object or Array, depending on the type of `coll`\n * @param {AsyncFunction} iteratee - A function applied to each item in the\n * collection that potentially modifies the accumulator.\n * Invoked with (accumulator, item, key, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Result is the transformed accumulator.\n * Invoked with (err, result).\n * @returns {Promise} a promise, if no callback provided\n * @example\n *\n * // file1.txt is a file that is 1000 bytes in size\n * // file2.txt is a file that is 2000 bytes in size\n * // file3.txt is a file that is 3000 bytes in size\n *\n * // helper function that returns human-readable size format from bytes\n * function formatBytes(bytes, decimals = 2) {\n *   // implementation not included for brevity\n *   return humanReadbleFilesize;\n * }\n *\n * const fileList = ['file1.txt','file2.txt','file3.txt'];\n *\n * // asynchronous function that returns the file size, transformed to human-readable format\n * // e.g. 1024 bytes = 1KB, 1234 bytes = 1.21 KB, 1048576 bytes = 1MB, etc.\n * function transformFileSize(acc, value, key, callback) {\n *     fs.stat(value, function(err, stat) {\n *         if (err) {\n *             return callback(err);\n *         }\n *         acc[key] = formatBytes(stat.size);\n *         callback(null);\n *     });\n * }\n *\n * // Using callbacks\n * async.transform(fileList, transformFileSize, function(err, result) {\n *     if(err) {\n *         console.log(err);\n *     } else {\n *         console.log(result);\n *         // [ '1000 Bytes', '1.95 KB', '2.93 KB' ]\n *     }\n * });\n *\n * // Using Promises\n * async.transform(fileList, transformFileSize)\n * .then(result => {\n *     console.log(result);\n *     // [ '1000 Bytes', '1.95 KB', '2.93 KB' ]\n * }).catch(err => {\n *     console.log(err);\n * });\n *\n * // Using async/await\n * (async () => {\n *     try {\n *         let result = await async.transform(fileList, transformFileSize);\n *         console.log(result);\n *         // [ '1000 Bytes', '1.95 KB', '2.93 KB' ]\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * })();\n *\n * @example\n *\n * // file1.txt is a file that is 1000 bytes in size\n * // file2.txt is a file that is 2000 bytes in size\n * // file3.txt is a file that is 3000 bytes in size\n *\n * // helper function that returns human-readable size format from bytes\n * function formatBytes(bytes, decimals = 2) {\n *   // implementation not included for brevity\n *   return humanReadbleFilesize;\n * }\n *\n * const fileMap = { f1: 'file1.txt', f2: 'file2.txt', f3: 'file3.txt' };\n *\n * // asynchronous function that returns the file size, transformed to human-readable format\n * // e.g. 1024 bytes = 1KB, 1234 bytes = 1.21 KB, 1048576 bytes = 1MB, etc.\n * function transformFileSize(acc, value, key, callback) {\n *     fs.stat(value, function(err, stat) {\n *         if (err) {\n *             return callback(err);\n *         }\n *         acc[key] = formatBytes(stat.size);\n *         callback(null);\n *     });\n * }\n *\n * // Using callbacks\n * async.transform(fileMap, transformFileSize, function(err, result) {\n *     if(err) {\n *         console.log(err);\n *     } else {\n *         console.log(result);\n *         // { f1: '1000 Bytes', f2: '1.95 KB', f3: '2.93 KB' }\n *     }\n * });\n *\n * // Using Promises\n * async.transform(fileMap, transformFileSize)\n * .then(result => {\n *     console.log(result);\n *     // { f1: '1000 Bytes', f2: '1.95 KB', f3: '2.93 KB' }\n * }).catch(err => {\n *     console.log(err);\n * });\n *\n * // Using async/await\n * async () => {\n *     try {\n *         let result = await async.transform(fileMap, transformFileSize);\n *         console.log(result);\n *         // { f1: '1000 Bytes', f2: '1.95 KB', f3: '2.93 KB' }\n *     }\n *     catch (err) {\n *         console.log(err);\n *     }\n * }\n *\n */\nfunction transform (coll, accumulator, iteratee, callback) {\n    if (arguments.length <= 3 && typeof accumulator === 'function') {\n        callback = iteratee;\n        iteratee = accumulator;\n        accumulator = Array.isArray(coll) ? [] : {};\n    }\n    callback = once(callback || promiseCallback());\n    var _iteratee = wrapAsync(iteratee);\n\n    eachOf$1(coll, (v, k, cb) => {\n        _iteratee(accumulator, v, k, cb);\n    }, err => callback(err, accumulator));\n    return callback[PROMISE_SYMBOL]\n}\n\n/**\n * It runs each task in series but stops whenever any of the functions were\n * successful. If one of the tasks were successful, the `callback` will be\n * passed the result of the successful task. If all tasks fail, the callback\n * will be passed the error and result (if any) of the final attempt.\n *\n * @name tryEach\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @param {Array|Iterable|AsyncIterable|Object} tasks - A collection containing functions to\n * run, each function is passed a `callback(err, result)` it must call on\n * completion with an error `err` (which can be `null`) and an optional `result`\n * value.\n * @param {Function} [callback] - An optional callback which is called when one\n * of the tasks has succeeded, or all have failed. It receives the `err` and\n * `result` arguments of the last attempt at completing the `task`. Invoked with\n * (err, results).\n * @returns {Promise} a promise, if no callback is passed\n * @example\n * async.tryEach([\n *     function getDataFromFirstWebsite(callback) {\n *         // Try getting the data from the first website\n *         callback(err, data);\n *     },\n *     function getDataFromSecondWebsite(callback) {\n *         // First website failed,\n *         // Try getting the data from the backup website\n *         callback(err, data);\n *     }\n * ],\n * // optional callback\n * function(err, results) {\n *     Now do something with the data.\n * });\n *\n */\nfunction tryEach(tasks, callback) {\n    var error = null;\n    var result;\n    return eachSeries$1(tasks, (task, taskCb) => {\n        wrapAsync(task)((err, ...args) => {\n            if (err === false) return taskCb(err);\n\n            if (args.length < 2) {\n                [result] = args;\n            } else {\n                result = args;\n            }\n            error = err;\n            taskCb(err ? null : {});\n        });\n    }, () => callback(error, result));\n}\n\nvar tryEach$1 = awaitify(tryEach);\n\n/**\n * Undoes a [memoize]{@link module:Utils.memoize}d function, reverting it to the original,\n * unmemoized form. Handy for testing.\n *\n * @name unmemoize\n * @static\n * @memberOf module:Utils\n * @method\n * @see [async.memoize]{@link module:Utils.memoize}\n * @category Util\n * @param {AsyncFunction} fn - the memoized function\n * @returns {AsyncFunction} a function that calls the original unmemoized function\n */\nfunction unmemoize(fn) {\n    return (...args) => {\n        return (fn.unmemoized || fn)(...args);\n    };\n}\n\n/**\n * Repeatedly call `iteratee`, while `test` returns `true`. Calls `callback` when\n * stopped, or an error occurs.\n *\n * @name whilst\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @param {AsyncFunction} test - asynchronous truth test to perform before each\n * execution of `iteratee`. Invoked with ().\n * @param {AsyncFunction} iteratee - An async function which is called each time\n * `test` passes. Invoked with (callback).\n * @param {Function} [callback] - A callback which is called after the test\n * function has failed and repeated execution of `iteratee` has stopped. `callback`\n * will be passed an error and any arguments passed to the final `iteratee`'s\n * callback. Invoked with (err, [results]);\n * @returns {Promise} a promise, if no callback is passed\n * @example\n *\n * var count = 0;\n * async.whilst(\n *     function test(cb) { cb(null, count < 5); },\n *     function iter(callback) {\n *         count++;\n *         setTimeout(function() {\n *             callback(null, count);\n *         }, 1000);\n *     },\n *     function (err, n) {\n *         // 5 seconds have passed, n = 5\n *     }\n * );\n */\nfunction whilst(test, iteratee, callback) {\n    callback = onlyOnce(callback);\n    var _fn = wrapAsync(iteratee);\n    var _test = wrapAsync(test);\n    var results = [];\n\n    function next(err, ...rest) {\n        if (err) return callback(err);\n        results = rest;\n        if (err === false) return;\n        _test(check);\n    }\n\n    function check(err, truth) {\n        if (err) return callback(err);\n        if (err === false) return;\n        if (!truth) return callback(null, ...results);\n        _fn(next);\n    }\n\n    return _test(check);\n}\nvar whilst$1 = awaitify(whilst, 3);\n\n/**\n * Repeatedly call `iteratee` until `test` returns `true`. Calls `callback` when\n * stopped, or an error occurs. `callback` will be passed an error and any\n * arguments passed to the final `iteratee`'s callback.\n *\n * The inverse of [whilst]{@link module:ControlFlow.whilst}.\n *\n * @name until\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.whilst]{@link module:ControlFlow.whilst}\n * @category Control Flow\n * @param {AsyncFunction} test - asynchronous truth test to perform before each\n * execution of `iteratee`. Invoked with (callback).\n * @param {AsyncFunction} iteratee - An async function which is called each time\n * `test` fails. Invoked with (callback).\n * @param {Function} [callback] - A callback which is called after the test\n * function has passed and repeated execution of `iteratee` has stopped. `callback`\n * will be passed an error and any arguments passed to the final `iteratee`'s\n * callback. Invoked with (err, [results]);\n * @returns {Promise} a promise, if a callback is not passed\n *\n * @example\n * const results = []\n * let finished = false\n * async.until(function test(cb) {\n *     cb(null, finished)\n * }, function iter(next) {\n *     fetchPage(url, (err, body) => {\n *         if (err) return next(err)\n *         results = results.concat(body.objects)\n *         finished = !!body.next\n *         next(err)\n *     })\n * }, function done (err) {\n *     // all pages have been fetched\n * })\n */\nfunction until(test, iteratee, callback) {\n    const _test = wrapAsync(test);\n    return whilst$1((cb) => _test((err, truth) => cb (err, !truth)), iteratee, callback);\n}\n\n/**\n * Runs the `tasks` array of functions in series, each passing their results to\n * the next in the array. However, if any of the `tasks` pass an error to their\n * own callback, the next function is not executed, and the main `callback` is\n * immediately called with the error.\n *\n * @name waterfall\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @param {Array} tasks - An array of [async functions]{@link AsyncFunction}\n * to run.\n * Each function should complete with any number of `result` values.\n * The `result` values will be passed as arguments, in order, to the next task.\n * @param {Function} [callback] - An optional callback to run once all the\n * functions have completed. This will be passed the results of the last task's\n * callback. Invoked with (err, [results]).\n * @returns undefined\n * @example\n *\n * async.waterfall([\n *     function(callback) {\n *         callback(null, 'one', 'two');\n *     },\n *     function(arg1, arg2, callback) {\n *         // arg1 now equals 'one' and arg2 now equals 'two'\n *         callback(null, 'three');\n *     },\n *     function(arg1, callback) {\n *         // arg1 now equals 'three'\n *         callback(null, 'done');\n *     }\n * ], function (err, result) {\n *     // result now equals 'done'\n * });\n *\n * // Or, with named functions:\n * async.waterfall([\n *     myFirstFunction,\n *     mySecondFunction,\n *     myLastFunction,\n * ], function (err, result) {\n *     // result now equals 'done'\n * });\n * function myFirstFunction(callback) {\n *     callback(null, 'one', 'two');\n * }\n * function mySecondFunction(arg1, arg2, callback) {\n *     // arg1 now equals 'one' and arg2 now equals 'two'\n *     callback(null, 'three');\n * }\n * function myLastFunction(arg1, callback) {\n *     // arg1 now equals 'three'\n *     callback(null, 'done');\n * }\n */\nfunction waterfall (tasks, callback) {\n    callback = once(callback);\n    if (!Array.isArray(tasks)) return callback(new Error('First argument to waterfall must be an array of functions'));\n    if (!tasks.length) return callback();\n    var taskIndex = 0;\n\n    function nextTask(args) {\n        var task = wrapAsync(tasks[taskIndex++]);\n        task(...args, onlyOnce(next));\n    }\n\n    function next(err, ...args) {\n        if (err === false) return\n        if (err || taskIndex === tasks.length) {\n            return callback(err, ...args);\n        }\n        nextTask(args);\n    }\n\n    nextTask([]);\n}\n\nvar waterfall$1 = awaitify(waterfall);\n\n/**\n * An \"async function\" in the context of Async is an asynchronous function with\n * a variable number of parameters, with the final parameter being a callback.\n * (`function (arg1, arg2, ..., callback) {}`)\n * The final callback is of the form `callback(err, results...)`, which must be\n * called once the function is completed.  The callback should be called with a\n * Error as its first argument to signal that an error occurred.\n * Otherwise, if no error occurred, it should be called with `null` as the first\n * argument, and any additional `result` arguments that may apply, to signal\n * successful completion.\n * The callback must be called exactly once, ideally on a later tick of the\n * JavaScript event loop.\n *\n * This type of function is also referred to as a \"Node-style async function\",\n * or a \"continuation passing-style function\" (CPS). Most of the methods of this\n * library are themselves CPS/Node-style async functions, or functions that\n * return CPS/Node-style async functions.\n *\n * Wherever we accept a Node-style async function, we also directly accept an\n * [ES2017 `async` function]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function}.\n * In this case, the `async` function will not be passed a final callback\n * argument, and any thrown error will be used as the `err` argument of the\n * implicit callback, and the return value will be used as the `result` value.\n * (i.e. a `rejected` of the returned Promise becomes the `err` callback\n * argument, and a `resolved` value becomes the `result`.)\n *\n * Note, due to JavaScript limitations, we can only detect native `async`\n * functions and not transpilied implementations.\n * Your environment must have `async`/`await` support for this to work.\n * (e.g. Node > v7.6, or a recent version of a modern browser).\n * If you are using `async` functions through a transpiler (e.g. Babel), you\n * must still wrap the function with [asyncify]{@link module:Utils.asyncify},\n * because the `async function` will be compiled to an ordinary function that\n * returns a promise.\n *\n * @typedef {Function} AsyncFunction\n * @static\n */\n\nvar index = {\n    apply,\n    applyEach: applyEach$1,\n    applyEachSeries,\n    asyncify,\n    auto,\n    autoInject,\n    cargo,\n    cargoQueue: cargo$1,\n    compose,\n    concat: concat$1,\n    concatLimit: concatLimit$1,\n    concatSeries: concatSeries$1,\n    constant,\n    detect: detect$1,\n    detectLimit: detectLimit$1,\n    detectSeries: detectSeries$1,\n    dir,\n    doUntil,\n    doWhilst: doWhilst$1,\n    each,\n    eachLimit: eachLimit$2,\n    eachOf: eachOf$1,\n    eachOfLimit: eachOfLimit$2,\n    eachOfSeries: eachOfSeries$1,\n    eachSeries: eachSeries$1,\n    ensureAsync,\n    every: every$1,\n    everyLimit: everyLimit$1,\n    everySeries: everySeries$1,\n    filter: filter$1,\n    filterLimit: filterLimit$1,\n    filterSeries: filterSeries$1,\n    forever: forever$1,\n    groupBy,\n    groupByLimit: groupByLimit$1,\n    groupBySeries,\n    log,\n    map: map$1,\n    mapLimit: mapLimit$1,\n    mapSeries: mapSeries$1,\n    mapValues,\n    mapValuesLimit: mapValuesLimit$1,\n    mapValuesSeries,\n    memoize,\n    nextTick,\n    parallel,\n    parallelLimit,\n    priorityQueue,\n    queue: queue$1,\n    race: race$1,\n    reduce: reduce$1,\n    reduceRight,\n    reflect,\n    reflectAll,\n    reject: reject$2,\n    rejectLimit: rejectLimit$1,\n    rejectSeries: rejectSeries$1,\n    retry,\n    retryable,\n    seq,\n    series,\n    setImmediate: setImmediate$1,\n    some: some$1,\n    someLimit: someLimit$1,\n    someSeries: someSeries$1,\n    sortBy: sortBy$1,\n    timeout,\n    times,\n    timesLimit,\n    timesSeries,\n    transform,\n    tryEach: tryEach$1,\n    unmemoize,\n    until,\n    waterfall: waterfall$1,\n    whilst: whilst$1,\n\n    // aliases\n    all: every$1,\n    allLimit: everyLimit$1,\n    allSeries: everySeries$1,\n    any: some$1,\n    anyLimit: someLimit$1,\n    anySeries: someSeries$1,\n    find: detect$1,\n    findLimit: detectLimit$1,\n    findSeries: detectSeries$1,\n    flatMap: concat$1,\n    flatMapLimit: concatLimit$1,\n    flatMapSeries: concatSeries$1,\n    forEach: each,\n    forEachSeries: eachSeries$1,\n    forEachLimit: eachLimit$2,\n    forEachOf: eachOf$1,\n    forEachOfSeries: eachOfSeries$1,\n    forEachOfLimit: eachOfLimit$2,\n    inject: reduce$1,\n    foldl: reduce$1,\n    foldr: reduceRight,\n    select: filter$1,\n    selectLimit: filterLimit$1,\n    selectSeries: filterSeries$1,\n    wrapSync: asyncify,\n    during: whilst$1,\n    doDuring: doWhilst$1\n};\n\nexport default index;\nexport { apply, applyEach$1 as applyEach, applyEachSeries, asyncify, auto, autoInject, cargo, cargo$1 as cargoQueue, compose, concat$1 as concat, concatLimit$1 as concatLimit, concatSeries$1 as concatSeries, constant, detect$1 as detect, detectLimit$1 as detectLimit, detectSeries$1 as detectSeries, dir, doUntil, doWhilst$1 as doWhilst, each, eachLimit$2 as eachLimit, eachOf$1 as eachOf, eachOfLimit$2 as eachOfLimit, eachOfSeries$1 as eachOfSeries, eachSeries$1 as eachSeries, ensureAsync, every$1 as every, everyLimit$1 as everyLimit, everySeries$1 as everySeries, filter$1 as filter, filterLimit$1 as filterLimit, filterSeries$1 as filterSeries, forever$1 as forever, groupBy, groupByLimit$1 as groupByLimit, groupBySeries, log, map$1 as map, mapLimit$1 as mapLimit, mapSeries$1 as mapSeries, mapValues, mapValuesLimit$1 as mapValuesLimit, mapValuesSeries, memoize, nextTick, parallel, parallelLimit, priorityQueue, queue$1 as queue, race$1 as race, reduce$1 as reduce, reduceRight, reflect, reflectAll, reject$2 as reject, rejectLimit$1 as rejectLimit, rejectSeries$1 as rejectSeries, retry, retryable, seq, series, setImmediate$1 as setImmediate, some$1 as some, someLimit$1 as someLimit, someSeries$1 as someSeries, sortBy$1 as sortBy, timeout, times, timesLimit, timesSeries, transform, tryEach$1 as tryEach, unmemoize, until, waterfall$1 as waterfall, whilst$1 as whilst, every$1 as all, everyLimit$1 as allLimit, everySeries$1 as allSeries, some$1 as any, someLimit$1 as anyLimit, someSeries$1 as anySeries, detect$1 as find, detectLimit$1 as findLimit, detectSeries$1 as findSeries, concat$1 as flatMap, concatLimit$1 as flatMapLimit, concatSeries$1 as flatMapSeries, each as forEach, eachSeries$1 as forEachSeries, eachLimit$2 as forEachLimit, eachOf$1 as forEachOf, eachOfSeries$1 as forEachOfSeries, eachOfLimit$2 as forEachOfLimit, reduce$1 as inject, reduce$1 as foldl, reduceRight as foldr, filter$1 as select, filterLimit$1 as selectLimit, filterSeries$1 as selectSeries, asyncify as wrapSync, whilst$1 as during, doWhilst$1 as doDuring };\n","import { getLogger } from '@jitsi/logger';\nimport { queue } from 'async';\n\nconst logger = getLogger(__filename);\n\n/**\n * A queue for async task execution.\n */\nexport default class AsyncQueue {\n    /**\n     * Creates new instance.\n     */\n    constructor() {\n        this._queue = queue(this._processQueueTasks.bind(this), 1);\n        this._stopped = false;\n    }\n\n    /**\n     * Removes any pending tasks from the queue.\n     */\n    clear() {\n        this._queue.kill();\n    }\n\n    /**\n     * Internal task processing implementation which makes things work.\n     */\n    _processQueueTasks(task, finishedCallback) {\n        try {\n            task(finishedCallback);\n        } catch (error) {\n            logger.error(`Task failed: ${error?.stack}`);\n            finishedCallback(error);\n        }\n    }\n\n    /**\n     * The 'task' function will be given a callback it MUST call with either:\n     *  1) No arguments if it was successful or\n     *  2) An error argument if there was an error\n     * If the task wants to process the success or failure of the task, it\n     * should pass the {@code callback} to the push function, e.g.:\n     * queue.push(task, (err) => {\n     *     if (err) {\n     *         // error handling\n     *     } else {\n     *         // success handling\n     *     }\n     * });\n     *\n     * @param {function} task - The task to be executed. See the description above.\n     * @param {function} [callback] - Optional callback to be called after the task has been executed.\n     */\n    push(task, callback) {\n        if (this._stopped) {\n            callback && callback(new Error('The queue has been stopped'));\n\n            return;\n        }\n        this._queue.push(task, callback);\n    }\n\n    /**\n     * Shutdowns the queue. All already queued tasks will execute, but no future tasks can be added. If a task is added\n     * after the queue has been shutdown then the callback will be called with an error.\n     */\n    shutdown() {\n        this._stopped = true;\n    }\n}\n","export enum JingleSessionState {\n    /**\n     * The pending Jingle session state which means the session as defined in\n     * XEP-0166(before 'session-invite/session-accept' took place).\n     */\n    PENDING = 'pending',\n\n    /**\n     * The active Jingle session state as defined in XEP-0166\n     * (after 'session-invite'/'session-accept').\n     */\n    ACTIVE = 'active',\n\n    /**\n     * The ended Jingle session state as defined in XEP-0166\n     * (after 'session-terminate').\n     */\n    ENDED = 'ended'\n};\n\n// exported for backward compatibility\nexport const PENDING = JingleSessionState.PENDING;\nexport const ACTIVE = JingleSessionState.ACTIVE;\nexport const ENDED = JingleSessionState.ENDED;\n","import { getLogger } from '@jitsi/logger';\n\nimport Listenable from '../util/Listenable';\n\nimport * as JingleSessionState from './JingleSessionState';\n\nconst logger = getLogger(__filename);\n\n/**\n * JingleSession provides an API to manage a single Jingle session. We will\n * have different implementations depending on the underlying interface used\n * (i.e. WebRTC and ORTC) and here we hold the code common to all of them.\n */\nexport default class JingleSession extends Listenable {\n\n    /* eslint-disable max-params */\n\n    /**\n     * Creates new <tt>JingleSession</tt>.\n     * @param {string} sid the Jingle session identifier\n     * @param {string} localJid our JID\n     * @param {string} remoteJid the JID of the remote peer\n     * @param {XmppConnection} connection the XMPP connection\n     * @param {Object} mediaConstraints the media constraints object passed to the PeerConnection onCreateAnswer/Offer.\n     * @param {Object} pcConfig The {@code RTCConfiguration} object passed to the PeerConnection's constructor.\n     * @param {boolean} isInitiator indicates if it will be the side which initiates the session.\n     */\n    constructor(\n            sid,\n            localJid,\n            remoteJid,\n            connection,\n            mediaConstraints,\n            pcConfig,\n            isInitiator) {\n        super();\n        this.sid = sid;\n        this.localJid = localJid;\n        this.remoteJid = remoteJid;\n        this.connection = connection;\n        this.mediaConstraints = mediaConstraints;\n        this.pcConfig = pcConfig;\n\n        /**\n         * Indicates whether this instance is an initiator or an answerer of\n         * the Jingle session.\n         * @type {boolean}\n         */\n        this.isInitiator = isInitiator;\n\n        /**\n         * Whether to use dripping or not. Dripping is sending trickle\n         * candidates not one-by-one.\n         */\n        this.usedrip = true;\n\n        /**\n         *  When dripping is used, stores ICE candidates which are to be sent.\n         */\n        this.dripContainer = [];\n\n        /**\n         * The chat room instance associated with the session.\n         * @type {ChatRoom}\n         */\n        this.room = null;\n\n        /**\n         * The signaling layer.\n         * @type {SignalingLayerImpl | null}\n         * @private\n         */\n        this._signalingLayer = null;\n\n        /**\n         * Jingle session state - uninitialized until {@link initialize} is\n         * called @type {JingleSessionState}\n         */\n        this.state = null;\n\n        /**\n         * The RTC service instance\n         * @type {RTC}\n         */\n        this.rtc = null;\n    }\n\n    /**\n     * Returns XMPP address of this session's initiator.\n     * @return {string}\n     */\n    get initiatorJid() {\n        return this.isInitiator ? this.localJid : this.remoteJid;\n    }\n\n    /**\n     * Returns XMPP address of this session's responder.\n     * @return {string}\n     */\n    get responderJid() {\n        return this.isInitiator ? this.remoteJid : this.localJid;\n    }\n\n    /* eslint-enable max-params */\n\n    /**\n     * Prepares this object to initiate a session.\n     * @param {ChatRoom} room the chat room for the conference associated with\n     * this session\n     * @param {RTC} rtc the RTC service instance\n     * @param {SignalingLayerImpl} signalingLayer - The signaling layer instance.\n     * @param {object} options - the options, see implementing class's\n     * {@link #doInitialize} description for more details.\n     */\n    initialize(room, rtc, signalingLayer, options) {\n        if (this.state !== null) {\n            const errmsg\n                = `attempt to initiate on session ${this.sid}\n                   in state ${this.state}`;\n\n            logger.error(errmsg);\n            throw new Error(errmsg);\n        }\n\n        // TODO decouple from room\n        this.room = room;\n        this.rtc = rtc;\n        this._signalingLayer = signalingLayer;\n        this.state = JingleSessionState.PENDING;\n        this.doInitialize(options);\n    }\n\n    /**\n     * The implementing class finishes initialization here. Called at the end of\n     * {@link initialize}.\n     * @param {Object} options - The options specific to the implementing class.\n     * @protected\n     */\n    doInitialize(options) { } // eslint-disable-line no-unused-vars, no-empty-function, max-len\n\n    /* eslint-disable no-unused-vars, no-empty-function */\n\n    /**\n     * Adds the ICE candidates found in the 'contents' array as remote\n     * candidates?\n     * Note: currently only used on transport-info\n     *\n     * @param contents\n     */\n    addIceCandidates(contents) {}\n\n    /* eslint-enable no-unused-vars, no-empty-function */\n\n    /**\n     * Returns current state of this <tt>JingleSession</tt> instance.\n     * @returns {JingleSessionState} the current state of this session instance.\n     */\n    getState() {\n        return this.state;\n    }\n\n    /* eslint-disable no-unused-vars, no-empty-function */\n\n    /**\n     * Handles an 'add-source' event.\n     *\n     * @param contents an array of Jingle 'content' elements.\n     */\n    addSources(contents) {}\n\n    /**\n     * Handles a 'remove-source' event.\n     *\n     * @param contents an array of Jingle 'content' elements.\n     */\n    removeSources(contents) {}\n\n    /**\n     * Terminates this Jingle session by sending session-terminate\n     * @param success a callback called once the 'session-terminate' packet has\n     * been acknowledged with RESULT.\n     * @param failure a callback called when either timeout occurs or ERROR\n     * response is received.\n     * @param {Object} options\n     * @param {string} [options.reason] XMPP Jingle error condition\n     * @param {string} [options.reasonDescription] some meaningful error message\n     * @param {boolean} [options.requestRestart=false] set to true to ask Jicofo to start a new session one this once is\n     * terminated.\n     * @param {boolean} [options.sendSessionTerminate=true] set to false to skip\n     * sending session-terminate. It may not make sense to send it if the XMPP\n     * connection has been closed already or if the remote peer has disconnected\n     */\n    terminate(success, failure, options) {}\n\n    /**\n     * Handles an offer from the remote peer (prepares to accept a session).\n     * @param jingle the 'jingle' XML element.\n     * @param success callback called when we the incoming session has been\n     * accepted\n     * @param failure callback called when we fail for any reason, will supply\n     * error object with details(which is meant more to be printed to the logger\n     * than analysed in the code, as the error is unrecoverable anyway)\n     */\n    acceptOffer(jingle, success, failure) {}\n\n    /**\n     * Returns the JID of the initiator of the jingle session.\n     */\n    _getInitiatorJid() {\n        return this.isInitiator ? this.localJid : this.remoteJid;\n    }\n\n    /* eslint-enable no-unused-vars, no-empty-function */\n}\n","enum MediaSessionEvents {\n    /**\n     * Event triggered when the remote party signals it's receive video max frame height.\n     */\n    REMOTE_VIDEO_CONSTRAINTS_CHANGED = 'media_session.REMOTE_VIDEO_CONSTRAINTS_CHANGED'\n};\n\nexport default MediaSessionEvents;","import { getLogger } from '@jitsi/logger';\nimport $ from 'jquery';\nimport { $iq, Strophe } from 'strophe.js';\n\nimport CodecMimeType from '../../service/RTC/CodecMimeType';\nimport MediaDirection from '../../service/RTC/MediaDirection';\nimport { MediaType } from '../../service/RTC/MediaType';\nimport {\n    ICE_DURATION,\n    ICE_STATE_CHANGED\n} from '../../service/statistics/AnalyticsEvents';\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\nimport { SS_DEFAULT_FRAME_RATE } from '../RTC/ScreenObtainer';\nimport FeatureFlags from '../flags/FeatureFlags';\nimport SDP from '../sdp/SDP';\nimport SDPDiffer from '../sdp/SDPDiffer';\nimport SDPUtil from '../sdp/SDPUtil';\nimport Statistics from '../statistics/statistics';\nimport AsyncQueue from '../util/AsyncQueue';\nimport GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';\nimport { integerHash } from '../util/StringUtils';\n\nimport browser from './../browser';\nimport JingleSession from './JingleSession';\nimport * as JingleSessionState from './JingleSessionState';\nimport MediaSessionEvents from './MediaSessionEvents';\nimport XmppConnection from './XmppConnection';\n\nconst logger = getLogger(__filename);\n\n/**\n * Constant tells how long we're going to wait for IQ response, before timeout\n * error is  triggered.\n * @type {number}\n */\nconst IQ_TIMEOUT = 10000;\n\n/*\n * The default number of samples (per stat) to keep when webrtc stats gathering\n * is enabled in TraceablePeerConnection.\n */\nconst DEFAULT_MAX_STATS = 300;\n\n/**\n * The time duration for which the client keeps gathering ICE candidates to be sent out in a single IQ.\n * @type {number} timeout in ms.\n */\nconst ICE_CAND_GATHERING_TIMEOUT = 150;\n\n/**\n * Reads the endpoint ID given a string which represents either the endpoint's full JID, or the endpoint ID itself.\n * @param {String} jidOrEndpointId A string which is either the full JID of a participant, or the ID of an\n * endpoint/participant.\n * @returns The endpoint ID associated with 'jidOrEndpointId'.\n */\nfunction getEndpointId(jidOrEndpointId) {\n    return Strophe.getResourceFromJid(jidOrEndpointId) || jidOrEndpointId;\n}\n\n/**\n * @typedef {Object} JingleSessionPCOptions\n * @property {Object} abTesting - A/B testing related options (ask George).\n * @property {boolean} abTesting.enableSuspendVideoTest - enables the suspend\n * video test ?(ask George).\n * @property {boolean} disableH264 - Described in the config.js[1].\n * @property {boolean} disableRtx - Described in the config.js[1].\n * @property {boolean} disableSimulcast - Described in the config.js[1].\n * @property {boolean} enableInsertableStreams - Set to true when the insertable streams constraints is to be enabled\n * on the PeerConnection.\n * @property {boolean} enableLayerSuspension - Described in the config.js[1].\n * @property {boolean} failICE - it's an option used in the tests. Set to\n * <tt>true</tt> to block any real candidates and make the ICE fail.\n * @property {boolean} gatherStats - Described in the config.js[1].\n * @property {object} p2p - Peer to peer related options (FIXME those could be\n * fetched from config.p2p on the upper level).\n * @property {boolean} preferH264 - Described in the config.js[1].\n * @property {Object} testing - Testing and/or experimental options.\n * @property {boolean} webrtcIceUdpDisable - Described in the config.js[1].\n * @property {boolean} webrtcIceTcpDisable - Described in the config.js[1].\n *\n * [1]: https://github.com/jitsi/jitsi-meet/blob/master/config.js\n */\n/**\n *\n */\nexport default class JingleSessionPC extends JingleSession {\n    /**\n     * Parses 'senders' attribute of the video content.\n     * @param {jQuery} jingleContents\n     * @return {string|null} one of the values of content \"senders\" attribute\n     * defined by Jingle. If there is no \"senders\" attribute or if the value is\n     * invalid then <tt>null</tt> will be returned.\n     * @private\n     */\n    static parseVideoSenders(jingleContents) {\n        const videoContents = jingleContents.find('>content[name=\"video\"]');\n\n        if (videoContents.length) {\n            const senders = videoContents[0].getAttribute('senders');\n\n            if (senders === 'both'\n                || senders === 'initiator'\n                || senders === 'responder'\n                || senders === 'none') {\n                return senders;\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * Parses the video max frame height value out of the 'content-modify' IQ.\n     *\n     * @param {jQuery} jingleContents - A jQuery selector pointing to the '>jingle' element.\n     * @returns {Number|null}\n     */\n    static parseMaxFrameHeight(jingleContents) {\n        const maxFrameHeightSel = jingleContents.find('>content[name=\"video\"]>max-frame-height');\n\n        return maxFrameHeightSel.length ? Number(maxFrameHeightSel.text()) : null;\n    }\n\n    /* eslint-disable max-params */\n\n    /**\n     * Creates new <tt>JingleSessionPC</tt>\n     * @param {string} sid the Jingle Session ID - random string which identifies the session\n     * @param {string} localJid our JID\n     * @param {string} remoteJid remote peer JID\n     * @param {XmppConnection} connection - The XMPP connection instance.\n     * @param mediaConstraints the media constraints object passed to createOffer/Answer, as defined\n     * by the WebRTC standard\n     * @param pcConfig The {@code RTCConfiguration} to use for the WebRTC peer connection.\n     * @param {boolean} isP2P indicates whether this instance is meant to be used in a direct, peer to\n     * peer connection or <tt>false</tt> if it's a JVB connection.\n     * @param {boolean} isInitiator indicates if it will be the side which initiates the session.\n     * @constructor\n     *\n     * @implements {SignalingLayer}\n     */\n    constructor(\n            sid,\n            localJid,\n            remoteJid,\n            connection,\n            mediaConstraints,\n            pcConfig,\n            isP2P,\n            isInitiator) {\n        super(\n            sid,\n            localJid,\n            remoteJid, connection, mediaConstraints, pcConfig, isInitiator);\n\n        /**\n         * The bridge session's identifier. One Jingle session can during\n         * it's lifetime participate in multiple bridge sessions managed by\n         * Jicofo. A new bridge session is started whenever Jicofo sends\n         * 'session-initiate' or 'transport-replace'.\n         *\n         * @type {?string}\n         * @private\n         */\n        this._bridgeSessionId = null;\n\n        /**\n         * The oldest SDP passed to {@link notifyMySSRCUpdate} while the XMPP connection was offline that will be\n         * used to update Jicofo once the XMPP connection goes back online.\n         * @type {SDP|undefined}\n         * @private\n         */\n        this._cachedOldLocalSdp = undefined;\n\n        /**\n         * The latest SDP passed to {@link notifyMySSRCUpdate} while the XMPP connection was offline that will be\n         * used to update Jicofo once the XMPP connection goes back online.\n         * @type {SDP|undefined}\n         * @private\n         */\n        this._cachedNewLocalSdp = undefined;\n\n        /**\n         * Stores result of {@link window.performance.now()} at the time when\n         * ICE enters 'checking' state.\n         * @type {number|null} null if no value has been stored yet\n         * @private\n         */\n        this._iceCheckingStartedTimestamp = null;\n\n        /**\n         * Stores result of {@link window.performance.now()} at the time when\n         * first ICE candidate is spawned by the peerconnection to mark when\n         * ICE gathering started. That's, because ICE gathering state changed\n         * events are not supported by most of the browsers, so we try something\n         * that will work everywhere. It may not be as accurate, but given that\n         * 'host' candidate usually comes first, the delay should be minimal.\n         * @type {number|null} null if no value has been stored yet\n         * @private\n         */\n        this._gatheringStartedTimestamp = null;\n\n        /**\n         * Local preference for the receive video max frame height.\n         *\n         * @type {Number|undefined}\n         */\n        this.localRecvMaxFrameHeight = undefined;\n\n        /**\n         * Indicates whether or not this session is willing to send/receive\n         * video media. When set to <tt>false</tt> the underlying peer\n         * connection will disable local video transfer and the remote peer will\n         * be will be asked to stop sending video via 'content-modify' IQ\n         * (the senders attribute of video contents will be adjusted\n         * accordingly). Note that this notification is sent only in P2P\n         * session, because Jicofo does not support it yet. Obviously when\n         * the value is changed from <tt>false</tt> to <tt>true</tt> another\n         * notification will be sent to resume video transfer on the remote\n         * side.\n         * @type {boolean}\n         * @private\n         */\n        this._localVideoActive = true;\n\n        /**\n         * Indicates whether or not the remote peer has video transfer active.\n         * When set to <tt>true</tt> it means that remote peer is neither\n         * sending nor willing to receive video. In such case we'll ask\n         * our peerconnection to stop sending video by calling\n         * {@link TraceablePeerConnection.setVideoTransferActive} with\n         * <tt>false</tt>.\n         * @type {boolean}\n         * @private\n         */\n        this._remoteVideoActive = true;\n\n        /**\n         * Marks that ICE gathering duration has been reported already. That\n         * prevents reporting it again, after eventual 'transport-replace' (JVB\n         * conference migration/ICE restart).\n         * @type {boolean}\n         * @private\n         */\n        this._gatheringReported = false;\n\n        this.lasticecandidate = false;\n        this.closed = false;\n\n        /**\n         * Indicates whether or not this <tt>JingleSessionPC</tt> is used in\n         * a peer to peer type of session.\n         * @type {boolean} <tt>true</tt> if it's a peer to peer\n         * session or <tt>false</tt> if it's a JVB session\n         */\n        this.isP2P = isP2P;\n\n        /**\n         * Remote preference for the receive video max frame height.\n         *\n         * @type {Number|undefined}\n         */\n        this.remoteRecvMaxFrameHeight = undefined;\n\n        /**\n         * The queue used to serialize operations done on the peerconnection.\n         *\n         * @type {AsyncQueue}\n         */\n        this.modificationQueue = new AsyncQueue();\n\n        /**\n         * Flag used to guarantee that the connection established event is\n         * triggered just once.\n         * @type {boolean}\n         */\n        this.wasConnected = false;\n\n        /**\n         * Keeps track of how long (in ms) it took from ICE start to ICE\n         * connect.\n         *\n         * @type {number}\n         */\n        this.establishmentDuration = undefined;\n\n        this._xmppListeners = [];\n        this._xmppListeners.push(\n            connection.addEventListener(\n                XmppConnection.Events.CONN_STATUS_CHANGED,\n                this.onXmppStatusChanged.bind(this))\n        );\n\n        this._removeSenderVideoConstraintsChangeListener = undefined;\n    }\n\n    /* eslint-enable max-params */\n\n    /**\n     * Checks whether or not this session instance is still operational.\n     * @private\n     * @returns {boolean} {@code true} if operation or {@code false} otherwise.\n     */\n    _assertNotEnded() {\n        return this.state !== JingleSessionState.ENDED;\n    }\n\n    /**\n     * @inheritDoc\n     * @param {JingleSessionPCOptions} options  - a set of config options.\n     */\n    doInitialize(options) {\n        this.failICE = Boolean(options.failICE);\n        this.lasticecandidate = false;\n        this.options = options;\n\n        /**\n         * {@code true} if reconnect is in progress.\n         * @type {boolean}\n         */\n        this.isReconnect = false;\n\n        /**\n         * Set to {@code true} if the connection was ever stable\n         * @type {boolean}\n         */\n        this.wasstable = false;\n        this.webrtcIceUdpDisable = Boolean(options.webrtcIceUdpDisable);\n        this.webrtcIceTcpDisable = Boolean(options.webrtcIceTcpDisable);\n\n        const pcOptions = { disableRtx: options.disableRtx };\n\n        if (options.gatherStats) {\n            pcOptions.maxstats = DEFAULT_MAX_STATS;\n        }\n        pcOptions.capScreenshareBitrate = false;\n        pcOptions.enableInsertableStreams = options.enableInsertableStreams;\n        pcOptions.videoQuality = options.videoQuality;\n        pcOptions.forceTurnRelay = options.forceTurnRelay;\n        pcOptions.audioQuality = options.audioQuality;\n        pcOptions.usesUnifiedPlan = this.usesUnifiedPlan\n            = browser.supportsUnifiedPlan()\n                && (browser.isFirefox()\n                    || browser.isWebKitBased()\n                    || (browser.isChromiumBased()\n\n                        // Provide a way to control the behavior for jvb and p2p connections independently.\n                        && this.isP2P\n                        ? options.p2p?.enableUnifiedOnChrome ?? true\n                        : options.enableUnifiedOnChrome ?? true));\n\n        if (this.isP2P) {\n            // simulcast needs to be disabled for P2P (121) calls\n            pcOptions.disableSimulcast = true;\n            const abtestSuspendVideo = this._abtestSuspendVideoEnabled(options);\n\n            if (typeof abtestSuspendVideo !== 'undefined') {\n                pcOptions.abtestSuspendVideo = abtestSuspendVideo;\n            }\n        } else {\n            // H264 does not support simulcast, so it needs to be disabled.\n            pcOptions.disableSimulcast\n                = options.disableSimulcast\n                    || (options.preferH264 && !options.disableH264)\n                    || (options.videoQuality && options.videoQuality.preferredCodec === CodecMimeType.H264);\n\n            // Disable simulcast for low fps screenshare and enable it for high fps screenshare.\n            // testing.capScreenshareBitrate config.js setting has now been deprecated.\n            pcOptions.capScreenshareBitrate = pcOptions.disableSimulcast\n                || !(typeof options.desktopSharingFrameRate?.max === 'number'\n                    && options.desktopSharingFrameRate?.max > SS_DEFAULT_FRAME_RATE);\n\n            // add the capScreenshareBitrate to the permanent properties so that it's included with every event that we\n            // send to the analytics backend.\n            Statistics.analytics.addPermanentProperties({ capScreenshareBitrate: pcOptions.capScreenshareBitrate });\n        }\n\n        if (options.startSilent) {\n            pcOptions.startSilent = true;\n        }\n\n        this.peerconnection\n            = this.rtc.createPeerConnection(\n                    this._signalingLayer,\n                    this.pcConfig,\n                    this.isP2P,\n                    pcOptions);\n\n        this.peerconnection.onicecandidate = ev => {\n            if (!ev) {\n                // There was an incomplete check for ev before which left\n                // the last line of the function unprotected from a potential\n                // throw of an exception. Consequently, it may be argued that\n                // the check is unnecessary. Anyway, I'm leaving it and making\n                // the check complete.\n                return;\n            }\n\n            // XXX this is broken, candidate is not parsed.\n            const candidate = ev.candidate;\n            const now = window.performance.now();\n\n            if (candidate) {\n                if (this._gatheringStartedTimestamp === null) {\n                    this._gatheringStartedTimestamp = now;\n                }\n\n                // Discard candidates of disabled protocols.\n                let protocol = candidate.protocol;\n\n                if (typeof protocol === 'string') {\n                    protocol = protocol.toLowerCase();\n                    if (protocol === 'tcp' || protocol === 'ssltcp') {\n                        if (this.webrtcIceTcpDisable) {\n                            return;\n                        }\n                    } else if (protocol === 'udp') {\n                        if (this.webrtcIceUdpDisable) {\n                            return;\n                        }\n                    }\n                }\n            } else if (!this._gatheringReported) {\n                // End of gathering\n                Statistics.sendAnalytics(\n                    ICE_DURATION,\n                    {\n                        phase: 'gathering',\n                        value: now - this._gatheringStartedTimestamp,\n                        p2p: this.isP2P,\n                        initiator: this.isInitiator\n                    });\n                this._gatheringReported = true;\n            }\n            this.sendIceCandidate(candidate);\n        };\n\n        // Note there is a change in the spec about closed:\n        // This value moved into the RTCPeerConnectionState enum in\n        // the May 13, 2016 draft of the specification, as it reflects the state\n        // of the RTCPeerConnection, not the signaling connection. You now\n        // detect a closed connection by checking for connectionState to be\n        // \"closed\" instead.\n        // I suppose at some point this will be moved to onconnectionstatechange\n        this.peerconnection.onsignalingstatechange = () => {\n            if (this.peerconnection.signalingState === 'stable') {\n                this.wasstable = true;\n            } else if (this.peerconnection.signalingState === 'closed'\n                || this.peerconnection.connectionState === 'closed') {\n                this.room.eventEmitter.emit(XMPPEvents.SUSPEND_DETECTED, this);\n            }\n        };\n\n        /**\n         * The oniceconnectionstatechange event handler contains the code to\n         * execute when the iceconnectionstatechange event, of type Event,\n         * is received by this RTCPeerConnection. Such an event is sent when\n         * the value of RTCPeerConnection.iceConnectionState changes.\n         */\n        this.peerconnection.oniceconnectionstatechange = () => {\n            const now = window.performance.now();\n            let isStable = false;\n\n            if (!this.isP2P) {\n                this.room.connectionTimes[\n                    `ice.state.${this.peerconnection.iceConnectionState}`]\n                    = now;\n            }\n            logger.log(`(TIME) ICE ${this.peerconnection.iceConnectionState} ${this.isP2P ? 'P2P' : 'JVB'}:\\t`, now);\n\n            Statistics.sendAnalytics(\n                ICE_STATE_CHANGED,\n                {\n                    p2p: this.isP2P,\n                    state: this.peerconnection.iceConnectionState,\n                    'signaling_state': this.peerconnection.signalingState,\n                    reconnect: this.isReconnect,\n                    value: now\n                });\n\n            this.room.eventEmitter.emit(\n                XMPPEvents.ICE_CONNECTION_STATE_CHANGED,\n                this,\n                this.peerconnection.iceConnectionState);\n            switch (this.peerconnection.iceConnectionState) {\n            case 'checking':\n                this._iceCheckingStartedTimestamp = now;\n                break;\n            case 'connected':\n                // Informs interested parties that the connection has been restored. This includes the case when\n                // media connection to the bridge has been restored after an ICE failure by using session-terminate.\n                if (this.peerconnection.signalingState === 'stable') {\n                    isStable = true;\n                    const usesTerminateForRestart = !this.options.enableIceRestart\n                        && this.room.supportsRestartByTerminate();\n\n                    if (this.isReconnect || usesTerminateForRestart) {\n                        this.room.eventEmitter.emit(\n                            XMPPEvents.CONNECTION_RESTORED, this);\n                    }\n                }\n\n                // Add a workaround for an issue on chrome in Unified plan when the local endpoint is the offerer.\n                // The 'signalingstatechange' event for 'stable' is handled after the 'iceconnectionstatechange' event\n                // for 'completed' is handled by the client. This prevents the client from firing a\n                // CONNECTION_ESTABLISHED event for the p2p session. As a result, the offerer continues to stay on the\n                // jvb connection while the remote peer switches to the p2p connection breaking the media flow between\n                // the endpoints.\n                // TODO - file a chromium bug and add the information here.\n                if (!this.wasConnected\n                    && (this.wasstable\n                        || isStable\n                        || (this.usesUnifiedPlan && this.isInitiator && browser.isChromiumBased()))) {\n\n                    Statistics.sendAnalytics(\n                        ICE_DURATION,\n                        {\n                            phase: 'checking',\n                            value: now - this._iceCheckingStartedTimestamp,\n                            p2p: this.isP2P,\n                            initiator: this.isInitiator\n                        });\n\n                    // Switch between ICE gathering and ICE checking whichever\n                    // started first (scenarios are different for initiator\n                    // vs responder)\n                    const iceStarted\n                        = Math.min(\n                            this._iceCheckingStartedTimestamp,\n                            this._gatheringStartedTimestamp);\n\n                    this.establishmentDuration = now - iceStarted;\n\n                    Statistics.sendAnalytics(\n                        ICE_DURATION,\n                        {\n                            phase: 'establishment',\n                            value: this.establishmentDuration,\n                            p2p: this.isP2P,\n                            initiator: this.isInitiator\n                        });\n\n                    this.wasConnected = true;\n                    this.room.eventEmitter.emit(\n                        XMPPEvents.CONNECTION_ESTABLISHED, this);\n                }\n                this.isReconnect = false;\n                break;\n            case 'disconnected':\n                this.isReconnect = true;\n\n                // Informs interested parties that the connection has been\n                // interrupted.\n                if (this.wasstable) {\n                    this.room.eventEmitter.emit(\n                        XMPPEvents.CONNECTION_INTERRUPTED, this);\n                }\n                break;\n            case 'failed':\n                this.room.eventEmitter.emit(\n                    XMPPEvents.CONNECTION_ICE_FAILED, this);\n                break;\n            }\n        };\n\n\n        /**\n         * The connection state event is fired whenever the aggregate of underlying\n         * transports change their state.\n         */\n        this.peerconnection.onconnectionstatechange = () => {\n            const icestate = this.peerconnection.iceConnectionState;\n\n            switch (this.peerconnection.connectionState) {\n            case 'failed':\n                // Since version 76 Chrome no longer switches ICE connection\n                // state to failed (see\n                // https://bugs.chromium.org/p/chromium/issues/detail?id=982793\n                // for details) we use this workaround to recover from lost connections\n                if (icestate === 'disconnected') {\n                    this.room.eventEmitter.emit(\n                        XMPPEvents.CONNECTION_ICE_FAILED, this);\n                }\n                break;\n            }\n        };\n\n        /**\n         * The negotiationneeded event is fired whenever we shake the media on the\n         * RTCPeerConnection object.\n         */\n        this.peerconnection.onnegotiationneeded = () => {\n            const state = this.peerconnection.signalingState;\n            const remoteDescription = this.peerconnection.remoteDescription;\n\n            if (this.usesUnifiedPlan\n                && !this.isP2P\n                && state === 'stable'\n                && remoteDescription\n                && typeof remoteDescription.sdp === 'string') {\n                logger.info(`${this} onnegotiationneeded fired on ${this.peerconnection}`);\n\n                const workFunction = finishedCallback => {\n                    const oldSdp = new SDP(this.peerconnection.localDescription.sdp);\n\n                    this._renegotiate()\n                        .then(() => this.peerconnection.configureSenderVideoEncodings())\n                        .then(() => {\n                            const newSdp = new SDP(this.peerconnection.localDescription.sdp);\n\n                            this.notifyMySSRCUpdate(oldSdp, newSdp);\n                        })\n                        .then(() => finishedCallback(), error => finishedCallback(error));\n                };\n\n                this.modificationQueue.push(\n                    workFunction,\n                    error => {\n                        if (error) {\n                            logger.error(`${this} onnegotiationneeded error`, error);\n                        } else {\n                            logger.debug(`${this} onnegotiationneeded executed - OK`);\n                        }\n                    });\n            }\n        };\n    }\n\n    /**\n     * Remote preference for receive video max frame height.\n     *\n     * @returns {Number|undefined}\n     */\n    getRemoteRecvMaxFrameHeight() {\n        if (this.isP2P) {\n            return this.remoteRecvMaxFrameHeight;\n        }\n\n        return undefined;\n    }\n\n    /**\n     * Sends given candidate in Jingle 'transport-info' message.\n     * @param {RTCIceCandidate} candidate the WebRTC ICE candidate instance\n     * @private\n     */\n    sendIceCandidate(candidate) {\n        const localSDP = new SDP(this.peerconnection.localDescription.sdp);\n\n        if (candidate && candidate.candidate.length && !this.lasticecandidate) {\n            const ice = SDPUtil.iceparams(localSDP.media[candidate.sdpMLineIndex], localSDP.session);\n            const jcand = SDPUtil.candidateToJingle(candidate.candidate);\n\n            if (!(ice && jcand)) {\n                const errorMesssage = 'failed to get ice && jcand';\n\n                GlobalOnErrorHandler.callErrorHandler(new Error(errorMesssage));\n                logger.error(errorMesssage);\n\n                return;\n            }\n            ice.xmlns = 'urn:xmpp:jingle:transports:ice-udp:1';\n\n            if (this.usedrip) {\n                if (this.dripContainer.length === 0) {\n                    setTimeout(() => {\n                        if (this.dripContainer.length === 0) {\n                            return;\n                        }\n                        this.sendIceCandidates(this.dripContainer);\n                        this.dripContainer = [];\n                    }, ICE_CAND_GATHERING_TIMEOUT);\n                }\n                this.dripContainer.push(candidate);\n            } else {\n                this.sendIceCandidates([ candidate ]);\n            }\n        } else {\n            logger.log(`${this} sendIceCandidate: last candidate`);\n\n            // FIXME: remember to re-think in ICE-restart\n            this.lasticecandidate = true;\n        }\n    }\n\n    /**\n     * Sends given candidates in Jingle 'transport-info' message.\n     * @param {Array<RTCIceCandidate>} candidates an array of the WebRTC ICE\n     * candidate instances\n     * @private\n     */\n    sendIceCandidates(candidates) {\n        if (!this._assertNotEnded('sendIceCandidates')) {\n\n            return;\n        }\n\n        logger.log(`${this} sendIceCandidates ${JSON.stringify(candidates)}`);\n        const cand = $iq({ to: this.remoteJid,\n            type: 'set' })\n            .c('jingle', { xmlns: 'urn:xmpp:jingle:1',\n                action: 'transport-info',\n                initiator: this.initiatorJid,\n                sid: this.sid });\n\n        const localSDP = new SDP(this.peerconnection.localDescription.sdp);\n\n        for (let mid = 0; mid < localSDP.media.length; mid++) {\n            const cands = candidates.filter(el => el.sdpMLineIndex === mid);\n            const mline\n                = SDPUtil.parseMLine(localSDP.media[mid].split('\\r\\n')[0]);\n\n            if (cands.length > 0) {\n                const ice\n                    = SDPUtil.iceparams(localSDP.media[mid], localSDP.session);\n\n                ice.xmlns = 'urn:xmpp:jingle:transports:ice-udp:1';\n                cand.c('content', {\n                    creator: this.initiatorJid === this.localJid\n                        ? 'initiator' : 'responder',\n                    name: cands[0].sdpMid ? cands[0].sdpMid : mline.media\n                }).c('transport', ice);\n                for (let i = 0; i < cands.length; i++) {\n                    const candidate\n                        = SDPUtil.candidateToJingle(cands[i].candidate);\n\n                    // Mangle ICE candidate if 'failICE' test option is enabled\n\n                    if (this.failICE) {\n                        candidate.ip = '1.1.1.1';\n                    }\n                    cand.c('candidate', candidate).up();\n                }\n\n                // add fingerprint\n                const fingerprintLine\n                    = SDPUtil.findLine(\n                        localSDP.media[mid],\n                        'a=fingerprint:', localSDP.session);\n\n                if (fingerprintLine) {\n                    const tmp = SDPUtil.parseFingerprint(fingerprintLine);\n\n                    tmp.required = true;\n                    cand.c(\n                        'fingerprint',\n                        { xmlns: 'urn:xmpp:jingle:apps:dtls:0' })\n                        .t(tmp.fingerprint);\n                    delete tmp.fingerprint;\n                    cand.attrs(tmp);\n                    cand.up();\n                }\n                cand.up(); // transport\n                cand.up(); // content\n            }\n        }\n\n        // might merge last-candidate notification into this, but it is called\n        // a lot later. See webrtc issue #2340\n        // logger.log('was this the last candidate', this.lasticecandidate);\n        this.connection.sendIQ(\n            cand, null, this.newJingleErrorHandler(cand), IQ_TIMEOUT);\n    }\n\n    /**\n     * Sends Jingle 'session-info' message which includes custom Jitsi Meet\n     * 'ice-state' element with the text value 'failed' to let Jicofo know\n     * that the ICE connection has entered the failed state. It can then\n     * choose to re-create JVB channels and send 'transport-replace' to\n     * retry the connection.\n     */\n    sendIceFailedNotification() {\n        const sessionInfo\n            = $iq({\n                to: this.remoteJid,\n                type: 'set' })\n            .c('jingle', { xmlns: 'urn:xmpp:jingle:1',\n                action: 'session-info',\n                initiator: this.initiatorJid,\n                sid: this.sid })\n            .c('ice-state', { xmlns: 'http://jitsi.org/protocol/focus' })\n            .t('failed')\n            .up();\n\n        this._bridgeSessionId\n            && sessionInfo.c(\n                'bridge-session', {\n                    xmlns: 'http://jitsi.org/protocol/focus',\n                    id: this._bridgeSessionId\n                });\n\n        this.connection.sendIQ2(\n            sessionInfo, {\n                /*\n                 * This message will be often sent when there are connectivity\n                 * issues, so make it slightly longer than Prosody's default BOSH\n                 * inactivity timeout of 60 seconds.\n                 */\n                timeout: 65\n            })\n            .catch(this.newJingleErrorHandler(sessionInfo));\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    addIceCandidates(elem) {\n        if (this.peerconnection.signalingState === 'closed') {\n            logger.warn(`${this} Ignored add ICE candidate when in closed state`);\n\n            return;\n        }\n\n        const iceCandidates = [];\n\n        elem.find('>content>transport>candidate')\n            .each((idx, candidate) => {\n                let line = SDPUtil.candidateFromJingle(candidate);\n\n                line = line.replace('\\r\\n', '').replace('a=', '');\n\n                // FIXME this code does not care to handle\n                // non-bundle transport\n                const rtcCandidate = new RTCIceCandidate({\n                    sdpMLineIndex: 0,\n\n                    // FF comes up with more complex names like audio-23423,\n                    // Given that it works on both Chrome and FF without\n                    // providing it, let's leave it like this for the time\n                    // being...\n                    // sdpMid: 'audio',\n                    sdpMid: '',\n                    candidate: line\n                });\n\n                iceCandidates.push(rtcCandidate);\n            });\n\n        if (!iceCandidates.length) {\n            logger.error(`${this} No ICE candidates to add ?`, elem[0] && elem[0].outerHTML);\n\n            return;\n        }\n\n        // We want to have this task queued, so that we know it is executed,\n        // after the initial sRD/sLD offer/answer cycle was done (based on\n        // the assumption that candidates are spawned after the offer/answer\n        // and XMPP preserves order).\n        const workFunction = finishedCallback => {\n            for (const iceCandidate of iceCandidates) {\n                this.peerconnection.addIceCandidate(iceCandidate)\n                    .then(\n                        () => logger.debug(`${this} addIceCandidate ok!`),\n                        err => logger.error(`${this} addIceCandidate failed!`, err));\n            }\n\n            finishedCallback();\n            logger.debug(`${this} ICE candidates task finished`);\n        };\n\n        logger.debug(`${this} Queued add (${iceCandidates.length}) ICE candidates task`);\n        this.modificationQueue.push(workFunction);\n    }\n\n    /**\n     *\n     * @param contents\n     */\n    readSsrcInfo(contents) {\n        const ssrcs\n            = $(contents).find(\n                '>description>'\n                    + 'source[xmlns=\"urn:xmpp:jingle:apps:rtp:ssma:0\"]');\n\n        ssrcs.each((i, ssrcElement) => {\n            const ssrc = Number(ssrcElement.getAttribute('ssrc'));\n\n            if (this.isP2P) {\n                // In P2P all SSRCs are owner by the remote peer\n                this._signalingLayer.setSSRCOwner(\n                    ssrc, Strophe.getResourceFromJid(this.remoteJid));\n            } else {\n                if (FeatureFlags.isSourceNameSignalingEnabled()) {\n                    // Only set sourceName for non-P2P case\n                    if (ssrcElement.hasAttribute('name')) {\n                        const sourceName = ssrcElement.getAttribute('name');\n\n                        this._signalingLayer.setTrackSourceName(ssrc, sourceName);\n                    }\n                }\n                $(ssrcElement)\n                    .find('>ssrc-info[xmlns=\"http://jitsi.org/jitmeet\"]')\n                    .each((i3, ssrcInfoElement) => {\n                        const owner = ssrcInfoElement.getAttribute('owner');\n\n                        if (owner && owner.length) {\n                            if (isNaN(ssrc) || ssrc < 0) {\n                                logger.warn(`${this} Invalid SSRC ${ssrc} value received for ${owner}`);\n                            } else {\n                                this._signalingLayer.setSSRCOwner(\n                                    ssrc,\n                                    getEndpointId(owner));\n                            }\n                        }\n                    });\n            }\n        });\n    }\n\n    /**\n     * Makes the underlying TraceablePeerConnection generate new SSRC for\n     * the recvonly video stream.\n     * @deprecated\n     */\n    generateRecvonlySsrc() {\n        if (this.peerconnection) {\n            this.peerconnection.generateRecvonlySsrc();\n        } else {\n            logger.error(`${this} Unable to generate recvonly SSRC - no peerconnection`);\n        }\n    }\n\n    /**\n     * Returns the video codec configured as the preferred codec on the peerconnection.\n     */\n    getConfiguredVideoCodec() {\n        return this.peerconnection.getConfiguredVideoCodec();\n    }\n\n    /* eslint-disable max-params */\n    /**\n     * Accepts incoming Jingle 'session-initiate' and should send\n     * 'session-accept' in result.\n     * @param jingleOffer jQuery selector pointing to the jingle element of\n     * the offer IQ\n     * @param success callback called when we accept incoming session\n     * successfully and receive RESULT packet to 'session-accept' sent.\n     * @param failure function(error) called if for any reason we fail to accept\n     * the incoming offer. 'error' argument can be used to log some details\n     * about the error.\n     * @param {Array<JitsiLocalTrack>} [localTracks] the optional list of\n     * the local tracks that will be added, before the offer/answer cycle\n     * executes. We allow the localTracks to optionally be passed in so that\n     * the addition of the local tracks and the processing of the initial offer\n     * can all be done atomically. We want to make sure that any other\n     * operations which originate in the XMPP Jingle messages related with\n     * this session to be executed with an assumption that the initial\n     * offer/answer cycle has been executed already.\n     */\n    acceptOffer(jingleOffer, success, failure, localTracks) {\n        this.setOfferAnswerCycle(\n            jingleOffer,\n            () => {\n                // FIXME we may not care about RESULT packet for session-accept\n                // then we should either call 'success' here immediately or\n                // modify sendSessionAccept method to do that\n                this.sendSessionAccept(() => {\n                    success();\n\n                    this.room.eventEmitter.emit(XMPPEvents.SESSION_ACCEPT, this);\n                },\n                error => {\n                    failure(error);\n\n                    this.room.eventEmitter.emit(XMPPEvents.SESSION_ACCEPT_ERROR, this, error);\n                });\n            },\n            failure,\n            localTracks);\n    }\n\n    /* eslint-enable max-params */\n\n    /**\n     * Creates an offer and sends Jingle 'session-initiate' to the remote peer.\n     * @param {Array<JitsiLocalTrack>} localTracks the local tracks that will be\n     * added, before the offer/answer cycle executes (for the local track\n     * addition to be an atomic operation together with the offer/answer).\n     */\n    invite(localTracks = []) {\n        if (!this.isInitiator) {\n            throw new Error('Trying to invite from the responder session');\n        }\n        const workFunction = finishedCallback => {\n            const addTracks = [];\n\n            for (const localTrack of localTracks) {\n                addTracks.push(this.peerconnection.addTrack(localTrack, this.isInitiator));\n            }\n\n            Promise.all(addTracks)\n                .then(() => this.peerconnection.createOffer(this.mediaConstraints))\n                .then(offerSdp => this.peerconnection.setLocalDescription(offerSdp))\n                .then(() => {\n                    // NOTE that the offer is obtained from the localDescription getter as it needs to go though\n                    // the transformation chain.\n                    this.sendSessionInitiate(this.peerconnection.localDescription.sdp);\n                })\n                .then(() => finishedCallback(), error => finishedCallback(error));\n        };\n\n        logger.debug(`${this} Queued invite task`);\n        this.modificationQueue.push(\n            workFunction,\n            error => {\n                if (error) {\n                    logger.error(`${this} invite error`, error);\n                } else {\n                    logger.debug(`${this} invite executed - OK`);\n                }\n            });\n    }\n\n    /**\n     * Sends 'session-initiate' to the remote peer.\n     *\n     * NOTE this method is synchronous and we're not waiting for the RESULT\n     * response which would delay the startup process.\n     *\n     * @param {string} offerSdp  - The local session description which will be\n     * used to generate an offer.\n     * @private\n     */\n    sendSessionInitiate(offerSdp) {\n        let init = $iq({\n            to: this.remoteJid,\n            type: 'set'\n        }).c('jingle', {\n            xmlns: 'urn:xmpp:jingle:1',\n            action: 'session-initiate',\n            initiator: this.initiatorJid,\n            sid: this.sid\n        });\n\n        new SDP(offerSdp).toJingle(\n            init,\n            this.isInitiator ? 'initiator' : 'responder');\n        init = init.tree();\n        logger.debug(`${this} Session-initiate: `, init);\n        this.connection.sendIQ(init,\n            () => {\n                logger.info(`${this} Got RESULT for \"session-initiate\"`);\n            },\n            error => {\n                logger.error(`${this} \"session-initiate\" error`, error);\n            },\n            IQ_TIMEOUT);\n    }\n\n    /**\n     * Sets the answer received from the remote peer.\n     * @param jingleAnswer\n     */\n    setAnswer(jingleAnswer) {\n        if (!this.isInitiator) {\n            throw new Error('Trying to set an answer on the responder session');\n        }\n        this.setOfferAnswerCycle(\n            jingleAnswer,\n            () => {\n                logger.info(`${this} setAnswer - succeeded`);\n                if (this.usesUnifiedPlan && browser.isChromiumBased()) {\n                    const workFunction = finishedCallback => {\n                        // This hack is needed for Chrome to create a decoder for the ssrcs in the remote SDP when\n                        // the local endpoint is the offerer and starts muted.\n                        const remoteSdp = this.peerconnection.remoteDescription.sdp;\n                        const remoteDescription = new RTCSessionDescription({\n                            type: 'offer',\n                            sdp: remoteSdp\n                        });\n\n                        return this._responderRenegotiate(remoteDescription)\n                        .then(() => finishedCallback(), error => finishedCallback(error));\n                    };\n\n                    logger.debug(`${this} Queued responderRenegotiate task`);\n                    this.modificationQueue.push(\n                        workFunction,\n                        error => {\n                            if (error) {\n                                logger.error(`${this} failed to renegotiate a decoder for muted endpoint ${error}`);\n                            } else {\n                                logger.debug(`${this} renegotiate a decoder for muted endpoint`);\n                            }\n                        });\n                }\n            },\n            error => {\n                logger.error(`${this} setAnswer failed: `, error);\n            });\n    }\n\n    /* eslint-disable max-params */\n    /**\n     * This is a setRemoteDescription/setLocalDescription cycle which starts at\n     * converting Strophe Jingle IQ into remote offer SDP. Once converted\n     * setRemoteDescription, createAnswer and setLocalDescription calls follow.\n     * @param jingleOfferAnswerIq jQuery selector pointing to the jingle element\n     *        of the offer (or answer) IQ\n     * @param success callback called when sRD/sLD cycle finishes successfully.\n     * @param failure callback called with an error object as an argument if we\n     *        fail at any point during setRD, createAnswer, setLD.\n     * @param {Array<JitsiLocalTrack>} [localTracks] the optional list of\n     * the local tracks that will be added, before the offer/answer cycle\n     * executes (for the local track addition to be an atomic operation together\n     * with the offer/answer).\n     */\n    setOfferAnswerCycle(jingleOfferAnswerIq, success, failure, localTracks = []) {\n        const workFunction = finishedCallback => {\n            const addTracks = [];\n\n            for (const track of localTracks) {\n                addTracks.push(this.peerconnection.addTrack(track, this.isInitiator));\n            }\n\n            const newRemoteSdp\n                = this._processNewJingleOfferIq(jingleOfferAnswerIq);\n            const oldLocalSdp\n                = this.peerconnection.localDescription.sdp;\n\n            const bridgeSession\n                = $(jingleOfferAnswerIq)\n                    .find('>bridge-session['\n                        + 'xmlns=\"http://jitsi.org/protocol/focus\"]');\n            const bridgeSessionId = bridgeSession.attr('id');\n\n            if (bridgeSessionId !== this._bridgeSessionId) {\n                this._bridgeSessionId = bridgeSessionId;\n            }\n\n            Promise.all(addTracks)\n                .then(() => this._renegotiate(newRemoteSdp.raw))\n                .then(() => {\n                    if (this.state === JingleSessionState.PENDING) {\n                        this.state = JingleSessionState.ACTIVE;\n\n                        // #1 Sync up video transfer active/inactive only after\n                        // the initial O/A cycle. We want to adjust the video\n                        // media direction only in the local SDP and the Jingle\n                        // contents direction included in the initial\n                        // offer/answer is mapped to the remote SDP. Jingle\n                        // 'content-modify' IQ is processed in a way that it\n                        // will only modify local SDP when remote peer is no\n                        // longer interested in receiving video content.\n                        // Changing media direction in the remote SDP will mess\n                        // up our SDP translation chain (simulcast, video mute,\n                        // RTX etc.)\n                        //\n                        // #2 Sends the max frame height if it was set, before the session-initiate/accept\n                        if (this.isP2P\n                            && (!this._localVideoActive || this.localRecvMaxFrameHeight)) {\n                            this.sendContentModify();\n                        }\n                    }\n\n                    // Old local SDP will be available when we're setting answer\n                    // for the first time, but not when offer and it's fine\n                    // since we're generating an answer now it will contain all\n                    // our SSRCs\n                    if (oldLocalSdp) {\n                        const newLocalSdp\n                            = new SDP(this.peerconnection.localDescription.sdp);\n\n                        this.notifyMySSRCUpdate(\n                            new SDP(oldLocalSdp), newLocalSdp);\n                    }\n                })\n                .then(() => finishedCallback(), error => finishedCallback(error));\n        };\n\n        logger.debug(`${this} Queued setOfferAnswerCycle task`);\n        this.modificationQueue.push(\n            workFunction,\n            error => {\n                if (error) {\n                    logger.error(`${this} setOfferAnswerCycle task failed: ${error}`);\n                    failure(error);\n                } else {\n                    logger.debug(`${this} setOfferAnswerCycle task done`);\n                    success();\n                }\n            });\n    }\n\n    /**\n     * Updates the codecs on the peerconnection and initiates a renegotiation for the\n     * new codec config to take effect.\n     *\n     * @param {CodecMimeType} preferred the preferred codec.\n     * @param {CodecMimeType} disabled the codec that needs to be disabled.\n     */\n    setVideoCodecs(preferred = null, disabled = null) {\n        const current = this.peerconnection.getConfiguredVideoCodec();\n\n        if (this._assertNotEnded() && preferred !== current) {\n            logger.info(`${this} Switching video codec from ${current} to ${preferred}`);\n            this.peerconnection.setVideoCodecs(preferred, disabled);\n\n            // Initiate a renegotiate for the codec setting to take effect.\n            const workFunction = finishedCallback => {\n                this._renegotiate().then(\n                    () => {\n                        logger.debug(`${this} setVideoCodecs task is done`);\n\n                        return finishedCallback();\n                    }, error => {\n                        logger.error(`${this} setVideoCodecs task failed: ${error}`);\n\n                        return finishedCallback(error);\n                    });\n            };\n\n            logger.debug(`${this} Queued setVideoCodecs task`);\n\n            // Queue and execute\n            this.modificationQueue.push(workFunction);\n        }\n    }\n\n    /* eslint-enable max-params */\n\n    /**\n     * Although it states \"replace transport\" it does accept full Jingle offer\n     * which should contain new ICE transport details.\n     * @param jingleOfferElem an element Jingle IQ that contains new offer and\n     *        transport info.\n     * @param success callback called when we succeed to accept new offer.\n     * @param failure function(error) called when we fail to accept new offer.\n     */\n    replaceTransport(jingleOfferElem, success, failure) {\n        if (this.options.enableForcedReload) {\n            const sdp = new SDP(this.peerconnection.localDescription.sdp);\n\n            this.sendTransportAccept(sdp, success, failure);\n            this.room.eventEmitter.emit(XMPPEvents.CONNECTION_RESTARTED, this);\n\n            return;\n        }\n        this.room.eventEmitter.emit(XMPPEvents.ICE_RESTARTING, this);\n\n        // We need to first reject the 'data' section to have the SCTP stack\n        // cleaned up to signal the known data channel is now invalid. After\n        // that the original offer is set to have the SCTP connection\n        // established with the new bridge.\n        const originalOffer = jingleOfferElem.clone();\n\n        jingleOfferElem\n            .find('>content[name=\\'data\\']')\n            .attr('senders', 'rejected');\n\n        // Remove all remote sources in order to reset the client's state\n        // for the remote MediaStreams. When a conference is moved to\n        // another bridge it will start streaming with a sequence number\n        // that is not in sync with the most recently seen by the client.\n        // The symptoms include frozen or black video and lots of \"failed to\n        // unprotect SRTP packets\" in Chrome logs.\n        jingleOfferElem\n            .find('>content>description>source')\n            .remove();\n        jingleOfferElem\n            .find('>content>description>ssrc-group')\n            .remove();\n\n        // On the JVB it's not a real ICE restart and all layers are re-initialized from scratch as Jicofo does\n        // the restart by re-allocating new channels. Chrome (or WebRTC stack) needs to have the DTLS transport layer\n        // reset to start a new handshake with fresh DTLS transport on the bridge. Make it think that the DTLS\n        // fingerprint has changed by setting an all zeros key.\n        const newFingerprint = jingleOfferElem.find('>content>transport>fingerprint');\n\n        newFingerprint.attr('hash', 'sha-1');\n        newFingerprint.text('00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00');\n\n        // First set an offer with a rejected 'data' section\n        this.setOfferAnswerCycle(\n            jingleOfferElem,\n            () => {\n                // Now set the original offer(with the 'data' section)\n                this.setOfferAnswerCycle(\n                    originalOffer,\n                    () => {\n                        const localSDP\n                            = new SDP(this.peerconnection.localDescription.sdp);\n\n                        this.sendTransportAccept(localSDP, success, failure);\n\n                        this.room.eventEmitter.emit(\n                            XMPPEvents.ICE_RESTART_SUCCESS,\n                            this,\n                            originalOffer);\n                    },\n                    failure);\n            },\n            failure\n        );\n    }\n\n    /**\n     * Sends Jingle 'session-accept' message.\n     * @param {function()} success callback called when we receive 'RESULT'\n     *        packet for the 'session-accept'\n     * @param {function(error)} failure called when we receive an error response\n     *        or when the request has timed out.\n     * @private\n     */\n    sendSessionAccept(success, failure) {\n        // NOTE: since we're just reading from it, we don't need to be within\n        //  the modification queue to access the local description\n        const localSDP = new SDP(this.peerconnection.localDescription.sdp);\n        const accept = $iq({ to: this.remoteJid,\n            type: 'set' })\n            .c('jingle', { xmlns: 'urn:xmpp:jingle:1',\n                action: 'session-accept',\n                initiator: this.initiatorJid,\n                responder: this.responderJid,\n                sid: this.sid });\n\n        if (this.webrtcIceTcpDisable) {\n            localSDP.removeTcpCandidates = true;\n        }\n        if (this.webrtcIceUdpDisable) {\n            localSDP.removeUdpCandidates = true;\n        }\n        if (this.failICE) {\n            localSDP.failICE = true;\n        }\n        localSDP.toJingle(\n            accept,\n            this.initiatorJid === this.localJid ? 'initiator' : 'responder');\n\n        logger.info(`${this} Sending session-accept`);\n        logger.debug(accept.tree());\n        this.connection.sendIQ(accept,\n            success,\n            this.newJingleErrorHandler(accept, error => {\n                failure(error);\n\n                // 'session-accept' is a critical timeout and we'll\n                // have to restart\n                this.room.eventEmitter.emit(\n                    XMPPEvents.SESSION_ACCEPT_TIMEOUT, this);\n            }),\n            IQ_TIMEOUT);\n\n        // XXX Videobridge needs WebRTC's answer (ICE ufrag and pwd, DTLS\n        // fingerprint and setup) ASAP in order to start the connection\n        // establishment.\n        //\n        // FIXME Flushing the connection at this point triggers an issue with\n        // BOSH request handling in Prosody on slow connections.\n        //\n        // The problem is that this request will be quite large and it may take\n        // time before it reaches Prosody. In the meantime Strophe may decide\n        // to send the next one. And it was observed that a small request with\n        // 'transport-info' usually follows this one. It does reach Prosody\n        // before the previous one was completely received. 'rid' on the server\n        // is increased and Prosody ignores the request with 'session-accept'.\n        // It will never reach Jicofo and everything in the request table is\n        // lost. Removing the flush does not guarantee it will never happen, but\n        // makes it much less likely('transport-info' is bundled with\n        // 'session-accept' and any immediate requests).\n        //\n        // this.connection.flush();\n    }\n\n    /**\n     * Will send 'content-modify' IQ in order to ask the remote peer to\n     * either stop or resume sending video media or to adjust sender's video constraints.\n     * @private\n     */\n    sendContentModify() {\n        const maxFrameHeight = this.localRecvMaxFrameHeight;\n        const senders = this._localVideoActive ? 'both' : 'none';\n\n        let sessionModify\n            = $iq({\n                to: this.remoteJid,\n                type: 'set'\n            })\n                .c('jingle', {\n                    xmlns: 'urn:xmpp:jingle:1',\n                    action: 'content-modify',\n                    initiator: this.initiatorJid,\n                    sid: this.sid\n                })\n                .c('content', {\n                    name: MediaType.VIDEO,\n                    senders\n                });\n\n        if (typeof maxFrameHeight !== 'undefined') {\n            sessionModify = sessionModify\n                .c('max-frame-height', { xmlns: 'http://jitsi.org/jitmeet/video' })\n                .t(maxFrameHeight);\n        }\n\n        logger.info(`${this} sending content-modify, video senders: ${senders}, max frame height: ${maxFrameHeight}`);\n        logger.debug(sessionModify.tree());\n\n        this.connection.sendIQ(\n            sessionModify,\n            null,\n            this.newJingleErrorHandler(sessionModify),\n            IQ_TIMEOUT);\n    }\n\n    /**\n     * Adjust the preference for max video frame height that the local party is willing to receive. Signals\n     * the remote party.\n     *\n     * @param {Number} maxFrameHeight - the new value to set.\n     */\n    setReceiverVideoConstraint(maxFrameHeight) {\n        logger.info(`${this} setReceiverVideoConstraint - max frame height: ${maxFrameHeight}`);\n\n        this.localRecvMaxFrameHeight = maxFrameHeight;\n\n        if (this.isP2P) {\n            // Tell the remote peer about our receive constraint. If Jingle session is not yet active the state will\n            // be synced after offer/answer.\n            if (this.state === JingleSessionState.ACTIVE) {\n                this.sendContentModify();\n            }\n        } else {\n            this.rtc.setReceiverVideoConstraint(maxFrameHeight);\n        }\n    }\n\n    /**\n     * Sends Jingle 'transport-accept' message which is a response to\n     * 'transport-replace'.\n     * @param localSDP the 'SDP' object with local session description\n     * @param success callback called when we receive 'RESULT' packet for\n     *        'transport-replace'\n     * @param failure function(error) called when we receive an error response\n     *        or when the request has timed out.\n     * @private\n     */\n    sendTransportAccept(localSDP, success, failure) {\n        const transportAccept = $iq({ to: this.remoteJid,\n            type: 'set' })\n            .c('jingle', {\n                xmlns: 'urn:xmpp:jingle:1',\n                action: 'transport-accept',\n                initiator: this.initiatorJid,\n                sid: this.sid\n            });\n\n        localSDP.media.forEach((medialines, idx) => {\n            const mline = SDPUtil.parseMLine(medialines.split('\\r\\n')[0]);\n\n            transportAccept.c('content',\n                {\n                    creator:\n                        this.initiatorJid === this.localJid\n                            ? 'initiator'\n                            : 'responder',\n                    name: mline.media\n                }\n            );\n            localSDP.transportToJingle(idx, transportAccept);\n            transportAccept.up();\n        });\n\n        logger.info(`${this} Sending transport-accept`);\n        logger.debug(transportAccept.tree());\n\n        this.connection.sendIQ(transportAccept,\n            success,\n            this.newJingleErrorHandler(transportAccept, failure),\n            IQ_TIMEOUT);\n    }\n\n    /**\n     * Sends Jingle 'transport-reject' message which is a response to\n     * 'transport-replace'.\n     * @param success callback called when we receive 'RESULT' packet for\n     *        'transport-replace'\n     * @param failure function(error) called when we receive an error response\n     *        or when the request has timed out.\n     *\n     * FIXME method should be marked as private, but there's some spaghetti that\n     *       needs to be fixed prior doing that\n     */\n    sendTransportReject(success, failure) {\n        // Send 'transport-reject', so that the focus will\n        // know that we've failed\n        const transportReject = $iq({ to: this.remoteJid,\n            type: 'set' })\n            .c('jingle', {\n                xmlns: 'urn:xmpp:jingle:1',\n                action: 'transport-reject',\n                initiator: this.initiatorJid,\n                sid: this.sid\n            });\n\n        logger.info(`${this} Sending 'transport-reject'`);\n        logger.debug(transportReject.tree());\n\n        this.connection.sendIQ(transportReject,\n            success,\n            this.newJingleErrorHandler(transportReject, failure),\n            IQ_TIMEOUT);\n    }\n\n    /**\n     * Sets the resolution constraint on the local camera track.\n     * @param {number} maxFrameHeight - The user preferred max frame height.\n     * @param {string} sourceName - The source name of the track.\n     * @returns {Promise} promise that will be resolved when the operation is\n     * successful and rejected otherwise.\n     */\n    setSenderVideoConstraint(maxFrameHeight, sourceName = null) {\n        if (this._assertNotEnded()) {\n            logger.info(`${this} setSenderVideoConstraint: ${maxFrameHeight}, sourceName: ${sourceName}`);\n\n            const jitsiLocalTrack = sourceName\n                ? this.rtc.getLocalVideoTracks().find(track => track.getSourceName() === sourceName)\n                : this.rtc.getLocalVideoTrack();\n\n            return this.peerconnection.setSenderVideoConstraints(maxFrameHeight, jitsiLocalTrack);\n        }\n\n        return Promise.resolve();\n    }\n\n    /**\n     * @inheritDoc\n     */\n    terminate(success, failure, options) {\n        if (this.state === JingleSessionState.ENDED) {\n            return;\n        }\n\n        if (!options || Boolean(options.sendSessionTerminate)) {\n            const sessionTerminate\n                = $iq({\n                    to: this.remoteJid,\n                    type: 'set'\n                })\n                    .c('jingle', {\n                        xmlns: 'urn:xmpp:jingle:1',\n                        action: 'session-terminate',\n                        initiator: this.initiatorJid,\n                        sid: this.sid\n                    })\n                    .c('reason')\n                    .c((options && options.reason) || 'success')\n                    .up();\n\n            if (options && options.reasonDescription) {\n                sessionTerminate\n                    .c('text')\n                    .t(options.reasonDescription)\n                    .up()\n                    .up();\n            } else {\n                sessionTerminate.up();\n            }\n\n            this._bridgeSessionId\n                && sessionTerminate.c(\n                    'bridge-session', {\n                        xmlns: 'http://jitsi.org/protocol/focus',\n                        id: this._bridgeSessionId,\n                        restart: options && options.requestRestart === true\n                    }).up();\n\n            logger.info(`${this} Sending session-terminate`);\n            logger.debug(sessionTerminate.tree());\n\n            this.connection.sendIQ(\n                sessionTerminate,\n                success,\n                this.newJingleErrorHandler(sessionTerminate, failure),\n                IQ_TIMEOUT);\n        } else {\n            logger.info(`${this} Skipped sending session-terminate`);\n        }\n\n        // this should result in 'onTerminated' being called by strope.jingle.js\n        this.connection.jingle.terminate(this.sid);\n    }\n\n    /**\n     *\n     * @param reasonCondition\n     * @param reasonText\n     */\n    onTerminated(reasonCondition, reasonText) {\n        // Do something with reason and reasonCondition when we start to care\n        // this.reasonCondition = reasonCondition;\n        // this.reasonText = reasonText;\n        logger.info(`${this} Session terminated`, reasonCondition, reasonText);\n\n        this._xmppListeners.forEach(removeListener => removeListener());\n        this._xmppListeners = [];\n\n        if (this._removeSenderVideoConstraintsChangeListener) {\n            this._removeSenderVideoConstraintsChangeListener();\n        }\n\n        this.close();\n    }\n\n    /**\n     * Handles XMPP connection state changes.\n     *\n     * @param {XmppConnection.Status} status - The new status.\n     */\n    onXmppStatusChanged(status) {\n        if (status === XmppConnection.Status.CONNECTED && this._cachedOldLocalSdp) {\n            logger.info(`${this} Sending SSRC update on reconnect`);\n            this.notifyMySSRCUpdate(\n                this._cachedOldLocalSdp,\n                this._cachedNewLocalSdp);\n        }\n    }\n\n    /**\n     * Parse the information from the xml sourceAddElem and translate it\n     *  into sdp lines\n     * @param {jquery xml element} sourceAddElem the source-add\n     *  element from jingle\n     * @param {SDP object} currentRemoteSdp the current remote\n     *  sdp (as of this new source-add)\n     * @returns {list} a list of SDP line strings that should\n     *  be added to the remote SDP\n     */\n    _parseSsrcInfoFromSourceAdd(sourceAddElem, currentRemoteSdp) {\n        const addSsrcInfo = [];\n        const self = this;\n\n        $(sourceAddElem).each((i1, content) => {\n            const name = $(content).attr('name');\n            let lines = '';\n\n            $(content)\n                .find('ssrc-group[xmlns=\"urn:xmpp:jingle:apps:rtp:ssma:0\"]')\n                .each(function() {\n                    // eslint-disable-next-line no-invalid-this\n                    const semantics = this.getAttribute('semantics');\n                    const ssrcs\n                        = $(this) // eslint-disable-line no-invalid-this\n                            .find('>source')\n                            .map(function() {\n                                // eslint-disable-next-line no-invalid-this\n                                return this.getAttribute('ssrc');\n                            })\n                            .get();\n\n                    if (ssrcs.length) {\n                        lines += `a=ssrc-group:${semantics} ${ssrcs.join(' ')}\\r\\n`;\n                    }\n                });\n\n            // handles both >source and >description>source\n            const tmp\n                = $(content).find(\n                    'source[xmlns=\"urn:xmpp:jingle:apps:rtp:ssma:0\"]');\n\n            /* eslint-disable no-invalid-this */\n            tmp.each(function() {\n                const ssrc = $(this).attr('ssrc');\n\n                if (currentRemoteSdp.containsSSRC(ssrc)) {\n\n                    // Do not print the warning for unified plan p2p case since ssrcs are never removed from the SDP.\n                    !(self.usesUnifiedPlan && self.isP2P)\n                        && logger.warn(`${self} Source-add request for existing SSRC: ${ssrc}`);\n\n                    return;\n                }\n\n                // eslint-disable-next-line newline-per-chained-call\n                $(this).find('>parameter').each(function() {\n                    lines += `a=ssrc:${ssrc} ${$(this).attr('name')}`;\n                    if ($(this).attr('value') && $(this).attr('value').length) {\n                        lines += `:${$(this).attr('value')}`;\n                    }\n                    lines += '\\r\\n';\n                });\n            });\n\n            /* eslint-enable no-invalid-this */\n            currentRemoteSdp.media.forEach((media, i2) => {\n                if (!SDPUtil.findLine(media, `a=mid:${name}`)) {\n                    return;\n                }\n                if (!addSsrcInfo[i2]) {\n                    addSsrcInfo[i2] = '';\n                }\n                addSsrcInfo[i2] += lines;\n            });\n        });\n\n        return addSsrcInfo;\n    }\n\n    /**\n     * Handles a Jingle source-add message for this Jingle session.\n     * @param elem An array of Jingle \"content\" elements.\n     */\n    addRemoteStream(elem) {\n        this._addOrRemoveRemoteStream(true /* add */, elem);\n    }\n\n    /**\n     * Handles a Jingle source-remove message for this Jingle session.\n     * @param elem An array of Jingle \"content\" elements.\n     */\n    removeRemoteStream(elem) {\n        this._addOrRemoveRemoteStream(false /* remove */, elem);\n    }\n\n    /**\n     * Handles the deletion of SSRCs associated with a remote user from the remote description when the user leaves.\n     *\n     * @param {string} id Endpoint id of the participant that has left the call.\n     * @returns {void}\n     */\n    removeRemoteStreamsOnLeave(id) {\n        const workFunction = finishCallback => {\n            const removeSsrcInfo = this.peerconnection.getRemoteSourceInfoByParticipant(id);\n\n            if (removeSsrcInfo.length) {\n                const oldLocalSdp = new SDP(this.peerconnection.localDescription.sdp);\n                const newRemoteSdp = this._processRemoteRemoveSource(removeSsrcInfo);\n\n                this._renegotiate(newRemoteSdp.raw)\n                    .then(() => {\n                        const newLocalSDP = new SDP(this.peerconnection.localDescription.sdp);\n\n                        this.notifyMySSRCUpdate(oldLocalSdp, newLocalSDP);\n                        finishCallback();\n                    })\n                    .catch(err => finishCallback(err));\n            } else {\n                finishCallback();\n            }\n        };\n\n        logger.debug(`${this} Queued removeRemoteStreamsOnLeave task for participant ${id}`);\n\n        this.modificationQueue.push(\n            workFunction,\n            error => {\n                if (error) {\n                    logger.error(`${this} removeRemoteStreamsOnLeave error:`, error);\n                } else {\n                    logger.info(`${this} removeRemoteStreamsOnLeave done!`);\n                }\n            });\n    }\n\n    /**\n     * Handles either Jingle 'source-add' or 'source-remove' message for this\n     * Jingle session.\n     * @param {boolean} isAdd <tt>true</tt> for 'source-add' or <tt>false</tt>\n     * otherwise.\n     * @param {Array<Element>} elem an array of Jingle \"content\" elements.\n     * @private\n     */\n    _addOrRemoveRemoteStream(isAdd, elem) {\n        const logPrefix = isAdd ? 'addRemoteStream' : 'removeRemoteStream';\n\n        if (isAdd) {\n            this.readSsrcInfo(elem);\n        }\n\n        const workFunction = finishedCallback => {\n            if (!this.peerconnection.localDescription\n                || !this.peerconnection.localDescription.sdp) {\n                const errMsg = `${logPrefix} - localDescription not ready yet`;\n\n                logger.error(errMsg);\n                finishedCallback(errMsg);\n\n                return;\n            }\n\n            logger.log(`${this} Processing ${logPrefix}`);\n\n            const oldLocalSdp = new SDP(this.peerconnection.localDescription.sdp);\n            const sdp = new SDP(this.peerconnection.remoteDescription.sdp);\n            const addOrRemoveSsrcInfo\n                = isAdd\n                    ? this._parseSsrcInfoFromSourceAdd(elem, sdp)\n                    : this._parseSsrcInfoFromSourceRemove(elem, sdp);\n            const newRemoteSdp\n                = isAdd\n                    ? this._processRemoteAddSource(addOrRemoveSsrcInfo)\n                    : this._processRemoteRemoveSource(addOrRemoveSsrcInfo);\n\n            // Add a workaround for a bug in Chrome (unified plan) for p2p connection. When the media direction on\n            // the transceiver goes from \"inactive\" (both users join muted) to \"recvonly\" (peer unmutes), the browser\n            // doesn't seem to create a decoder if the signaling state changes from \"have-local-offer\" to \"stable\".\n            // Therefore, initiate a responder renegotiate even if the endpoint is the offerer to workaround this issue.\n            // TODO - open a chrome bug and update the comments.\n            const remoteDescription = new RTCSessionDescription({\n                type: 'offer',\n                sdp: newRemoteSdp.raw\n            });\n            const promise = isAdd && this.usesUnifiedPlan && this.isP2P && browser.isChromiumBased()\n                ? this._responderRenegotiate(remoteDescription)\n                : this._renegotiate(newRemoteSdp.raw);\n\n            promise.then(() => {\n                const newLocalSdp = new SDP(this.peerconnection.localDescription.sdp);\n\n                logger.log(`${this} ${logPrefix} - OK`);\n                this.notifyMySSRCUpdate(oldLocalSdp, newLocalSdp);\n                finishedCallback();\n            }, error => {\n                logger.error(`${this} ${logPrefix} failed:`, error);\n                finishedCallback(error);\n            });\n        };\n\n        logger.debug(`${this} Queued ${logPrefix} task`);\n\n        // Queue and execute\n        this.modificationQueue.push(workFunction);\n    }\n\n    /**\n     * Takes in a jingle offer iq, returns the new sdp offer\n     * @param {jquery xml element} offerIq the incoming offer\n     * @returns {SDP object} the jingle offer translated to SDP\n     */\n    _processNewJingleOfferIq(offerIq) {\n        const remoteSdp = new SDP('');\n\n        if (this.webrtcIceTcpDisable) {\n            remoteSdp.removeTcpCandidates = true;\n        }\n        if (this.webrtcIceUdpDisable) {\n            remoteSdp.removeUdpCandidates = true;\n        }\n        if (this.failICE) {\n            remoteSdp.failICE = true;\n        }\n\n        remoteSdp.fromJingle(offerIq);\n        this.readSsrcInfo($(offerIq).find('>content'));\n\n        return remoteSdp;\n    }\n\n    /**\n     * Remove the given ssrc lines from the current remote sdp\n     * @param {list} removeSsrcInfo a list of SDP line strings that\n     *  should be removed from the remote SDP\n     * @returns type {SDP Object} the new remote SDP (after removing the lines\n     *  in removeSsrcInfo\n     */\n    _processRemoteRemoveSource(removeSsrcInfo) {\n        const remoteSdp = this.usesUnifiedPlan\n            ? new SDP(this.peerconnection.peerconnection.remoteDescription.sdp)\n            : new SDP(this.peerconnection.remoteDescription.sdp);\n\n        removeSsrcInfo.forEach((lines, idx) => {\n            // eslint-disable-next-line no-param-reassign\n            lines = lines.split('\\r\\n');\n            lines.pop(); // remove empty last element;\n            if (this.usesUnifiedPlan) {\n                lines.forEach(line => {\n                    const mid = remoteSdp.media.findIndex(mLine => mLine.includes(line));\n\n                    if (mid > -1) {\n                        remoteSdp.media[mid] = remoteSdp.media[mid].replace(`${line}\\r\\n`, '');\n                        if (this.isP2P) {\n                            const mediaType = SDPUtil.parseMLine(remoteSdp.media[mid].split('\\r\\n')[0])?.media;\n                            const desiredDirection = this.peerconnection.getDesiredMediaDirection(mediaType, false);\n\n                            [ MediaDirection.SENDRECV, MediaDirection.SENDONLY ].forEach(direction => {\n                                remoteSdp.media[mid] = remoteSdp.media[mid]\n                                    .replace(`a=${direction}`, `a=${desiredDirection}`);\n                            });\n                        } else {\n                            // Jvb connections will have direction set to 'sendonly' for the remote sources.\n                            remoteSdp.media[mid] = remoteSdp.media[mid]\n                                .replace(`a=${MediaDirection.SENDONLY}`, `a=${MediaDirection.INACTIVE}`);\n                        }\n                    }\n                });\n            } else {\n                lines.forEach(line => {\n                    remoteSdp.media[idx] = remoteSdp.media[idx].replace(`${line}\\r\\n`, '');\n                });\n            }\n        });\n        remoteSdp.raw = remoteSdp.session + remoteSdp.media.join('');\n\n        return remoteSdp;\n    }\n\n    /**\n     * Add the given ssrc lines to the current remote sdp\n     * @param {list} addSsrcInfo a list of SDP line strings that\n     *  should be added to the remote SDP\n     * @returns type {SDP Object} the new remote SDP (after removing the lines\n     *  in removeSsrcInfo\n     */\n    _processRemoteAddSource(addSsrcInfo) {\n        const remoteSdp = new SDP(this.peerconnection.remoteDescription.sdp);\n\n        addSsrcInfo.forEach((lines, idx) => {\n            remoteSdp.media[idx] += lines;\n\n            // Make sure to change the direction to 'sendrecv/sendonly' only for p2p connections. For jvb connections,\n            // a new m-line is added for the new remote sources.\n            if (this.isP2P && this.usesUnifiedPlan) {\n                const mediaType = SDPUtil.parseMLine(remoteSdp.media[idx].split('\\r\\n')[0])?.media;\n                const desiredDirection = this.peerconnection.getDesiredMediaDirection(mediaType, true);\n\n                [ MediaDirection.RECVONLY, MediaDirection.INACTIVE ].forEach(direction => {\n                    remoteSdp.media[idx] = remoteSdp.media[idx]\n                        .replace(`a=${direction}`, `a=${desiredDirection}`);\n                });\n            }\n        });\n        remoteSdp.raw = remoteSdp.session + remoteSdp.media.join('');\n\n        return remoteSdp;\n    }\n\n    /**\n     * Do a new o/a flow using the existing remote description\n     * @param {string} [optionalRemoteSdp] optional, raw remote sdp\n     *  to use.  If not provided, the remote sdp from the\n     *  peerconnection will be used\n     * @returns {Promise} promise which resolves when the\n     *  o/a flow is complete with no arguments or\n     *  rejects with an error {string}\n     */\n    _renegotiate(optionalRemoteSdp) {\n        if (this.peerconnection.signalingState === 'closed') {\n            const error = new Error('Attempted to renegotiate in state closed');\n\n            this.room.eventEmitter.emit(XMPPEvents.RENEGOTIATION_FAILED, error, this);\n\n            return Promise.reject(error);\n        }\n\n        const remoteSdp\n            = optionalRemoteSdp || this.peerconnection.remoteDescription.sdp;\n\n        if (!remoteSdp) {\n            const error = new Error(`Can not renegotiate without remote description, current state: ${this.state}`);\n\n            this.room.eventEmitter.emit(XMPPEvents.RENEGOTIATION_FAILED, error, this);\n\n            return Promise.reject(error);\n        }\n\n        const remoteDescription = new RTCSessionDescription({\n            type: this.isInitiator ? 'answer' : 'offer',\n            sdp: remoteSdp\n        });\n\n        if (this.isInitiator) {\n            return this._initiatorRenegotiate(remoteDescription);\n        }\n\n        return this._responderRenegotiate(remoteDescription);\n    }\n\n    /**\n     * Renegotiate cycle implementation for the responder case.\n     * @param {object} remoteDescription the SDP object as defined by the WebRTC\n     * which will be used as remote description in the cycle.\n     * @private\n     */\n    _responderRenegotiate(remoteDescription) {\n        logger.debug(`${this} Renegotiate: setting remote description`);\n\n        return this.peerconnection.setRemoteDescription(remoteDescription)\n            .then(() => {\n                logger.debug(`${this} Renegotiate: creating answer`);\n\n                return this.peerconnection.createAnswer(this.mediaConstraints)\n                    .then(answer => {\n                        logger.debug(`${this} Renegotiate: setting local description`);\n\n                        return this.peerconnection.setLocalDescription(answer);\n                    });\n            });\n    }\n\n    /**\n     * Renegotiate cycle implementation for the initiator's case.\n     * @param {object} remoteDescription the SDP object as defined by the WebRTC\n     * which will be used as remote description in the cycle.\n     * @private\n     */\n    _initiatorRenegotiate(remoteDescription) {\n        logger.debug(`${this} Renegotiate: creating offer`);\n\n        return this.peerconnection.createOffer(this.mediaConstraints)\n            .then(offer => {\n                logger.debug(`${this} Renegotiate: setting local description`);\n\n                return this.peerconnection.setLocalDescription(offer)\n                    .then(() => {\n                        logger.debug(`${this} Renegotiate: setting remote description`);\n\n                        // eslint-disable-next-line max-len\n                        return this.peerconnection.setRemoteDescription(remoteDescription);\n                    });\n            });\n    }\n\n    /**\n     * Adds a new track to the peerconnection. This method needs to be called only when a secondary JitsiLocalTrack is\n     * being added to the peerconnection for the first time.\n     *\n     * @param {JitsiLocalTrack} localTrack track to be added to the peer connection.\n     * @returns {Promise<void>} that resolves when the track is successfully added to the peerconnection, rejected\n     * otherwise.\n     */\n    addTrack(localTrack) {\n        if (!FeatureFlags.isMultiStreamSupportEnabled()\n            || !this.usesUnifiedPlan\n            || localTrack.type !== MediaType.VIDEO) {\n            return Promise.reject(new Error('Multiple tracks of a given media type are not supported'));\n        }\n\n        const workFunction = finishedCallback => {\n            const remoteSdp = new SDP(this.peerconnection.peerconnection.remoteDescription.sdp);\n\n            // Add a new transceiver by adding a new mline in the remote description.\n            remoteSdp.addMlineForNewLocalSource(MediaType.VIDEO);\n            this._renegotiate(remoteSdp.raw)\n                .then(() => finishedCallback(), error => finishedCallback(error));\n        };\n\n        return new Promise((resolve, reject) => {\n            logger.debug(`${this} Queued renegotiation after addTrack`);\n\n            this.modificationQueue.push(\n                workFunction,\n                error => {\n                    if (error) {\n                        logger.error(`${this} renegotiation after addTrack error`, error);\n                        reject(error);\n                    } else {\n                        logger.debug(`${this} renegotiation after addTrack executed - OK`);\n\n                        // Replace the track on the newly generated transceiver.\n                        return this.replaceTrack(null, localTrack)\n                            .then(() => resolve())\n                            .catch(() => reject());\n                    }\n                });\n        });\n    }\n\n    /**\n     * Replaces <tt>oldTrack</tt> with <tt>newTrack</tt> and performs a single\n     * offer/answer cycle after both operations are done. Either\n     * <tt>oldTrack</tt> or <tt>newTrack</tt> can be null; replacing a valid\n     * <tt>oldTrack</tt> with a null <tt>newTrack</tt> effectively just removes\n     * <tt>oldTrack</tt>\n     * @param {JitsiLocalTrack|null} oldTrack the current track in use to be\n     * replaced\n     * @param {JitsiLocalTrack|null} newTrack the new track to use\n     * @returns {Promise} which resolves once the replacement is complete\n     *  with no arguments or rejects with an error {string}\n     */\n    replaceTrack(oldTrack, newTrack) {\n        const workFunction = finishedCallback => {\n            logger.debug(`${this} replaceTrack worker started. oldTrack = ${oldTrack}, newTrack = ${newTrack}`);\n\n            const oldLocalSdp = this.peerconnection.localDescription.sdp;\n\n            if (!this.usesUnifiedPlan) {\n                // NOTE the code below assumes that no more than 1 video track\n                // can be added to the peer connection.\n                // Transition from camera to desktop share\n                // or transition from one camera source to another.\n                if (this.peerconnection.options.capScreenshareBitrate\n                    && oldTrack && newTrack && newTrack.isVideoTrack()) {\n                    // Clearing current primary SSRC will make\n                    // the SdpConsistency generate a new one which will result\n                    // with:\n                    // 1. source-remove for the old video stream.\n                    // 2. source-add for the new video stream.\n                    this.peerconnection.clearRecvonlySsrc();\n                }\n\n                // Transition from no video to video (unmute).\n                if (!oldTrack && newTrack && newTrack.isVideoTrack()) {\n                    // Clearing current primary SSRC will make\n                    // the SdpConsistency generate a new one which will result\n                    // with:\n                    // 1. source-remove for the recvonly\n                    // 2. source-add for the new video stream\n                    this.peerconnection.clearRecvonlySsrc();\n\n                // Transition from video to no video\n                } else if (oldTrack && oldTrack.isVideoTrack() && !newTrack) {\n                    // Clearing current primary SSRC and generating the recvonly\n                    // will result in:\n                    // 1. source-remove for the old video stream\n                    // 2. source-add for the recvonly stream\n                    this.peerconnection.clearRecvonlySsrc();\n                    this.peerconnection.generateRecvonlySsrc();\n                }\n            }\n\n            this.peerconnection.replaceTrack(oldTrack, newTrack)\n                .then(shouldRenegotiate => {\n                    let promise = Promise.resolve();\n\n                    logger.debug(`${this} TPC.replaceTrack finished. shouldRenegotiate = ${\n                        shouldRenegotiate}, JingleSessionState = ${this.state}`);\n\n                    if (shouldRenegotiate\n                        && (oldTrack || newTrack)\n                        && this.state === JingleSessionState.ACTIVE) {\n                        promise = this._renegotiate().then(() => {\n                            const newLocalSDP = new SDP(this.peerconnection.localDescription.sdp);\n\n                            this.notifyMySSRCUpdate(new SDP(oldLocalSdp), newLocalSDP);\n                        });\n                    }\n\n                    return promise.then(() => {\n                        if (newTrack?.isVideoTrack()) {\n                            logger.debug(`${this} replaceTrack worker: configuring video stream`);\n\n                            // Configure the video encodings after the track is replaced.\n                            return this.peerconnection.configureSenderVideoEncodings(newTrack);\n                        }\n                    });\n                })\n                .then(() => finishedCallback(), error => finishedCallback(error));\n        };\n\n        return new Promise((resolve, reject) => {\n            logger.debug(`${this} Queued replaceTrack task. Old track = ${oldTrack}, new track = ${newTrack}`);\n\n            this.modificationQueue.push(\n                workFunction,\n                error => {\n                    if (error) {\n                        logger.error(`${this} Replace track error:`, error);\n                        reject(error);\n                    } else {\n                        logger.info(`${this}  Replace track done!`);\n                        resolve();\n                    }\n                });\n        });\n    }\n\n    /**\n     * Parse the information from the xml sourceRemoveElem and translate it\n     *  into sdp lines\n     * @param {jquery xml element} sourceRemoveElem the source-remove\n     *  element from jingle\n     * @param {SDP object} currentRemoteSdp the current remote\n     *  sdp (as of this new source-remove)\n     * @returns {list} a list of SDP line strings that should\n     *  be removed from the remote SDP\n     */\n    _parseSsrcInfoFromSourceRemove(sourceRemoveElem, currentRemoteSdp) {\n        const removeSsrcInfo = [];\n\n        $(sourceRemoveElem).each((i1, content) => {\n            const name = $(content).attr('name');\n            let lines = '';\n\n            $(content)\n                .find('ssrc-group[xmlns=\"urn:xmpp:jingle:apps:rtp:ssma:0\"]')\n                .each(function() {\n                    /* eslint-disable no-invalid-this */\n                    const semantics = this.getAttribute('semantics');\n                    const ssrcs\n                        = $(this)\n                            .find('>source')\n                            .map(function() {\n                                return this.getAttribute('ssrc');\n                            })\n                            .get();\n\n                    if (ssrcs.length) {\n                        lines\n                            += `a=ssrc-group:${semantics} ${\n                                ssrcs.join(' ')}\\r\\n`;\n                    }\n\n                    /* eslint-enable no-invalid-this */\n                });\n            const ssrcs = [];\n\n            // handles both >source and >description>source versions\n            const tmp\n                = $(content).find(\n                    'source[xmlns=\"urn:xmpp:jingle:apps:rtp:ssma:0\"]');\n\n            tmp.each(function() {\n                // eslint-disable-next-line no-invalid-this\n                const ssrc = $(this).attr('ssrc');\n\n                ssrcs.push(ssrc);\n            });\n            currentRemoteSdp.media.forEach((media, i2) => {\n                if (!SDPUtil.findLine(media, `a=mid:${name}`)) {\n                    return;\n                }\n                if (!removeSsrcInfo[i2]) {\n                    removeSsrcInfo[i2] = '';\n                }\n                ssrcs.forEach(ssrc => {\n                    const ssrcLines\n                        = SDPUtil.findLines(media, `a=ssrc:${ssrc}`);\n\n                    if (ssrcLines.length) {\n                        removeSsrcInfo[i2] += `${ssrcLines.join('\\r\\n')}\\r\\n`;\n                    }\n                });\n                removeSsrcInfo[i2] += lines;\n            });\n        });\n\n        return removeSsrcInfo;\n    }\n\n    /**\n     * Will print an error if there is any difference, between the SSRCs given\n     * in the <tt>oldSDP</tt> and the ones currently described in\n     * the peerconnection's local description.\n     * @param {string} operationName the operation's name which will be printed\n     * in the error message.\n     * @param {SDP} oldSDP the old local SDP which will be compared with\n     * the current one.\n     * @return {boolean} <tt>true</tt> if there was any change or <tt>false</tt>\n     * otherwise.\n     * @private\n     */\n    _verifyNoSSRCChanged(operationName, oldSDP) {\n        const currentLocalSDP\n            = new SDP(this.peerconnection.localDescription.sdp);\n        let sdpDiff = new SDPDiffer(oldSDP, currentLocalSDP);\n        const addedMedia = sdpDiff.getNewMedia();\n\n        if (Object.keys(addedMedia).length) {\n            logger.error(`${this} - some SSRC were added on ${operationName}`, addedMedia);\n\n            return false;\n        }\n\n        sdpDiff = new SDPDiffer(currentLocalSDP, oldSDP);\n        const removedMedia = sdpDiff.getNewMedia();\n\n        if (Object.keys(removedMedia).length) {\n            logger.error(`${this} - some SSRCs were removed on ${operationName}`, removedMedia);\n\n            return false;\n        }\n\n        return true;\n    }\n\n    /**\n     * Adds local track back to this session, as part of the unmute operation.\n     * @param {JitsiLocalTrack} track\n     * @return {Promise} a promise that will resolve once the local track is\n     * added back to this session and renegotiation succeeds. Will be rejected\n     * with a <tt>string</tt> that provides some error details in case something\n     * goes wrong.\n     */\n    addTrackAsUnmute(track) {\n        return this._addRemoveTrackAsMuteUnmute(\n            false /* add as unmute */, track)\n            .then(() => {\n                // Configure the video encodings after the track is unmuted. If the user joins the call muted and\n                // unmutes it the first time, all the parameters need to be configured.\n                if (track.isVideoTrack()) {\n                    return this.peerconnection.configureSenderVideoEncodings(track);\n                }\n            });\n    }\n\n    /**\n     * Remove local track as part of the mute operation.\n     * @param {JitsiLocalTrack} track the local track to be removed\n     * @return {Promise} a promise which will be resolved once the local track\n     * is removed from this session and the renegotiation is performed.\n     * The promise will be rejected with a <tt>string</tt> that the describes\n     * the error if anything goes wrong.\n     */\n    removeTrackAsMute(track) {\n        return this._addRemoveTrackAsMuteUnmute(\n            true /* remove as mute */, track);\n    }\n\n    /**\n     * See {@link addTrackAsUnmute} and {@link removeTrackAsMute}.\n     * @param {boolean} isMute <tt>true</tt> for \"remove as mute\" or\n     * <tt>false</tt> for \"add as unmute\".\n     * @param {JitsiLocalTrack} track the track that will be added/removed\n     * @private\n     */\n    _addRemoveTrackAsMuteUnmute(isMute, track) {\n        if (!track) {\n            return Promise.reject('invalid \"track\" argument value');\n        }\n        const operationName = isMute ? 'removeTrackMute' : 'addTrackUnmute';\n        const workFunction = finishedCallback => {\n            const tpc = this.peerconnection;\n\n            if (!tpc) {\n                finishedCallback(\n                    `Error:  tried ${operationName} track with no active peer`\n                        + 'connection');\n\n                return;\n            }\n            const oldLocalSDP = tpc.localDescription.sdp;\n            const operationPromise\n                = isMute\n                    ? tpc.removeTrackMute(track)\n                    : tpc.addTrackUnmute(track);\n\n            operationPromise\n                .then(shouldRenegotiate => {\n                    if (shouldRenegotiate && oldLocalSDP && tpc.remoteDescription.sdp) {\n                        this._renegotiate()\n                            .then(() => {\n                                // The results are ignored, as this check failure is not enough to fail the whole\n                                // operation. It will log an error inside for plan-b.\n                                !this.usesUnifiedPlan && this._verifyNoSSRCChanged(operationName, new SDP(oldLocalSDP));\n                                const newLocalSdp = tpc.localDescription.sdp;\n\n                                // Signal the ssrc if an unmute operation results in a new ssrc being generated.\n                                this.notifyMySSRCUpdate(new SDP(oldLocalSDP), new SDP(newLocalSdp));\n                                finishedCallback();\n                            });\n                    } else {\n                        finishedCallback();\n                    }\n                },\n                finishedCallback /* will be called with an error */);\n        };\n\n        logger.debug(`${this} Queued ${operationName} task`);\n\n        return new Promise((resolve, reject) => {\n            this.modificationQueue.push(\n                workFunction,\n                error => {\n                    if (error) {\n                        logger.error(`${this} ${operationName} failed`);\n                        reject(error);\n                    } else {\n                        logger.debug(`${this} ${operationName} done`);\n                        resolve();\n                    }\n                });\n        });\n    }\n\n    /**\n     * Resumes or suspends media transfer over the underlying peer connection.\n     * @param {boolean} audioActive <tt>true</tt> to enable audio media\n     * transfer or <tt>false</tt> to suspend audio media transmission.\n     * @param {boolean} videoActive <tt>true</tt> to enable video media\n     * transfer or <tt>false</tt> to suspend video media transmission.\n     * @return {Promise} a <tt>Promise</tt> which will resolve once\n     * the operation is done. It will be rejected with an error description as\n     * a string in case anything goes wrong.\n     */\n    setMediaTransferActive(audioActive, videoActive) {\n        if (!this.peerconnection) {\n            return Promise.reject(\n                'Can not modify transfer active state,'\n                    + ' before \"initialize\" is called');\n        }\n\n        const logAudioStr = audioActive ? 'audio active' : 'audio inactive';\n        const logVideoStr = videoActive ? 'video active' : 'video inactive';\n\n        logger.info(`${this} Queued make ${logVideoStr}, ${logAudioStr} task`);\n\n        const workFunction = finishedCallback => {\n            const isSessionActive = this.state === JingleSessionState.ACTIVE;\n\n            // Because the value is modified on the queue it's impossible to\n            // check it's final value reliably prior to submitting the task.\n            // The rule here is that the last submitted state counts.\n            // Check the values here to avoid unnecessary renegotiation cycle.\n            const audioActiveChanged\n                = this.peerconnection.setAudioTransferActive(audioActive);\n\n            if (this._localVideoActive !== videoActive) {\n                this._localVideoActive = videoActive;\n\n                // Do only for P2P - Jicofo will reply with 'bad-request'\n                // We don't want to send 'content-modify', before the initial\n                // O/A (state === JingleSessionState.ACTIVE), because that will\n                // mess up video media direction in the remote SDP.\n                // 'content-modify' when processed only affects the media\n                // direction in the local SDP. We're doing that, because setting\n                // 'inactive' on video media in remote SDP will mess up our SDP\n                // translation chain (simulcast, RTX, video mute etc.).\n                if (this.isP2P && isSessionActive) {\n                    this.sendContentModify();\n                }\n            }\n\n            const pcVideoActiveChanged\n                = this.peerconnection.setVideoTransferActive(\n                    this._localVideoActive && this._remoteVideoActive);\n\n            // Will do the sRD/sLD cycle to update SDPs and adjust the media\n            // direction\n            if (isSessionActive\n                    && (audioActiveChanged || pcVideoActiveChanged)) {\n                this._renegotiate()\n                    .then(\n                        finishedCallback,\n                        finishedCallback /* will be called with an error */);\n            } else {\n                finishedCallback();\n            }\n        };\n\n        return new Promise((resolve, reject) => {\n            this.modificationQueue.push(\n                workFunction,\n                error => {\n                    if (error) {\n                        logger.error(`${this} Make ${logVideoStr}, ${logAudioStr} task failed!`);\n                        reject(error);\n                    } else {\n                        logger.debug(`${this} Make ${logVideoStr}, ${logAudioStr} task done!`);\n                        resolve();\n                    }\n                });\n        });\n    }\n\n    /**\n     * Will put and execute on the queue a session modify task. Currently it\n     * only checks the senders attribute of the video content in order to figure\n     * out if the remote peer has video in the inactive state (stored locally\n     * in {@link _remoteVideoActive} - see field description for more info).\n     * @param {jQuery} jingleContents jQuery selector pointing to the jingle\n     * element of the session modify IQ.\n     * @see {@link _remoteVideoActive}\n     * @see {@link _localVideoActive}\n     */\n    modifyContents(jingleContents) {\n        const newVideoSenders\n            = JingleSessionPC.parseVideoSenders(jingleContents);\n        const newMaxFrameHeight\n            = JingleSessionPC.parseMaxFrameHeight(jingleContents);\n\n        // frame height is optional in our content-modify protocol\n        if (newMaxFrameHeight) {\n            logger.info(`${this} received remote max frame height: ${newMaxFrameHeight}`);\n            this.remoteRecvMaxFrameHeight = newMaxFrameHeight;\n            this.eventEmitter.emit(\n                MediaSessionEvents.REMOTE_VIDEO_CONSTRAINTS_CHANGED, this);\n        }\n\n        if (newVideoSenders === null) {\n            logger.error(\n                `${this} - failed to parse video \"senders\" attribute in`\n                    + '\"content-modify\" action');\n\n            return;\n        }\n\n        const workFunction = finishedCallback => {\n            if (this._assertNotEnded('content-modify')\n                    && this._modifyRemoteVideoActive(newVideoSenders)) {\n                // Will do the sRD/sLD cycle to update SDPs and adjust\n                // the media direction\n                this._renegotiate()\n                    .then(finishedCallback, finishedCallback /* (error) */);\n            } else {\n                finishedCallback();\n            }\n        };\n\n        logger.debug(`${this} queued \"content-modify\" task(video senders=\"${newVideoSenders}\")`);\n\n        this.modificationQueue.push(\n            workFunction,\n            error => {\n                if (error) {\n                    logger.error(`${this} \"content-modify\" failed`, error);\n                } else {\n                    logger.debug(`${this} \"content-modify\" task(video senders=\"${newVideoSenders}\") done`);\n                }\n            });\n    }\n\n    /**\n     * Processes new value of remote video \"senders\" Jingle attribute and tries\n     * to apply it for {@link _remoteVideoActive}.\n     * @param {string} remoteVideoSenders the value of \"senders\" attribute of\n     * Jingle video content element advertised by remote peer.\n     * @return {boolean} <tt>true</tt> if the change affected state of\n     * the underlying peerconnection and renegotiation is required for\n     * the changes to take effect.\n     * @private\n     */\n    _modifyRemoteVideoActive(remoteVideoSenders) {\n        const isRemoteVideoActive\n            = remoteVideoSenders === 'both'\n                || (remoteVideoSenders === 'initiator' && this.isInitiator)\n                || (remoteVideoSenders === 'responder' && !this.isInitiator);\n\n        if (isRemoteVideoActive !== this._remoteVideoActive) {\n            logger.debug(`${this} new remote video active: ${isRemoteVideoActive}`);\n            this._remoteVideoActive = isRemoteVideoActive;\n        }\n\n        return this.peerconnection.setVideoTransferActive(\n            this._localVideoActive && this._remoteVideoActive);\n    }\n\n    /**\n     * Figures out added/removed ssrcs and send update IQs.\n     * @param oldSDP SDP object for old description.\n     * @param newSDP SDP object for new description.\n     */\n    notifyMySSRCUpdate(oldSDP, newSDP) {\n        if (this.state !== JingleSessionState.ACTIVE) {\n            logger.warn(`${this} Skipping SSRC update in '${this.state} ' state.`);\n\n            return;\n        }\n\n        if (!this.connection.connected) {\n            // The goal is to compare the oldest SDP with the latest one upon reconnect\n            if (!this._cachedOldLocalSdp) {\n                this._cachedOldLocalSdp = oldSDP;\n            }\n            this._cachedNewLocalSdp = newSDP;\n            logger.warn(`${this} Not sending SSRC update while the signaling is disconnected`);\n\n            return;\n        }\n\n        this._cachedOldLocalSdp = undefined;\n        this._cachedNewLocalSdp = undefined;\n\n        const getSignaledSourceInfo = sdpDiffer => {\n            const newMedia = sdpDiffer.getNewMedia();\n            let ssrcs = [];\n            let mediaType = null;\n\n            // It is assumed that sources are signaled one at a time.\n            Object.keys(newMedia).forEach(mediaIndex => {\n                const signaledSsrcs = Object.keys(newMedia[mediaIndex].ssrcs);\n\n                mediaType = newMedia[mediaIndex].mid;\n                if (signaledSsrcs?.length) {\n                    ssrcs = ssrcs.concat(signaledSsrcs);\n                }\n            });\n\n            return {\n                mediaType,\n                ssrcs\n            };\n        };\n\n        // send source-remove IQ.\n        let sdpDiffer = new SDPDiffer(newSDP, oldSDP);\n        const remove = $iq({ to: this.remoteJid,\n            type: 'set' })\n            .c('jingle', {\n                xmlns: 'urn:xmpp:jingle:1',\n                action: 'source-remove',\n                initiator: this.initiatorJid,\n                sid: this.sid\n            }\n            );\n        const removedAnySSRCs = sdpDiffer.toJingle(remove);\n\n        // context a common object for one run of ssrc update (source-add and source-remove) so we can match them if we\n        // need to\n        const ctx = {};\n\n        if (removedAnySSRCs) {\n            const sourceInfo = getSignaledSourceInfo(sdpDiffer);\n\n            // Log only the SSRCs instead of the full IQ.\n            logger.info(`${this} Sending source-remove for ${sourceInfo.mediaType} ssrcs=${sourceInfo.ssrcs}`);\n            this.connection.sendIQ(\n                remove,\n                () => {\n                    this.room.eventEmitter.emit(XMPPEvents.SOURCE_REMOVE, this, ctx);\n                },\n                this.newJingleErrorHandler(remove, error => {\n                    this.room.eventEmitter.emit(XMPPEvents.SOURCE_REMOVE_ERROR, this, error, ctx);\n                }),\n                IQ_TIMEOUT);\n        }\n\n        // send source-add IQ.\n        sdpDiffer = new SDPDiffer(oldSDP, newSDP);\n        const add = $iq({ to: this.remoteJid,\n            type: 'set' })\n            .c('jingle', {\n                xmlns: 'urn:xmpp:jingle:1',\n                action: 'source-add',\n                initiator: this.initiatorJid,\n                sid: this.sid\n            }\n            );\n\n        const containsNewSSRCs = sdpDiffer.toJingle(add);\n\n        if (containsNewSSRCs) {\n            const sourceInfo = getSignaledSourceInfo(sdpDiffer);\n\n            // Log only the SSRCs instead of the full IQ.\n            logger.info(`${this} Sending source-add for ${sourceInfo.mediaType} ssrcs=${sourceInfo.ssrcs}`);\n            this.connection.sendIQ(\n                add,\n                () => {\n                    this.room.eventEmitter.emit(XMPPEvents.SOURCE_ADD, this, ctx);\n                },\n                this.newJingleErrorHandler(add, error => {\n                    this.room.eventEmitter.emit(XMPPEvents.SOURCE_ADD_ERROR, this, error, sourceInfo.mediaType, ctx);\n                }),\n                IQ_TIMEOUT);\n        }\n    }\n\n    /**\n     * Method returns function(errorResponse) which is a callback to be passed\n     * to Strophe connection.sendIQ method. An 'error' structure is created that\n     * is passed as 1st argument to given <tt>failureCb</tt>. The format of this\n     * structure is as follows:\n     * {\n     *  code: {XMPP error response code}\n     *  reason: {the name of XMPP error reason element or 'timeout' if the\n      *          request has timed out within <tt>IQ_TIMEOUT</tt> milliseconds}\n     *  source: {request.tree() that provides original request}\n     *  session: {this JingleSessionPC.toString()}\n     * }\n     * @param request Strophe IQ instance which is the request to be dumped into\n     *        the error structure\n     * @param failureCb function(error) called when error response was returned\n     *        or when a timeout has occurred.\n     * @returns {function(this:JingleSessionPC)}\n     */\n    newJingleErrorHandler(request, failureCb) {\n        return errResponse => {\n\n            const error = {};\n\n            // Get XMPP error code and condition(reason)\n            const errorElSel = $(errResponse).find('error');\n\n            if (errorElSel.length) {\n                error.code = errorElSel.attr('code');\n                const errorReasonSel = $(errResponse).find('error :first');\n\n                if (errorReasonSel.length) {\n                    error.reason = errorReasonSel[0].tagName;\n                }\n\n                const errorMsgSel = errorElSel.find('>text');\n\n                if (errorMsgSel.length) {\n                    error.msg = errorMsgSel.text();\n                }\n            }\n\n            if (!errResponse) {\n                error.reason = 'timeout';\n            }\n\n            error.session = this.toString();\n\n            if (failureCb) {\n                failureCb(error);\n            } else if (this.state === JingleSessionState.ENDED\n                        && error.reason === 'item-not-found') {\n                // When remote peer decides to terminate the session, but it\n                // still have few messages on the queue for processing,\n                // it will first send us 'session-terminate' (we enter ENDED)\n                // and then follow with 'item-not-found' for the queued requests\n                // We don't want to have that logged on error level.\n                logger.debug(`${this} Jingle error: ${JSON.stringify(error)}`);\n            } else {\n                GlobalOnErrorHandler.callErrorHandler(\n                    new Error(\n                        `Jingle error: ${JSON.stringify(error)}`));\n            }\n        };\n    }\n\n    /**\n     * Returns the ice connection state for the peer connection.\n     * @returns the ice connection state for the peer connection.\n     */\n    getIceConnectionState() {\n        return this.peerconnection.getConnectionState();\n    }\n\n    /**\n     * Closes the peerconnection.\n     */\n    close() {\n        this.state = JingleSessionState.ENDED;\n        this.establishmentDuration = undefined;\n\n        if (this.peerconnection) {\n            this.peerconnection.onicecandidate = null;\n            this.peerconnection.oniceconnectionstatechange = null;\n            this.peerconnection.onnegotiationneeded = null;\n            this.peerconnection.onsignalingstatechange = null;\n        }\n\n        logger.debug(`${this} Clearing modificationQueue`);\n\n        // Remove any pending tasks from the queue\n        this.modificationQueue.clear();\n\n        logger.debug(`${this} Queued PC close task`);\n        this.modificationQueue.push(finishCallback => {\n            // do not try to close if already closed.\n            this.peerconnection && this.peerconnection.close();\n            finishCallback();\n            logger.debug(`${this} PC close task done!`);\n        });\n\n        logger.debug(`${this} Shutdown modificationQueue!`);\n\n        // No more tasks can go in after the close task\n        this.modificationQueue.shutdown();\n    }\n\n    /**\n     * Converts to string with minor summary.\n     * @return {string}\n     */\n    toString() {\n        return `JingleSessionPC[session=${this.isP2P ? 'P2P' : 'JVB'},initiator=${this.isInitiator},sid=${this.sid}]`;\n    }\n\n    /**\n     * If the A/B test for suspend video is disabled according to the room's\n     * configuration, returns undefined. Otherwise returns a boolean which\n     * indicates whether the suspend video option should be enabled or disabled.\n     * @param {JingleSessionPCOptions} options - The config options.\n     */\n    _abtestSuspendVideoEnabled({ abTesting }) {\n        if (!abTesting || !abTesting.enableSuspendVideoTest) {\n            return;\n        }\n\n        // We want the two participants in a P2P call to agree on the value of\n        // the \"suspend\" option. We use the JID of the initiator, because it is\n        // both randomly selected and agreed upon by both participants.\n        const jid = this._getInitiatorJid();\n\n        return integerHash(jid) % 2 === 0;\n    }\n}\n","import { getLogger } from '@jitsi/logger';\nimport $ from 'jquery';\nimport { $iq, Strophe } from 'strophe.js';\n\nimport { MediaType } from '../../service/RTC/MediaType';\nimport {\n    ACTION_JINGLE_TR_RECEIVED,\n    ACTION_JINGLE_TR_SUCCESS,\n    createJingleEvent\n} from '../../service/statistics/AnalyticsEvents';\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\nimport Statistics from '../statistics/statistics';\nimport GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';\nimport RandomUtil from '../util/RandomUtil';\n\nimport ConnectionPlugin from './ConnectionPlugin';\nimport { expandSourcesFromJson } from './JingleHelperFunctions';\nimport JingleSessionPC from './JingleSessionPC';\n\nconst logger = getLogger(__filename);\n\n// XXX Strophe is build around the idea of chaining function calls so allow long\n// function call chains.\n/* eslint-disable newline-per-chained-call */\n\n/**\n * Parses the transport XML element and returns the list of ICE candidates formatted as text.\n *\n * @param {*} transport Transport XML element extracted from the IQ.\n * @returns {Array<string>}\n */\nfunction _parseIceCandidates(transport) {\n    const candidates = $(transport).find('>candidate');\n    const parseCandidates = [];\n\n    // Extract the candidate information from the IQ.\n    candidates.each((_, candidate) => {\n        const attributes = candidate.attributes;\n        const candidateAttrs = [];\n\n        for (let i = 0; i < attributes.length; i++) {\n            const attr = attributes[i];\n\n            candidateAttrs.push(`${attr.name}: ${attr.value}`);\n        }\n        parseCandidates.push(candidateAttrs.join(' '));\n    });\n\n    return parseCandidates;\n}\n\n/**\n *\n */\nexport default class JingleConnectionPlugin extends ConnectionPlugin {\n    /**\n     * Creates new <tt>JingleConnectionPlugin</tt>\n     * @param {XMPP} xmpp\n     * @param {EventEmitter} eventEmitter\n     * @param {Object} iceConfig an object that holds the iceConfig to be passed\n     * to the p2p and the jvb <tt>PeerConnection</tt>.\n     */\n    constructor(xmpp, eventEmitter, iceConfig) {\n        super();\n        this.xmpp = xmpp;\n        this.eventEmitter = eventEmitter;\n        this.sessions = {};\n        this.jvbIceConfig = iceConfig.jvb;\n        this.p2pIceConfig = iceConfig.p2p;\n        this.mediaConstraints = {\n            offerToReceiveAudio: true,\n            offerToReceiveVideo: true\n        };\n    }\n\n    /**\n     *\n     * @param connection\n     */\n    init(connection) {\n        super.init(connection);\n        this.connection.addHandler(this.onJingle.bind(this),\n            'urn:xmpp:jingle:1', 'iq', 'set', null, null);\n    }\n\n    /**\n     *\n     * @param iq\n     */\n    onJingle(iq) {\n        const sid = $(iq).find('jingle').attr('sid');\n        const action = $(iq).find('jingle').attr('action');\n        const fromJid = iq.getAttribute('from');\n\n        // send ack first\n        const ack = $iq({ type: 'result',\n            to: fromJid,\n            id: iq.getAttribute('id')\n        });\n\n        let sess = this.sessions[sid];\n\n        if (action !== 'session-initiate') {\n            if (!sess) {\n                ack.attrs({ type: 'error' });\n                ack.c('error', { type: 'cancel' })\n                    .c('item-not-found', {\n                        xmlns: 'urn:ietf:params:xml:ns:xmpp-stanzas'\n                    })\n                    .up()\n                    .c('unknown-session', {\n                        xmlns: 'urn:xmpp:jingle:errors:1'\n                    });\n                logger.warn(`invalid session id: ${sid}`);\n                logger.debug(iq);\n                this.connection.send(ack);\n\n                return true;\n            }\n\n            // local jid is not checked\n            if (fromJid !== sess.remoteJid) {\n                logger.warn(\n                    'jid mismatch for session id', sid, sess.remoteJid, iq);\n                ack.attrs({ type: 'error' });\n                ack.c('error', { type: 'cancel' })\n                    .c('item-not-found', {\n                        xmlns: 'urn:ietf:params:xml:ns:xmpp-stanzas'\n                    })\n                    .up()\n                    .c('unknown-session', {\n                        xmlns: 'urn:xmpp:jingle:errors:1'\n                    });\n                this.connection.send(ack);\n\n                return true;\n            }\n        } else if (sess !== undefined) {\n            // Existing session with same session id. This might be out-of-order\n            // if the sess.remoteJid is the same as from.\n            ack.attrs({ type: 'error' });\n            ack.c('error', { type: 'cancel' })\n                .c('service-unavailable', {\n                    xmlns: 'urn:ietf:params:xml:ns:xmpp-stanzas'\n                })\n                .up();\n            logger.warn('duplicate session id', sid, iq);\n            this.connection.send(ack);\n\n            return true;\n        }\n        const now = window.performance.now();\n\n        // FIXME that should work most of the time, but we'd have to\n        // think how secure it is to assume that user with \"focus\"\n        // nickname is Jicofo.\n        const isP2P = Strophe.getResourceFromJid(fromJid) !== 'focus';\n\n        // see http://xmpp.org/extensions/xep-0166.html#concepts-session\n\n        const jsonMessages = $(iq).find('jingle>json-message');\n\n        if (jsonMessages?.length) {\n            let audioVideoSsrcs;\n\n            logger.info(`Found a JSON-encoded element in ${action}, translating to standard Jingle.`);\n            for (let i = 0; i < jsonMessages.length; i++) {\n                // Currently there is always a single json-message in the IQ with the source information.\n                audioVideoSsrcs = expandSourcesFromJson(iq, jsonMessages[i]);\n            }\n\n            if (audioVideoSsrcs?.size) {\n                const logMessage = [];\n\n                for (const endpoint of audioVideoSsrcs.keys()) {\n                    logMessage.push(`${endpoint}:[${audioVideoSsrcs.get(endpoint)}]`);\n                }\n                logger.debug(`Received ${action} from ${fromJid} with sources=${logMessage.join(', ')}`);\n            }\n\n            // TODO: is there a way to remove the json-message elements once we've extracted the information?\n            // removeChild doesn't seem to work.\n        }\n\n        switch (action) {\n        case 'session-initiate': {\n            logger.log('(TIME) received session-initiate:\\t', now);\n            const startMuted = $(iq).find('jingle>startmuted');\n\n            isP2P && logger.debug(`Received ${action} from ${fromJid}`);\n            if (startMuted?.length) {\n                const audioMuted = startMuted.attr(MediaType.AUDIO);\n                const videoMuted = startMuted.attr(MediaType.VIDEO);\n\n                this.eventEmitter.emit(\n                    XMPPEvents.START_MUTED_FROM_FOCUS,\n                    audioMuted === 'true',\n                    videoMuted === 'true');\n            }\n            const pcConfig = isP2P ? this.p2pIceConfig : this.jvbIceConfig;\n\n            sess\n                = new JingleSessionPC(\n                    $(iq).find('jingle').attr('sid'),\n                    $(iq).attr('to'),\n                    fromJid,\n                    this.connection,\n                    this.mediaConstraints,\n\n                    // Makes a copy in order to prevent exception thrown on RN when either this.p2pIceConfig or\n                    // this.jvbIceConfig is modified and there's a PeerConnection instance holding a reference\n                    JSON.parse(JSON.stringify(pcConfig)),\n                    isP2P,\n                    /* initiator */ false);\n\n            this.sessions[sess.sid] = sess;\n            this.eventEmitter.emit(XMPPEvents.CALL_INCOMING, sess, $(iq).find('>jingle'), now);\n            break;\n        }\n        case 'session-accept': {\n            const ssrcs = [];\n            const contents = $(iq).find('jingle>content');\n\n            // Extract the SSRCs from the session-accept received from a p2p peer.\n            for (const content of contents) {\n                const ssrc = $(content).find('description').attr('ssrc');\n\n                ssrc && ssrcs.push(ssrc);\n            }\n            logger.debug(`Received ${action} from ${fromJid} with ssrcs=${ssrcs}`);\n            this.eventEmitter.emit(XMPPEvents.CALL_ACCEPTED, sess, $(iq).find('>jingle'));\n            break;\n        }\n        case 'content-modify': {\n            const height = $(iq).find('jingle>content[name=\"video\"]>max-frame-height');\n\n            logger.debug(`Received ${action} from ${fromJid} with a max-frame-height=${height?.text()}`);\n            sess.modifyContents($(iq).find('>jingle'));\n            break;\n        }\n        case 'transport-info': {\n            const candidates = _parseIceCandidates($(iq).find('jingle>content>transport'));\n\n            logger.debug(`Received ${action} from ${fromJid} for candidates=${candidates.join(', ')}`);\n            this.eventEmitter.emit(XMPPEvents.TRANSPORT_INFO, sess, $(iq).find('>jingle'));\n            break;\n        }\n        case 'session-terminate': {\n            logger.log('terminating...', sess.sid);\n            let reasonCondition = null;\n            let reasonText = null;\n\n            if ($(iq).find('>jingle>reason').length) {\n                reasonCondition\n                    = $(iq).find('>jingle>reason>:first')[0].tagName;\n                reasonText = $(iq).find('>jingle>reason>text').text();\n            }\n            logger.debug(`Received ${action} from ${fromJid} disconnect reason=${reasonText}`);\n            this.terminate(sess.sid, reasonCondition, reasonText);\n            this.eventEmitter.emit(XMPPEvents.CALL_ENDED, sess, reasonCondition, reasonText);\n            break;\n        }\n        case 'transport-replace': {\n            logger.info('(TIME) Start transport replace:\\t', now);\n            const transport = $(iq).find('jingle>content>transport');\n            const candidates = _parseIceCandidates(transport);\n            const iceUfrag = $(transport).attr('ufrag');\n            const icePwd = $(transport).attr('pwd');\n            const dtlsFingerprint = $(transport).find('>fingerprint')?.text();\n\n            logger.debug(`Received ${action} from ${fromJid} with iceUfrag=${iceUfrag},`\n            + ` icePwd=${icePwd}, DTLS fingerprint=${dtlsFingerprint}, candidates=${candidates.join(', ')}`);\n\n            Statistics.sendAnalytics(createJingleEvent(\n                ACTION_JINGLE_TR_RECEIVED,\n                {\n                    p2p: isP2P,\n                    value: now\n                }));\n\n            sess.replaceTransport($(iq).find('>jingle'), () => {\n                const successTime = window.performance.now();\n\n                logger.info('(TIME) Transport replace success:\\t', successTime);\n                Statistics.sendAnalytics(createJingleEvent(\n                    ACTION_JINGLE_TR_SUCCESS,\n                    {\n                        p2p: isP2P,\n                        value: successTime\n                    }));\n            }, error => {\n                GlobalOnErrorHandler.callErrorHandler(error);\n                logger.error('Transport replace failed', error);\n                sess.sendTransportReject();\n            });\n            break;\n        }\n        case 'source-add':\n            sess.addRemoteStream($(iq).find('>jingle>content'));\n            break;\n        case 'source-remove':\n            sess.removeRemoteStream($(iq).find('>jingle>content'));\n            break;\n        default:\n            logger.warn('jingle action not implemented', action);\n            ack.attrs({ type: 'error' });\n            ack.c('error', { type: 'cancel' })\n                .c('bad-request',\n                    { xmlns: 'urn:ietf:params:xml:ns:xmpp-stanzas' })\n                .up();\n            break;\n        }\n        this.connection.send(ack);\n\n        return true;\n    }\n\n    /**\n     * Creates new <tt>JingleSessionPC</tt> meant to be used in a direct P2P\n     * connection, configured as 'initiator'.\n     * @param {string} me our JID\n     * @param {string} peer remote participant's JID\n     * @return {JingleSessionPC}\n     */\n    newP2PJingleSession(me, peer) {\n        const sess\n            = new JingleSessionPC(\n                RandomUtil.randomHexString(12),\n                me,\n                peer,\n                this.connection,\n                this.mediaConstraints,\n                this.p2pIceConfig,\n                /* P2P */ true,\n                /* initiator */ true);\n\n        this.sessions[sess.sid] = sess;\n\n        return sess;\n    }\n\n    /**\n     *\n     * @param sid\n     * @param reasonCondition\n     * @param reasonText\n     */\n    terminate(sid, reasonCondition, reasonText) {\n        if (this.sessions.hasOwnProperty(sid)) {\n            if (this.sessions[sid].state !== 'ended') {\n                this.sessions[sid].onTerminated(reasonCondition, reasonText);\n            }\n            delete this.sessions[sid];\n        }\n    }\n\n    /**\n     *\n     */\n    getStunAndTurnCredentials() {\n        // get stun and turn configuration from server via xep-0215\n        // uses time-limited credentials as described in\n        // http://tools.ietf.org/html/draft-uberti-behave-turn-rest-00\n        //\n        // See https://modules.prosody.im/mod_turncredentials.html\n        // for a prosody module which implements this.\n        // Or the new implementation https://modules.prosody.im/mod_external_services which will be in prosody 0.12\n        //\n        // Currently, this doesn't work with updateIce and therefore credentials\n        // with a long validity have to be fetched before creating the\n        // peerconnection.\n        // TODO: implement refresh via updateIce as described in\n        //      https://code.google.com/p/webrtc/issues/detail?id=1650\n        this.connection.sendIQ(\n            $iq({ type: 'get',\n                to: this.xmpp.options.hosts.domain })\n                .c('services', { xmlns: 'urn:xmpp:extdisco:2' }),\n            v2Res => this.onReceiveStunAndTurnCredentials(v2Res),\n            () => {\n                logger.warn('getting turn credentials with extdisco:2 failed, trying extdisco:1');\n                this.connection.sendIQ(\n                    $iq({ type: 'get',\n                        to: this.xmpp.options.hosts.domain })\n                        .c('services', { xmlns: 'urn:xmpp:extdisco:1' }),\n                    v1Res => this.onReceiveStunAndTurnCredentials(v1Res),\n                    () => {\n                        logger.warn('getting turn credentials failed');\n                        logger.warn('is mod_turncredentials or similar installed and configured?');\n                    }\n                );\n            });\n    }\n\n    /**\n     * Parses response when querying for services using urn:xmpp:extdisco:1 or urn:xmpp:extdisco:2.\n     * Stores results in jvbIceConfig and p2pIceConfig.\n     * @param res The response iq.\n     * @return {boolean} Whether something was processed from the supplied message.\n     */\n    onReceiveStunAndTurnCredentials(res) {\n        const iceservers = [];\n\n        $(res).find('>services>service').each((idx, el) => {\n            // eslint-disable-next-line no-param-reassign\n            el = $(el);\n            const dict = {};\n            const type = el.attr('type');\n\n            switch (type) {\n            case 'stun':\n                dict.urls = `stun:${el.attr('host')}`;\n                if (el.attr('port')) {\n                    dict.urls += `:${el.attr('port')}`;\n                }\n                iceservers.push(dict);\n                break;\n            case 'turn':\n            case 'turns': {\n                dict.urls = `${type}:`;\n                dict.username = el.attr('username');\n                dict.urls += el.attr('host');\n                const port = el.attr('port');\n\n                if (port) {\n                    dict.urls += `:${el.attr('port')}`;\n                }\n                const transport = el.attr('transport');\n\n                if (transport && transport !== 'udp') {\n                    dict.urls += `?transport=${transport}`;\n                }\n\n                dict.credential = el.attr('password')\n                        || dict.credential;\n                iceservers.push(dict);\n                break;\n            }\n            }\n        });\n\n        const options = this.xmpp.options;\n\n        // Shuffle ICEServers for loadbalancing\n        for (let i = iceservers.length - 1; i > 0; i--) {\n            const j = Math.floor(Math.random() * (i + 1));\n            const temp = iceservers[i];\n\n            iceservers[i] = iceservers[j];\n            iceservers[j] = temp;\n        }\n\n        let filter;\n\n        if (options.useTurnUdp) {\n            filter = s => s.urls.startsWith('turn');\n        } else {\n            // By default we filter out STUN and TURN/UDP and leave only TURN/TCP.\n            filter = s => s.urls.startsWith('turn') && (s.urls.indexOf('transport=tcp') >= 0);\n        }\n\n        this.jvbIceConfig.iceServers = iceservers.filter(filter);\n        this.p2pIceConfig.iceServers = iceservers;\n\n        return iceservers.length > 0;\n    }\n\n    /**\n     * Returns the data saved in 'updateLog' in a format to be logged.\n     */\n    getLog() {\n        const data = {};\n\n        Object.keys(this.sessions).forEach(sid => {\n            const session = this.sessions[sid];\n            const pc = session.peerconnection;\n\n            if (pc && pc.updateLog) {\n                // FIXME: should probably be a .dump call\n                data[`jingle_${sid}`] = {\n                    updateLog: pc.updateLog,\n                    stats: pc.stats,\n                    url: window.location.href\n                };\n            }\n        });\n\n        return data;\n    }\n}\n\n/* eslint-enable newline-per-chained-call */\n","import { Strophe } from 'strophe.js';\n\nimport ConnectionPlugin from './ConnectionPlugin';\n\n/**\n *  Logs raw stanzas and makes them available for download as JSON\n */\nclass StropheLogger extends ConnectionPlugin {\n    /**\n     *\n     */\n    constructor() {\n        super();\n        this.log = [];\n    }\n\n    /**\n     *\n     * @param connection\n     */\n    init(connection) {\n        super.init(connection);\n        this.connection.rawInput = this.logIncoming.bind(this);\n        this.connection.rawOutput = this.logOutgoing.bind(this);\n    }\n\n    /**\n     *\n     * @param stanza\n     */\n    logIncoming(stanza) {\n        this.log.push([ new Date().getTime(), 'incoming', stanza ]);\n    }\n\n    /**\n     *\n     * @param stanza\n     */\n    logOutgoing(stanza) {\n        this.log.push([ new Date().getTime(), 'outgoing', stanza ]);\n    }\n}\n\n/**\n *\n */\nexport default function() {\n    Strophe.addConnectionPlugin('logger', new StropheLogger());\n}\n","import { getLogger } from '@jitsi/logger';\nimport $ from 'jquery';\nimport { $iq } from 'strophe.js';\n\nimport ConnectionPlugin from './ConnectionPlugin';\n\nconst logger = getLogger(__filename);\n\nconst RAYO_XMLNS = 'urn:xmpp:rayo:1';\n\n/**\n *\n */\nexport default class RayoConnectionPlugin extends ConnectionPlugin {\n    /**\n     *\n     * @param connection\n     */\n    init(connection) {\n        super.init(connection);\n\n        this.connection.addHandler(\n            this.onRayo.bind(this), RAYO_XMLNS, 'iq', 'set', null, null);\n    }\n\n    /**\n     *\n     * @param iq\n     */\n    onRayo(iq) {\n        logger.info('Rayo IQ', iq);\n    }\n\n    /* eslint-disable max-params */\n\n    /**\n     *\n     * @param to\n     * @param from\n     * @param roomName\n     * @param roomPass\n     * @param focusMucJid\n     */\n    dial(to, from, roomName, roomPass, focusMucJid) {\n        return new Promise((resolve, reject) => {\n            if (!focusMucJid) {\n                reject(new Error('Internal error!'));\n\n                return;\n            }\n            const req = $iq({\n                type: 'set',\n                to: focusMucJid\n            });\n\n            req.c('dial', {\n                xmlns: RAYO_XMLNS,\n                to,\n                from\n            });\n            req.c('header', {\n                name: 'JvbRoomName',\n                value: roomName\n            }).up();\n\n            if (roomPass && roomPass.length) {\n                req.c('header', {\n                    name: 'JvbRoomPassword',\n                    value: roomPass\n                }).up();\n            }\n\n            this.connection.sendIQ(\n                req,\n                result => {\n                    logger.info('Dial result ', result);\n\n                    // eslint-disable-next-line newline-per-chained-call\n                    const resource = $(result).find('ref').attr('uri');\n\n                    this.callResource = resource.substr('xmpp:'.length);\n                    logger.info(`Received call resource: ${this.callResource}`);\n                    resolve();\n                },\n                error => {\n                    logger.info('Dial error ', error);\n                    reject(error);\n                });\n        });\n    }\n\n    /* eslint-enable max-params */\n\n    /**\n     *\n     */\n    hangup() {\n        return new Promise((resolve, reject) => {\n            if (!this.callResource) {\n                reject(new Error('No call in progress'));\n                logger.warn('No call in progress');\n\n                return;\n            }\n\n            const req = $iq({\n                type: 'set',\n                to: this.callResource\n            });\n\n            req.c('hangup', {\n                xmlns: RAYO_XMLNS\n            });\n\n            this.connection.sendIQ(req, result => {\n                logger.info('Hangup result ', result);\n                this.callResource = null;\n                resolve();\n            }, error => {\n                logger.info('Hangup error ', error);\n                this.callResource = null;\n                reject(new Error('Hangup error '));\n            });\n        });\n    }\n}\n","/**\n * Strophe logger implementation. Logs from level WARN and above.\n */\nimport { getLogger } from '@jitsi/logger';\nimport { Strophe } from 'strophe.js';\n\nimport GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';\n\nconst logger = getLogger(__filename);\n\n/**\n * This is the last HTTP error status captured from Strophe debug logs.\n * The purpose of storing it is to distinguish between the network and\n * infrastructure reason for connection being dropped (see connectionHandler in\n * xmpp.js). The value will be cleared (-1) if the subsequent request succeeds\n * which means that the failure could be transient.\n *\n * FIXME in the latest Strophe (not released on npm) there is API to handle\n * particular HTTP errors, but there is no way to learn if the subsequent\n * request succeeded in order to tell if the error was one time incident or if\n * it was the reason for dropping the connection by Strophe (the connection is\n * dropped after 5 subsequent failures). Ideally Strophe should provide more\n * details about the reason on why the connection stopped.\n *\n * @type {number}\n */\nlet lastErrorStatus = -1;\n\n/**\n * A regular expression used to catch Strophe's log message indicating that the\n * last BOSH request was successful. When there is such message seen the\n * {@link lastErrorStatus} will be set back to '-1'.\n * @type {RegExp}\n */\nconst resetLastErrorStatusRegExpr = /request id \\d+.\\d+ got 200/;\n\n/**\n * A regular expression used to capture the current value of the BOSH request\n * error status (HTTP error code or '0' or something else).\n * @type {RegExp}\n */\nconst lastErrorStatusRegExpr\n    = /request errored, status: (\\d+), number of errors: \\d+/;\n\n/**\n *\n */\nexport default function() {\n\n    Strophe.log = function(level, msg) {\n        // Our global handler reports uncaught errors to the stats which may\n        // interpret those as partial call failure.\n        // Strophe log entry about secondary request timeout does not mean that\n        // it's a final failure(the request will be restarted), so we lower it's\n        // level here to a warning.\n        logger.trace('Strophe', level, msg);\n        if (typeof msg === 'string'\n                && msg.indexOf('Request ') !== -1\n                && msg.indexOf('timed out (secondary), restarting') !== -1) {\n            // eslint-disable-next-line no-param-reassign\n            level = Strophe.LogLevel.WARN;\n        }\n\n        /* eslint-disable no-case-declarations */\n        switch (level) {\n        case Strophe.LogLevel.DEBUG:\n            // The log message which reports successful status is logged on\n            // Strophe's DEBUG level.\n            if (lastErrorStatus !== -1\n                    && resetLastErrorStatusRegExpr.test(msg)) {\n                logger.debug('Reset lastErrorStatus');\n                lastErrorStatus = -1;\n            }\n            break;\n        case Strophe.LogLevel.WARN:\n            logger.warn(`Strophe: ${msg}`);\n            const errStatusCapture = lastErrorStatusRegExpr.exec(msg);\n\n            if (errStatusCapture && errStatusCapture.length === 2) {\n                lastErrorStatus = parseInt(errStatusCapture[1], 10);\n                logger.debug(`lastErrorStatus set to: ${lastErrorStatus}`);\n            }\n            break;\n        case Strophe.LogLevel.ERROR:\n        case Strophe.LogLevel.FATAL:\n            // eslint-disable-next-line no-param-reassign\n            msg = `Strophe: ${msg}`;\n            GlobalOnErrorHandler.callErrorHandler(new Error(msg));\n            logger.error(msg);\n            break;\n        }\n\n        /* eslint-enable no-case-declarations */\n    };\n\n    /**\n     * Returns error status (HTTP error code) of the last BOSH request.\n     *\n     * @return {number} HTTP error code, '0' for unknown or \"god knows what\"\n     * (this is a hack).\n     */\n    Strophe.getLastErrorStatus = function() {\n        return lastErrorStatus;\n    };\n\n    Strophe.getStatusString = function(status) {\n        switch (status) {\n        case Strophe.Status.BINDREQUIRED:\n            return 'BINDREQUIRED';\n        case Strophe.Status.ERROR:\n            return 'ERROR';\n        case Strophe.Status.CONNECTING:\n            return 'CONNECTING';\n        case Strophe.Status.CONNFAIL:\n            return 'CONNFAIL';\n        case Strophe.Status.AUTHENTICATING:\n            return 'AUTHENTICATING';\n        case Strophe.Status.AUTHFAIL:\n            return 'AUTHFAIL';\n        case Strophe.Status.CONNECTED:\n            return 'CONNECTED';\n        case Strophe.Status.DISCONNECTED:\n            return 'DISCONNECTED';\n        case Strophe.Status.DISCONNECTING:\n            return 'DISCONNECTING';\n        case Strophe.Status.ATTACHED:\n            return 'ATTACHED';\n        default:\n            return 'unknown';\n        }\n    };\n}\n","import { getLogger } from '@jitsi/logger';\nimport $ from 'jquery';\nimport { $msg, Strophe } from 'strophe.js';\nimport 'strophejs-plugin-disco';\n\nimport * as JitsiConnectionErrors from '../../JitsiConnectionErrors';\nimport * as JitsiConnectionEvents from '../../JitsiConnectionEvents';\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\nimport browser from '../browser';\nimport { E2EEncryption } from '../e2ee/E2EEncryption';\nimport Statistics from '../statistics/statistics';\nimport GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';\nimport Listenable from '../util/Listenable';\nimport RandomUtil from '../util/RandomUtil';\n\nimport Caps, { parseDiscoInfo } from './Caps';\nimport XmppConnection from './XmppConnection';\nimport MucConnectionPlugin from './strophe.emuc';\nimport JingleConnectionPlugin from './strophe.jingle';\nimport initStropheLogger from './strophe.logger';\nimport RayoConnectionPlugin from './strophe.rayo';\nimport initStropheUtil from './strophe.util';\n\nconst logger = getLogger(__filename);\n\n/**\n* Regex to extract exact error message on jwt error.\n*/\nconst FAILURE_REGEX = /<failure.*><not-allowed\\/><text>(.*)<\\/text><\\/failure>/gi;\n\n/**\n * Creates XMPP connection.\n *\n * @param {Object} options\n * @param {string} [options.token] - JWT token used for authentication(JWT authentication module must be enabled in\n * Prosody).\n * @param {string} options.serviceUrl - The service URL for XMPP connection.\n * @param {string} options.shard - The shard where XMPP connection initially landed.\n * @param {string} options.enableWebsocketResume - True to enable stream resumption.\n * @param {number} [options.websocketKeepAlive] - See {@link XmppConnection} constructor.\n * @param {number} [options.websocketKeepAliveUrl] - See {@link XmppConnection} constructor.\n * @param {Object} [options.xmppPing] - See {@link XmppConnection} constructor.\n * @returns {XmppConnection}\n */\nfunction createConnection({\n    enableWebsocketResume,\n    serviceUrl = '/http-bind',\n    shard,\n    token,\n    websocketKeepAlive,\n    websocketKeepAliveUrl,\n    xmppPing }) {\n\n    // Append token as URL param\n    if (token) {\n        // eslint-disable-next-line no-param-reassign\n        serviceUrl += `${serviceUrl.indexOf('?') === -1 ? '?' : '&'}token=${token}`;\n    }\n\n    return new XmppConnection({\n        enableWebsocketResume,\n        serviceUrl,\n        websocketKeepAlive,\n        websocketKeepAliveUrl,\n        xmppPing,\n        shard\n    });\n}\n\n/**\n * Initializes Strophe plugins that need to work with Strophe.Connection directly rather than the lib-jitsi-meet's\n * {@link XmppConnection} wrapper.\n *\n * @returns {void}\n */\nfunction initStropheNativePlugins() {\n    initStropheUtil();\n    initStropheLogger();\n}\n\n// FIXME: remove once we have a default config template. -saghul\n/**\n * A list of ice servers to use by default for P2P.\n */\nexport const DEFAULT_STUN_SERVERS = [\n    { urls: 'stun:meet-jit-si-turnrelay.jitsi.net:443' }\n];\n\n/**\n * The name of the field used to recognize a chat message as carrying a JSON\n * payload from another endpoint.\n * If the json-message of a chat message contains a valid JSON object, and\n * the JSON has this key, then it is a valid json-message to be sent.\n */\nexport const JITSI_MEET_MUC_TYPE = 'type';\n\n/**\n * The feature used by jigasi participants.\n * @type {string}\n */\nexport const FEATURE_JIGASI = 'http://jitsi.org/protocol/jigasi';\n\n/**\n * The feature used by the lib to mark support for e2ee. We use the feature by putting it in the presence\n * to avoid additional signaling (disco-info).\n * @type {string}\n */\nexport const FEATURE_E2EE = 'https://jitsi.org/meet/e2ee';\n\n/**\n *\n */\nexport default class XMPP extends Listenable {\n    /**\n     * FIXME describe all options\n     * @param {Object} options\n     * @param {String} options.serviceUrl - URL passed to the XMPP client which will be used to establish XMPP\n     * connection with the server.\n     * @param {String} options.bosh - Deprecated, use {@code serviceUrl}.\n     * @param {boolean} options.enableWebsocketResume - Enables XEP-0198 stream management which will make the XMPP\n     * module try to resume the session in case the Websocket connection breaks.\n     * @param {number} [options.websocketKeepAlive] - The websocket keep alive interval. See {@link XmppConnection}\n     * constructor for more details.\n     * @param {number} [options.websocketKeepAliveUrl] - The websocket keep alive url. See {@link XmppConnection}\n     * constructor for more details.\n     * @param {Object} [options.xmppPing] - The xmpp ping settings.\n     * @param {Array<Object>} options.p2pStunServers see {@link JingleConnectionPlugin} for more details.\n     * @param token\n     */\n    constructor(options, token) {\n        super();\n        this.connection = null;\n        this.disconnectInProgress = false;\n        this.connectionTimes = {};\n        this.options = options;\n        this.token = token;\n        this.authenticatedUser = false;\n\n        initStropheNativePlugins();\n\n        const xmppPing = options.xmppPing || {};\n\n        // let's ping the main domain (in case a guest one is used for the connection)\n        xmppPing.domain = options.hosts.domain;\n\n        this.connection = createConnection({\n            enableWebsocketResume: options.enableWebsocketResume,\n\n            // FIXME remove deprecated bosh option at some point\n            serviceUrl: options.serviceUrl || options.bosh,\n            token,\n            websocketKeepAlive: options.websocketKeepAlive,\n            websocketKeepAliveUrl: options.websocketKeepAliveUrl,\n            xmppPing,\n            shard: options.deploymentInfo?.shard\n        });\n\n        // forwards the shard changed event\n        this.connection.on(XmppConnection.Events.CONN_SHARD_CHANGED, () => {\n            /* eslint-disable camelcase */\n            const details = {\n                shard_changed: true,\n                suspend_time: this.connection.ping.getPingSuspendTime(),\n                time_since_last_success: this.connection.getTimeSinceLastSuccess()\n            };\n            /* eslint-enable camelcase */\n\n            this.eventEmitter.emit(\n                JitsiConnectionEvents.CONNECTION_FAILED,\n                JitsiConnectionErrors.OTHER_ERROR,\n                undefined,\n                undefined,\n                details);\n        });\n\n        this._initStrophePlugins();\n\n        this.caps = new Caps(this.connection, /* clientNode */ 'https://jitsi.org/jitsi-meet');\n\n        // Initialize features advertised in disco-info\n        this.initFeaturesList();\n\n        // Setup a disconnect on unload as a way to facilitate API consumers. It\n        // sounds like they would want that. A problem for them though may be if\n        // they wanted to utilize the connected connection in an unload handler\n        // of their own. However, it should be fairly easy for them to do that\n        // by registering their unload handler before us.\n        $(window).on(`${this.options.disableBeforeUnloadHandlers ? '' : 'beforeunload '}unload`, ev => {\n            this.disconnect(ev).catch(() => {\n                // ignore errors in order to not brake the unload.\n            });\n        });\n    }\n\n    /**\n     * Initializes the list of feature advertised through the disco-info\n     * mechanism.\n     */\n    initFeaturesList() {\n        // http://xmpp.org/extensions/xep-0167.html#support\n        // http://xmpp.org/extensions/xep-0176.html#support\n        this.caps.addFeature('urn:xmpp:jingle:1');\n        this.caps.addFeature('urn:xmpp:jingle:apps:rtp:1');\n        this.caps.addFeature('urn:xmpp:jingle:transports:ice-udp:1');\n        this.caps.addFeature('urn:xmpp:jingle:apps:dtls:0');\n        this.caps.addFeature('urn:xmpp:jingle:transports:dtls-sctp:1');\n        this.caps.addFeature('urn:xmpp:jingle:apps:rtp:audio');\n        this.caps.addFeature('urn:xmpp:jingle:apps:rtp:video');\n        this.caps.addFeature('http://jitsi.org/json-encoded-sources');\n\n        if (!(this.options.disableRtx || !browser.supportsRTX())) {\n            this.caps.addFeature('urn:ietf:rfc:4588');\n        }\n        if (this.options.enableOpusRed === true && browser.supportsAudioRed()) {\n            this.caps.addFeature('http://jitsi.org/opus-red');\n        }\n\n        if (typeof this.options.enableRemb === 'undefined' || this.options.enableRemb) {\n            this.caps.addFeature('http://jitsi.org/remb');\n        }\n\n        // Disable TCC on Firefox because of a known issue where BWE is halved on every renegotiation.\n        if (!browser.isFirefox() && (typeof this.options.enableTcc === 'undefined' || this.options.enableTcc)) {\n            this.caps.addFeature('http://jitsi.org/tcc');\n        }\n\n        // this is dealt with by SDP O/A so we don't need to announce this\n        // XEP-0293\n        // this.caps.addFeature('urn:xmpp:jingle:apps:rtp:rtcp-fb:0');\n        // XEP-0294\n        // this.caps.addFeature('urn:xmpp:jingle:apps:rtp:rtp-hdrext:0');\n\n        this.caps.addFeature('urn:ietf:rfc:5761'); // rtcp-mux\n        this.caps.addFeature('urn:ietf:rfc:5888'); // a=group, e.g. bundle\n\n        // this.caps.addFeature('urn:ietf:rfc:5576'); // a=ssrc\n\n        // Enable Lipsync ?\n        if (browser.isChromiumBased() && this.options.enableLipSync === true) {\n            logger.info('Lip-sync enabled !');\n            this.caps.addFeature('http://jitsi.org/meet/lipsync');\n        }\n\n        if (this.connection.rayo) {\n            this.caps.addFeature('urn:xmpp:rayo:client:1');\n        }\n\n        if (E2EEncryption.isSupported(this.options)) {\n            this.caps.addFeature(FEATURE_E2EE, false, true);\n        }\n    }\n\n    /**\n     *\n     */\n    getConnection() {\n        return this.connection;\n    }\n\n    /**\n     * Receive connection status changes and handles them.\n     *\n     * @param {Object} credentials\n     * @param {string} credentials.jid - The user's XMPP ID passed to the\n     * connect method. For example, 'user@xmpp.com'.\n     * @param {string} credentials.password - The password passed to the connect\n     * method.\n     * @param {string} status - One of Strophe's connection status strings.\n     * @param {string} [msg] - The connection error message provided by Strophe.\n     */\n    connectionHandler(credentials = {}, status, msg) {\n        const now = window.performance.now();\n        const statusStr = Strophe.getStatusString(status).toLowerCase();\n\n        this.connectionTimes[statusStr] = now;\n        logger.log(\n            `(TIME) Strophe ${statusStr}${msg ? `[${msg}]` : ''}:\\t`,\n            now);\n\n        this.eventEmitter.emit(XMPPEvents.CONNECTION_STATUS_CHANGED, credentials, status, msg);\n        this._maybeSendDeploymentInfoStat();\n        if (status === Strophe.Status.CONNECTED || status === Strophe.Status.ATTACHED) {\n            // once connected or attached we no longer need this handle, drop it if it exist\n            if (this._sysMessageHandler) {\n                this.connection._stropheConn.deleteHandler(this._sysMessageHandler);\n                this._sysMessageHandler = null;\n            }\n\n            this.sendDiscoInfo && this.connection.jingle.getStunAndTurnCredentials();\n\n            logger.info(`My Jabber ID: ${this.connection.jid}`);\n\n            // XmppConnection emits CONNECTED again on reconnect - a good opportunity to clear any \"last error\" flags\n            this._resetState();\n\n            // make sure we will send the info after the features request succeeds or fails\n            this.sendDeploymentInfo = false;\n            this.sendDiscoInfo && this.caps.getFeaturesAndIdentities(this.options.hosts.domain)\n                .then(({ features, identities }) => {\n                    if (!features.has(Strophe.NS.PING)) {\n                        logger.error(`Ping NOT supported by ${\n                            this.options.hosts.domain} - please enable ping in your XMPP server config`);\n                    }\n\n                    this._processDiscoInfoIdentities(\n                        identities, undefined /* when querying we will query for features */);\n                })\n                .catch(error => {\n                    const errmsg = 'Feature discovery error';\n\n                    GlobalOnErrorHandler.callErrorHandler(\n                        new Error(`${errmsg}: ${error}`));\n                    logger.error(errmsg, error);\n\n                    this._maybeSendDeploymentInfoStat(true);\n                });\n\n            // make sure we don't query again\n            this.sendDiscoInfo = false;\n\n            if (credentials.password) {\n                this.authenticatedUser = true;\n            }\n            if (this.connection && this.connection.connected\n                && Strophe.getResourceFromJid(this.connection.jid)) {\n                // .connected is true while connecting?\n                // this.connection.send($pres());\n                this.eventEmitter.emit(\n                    JitsiConnectionEvents.CONNECTION_ESTABLISHED,\n                    Strophe.getResourceFromJid(this.connection.jid));\n            }\n        } else if (status === Strophe.Status.CONNFAIL) {\n            if (msg === 'x-strophe-bad-non-anon-jid') {\n                this.anonymousConnectionFailed = true;\n            } else {\n                this.connectionFailed = true;\n            }\n            this.lastErrorMsg = msg;\n            if (msg === 'giving-up') {\n                this.eventEmitter.emit(\n                    JitsiConnectionEvents.CONNECTION_FAILED,\n                    JitsiConnectionErrors.OTHER_ERROR, msg);\n            }\n        } else if (status === Strophe.Status.ERROR) {\n            this.lastErrorMsg = msg;\n        } else if (status === Strophe.Status.DISCONNECTED) {\n            // Stop ping interval\n            this.connection.ping.stopInterval();\n            const wasIntentionalDisconnect = Boolean(this.disconnectInProgress);\n            const errMsg = msg || this.lastErrorMsg;\n\n            if (this.anonymousConnectionFailed) {\n                // prompt user for username and password\n                this.eventEmitter.emit(\n                    JitsiConnectionEvents.CONNECTION_FAILED,\n                    JitsiConnectionErrors.PASSWORD_REQUIRED);\n            } else if (this.connectionFailed) {\n                this.eventEmitter.emit(\n                    JitsiConnectionEvents.CONNECTION_FAILED,\n                    JitsiConnectionErrors.OTHER_ERROR,\n                    errMsg,\n                    undefined, /* credentials */\n                    this._getConnectionFailedReasonDetails());\n            } else if (wasIntentionalDisconnect) {\n                this.eventEmitter.emit(\n                    JitsiConnectionEvents.CONNECTION_DISCONNECTED, errMsg);\n            } else {\n                // XXX if Strophe drops the connection while not being asked to,\n                // it means that most likely some serious error has occurred.\n                // One currently known case is when a BOSH request fails for\n                // more than 4 times. The connection is dropped without\n                // supplying a reason(error message/event) through the API.\n                logger.error('XMPP connection dropped!');\n\n                // XXX if the last request error is within 5xx range it means it\n                // was a server failure\n                const lastErrorStatus = Strophe.getLastErrorStatus();\n\n                if (lastErrorStatus >= 500 && lastErrorStatus < 600) {\n                    this.eventEmitter.emit(\n                        JitsiConnectionEvents.CONNECTION_FAILED,\n                        JitsiConnectionErrors.SERVER_ERROR,\n                        errMsg || 'server-error',\n                        /* credentials */ undefined,\n                        this._getConnectionFailedReasonDetails());\n                } else {\n                    this.eventEmitter.emit(\n                        JitsiConnectionEvents.CONNECTION_FAILED,\n                        JitsiConnectionErrors.CONNECTION_DROPPED_ERROR,\n                        errMsg || 'connection-dropped-error',\n                        /* credentials */ undefined,\n                        this._getConnectionFailedReasonDetails());\n                }\n            }\n        } else if (status === Strophe.Status.AUTHFAIL) {\n            const lastFailedRawMessage = this.getConnection().getLastFailedMessage();\n\n            // wrong password or username, prompt user\n            this.eventEmitter.emit(\n                JitsiConnectionEvents.CONNECTION_FAILED,\n                JitsiConnectionErrors.PASSWORD_REQUIRED,\n                msg || this._parseConnectionFailedMessage(lastFailedRawMessage),\n                credentials);\n        }\n    }\n\n    /**\n     * Process received identities.\n     * @param {Set<String>} identities The identities to process.\n     * @param {Set<String>} features The features to process, optional. If missing lobby component will be queried\n     * for more features.\n     * @private\n     */\n    _processDiscoInfoIdentities(identities, features) {\n        // check for speakerstats\n        identities.forEach(identity => {\n            if (identity.type === 'av_moderation') {\n                this.avModerationComponentAddress = identity.name;\n            }\n\n            if (identity.type === 'speakerstats') {\n                this.speakerStatsComponentAddress = identity.name;\n            }\n\n            if (identity.type === 'conference_duration') {\n                this.conferenceDurationComponentAddress = identity.name;\n            }\n\n            if (identity.type === 'lobbyrooms') {\n                this.lobbySupported = true;\n                const processLobbyFeatures = f => {\n                    f.forEach(fr => {\n                        if (fr.endsWith('#displayname_required')) {\n                            this.eventEmitter.emit(JitsiConnectionEvents.DISPLAY_NAME_REQUIRED);\n                        }\n                    });\n                };\n\n                if (features) {\n                    processLobbyFeatures(features);\n                } else {\n                    identity.name && this.caps.getFeaturesAndIdentities(identity.name, identity.type)\n                        .then(({ features: f }) => processLobbyFeatures(f))\n                        .catch(e => logger.warn('Error getting features from lobby.', e && e.message));\n                }\n            }\n\n            if (identity.type === 'shard') {\n                this.options.deploymentInfo.shard = this.connection.shard = identity.name;\n            }\n\n            if (identity.type === 'region') {\n                this.options.deploymentInfo.region = this.connection.region = identity.name;\n            }\n\n            if (identity.type === 'breakout_rooms') {\n                this.breakoutRoomsComponentAddress = identity.name;\n            }\n        });\n\n        this._maybeSendDeploymentInfoStat(true);\n\n        if (this.avModerationComponentAddress\n            || this.speakerStatsComponentAddress\n            || this.conferenceDurationComponentAddress\n            || this.breakoutRoomsComponentAddress) {\n            this.connection.addHandler(this._onPrivateMessage.bind(this), null, 'message', null, null);\n        }\n    }\n\n    /**\n    * Parses a raw failure xmpp xml message received on auth failed.\n    *\n    * @param {string} msg - The raw failure message from xmpp.\n    * @returns {string|null} - The parsed message from the raw xmpp message.\n    */\n    _parseConnectionFailedMessage(msg) {\n        if (!msg) {\n            return null;\n        }\n\n        const matches = FAILURE_REGEX.exec(msg);\n\n        return matches ? matches[1] : null;\n    }\n\n    /**\n     *\n     * @param jid\n     * @param password\n     */\n    _connect(jid, password) {\n        // connection.connect() starts the connection process.\n        //\n        // As the connection process proceeds, the user supplied callback will\n        // be triggered multiple times with status updates. The callback should\n        // take two arguments - the status code and the error condition.\n        //\n        // The status code will be one of the values in the Strophe.Status\n        // constants. The error condition will be one of the conditions defined\n        // in RFC 3920 or the condition ‘strophe-parsererror’.\n        //\n        // The Parameters wait, hold and route are optional and only relevant\n        // for BOSH connections. Please see XEP 124 for a more detailed\n        // explanation of the optional parameters.\n        //\n        // Connection status constants for use by the connection handler\n        // callback.\n        //\n        //  Status.ERROR - An error has occurred (websockets specific)\n        //  Status.CONNECTING - The connection is currently being made\n        //  Status.CONNFAIL - The connection attempt failed\n        //  Status.AUTHENTICATING - The connection is authenticating\n        //  Status.AUTHFAIL - The authentication attempt failed\n        //  Status.CONNECTED - The connection has succeeded\n        //  Status.DISCONNECTED - The connection has been terminated\n        //  Status.DISCONNECTING - The connection is currently being terminated\n        //  Status.ATTACHED - The connection has been attached\n\n        this._resetState();\n\n        // we want to send this only on the initial connect\n        this.sendDiscoInfo = true;\n        this.sendDeploymentInfo = true;\n\n        if (this.connection._stropheConn && this.connection._stropheConn._addSysHandler) {\n            this._sysMessageHandler = this.connection._stropheConn._addSysHandler(\n                this._onSystemMessage.bind(this),\n                null,\n                'message'\n            );\n        } else {\n            logger.warn('Cannot attach strophe system handler, jiconop cannot operate');\n        }\n\n        this.connection.connect(\n            jid,\n            password,\n            this.connectionHandler.bind(this, {\n                jid,\n                password\n            }));\n    }\n\n    /**\n     * Receives system messages during the connect/login process and checks for services or\n     * @param msg The received message.\n     * @returns {void}\n     * @private\n     */\n    _onSystemMessage(msg) {\n        // proceed only if the message has any of the expected information\n        if ($(msg).find('>services').length === 0 && $(msg).find('>query').length === 0) {\n            return;\n        }\n\n        this.sendDiscoInfo = false;\n\n        const foundIceServers = this.connection.jingle.onReceiveStunAndTurnCredentials(msg);\n\n        const { features, identities } = parseDiscoInfo(msg);\n\n        this._processDiscoInfoIdentities(identities, features);\n\n        if (foundIceServers || identities.size > 0 || features.size > 0) {\n            this.connection._stropheConn.deleteHandler(this._sysMessageHandler);\n            this._sysMessageHandler = null;\n        }\n    }\n\n    /**\n     * Attach to existing connection. Can be used for optimizations. For\n     * example: if the connection is created on the server we can attach to it\n     * and start using it.\n     *\n     * @param options {object} connecting options - rid, sid, jid and password.\n     */\n    attach(options) {\n        this._resetState();\n\n        // we want to send this only on the initial connect\n        this.sendDiscoInfo = true;\n\n        const now = this.connectionTimes.attaching = window.performance.now();\n\n        logger.log('(TIME) Strophe Attaching:\\t', now);\n        this.connection.attach(options.jid, options.sid,\n            parseInt(options.rid, 10) + 1,\n            this.connectionHandler.bind(this, {\n                jid: options.jid,\n                password: options.password\n            }));\n    }\n\n    /**\n     * Resets any state/flag before starting a new connection.\n     * @private\n     */\n    _resetState() {\n        this.anonymousConnectionFailed = false;\n        this.connectionFailed = false;\n        this.lastErrorMsg = undefined;\n        this.disconnectInProgress = undefined;\n    }\n\n    /**\n     *\n     * @param jid\n     * @param password\n     */\n    connect(jid, password) {\n        if (!jid) {\n            const { anonymousdomain, domain } = this.options.hosts;\n            let configDomain = anonymousdomain || domain;\n\n            // Force authenticated domain if room is appended with '?login=true'\n            // or if we're joining with the token\n\n            // FIXME Do not rely on window.location because (1) React Native\n            // does not have a window.location by default and (2) here we cannot\n            // know for sure that query/search has not be stripped from\n            // window.location by the time the following executes.\n            const { location } = window;\n\n            if (anonymousdomain) {\n                const search = location && location.search;\n\n                if ((search && search.indexOf('login=true') !== -1)\n                        || this.token) {\n                    configDomain = domain;\n                }\n            }\n\n            // eslint-disable-next-line no-param-reassign\n            jid = configDomain || (location && location.hostname);\n        }\n\n        return this._connect(jid, password);\n    }\n\n    /**\n     * Joins or creates a muc with the provided jid, created from the passed\n     * in room name and muc host and onCreateResource result.\n     *\n     * @param {string} roomName - The name of the muc to join.\n     * @param {Object} options - Configuration for how to join the muc.\n     * @param {Function} [onCreateResource] - Callback to invoke when a resource\n     * is to be added to the jid.\n     * @returns {Promise} Resolves with an instance of a strophe muc.\n     */\n    createRoom(roomName, options, onCreateResource) {\n        // Support passing the domain in a String object as part of the room name.\n        const domain = roomName.domain || options.customDomain;\n\n        // There are cases (when using subdomain) where muc can hold an uppercase part\n        let roomjid = `${this.getRoomJid(roomName, domain)}/`;\n        const mucNickname = onCreateResource\n            ? onCreateResource(this.connection.jid, this.authenticatedUser)\n            : RandomUtil.randomHexString(8).toLowerCase();\n\n        logger.info(`JID ${this.connection.jid} using MUC nickname ${mucNickname}`);\n        roomjid += mucNickname;\n\n        return this.connection.emuc.createRoom(roomjid, null, options);\n    }\n\n    /**\n     * Returns the room JID based on the passed room name and domain.\n     *\n     * @param {string} roomName - The room name.\n     * @param {string} domain - The domain.\n     * @returns {string} - The room JID.\n     */\n    getRoomJid(roomName, domain) {\n        return `${roomName}@${domain ? domain : this.options.hosts.muc.toLowerCase()}`;\n    }\n\n    /**\n     * Check if a room with the passed JID is already created.\n     *\n     * @param {string} roomJid - The JID of the room.\n     * @returns {boolean}\n     */\n    isRoomCreated(roomName, domain) {\n        return this.connection.emuc.isRoomCreated(this.getRoomJid(roomName, domain));\n    }\n\n    /**\n     * Returns the jid of the participant associated with the Strophe connection.\n     *\n     * @returns {string} The jid of the participant.\n     */\n    getJid() {\n        return this.connection.jid;\n    }\n\n    /**\n     * Returns the logs from strophe.jingle.\n     * @returns {Object}\n     */\n    getJingleLog() {\n        const jingle = this.connection.jingle;\n\n\n        return jingle ? jingle.getLog() : {};\n    }\n\n    /**\n     * Returns the logs from strophe.\n     */\n    getXmppLog() {\n        return (this.connection.logger || {}).log || null;\n    }\n\n    /**\n     *\n     */\n    dial(...args) {\n        this.connection.rayo.dial(...args);\n    }\n\n    /**\n     * Pings the server.\n     * @param timeout how many ms before a timeout should occur.\n     * @returns {Promise} resolved on ping success and reject on an error or\n     * a timeout.\n     */\n    ping(timeout) {\n        return new Promise((resolve, reject) => {\n            this.connection.ping.ping(this.connection.pingDomain, resolve, reject, timeout);\n        });\n    }\n\n    /**\n     *\n     */\n    getSessions() {\n        return this.connection.jingle.sessions;\n    }\n\n    /**\n     * Disconnects this from the XMPP server (if this is connected).\n     *\n     * @param {Object} ev - Optionally, the event which triggered the necessity to\n     * disconnect from the XMPP server (e.g. beforeunload, unload).\n     * @returns {Promise} - Resolves when the disconnect process is finished or rejects with an error.\n     */\n    disconnect(ev) {\n        if (this.disconnectInProgress) {\n            return this.disconnectInProgress;\n        } else if (!this.connection) {\n            return Promise.resolve();\n        }\n\n        this.disconnectInProgress = new Promise(resolve => {\n            const disconnectListener = (credentials, status) => {\n                if (status === Strophe.Status.DISCONNECTED) {\n                    resolve();\n                    this.eventEmitter.removeListener(XMPPEvents.CONNECTION_STATUS_CHANGED, disconnectListener);\n                }\n            };\n\n            this.eventEmitter.on(XMPPEvents.CONNECTION_STATUS_CHANGED, disconnectListener);\n        });\n\n        this._cleanupXmppConnection(ev);\n\n        return this.disconnectInProgress;\n    }\n\n    /**\n     * The method is supposed to gracefully close the XMPP connection and the main goal is to make sure that the current\n     * participant will be removed from the conference XMPP MUC, so that it doesn't leave a \"ghost\" participant behind.\n     *\n     * @param {Object} ev - Optionally, the event which triggered the necessity to disconnect from the XMPP server\n     * (e.g. beforeunload, unload).\n     * @private\n     * @returns {void}\n     */\n    _cleanupXmppConnection(ev) {\n        // XXX Strophe is asynchronously sending by default. Unfortunately, that means that there may not be enough time\n        // to send an unavailable presence or disconnect at all. Switching Strophe to synchronous sending is not much of\n        // an option because it may lead to a noticeable delay in navigating away from the current location. As\n        // a compromise, we will try to increase the chances of sending an unavailable presence and/or disconnecting\n        // within the short time span that we have upon unloading by invoking flush() on the connection. We flush() once\n        // before disconnect() in order to attempt to have its unavailable presence at the top of the send queue. We\n        // flush() once more after disconnect() in order to attempt to have its unavailable presence sent as soon as\n        // possible.\n        !this.connection.isUsingWebSocket && this.connection.flush();\n\n        if (!this.connection.isUsingWebSocket && ev !== null && typeof ev !== 'undefined') {\n            const evType = ev.type;\n\n            if (evType === 'beforeunload' || evType === 'unload') {\n                // XXX Whatever we said above, synchronous sending is the best (known) way to properly disconnect from\n                // the XMPP server. Consequently, it may be fine to have the source code and comment it in or out\n                // depending on whether we want to run with it for some time.\n                this.connection.options.sync = true;\n\n                // This is needed in some browsers where sync xhr sending is disabled by default on unload.\n                if (this.connection.sendUnavailableBeacon()) {\n\n                    return;\n                }\n            }\n        }\n\n        this.connection.disconnect();\n\n        if (this.connection.options.sync !== true) {\n            this.connection.flush();\n        }\n    }\n\n    /**\n     *\n     */\n    _initStrophePlugins() {\n        const iceConfig = {\n            jvb: { iceServers: [ ] },\n            p2p: { iceServers: [ ] }\n        };\n\n        const p2pStunServers = (this.options.p2p\n            && this.options.p2p.stunServers) || DEFAULT_STUN_SERVERS;\n\n        if (Array.isArray(p2pStunServers)) {\n            logger.info('P2P STUN servers: ', p2pStunServers);\n            iceConfig.p2p.iceServers = p2pStunServers;\n        }\n\n        if (this.options.p2p && this.options.p2p.iceTransportPolicy) {\n            logger.info('P2P ICE transport policy: ',\n                this.options.p2p.iceTransportPolicy);\n\n            iceConfig.p2p.iceTransportPolicy\n                = this.options.p2p.iceTransportPolicy;\n        }\n\n        this.connection.addConnectionPlugin('emuc', new MucConnectionPlugin(this));\n        this.connection.addConnectionPlugin('jingle', new JingleConnectionPlugin(this, this.eventEmitter, iceConfig));\n        this.connection.addConnectionPlugin('rayo', new RayoConnectionPlugin());\n    }\n\n    /**\n     * Returns details about connection failure. Shard change or is it after\n     * suspend.\n     * @returns {object} contains details about a connection failure.\n     * @private\n     */\n    _getConnectionFailedReasonDetails() {\n        const details = {};\n\n        // check for moving between shard if information is available\n        if (this.options.deploymentInfo\n            && this.options.deploymentInfo.shard\n            && this.connection.lastResponseHeaders) {\n\n            // split headers by line\n            const headersArr = this.connection.lastResponseHeaders\n                .trim().split(/[\\r\\n]+/);\n            const headers = {};\n\n            headersArr.forEach(line => {\n                const parts = line.split(': ');\n                const header = parts.shift();\n                const value = parts.join(': ');\n\n                headers[header] = value;\n            });\n\n            /* eslint-disable camelcase */\n            details.shard_changed\n                = this.options.deploymentInfo.shard\n                    !== headers['x-jitsi-shard'];\n            /* eslint-enable camelcase */\n        }\n\n        /* eslint-disable camelcase */\n        // check for possible suspend\n        details.suspend_time = this.connection.ping.getPingSuspendTime();\n        details.time_since_last_success = this.connection.getTimeSinceLastSuccess();\n        /* eslint-enable camelcase */\n\n        return details;\n    }\n\n    /**\n     * Notifies speaker stats component if available that we are the new\n     * dominant speaker in the conference.\n     * @param {String} roomJid - The room jid where the speaker event occurred.\n     */\n    sendDominantSpeakerEvent(roomJid) {\n        // no speaker stats component advertised\n        if (!this.speakerStatsComponentAddress || !roomJid) {\n            return;\n        }\n\n        const msg = $msg({ to: this.speakerStatsComponentAddress });\n\n        msg.c('speakerstats', {\n            xmlns: 'http://jitsi.org/jitmeet',\n            room: roomJid })\n            .up();\n\n        this.connection.send(msg);\n    }\n\n    /**\n     * Sends facial expression to speaker stats component.\n     * @param {String} roomJid - The room jid where the speaker event occurred.\n     * @param {Object} payload - The expression to be sent to the speaker stats.\n     */\n    sendFacialExpressionEvent(roomJid, payload) {\n        // no speaker stats component advertised\n        if (!this.speakerStatsComponentAddress || !roomJid) {\n            return;\n        }\n\n        const msg = $msg({ to: this.speakerStatsComponentAddress });\n\n        msg.c('facialExpression', {\n            xmlns: 'http://jitsi.org/jitmeet',\n            room: roomJid,\n            expression: payload.facialExpression,\n            duration: payload.duration\n        }).up();\n\n        this.connection.send(msg);\n    }\n\n    /**\n     * Check if the given argument is a valid JSON ENDPOINT_MESSAGE string by\n     * parsing it and checking if it has a field called 'type'.\n     *\n     * @param {string} jsonString check if this string is a valid json string\n     * and contains the special structure.\n     * @returns {boolean, object} if given object is a valid JSON string, return\n     * the json object. Otherwise, returns false.\n     */\n    tryParseJSONAndVerify(jsonString) {\n        // ignore empty strings, like message errors\n        if (!jsonString) {\n            return false;\n        }\n\n        try {\n            const json = JSON.parse(jsonString);\n\n            // Handle non-exception-throwing cases:\n            // Neither JSON.parse(false) or JSON.parse(1234) throw errors,\n            // hence the type-checking,\n            // but... JSON.parse(null) returns null, and\n            // typeof null === \"object\",\n            // so we must check for that, too.\n            // Thankfully, null is falsey, so this suffices:\n            if (json && typeof json === 'object') {\n                const type = json[JITSI_MEET_MUC_TYPE];\n\n                if (typeof type !== 'undefined') {\n                    return json;\n                }\n\n                logger.debug('parsing valid json but does not have correct '\n                    + 'structure', 'topic: ', type);\n            }\n        } catch (e) {\n            logger.error(`Error parsing json ${jsonString}`, e);\n\n            return false;\n        }\n\n        return false;\n    }\n\n    /**\n     * A private message is received, message that is not addressed to the muc.\n     * We expect private message coming from plugins component if it is\n     * enabled and running.\n     *\n     * @param {string} msg - The message.\n     */\n    _onPrivateMessage(msg) {\n        const from = msg.getAttribute('from');\n\n        if (!(from === this.speakerStatsComponentAddress\n            || from === this.conferenceDurationComponentAddress\n            || from === this.avModerationComponentAddress\n            || from === this.breakoutRoomsComponentAddress)) {\n            return true;\n        }\n\n        const jsonMessage = $(msg).find('>json-message')\n            .text();\n        const parsedJson = this.tryParseJSONAndVerify(jsonMessage);\n\n        if (!parsedJson) {\n            return true;\n        }\n\n        if (parsedJson[JITSI_MEET_MUC_TYPE] === 'speakerstats' && parsedJson.users) {\n            this.eventEmitter.emit(XMPPEvents.SPEAKER_STATS_RECEIVED, parsedJson.users);\n        } else if (parsedJson[JITSI_MEET_MUC_TYPE] === 'conference_duration' && parsedJson.created_timestamp) {\n            this.eventEmitter.emit(XMPPEvents.CONFERENCE_TIMESTAMP_RECEIVED, parsedJson.created_timestamp);\n        } else if (parsedJson[JITSI_MEET_MUC_TYPE] === 'av_moderation') {\n            this.eventEmitter.emit(XMPPEvents.AV_MODERATION_RECEIVED, parsedJson);\n        } else if (parsedJson[JITSI_MEET_MUC_TYPE] === 'breakout_rooms') {\n            this.eventEmitter.emit(XMPPEvents.BREAKOUT_ROOMS_EVENT, parsedJson);\n        }\n\n        return true;\n    }\n\n    /**\n     * Sends deployment info to stats if not sent already.\n     * We want to try sending it on failure to connect\n     * or when we get a sys message(from jiconop2)\n     * or after success or failure of disco-info\n     * @param force Whether to force sending without checking anything.\n     * @private\n     */\n    _maybeSendDeploymentInfoStat(force) {\n        const acceptedStatuses = [\n            Strophe.Status.ERROR,\n            Strophe.Status.CONNFAIL,\n            Strophe.Status.AUTHFAIL,\n            Strophe.Status.DISCONNECTED,\n            Strophe.Status.CONNTIMEOUT\n        ];\n\n        if (!force && !(acceptedStatuses.includes(this.connection.status) && this.sendDeploymentInfo)) {\n            return;\n        }\n\n        // Log deployment-specific information, if available. Defined outside\n        // the application by individual deployments\n        const aprops = this.options.deploymentInfo;\n\n        if (aprops && Object.keys(aprops).length > 0) {\n            const logObject = {};\n\n            logObject.id = 'deployment_info';\n            for (const attr in aprops) {\n                if (aprops.hasOwnProperty(attr)) {\n                    logObject[attr] = aprops[attr];\n                }\n            }\n\n            Statistics.sendLog(JSON.stringify(logObject));\n        }\n\n        this.sendDeploymentInfo = false;\n    }\n}\n","import {\n    CONNECTION_DISCONNECTED,\n    CONNECTION_ESTABLISHED,\n    CONNECTION_FAILED\n} from './JitsiConnectionEvents';\nimport XMPP from './modules/xmpp/xmpp';\n\n/**\n * @typedef {Object} UpgradeRoleError\n *\n * @property {JitsiConnectionErrors} [connectionError] - One of\n * {@link JitsiConnectionErrors} which occurred when trying to connect to the\n * XMPP server.\n * @property {String} [authenticationError] - One of XMPP error conditions\n * returned by Jicofo on authentication attempt. See\n * {@link https://xmpp.org/rfcs/rfc3920.html#streams-error}.\n * @property {String} [message] - More details about the error.\n * @property {Object} [credentials] - The credentials that failed the\n * authentication.\n * @property {String} [credentials.jid] - The XMPP ID part of the credentials\n * that failed the authentication.\n * @property {string} [credentials.password] - The password part of the\n * credentials that failed the authentication.\n *\n * NOTE If neither one of the errors is present, then the operation has been\n * canceled.\n */\n\n/* eslint-disable no-invalid-this */\n\n/**\n * Connects to the XMPP server using the specified credentials and contacts\n * Jicofo in order to obtain a session ID (which is then stored in the local\n * storage). The user's role of the parent conference will be upgraded to\n * moderator (by Jicofo). It's also used to join the conference when starting\n * from anonymous domain and only authenticated users are allowed to create new\n * rooms.\n *\n * @param {Object} options\n * @param {string} options.id - XMPP user's ID to log in. For example,\n * user@xmpp-server.com.\n * @param {string} options.password - XMPP user's password to log in with.\n * @param {string} [options.roomPassword] - The password to join the MUC with.\n * @param {Function} [options.onLoginSuccessful] - Callback called when logging\n * into the XMPP server was successful. The next step will be to obtain a new\n * session ID from Jicofo and join the MUC using it which will effectively\n * upgrade the user's role to moderator.\n * @returns {Object} A <tt>thenable</tt> which (1) settles when the process of\n * authenticating and upgrading the role of the specified XMPP user finishes and\n * (2) has a <tt>cancel</tt> method that allows the caller to interrupt the\n * process. If the process finishes successfully, the session ID has been stored\n * in the settings and the <tt>thenable</tt> is resolved. If the process\n * finishes with failure, the <tt>thenable</tt> is rejected with reason of type\n * {@link UpgradeRoleError} which will have either <tt>connectionError</tt> or\n * <tt>authenticationError</tt> property set depending on which of the steps has\n * failed. If <tt>cancel</tt> is called before the process finishes, then the\n * thenable will be rejected with an empty object (i.e. no error property will\n * be set on the rejection reason).\n */\nexport default function authenticateAndUpgradeRole({\n    // 1. Log the specified XMPP user in.\n    id,\n    password,\n    onCreateResource,\n\n    // 2. Let the API client/consumer know as soon as the XMPP user has been\n    //    successfully logged in.\n    onLoginSuccessful,\n\n    // 3. Join the MUC.\n    roomPassword\n}) {\n    let canceled = false;\n    let rejectPromise;\n    let xmpp = new XMPP(this.connection.options);\n\n    const process = new Promise((resolve, reject) => {\n        // The process is represented by a Thenable with a cancel method. The\n        // Thenable is implemented using Promise and the cancel using the\n        // Promise's reject function.\n        rejectPromise = reject;\n\n\n        xmpp.addListener(\n            CONNECTION_DISCONNECTED,\n            () => {\n                xmpp = undefined;\n            });\n        xmpp.addListener(\n            CONNECTION_ESTABLISHED,\n            () => {\n                if (canceled) {\n                    return;\n                }\n\n                // Let the caller know that the XMPP login was successful.\n                onLoginSuccessful && onLoginSuccessful();\n\n                // Now authenticate with Jicofo and get a new session ID.\n                const room = xmpp.createRoom(\n                    this.options.name,\n                    this.options.config,\n                    onCreateResource\n                );\n\n                room.moderator.authenticate()\n                    .then(() => {\n                        xmpp && xmpp.disconnect();\n\n                        if (canceled) {\n                            return;\n                        }\n\n                        // At this point we should have the new session ID\n                        // stored in the settings. Jicofo will allow to join the\n                        // room.\n                        this.join(roomPassword);\n\n                        resolve();\n                    })\n                    .catch(({ error, message }) => {\n                        xmpp.disconnect();\n\n                        reject({\n                            authenticationError: error,\n                            message\n                        });\n                    });\n            });\n        xmpp.addListener(\n            CONNECTION_FAILED,\n            (connectionError, message, credentials) => {\n                reject({\n                    connectionError,\n                    credentials,\n                    message\n                });\n                xmpp = undefined;\n            });\n\n        canceled || xmpp.connect(id, password);\n    });\n\n    /**\n     * Cancels the process, if it's in progress, of authenticating and upgrading\n     * the role of the local participant/user.\n     *\n     * @public\n     * @returns {void}\n     */\n    process.cancel = () => {\n        canceled = true;\n        rejectPromise({});\n        xmpp && xmpp.disconnect();\n    };\n\n    return process;\n}\n\n/* eslint-enable no-invalid-this */\n","\nimport { getLogger } from '@jitsi/logger';\n\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\nimport CodecMimeType from '../../service/RTC/CodecMimeType';\nimport { MediaType } from '../../service/RTC/MediaType';\nimport browser from '../browser';\n\nconst logger = getLogger(__filename);\n\n/**\n * This class handles the codec selection mechanism for the conference based on the config.js settings.\n * The preferred codec is selected based on the settings and the list of codecs supported by the browser.\n * The preferred codec is published in presence which is then used by the other endpoints in the\n * conference to pick a supported codec at join time and when the call transitions between p2p and jvb\n * connections.\n */\nexport class CodecSelection {\n    /**\n     * Creates a new instance for a given conference.\n     *\n     * @param {JitsiConference} conference the conference instance\n     * @param {*} options\n     * @param {string} options.disabledCodec the codec that needs to be disabled.\n     * @param {boolean} options.enforcePreferredCodec whether codec preference has to be\n     * enforced even when an endpoints that doesn't support the preferred codec joins the call.\n     * Falling back to the standard codec will be skipped when this option is true, endpoints\n     * that do not support the preferred codec may not be able to encode/decode video when this happens.\n     * @param {string} options.jvbCodec the codec that is preferred on jvb connection.\n     * @param {string} options.p2pCodec the codec that is preferred on p2p connection.\n     */\n    constructor(conference, options) {\n        this.conference = conference;\n        this.options = options;\n\n        // VP8 cannot be disabled and it will be the default codec when no preference is set.\n        this.disabledCodec = options.disabledCodec === CodecMimeType.VP8\n            ? undefined\n            : this._getCodecMimeType(options.disabledCodec);\n\n        // Check if the codec values passed are valid.\n        const jvbCodec = this._getCodecMimeType(options.jvbCodec);\n        const p2pCodec = this._getCodecMimeType(options.p2pCodec);\n\n        this.jvbPreferredCodec = jvbCodec && this._isCodecSupported(jvbCodec) ? jvbCodec : CodecMimeType.VP8;\n        this.p2pPreferredCodec = p2pCodec && this._isCodecSupported(p2pCodec) ? p2pCodec : CodecMimeType.VP8;\n        logger.debug(`Codec preferences for the conference are JVB: ${this.jvbPreferredCodec},\n            P2P: ${this.p2pPreferredCodec}`);\n\n        if (this.jvbPreferredCodec === CodecMimeType.VP9 && !browser.supportsVP9()) {\n            this.jvbPreferredCodec = CodecMimeType.VP8;\n        }\n\n        this.conference.on(\n            JitsiConferenceEvents.USER_JOINED,\n            () => this._selectPreferredCodec());\n        this.conference.on(\n            JitsiConferenceEvents.USER_LEFT,\n            () => this._selectPreferredCodec());\n        this.conference.on(\n            JitsiConferenceEvents._MEDIA_SESSION_STARTED,\n            session => this._onMediaSessionStarted(session));\n    }\n\n    /**\n     * Checks if a given string is a valid video codec mime type.\n     *\n     * @param {string} codec the codec string that needs to be validated.\n     * @returns {CodecMimeType|null} mime type if valid, null otherwise.\n     * @private\n     */\n    _getCodecMimeType(codec) {\n        if (typeof codec === 'string') {\n            return Object.values(CodecMimeType).find(value => value === codec.toLowerCase());\n        }\n\n        return null;\n    }\n\n    /**\n     * Checks if the given codec is supported by the browser.\n     *\n     * @param {CodecMimeType} preferredCodec codec to be checked.\n     * @returns {boolean} true if the given codec is supported, false otherwise.\n     * @private\n     */\n    _isCodecSupported(preferredCodec) {\n        // Skip the check on FF and RN because they do not support the getCapabilities API.\n        // It is safe to assume both of them support all the codecs supported by Chrome.\n        if (browser.isFirefox() || browser.isReactNative()) {\n            return true;\n        }\n\n        return window.RTCRtpReceiver\n            && window.RTCRtpReceiver.getCapabilities\n            && window.RTCRtpReceiver.getCapabilities('video').codecs\n            .some(codec => codec.mimeType.toLowerCase() === `video/${preferredCodec}`);\n    }\n\n    /**\n     * Handles the {@link JitsiConferenceEvents._MEDIA_SESSION_STARTED} event. Codecs need to be\n     * configured on the media session that is newly created.\n     *\n     * @param {JingleSessionPC} mediaSession media session that started.\n     * @returns {void}\n     * @private\n     */\n    _onMediaSessionStarted(mediaSession) {\n        const preferredCodec = mediaSession.isP2P ? this.p2pPreferredCodec : this.jvbPreferredCodec;\n        const disabledCodec = this.disabledCodec && this._isCodecSupported(this.disabledCodec)\n            ? this.disabledCodec\n            : null;\n\n        this._selectPreferredCodec(mediaSession, preferredCodec, disabledCodec);\n    }\n\n    /**\n     * Sets the codec on the media session based on the preferred codec setting and the supported codecs\n     * published by the remote participants in their presence.\n     *\n     * @param {JingleSessionPC} mediaSession session for which the codec selection has to be made.\n     * @param {CodecMimeType} preferredCodec preferred codec.\n     * @param {CodecMimeType} disabledCodec codec that needs to be disabled.\n     */\n    _selectPreferredCodec(mediaSession = null, preferredCodec = null, disabledCodec = null) {\n        const session = mediaSession ? mediaSession : this.conference.jvbJingleSession;\n        const currentCodec = preferredCodec ? preferredCodec : this.jvbPreferredCodec;\n        let selectedCodec = currentCodec;\n\n        if (session && !session.isP2P && !this.options.enforcePreferredCodec) {\n            const remoteParticipants = this.conference.getParticipants().map(participant => participant.getId());\n\n            for (const remote of remoteParticipants) {\n                const peerMediaInfo = session._signalingLayer.getPeerMediaInfo(remote, MediaType.VIDEO);\n                const peerCodec = peerMediaInfo?.codecType;\n\n                if (peerCodec\n                    && peerCodec !== currentCodec\n                    && (peerCodec !== CodecMimeType.VP9 || browser.supportsVP9())) {\n                    selectedCodec = peerCodec;\n                }\n            }\n        }\n        session && session.setVideoCodecs(selectedCodec, disabledCodec);\n    }\n\n    /**\n     * Returns the preferred codec for the conference. The preferred codec for the JVB media session\n     * is the one that gets published in presence and a comparision is made whenever a participant joins\n     * or leaves the call.\n     *\n     * @returns {CodecMimeType} preferred codec.\n     */\n    getPreferredCodec() {\n        return this.jvbPreferredCodec;\n    }\n}\n","/**\n * Enumeration of the video types that are signaled to the bridge\n * @type {{CAMERA: string, DESKTOP: string, DESKTOP_HIGH_FPS: string, NONE: string}}\n */\nexport const BridgeVideoType = {\n    /**\n     * The camera video type.\n     */\n    CAMERA: 'camera',\n\n    /**\n     * The low fps desktop video type.\n     */\n    DESKTOP: 'desktop',\n\n    /**\n     * The high fps desktop video type.\n     */\n    DESKTOP_HIGH_FPS: 'desktop_high_fps',\n\n    /**\n     * Video type when no local source is present.\n     */\n    NONE: 'none'\n};\n\nexport default BridgeVideoType;\n","import { getLogger } from '@jitsi/logger';\n\nimport RTCEvents from '../../service/RTC/RTCEvents';\nimport { createBridgeChannelClosedEvent } from '../../service/statistics/AnalyticsEvents';\nimport FeatureFlags from '../flags/FeatureFlags';\nimport Statistics from '../statistics/statistics';\nimport GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';\n\nconst logger = getLogger(__filename);\n\n/**\n * Handles a WebRTC RTCPeerConnection or a WebSocket instance to communicate\n * with the videobridge.\n */\nexport default class BridgeChannel {\n    /**\n     * Binds \"ondatachannel\" event listener on the given RTCPeerConnection\n     * instance, or creates a WebSocket connection with the videobridge.\n     * At least one of both, peerconnection or wsUrl parameters, must be\n     * given.\n     * @param {RTCPeerConnection} [peerconnection] WebRTC peer connection\n     * instance.\n     * @param {string} [wsUrl] WebSocket URL.\n     * @param {EventEmitter} emitter the EventEmitter instance to use for event emission.\n     */\n    constructor(peerconnection, wsUrl, emitter) {\n        if (!peerconnection && !wsUrl) {\n            throw new TypeError('At least peerconnection or wsUrl must be given');\n        } else if (peerconnection && wsUrl) {\n            throw new TypeError('Just one of peerconnection or wsUrl must be given');\n        }\n\n        if (peerconnection) {\n            logger.debug('constructor() with peerconnection');\n        } else {\n            logger.debug(`constructor() with wsUrl:\"${wsUrl}\"`);\n        }\n\n        // The underlying WebRTC RTCDataChannel or WebSocket instance.\n        // @type {RTCDataChannel|WebSocket}\n        this._channel = null;\n\n        // @type {EventEmitter}\n        this._eventEmitter = emitter;\n\n        // Whether a RTCDataChannel or WebSocket is internally used.\n        // @type {string} \"datachannel\" / \"websocket\"\n        this._mode = null;\n\n        // Indicates whether the connection retries are enabled or not.\n        this._areRetriesEnabled = false;\n\n        // Indicates whether the connection was closed from the client or not.\n        this._closedFromClient = false;\n\n        // If a RTCPeerConnection is given, listen for new RTCDataChannel\n        // event.\n        if (peerconnection) {\n            const datachannel\n                = peerconnection.createDataChannel(\n                    'JVB data channel', {\n                        protocol: 'http://jitsi.org/protocols/colibri'\n                    });\n\n            // Handle the RTCDataChannel.\n            this._handleChannel(datachannel);\n            this._mode = 'datachannel';\n\n        // Otherwise create a WebSocket connection.\n        } else if (wsUrl) {\n            this._areRetriesEnabled = true;\n            this._wsUrl = wsUrl;\n            this._initWebSocket();\n        }\n    }\n\n    /**\n     * Initializes the web socket channel.\n     *\n     * @returns {void}\n     */\n    _initWebSocket() {\n        // Create a WebSocket instance.\n        const ws = new WebSocket(this._wsUrl);\n\n        // Handle the WebSocket.\n        this._handleChannel(ws);\n        this._mode = 'websocket';\n    }\n\n    /**\n     * Starts the websocket connection retries.\n     *\n     * @returns {void}\n     */\n    _startConnectionRetries() {\n        let timeoutS = 1;\n\n        const reload = () => {\n            if (this.isOpen()) {\n                return;\n            }\n            this._initWebSocket(this._wsUrl);\n            timeoutS = Math.min(timeoutS * 2, 60);\n            this._retryTimeout = setTimeout(reload, timeoutS * 1000);\n        };\n\n        this._retryTimeout = setTimeout(reload, timeoutS * 1000);\n    }\n\n    /**\n     * Stops the websocket connection retries.\n     *\n     * @returns {void}\n     */\n    _stopConnectionRetries() {\n        if (this._retryTimeout) {\n            clearTimeout(this._retryTimeout);\n            this._retryTimeout = undefined;\n        }\n    }\n\n    /**\n     * Retries to establish the websocket connection after the connection was closed by the server.\n     *\n     * @param {CloseEvent} closeEvent - The close event that triggered the retries.\n     * @returns {void}\n     */\n    _retryWebSocketConnection(closeEvent) {\n        if (!this._areRetriesEnabled) {\n            return;\n        }\n        const { code, reason } = closeEvent;\n\n        Statistics.sendAnalytics(createBridgeChannelClosedEvent(code, reason));\n        this._areRetriesEnabled = false;\n        this._eventEmitter.once(RTCEvents.DATA_CHANNEL_OPEN, () => {\n            this._stopConnectionRetries();\n            this._areRetriesEnabled = true;\n        });\n        this._startConnectionRetries();\n    }\n\n    /**\n     * The channel mode.\n     * @return {string} \"datachannel\" or \"websocket\" (or null if not yet set).\n     */\n    get mode() {\n        return this._mode;\n    }\n\n    /**\n     * Closes the currently opened channel.\n     */\n    close() {\n        this._closedFromClient = true;\n        this._stopConnectionRetries();\n        this._areRetriesEnabled = false;\n        if (this._channel) {\n            try {\n                this._channel.close();\n            } catch (error) {} // eslint-disable-line no-empty\n\n            this._channel = null;\n        }\n    }\n\n    /**\n     * Whether there is an underlying RTCDataChannel or WebSocket and it's\n     * open.\n     * @return {boolean}\n     */\n    isOpen() {\n        return this._channel && (this._channel.readyState === 'open'\n            || this._channel.readyState === WebSocket.OPEN);\n    }\n\n    /**\n     * Sends local stats via the bridge channel.\n     * @param {Object} payload The payload of the message.\n     * @throws NetworkError/InvalidStateError/Error if the operation fails or if there is no data channel created.\n     */\n    sendEndpointStatsMessage(payload) {\n        this._send({\n            colibriClass: 'EndpointStats',\n            ...payload\n        });\n    }\n\n    /**\n     * Sends message via the channel.\n     * @param {string} to The id of the endpoint that should receive the\n     * message. If \"\" the message will be sent to all participants.\n     * @param  {object} payload The payload of the message.\n     * @throws NetworkError or InvalidStateError from RTCDataChannel#send (@see\n     * {@link https://developer.mozilla.org/docs/Web/API/RTCDataChannel/send})\n     * or from WebSocket#send or Error with \"No opened channel\" message.\n     */\n    sendMessage(to, payload) {\n        this._send({\n            colibriClass: 'EndpointMessage',\n            msgPayload: payload,\n            to\n        });\n    }\n\n    /**\n     * Sends a \"lastN value changed\" message via the channel.\n     * @param {number} value The new value for lastN. -1 means unlimited.\n     */\n    sendSetLastNMessage(value) {\n        logger.log(`Sending lastN=${value}.`);\n\n        this._send({\n            colibriClass: 'LastNChangedEvent',\n            lastN: value\n        });\n    }\n\n    /**\n     * Sends a \"selected endpoints changed\" message via the channel.\n     *\n     * @param {Array<string>} endpointIds - The ids of the selected endpoints.\n     * @throws NetworkError or InvalidStateError from RTCDataChannel#send (@see\n     * {@link https://developer.mozilla.org/docs/Web/API/RTCDataChannel/send})\n     * or from WebSocket#send or Error with \"No opened channel\" message.\n     */\n    sendSelectedEndpointsMessage(endpointIds) {\n        logger.log(`Sending selected endpoints: ${endpointIds}.`);\n\n        this._send({\n            colibriClass: 'SelectedEndpointsChangedEvent',\n            selectedEndpoints: endpointIds\n        });\n    }\n\n    /**\n     * Sends a \"receiver video constraint\" message via the channel.\n     * @param {Number} maxFrameHeightPixels the maximum frame height,\n     * in pixels, this receiver is willing to receive\n     */\n    sendReceiverVideoConstraintMessage(maxFrameHeightPixels) {\n        logger.log(`Sending ReceiverVideoConstraint with maxFrameHeight=${maxFrameHeightPixels}px`);\n        this._send({\n            colibriClass: 'ReceiverVideoConstraint',\n            maxFrameHeight: maxFrameHeightPixels\n        });\n    }\n\n    /**\n     * Sends a 'ReceiverVideoConstraints' message via the bridge channel.\n     *\n     * @param {ReceiverVideoConstraints} constraints video constraints.\n     */\n    sendNewReceiverVideoConstraintsMessage(constraints) {\n        logger.log(`Sending ReceiverVideoConstraints with ${JSON.stringify(constraints)}`);\n        this._send({\n            colibriClass: 'ReceiverVideoConstraints',\n            ...constraints\n        });\n    }\n\n    /**\n     * Sends a 'VideoTypeMessage' message via the bridge channel.\n     *\n     * @param {string} videoType 'camera', 'desktop' or 'none'.\n     * @deprecated to be replaced with sendSourceVideoTypeMessage\n     */\n    sendVideoTypeMessage(videoType) {\n        logger.debug(`Sending VideoTypeMessage with video type as ${videoType}`);\n        this._send({\n            colibriClass: 'VideoTypeMessage',\n            videoType\n        });\n    }\n\n    /**\n     * Sends a 'VideoTypeMessage' message via the bridge channel.\n     *\n     * @param {BridgeVideoType} videoType - the video type.\n     * @param {SourceName} sourceName - the source name of the video track.\n     * @returns {void}\n     */\n    sendSourceVideoTypeMessage(sourceName, videoType) {\n        logger.info(`Sending SourceVideoTypeMessage with video type ${sourceName}: ${videoType}`);\n        this._send({\n            colibriClass: 'SourceVideoTypeMessage',\n            sourceName,\n            videoType\n        });\n    }\n\n    /**\n     * Set events on the given RTCDataChannel or WebSocket instance.\n     */\n    _handleChannel(channel) {\n        const emitter = this._eventEmitter;\n\n        channel.onopen = () => {\n            logger.info(`${this._mode} channel opened`);\n\n            // Code sample for sending string and/or binary data.\n            // Sends string message to the bridge:\n            //     channel.send(\"Hello bridge!\");\n            // Sends 12 bytes binary message to the bridge:\n            //     channel.send(new ArrayBuffer(12));\n\n            emitter.emit(RTCEvents.DATA_CHANNEL_OPEN);\n        };\n\n        channel.onerror = event => {\n            // WS error events contain no information about the failure (this is available in the onclose event) and\n            // the event references the WS object itself, which causes hangs on mobile.\n            if (this._mode !== 'websocket') {\n                logger.error(`Channel error: ${event.message}`);\n            }\n        };\n\n        channel.onmessage = ({ data }) => {\n            // JSON object.\n            let obj;\n\n            try {\n                obj = JSON.parse(data);\n            } catch (error) {\n                GlobalOnErrorHandler.callErrorHandler(error);\n                logger.error('Failed to parse channel message as JSON: ', data, error);\n\n                return;\n            }\n\n            const colibriClass = obj.colibriClass;\n\n            switch (colibriClass) {\n            case 'DominantSpeakerEndpointChangeEvent': {\n                const { dominantSpeakerEndpoint, previousSpeakers = [] } = obj;\n\n                logger.debug(`Dominant speaker: ${dominantSpeakerEndpoint}, previous speakers: ${previousSpeakers}`);\n                emitter.emit(RTCEvents.DOMINANT_SPEAKER_CHANGED, dominantSpeakerEndpoint, previousSpeakers);\n                break;\n            }\n            case 'EndpointConnectivityStatusChangeEvent': {\n                const endpoint = obj.endpoint;\n                const isActive = obj.active === 'true';\n\n                logger.info(`Endpoint connection status changed: ${endpoint} active=${isActive}`);\n                emitter.emit(RTCEvents.ENDPOINT_CONN_STATUS_CHANGED, endpoint, isActive);\n\n                break;\n            }\n            case 'EndpointMessage': {\n                emitter.emit(RTCEvents.ENDPOINT_MESSAGE_RECEIVED, obj.from, obj.msgPayload);\n\n                break;\n            }\n            case 'EndpointStats': {\n                emitter.emit(RTCEvents.ENDPOINT_STATS_RECEIVED, obj.from, obj);\n\n                break;\n            }\n            case 'LastNEndpointsChangeEvent': {\n                if (!FeatureFlags.isSourceNameSignalingEnabled()) {\n                    // The new/latest list of last-n endpoint IDs (i.e. endpoints for which the bridge is sending\n                    // video).\n                    const lastNEndpoints = obj.lastNEndpoints;\n\n                    logger.info(`New forwarded endpoints: ${lastNEndpoints}`);\n                    emitter.emit(RTCEvents.LASTN_ENDPOINT_CHANGED, lastNEndpoints);\n                }\n\n                break;\n            }\n            case 'ForwardedSources': {\n                if (FeatureFlags.isSourceNameSignalingEnabled()) {\n                    // The new/latest list of forwarded sources\n                    const forwardedSources = obj.forwardedSources;\n\n                    logger.info(`New forwarded sources: ${forwardedSources}`);\n                    emitter.emit(RTCEvents.FORWARDED_SOURCES_CHANGED, forwardedSources);\n                }\n\n                break;\n            }\n            case 'SenderVideoConstraints': {\n                const videoConstraints = obj.videoConstraints;\n\n                if (videoConstraints) {\n                    logger.info(`SenderVideoConstraints: ${JSON.stringify(videoConstraints)}`);\n                    emitter.emit(RTCEvents.SENDER_VIDEO_CONSTRAINTS_CHANGED, videoConstraints);\n                }\n                break;\n            }\n            case 'SenderSourceConstraints': {\n                if (FeatureFlags.isSourceNameSignalingEnabled()) {\n                    const { sourceName, maxHeight } = obj;\n\n                    if (typeof sourceName === 'string' && typeof maxHeight === 'number') {\n                        // eslint-disable-next-line object-property-newline\n                        logger.info(`SenderSourceConstraints: ${JSON.stringify({ sourceName, maxHeight })}`);\n                        emitter.emit(\n                            RTCEvents.SENDER_VIDEO_CONSTRAINTS_CHANGED, {\n                                sourceName,\n                                maxHeight\n                            }\n                        );\n                    } else {\n                        logger.error(`Invalid SenderSourceConstraints: ${JSON.stringify(obj)}`);\n                    }\n                }\n                break;\n            }\n            case 'ServerHello': {\n                logger.info(`Received ServerHello, version=${obj.version}.`);\n                break;\n            }\n            default: {\n                logger.debug('Channel JSON-formatted message: ', obj);\n\n                // The received message appears to be appropriately formatted\n                // (i.e. is a JSON object which assigns a value to the\n                // mandatory property colibriClass) so don't just swallow it,\n                // expose it to public consumption.\n                emitter.emit(`rtc.datachannel.${colibriClass}`, obj);\n            }\n            }\n        };\n\n        channel.onclose = event => {\n            logger.info(`Channel closed by ${this._closedFromClient ? 'client' : 'server'}`);\n\n            if (this._mode === 'websocket') {\n                if (!this._closedFromClient) {\n                    logger.error(`Channel closed: ${event.code} ${event.reason}`);\n                    this._retryWebSocketConnection(event);\n                }\n            }\n\n            // Remove the channel.\n            this._channel = null;\n        };\n\n        // Store the channel.\n        this._channel = channel;\n    }\n\n    /**\n     * Sends passed object via the channel.\n     * @param {object} jsonObject The object that will be sent.\n     * @throws NetworkError or InvalidStateError from RTCDataChannel#send (@see\n     * {@link https://developer.mozilla.org/docs/Web/API/RTCDataChannel/send})\n     * or from WebSocket#send or Error with \"No opened channel\" message.\n     */\n    _send(jsonObject) {\n        const channel = this._channel;\n\n        if (!this.isOpen()) {\n            logger.error('Bridge Channel send: no opened channel.');\n            throw new Error('No opened channel');\n        }\n\n        channel.send(JSON.stringify(jsonObject));\n    }\n}\n","/**\n * The possible camera facing modes. For now support only 'user' and\n * 'environment' because 'left' and 'right' are not used anywhere in our\n * projects at the time of this writing. For more information please refer to\n * https://w3c.github.io/mediacapture-main/getusermedia.html\n * #def-constraint-facingMode.\n *\n * @enum {string}\n */\nexport const CameraFacingMode = {\n    /**\n     * The mode which specifies the environment-facing camera.\n     */\n    ENVIRONMENT: 'environment',\n\n    /**\n     * The mode which specifies the user-facing camera.\n     */\n    USER: 'user'\n};\n\nexport default CameraFacingMode;\n","import { getLogger } from '@jitsi/logger';\nimport EventEmitter from 'events';\nimport clonedeep from 'lodash.clonedeep';\n\nimport JitsiTrackError from '../../JitsiTrackError';\nimport * as JitsiTrackErrors from '../../JitsiTrackErrors';\nimport CameraFacingMode from '../../service/RTC/CameraFacingMode';\nimport RTCEvents from '../../service/RTC/RTCEvents';\nimport Resolutions from '../../service/RTC/Resolutions';\nimport { VideoType } from '../../service/RTC/VideoType';\nimport { AVAILABLE_DEVICE } from '../../service/statistics/AnalyticsEvents';\nimport browser from '../browser';\nimport SDPUtil from '../sdp/SDPUtil';\nimport Statistics from '../statistics/statistics';\nimport GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';\nimport Listenable from '../util/Listenable';\n\nimport screenObtainer from './ScreenObtainer';\n\nconst logger = getLogger(__filename);\n\n// Require adapter only for certain browsers. This is being done for\n// react-native, which has its own shims, and while browsers are being migrated\n// over to use adapter's shims.\nif (browser.usesAdapter()) {\n    require('webrtc-adapter');\n}\n\nconst eventEmitter = new EventEmitter();\n\nconst AVAILABLE_DEVICES_POLL_INTERVAL_TIME = 3000; // ms\n\n/**\n * Default MediaStreamConstraints to use for calls to getUserMedia.\n *\n * @private\n */\nconst DEFAULT_CONSTRAINTS = {\n    video: {\n        height: {\n            ideal: 720,\n            max: 720,\n            min: 180\n        },\n        width: {\n            ideal: 1280,\n            max: 1280,\n            min: 320\n        }\n    }\n};\n\n// Currently audio output device change is supported only in Chrome and\n// default output always has 'default' device ID\nlet audioOutputDeviceId = 'default'; // default device\n// whether user has explicitly set a device to use\nlet audioOutputChanged = false;\n\n// Disables all audio processing\nlet disableAP = false;\n\n// Disables Acoustic Echo Cancellation\nlet disableAEC = false;\n\n// Disables Noise Suppression\nlet disableNS = false;\n\n// Disables Automatic Gain Control\nlet disableAGC = false;\n\n// Enables stereo.\nlet stereo = null;\n\nconst featureDetectionAudioEl = document.createElement('audio');\nconst isAudioOutputDeviceChangeAvailable\n    = typeof featureDetectionAudioEl.setSinkId !== 'undefined';\n\nlet availableDevices = [];\nlet availableDevicesPollTimer;\n\n/**\n * An empty function.\n */\nfunction emptyFuncton() {\n    // no-op\n}\n\n/**\n * Creates a constraints object to be passed into a call to getUserMedia.\n *\n * @param {Array} um - An array of user media types to get. The accepted types are \"video\", \"audio\", and \"desktop.\"\n * @param {Object} options - Various values to be added to the constraints.\n * @param {string} options.cameraDeviceId - The device id for the video capture device to get video from.\n * @param {Object} options.constraints - Default constraints object to use as a base for the returned constraints.\n * @param {Object} options.desktopStream - The desktop source id from which to capture a desktop sharing video.\n * @param {string} options.facingMode - Which direction the camera is pointing to (applicable on mobile)\n * @param {string} options.micDeviceId - The device id for the audio capture device to get audio from.\n * @private\n * @returns {Object}\n */\nfunction getConstraints(um = [], options = {}) {\n    // Create a deep copy of the constraints to avoid any modification of\n    // the passed in constraints object.\n    const constraints = clonedeep(options.constraints || DEFAULT_CONSTRAINTS);\n\n    if (um.indexOf('video') >= 0) {\n        // The \"resolution\" option is a shortcut and takes precendence.\n        if (Resolutions[options.resolution]) {\n            const r = Resolutions[options.resolution];\n\n            constraints.video.height = { ideal: r.height };\n            constraints.video.width = { ideal: r.width };\n        }\n\n        if (!constraints.video) {\n            constraints.video = {};\n        }\n\n        // Override the constraints on Safari because of the following webkit bug.\n        // https://bugs.webkit.org/show_bug.cgi?id=210932\n        // Camera doesn't start on older macOS versions if min/max constraints are specified.\n        // TODO: remove this hack when the bug fix is available on Mojave, Sierra and High Sierra.\n        if (browser.isWebKitBased()) {\n            if (constraints.video.height && constraints.video.height.ideal) {\n                constraints.video.height = { ideal: constraints.video.height.ideal };\n            } else {\n                logger.warn('Ideal camera height missing, camera may not start properly');\n            }\n            if (constraints.video.width && constraints.video.width.ideal) {\n                constraints.video.width = { ideal: constraints.video.width.ideal };\n            } else {\n                logger.warn('Ideal camera width missing, camera may not start properly');\n            }\n        }\n        if (options.cameraDeviceId) {\n            constraints.video.deviceId = options.cameraDeviceId;\n        } else {\n            const facingMode = options.facingMode || CameraFacingMode.USER;\n\n            constraints.video.facingMode = facingMode;\n        }\n    } else {\n        constraints.video = false;\n    }\n\n    if (um.indexOf('audio') >= 0) {\n        if (!constraints.audio || typeof constraints.audio === 'boolean') {\n            constraints.audio = {};\n        }\n\n        constraints.audio = {\n            autoGainControl: !disableAGC && !disableAP,\n            deviceId: options.micDeviceId,\n            echoCancellation: !disableAEC && !disableAP,\n            noiseSuppression: !disableNS && !disableAP\n        };\n\n        if (stereo) {\n            Object.assign(constraints.audio, { channelCount: 2 });\n        }\n    } else {\n        constraints.audio = false;\n    }\n\n    return constraints;\n}\n\n/**\n * Updates the granted permissions based on the options we requested and the\n * streams we received.\n * @param um the options we requested to getUserMedia.\n * @param stream the stream we received from calling getUserMedia.\n */\nfunction updateGrantedPermissions(um, stream) {\n    const audioTracksReceived\n        = Boolean(stream) && stream.getAudioTracks().length > 0;\n    const videoTracksReceived\n        = Boolean(stream) && stream.getVideoTracks().length > 0;\n    const grantedPermissions = {};\n\n    if (um.indexOf('video') !== -1) {\n        grantedPermissions.video = videoTracksReceived;\n    }\n    if (um.indexOf('audio') !== -1) {\n        grantedPermissions.audio = audioTracksReceived;\n    }\n\n    eventEmitter.emit(RTCEvents.PERMISSIONS_CHANGED, grantedPermissions);\n}\n\n/**\n * Checks if new list of available media devices differs from previous one.\n * @param {MediaDeviceInfo[]} newDevices - list of new devices.\n * @returns {boolean} - true if list is different, false otherwise.\n */\nfunction compareAvailableMediaDevices(newDevices) {\n    if (newDevices.length !== availableDevices.length) {\n        return true;\n    }\n\n    /* eslint-disable newline-per-chained-call */\n\n    return (\n        newDevices.map(mediaDeviceInfoToJSON).sort().join('')\n            !== availableDevices\n                .map(mediaDeviceInfoToJSON).sort().join(''));\n\n    /* eslint-enable newline-per-chained-call */\n\n    /**\n     *\n     * @param info\n     */\n    function mediaDeviceInfoToJSON(info) {\n        return JSON.stringify({\n            kind: info.kind,\n            deviceId: info.deviceId,\n            groupId: info.groupId,\n            label: info.label,\n            facing: info.facing\n        });\n    }\n}\n\n/**\n * Sends analytics event with the passed device list.\n *\n * @param {Array<MediaDeviceInfo>} deviceList - List with info about the\n * available devices.\n * @returns {void}\n */\nfunction sendDeviceListToAnalytics(deviceList) {\n    const audioInputDeviceCount\n        = deviceList.filter(d => d.kind === 'audioinput').length;\n    const audioOutputDeviceCount\n        = deviceList.filter(d => d.kind === 'audiooutput').length;\n    const videoInputDeviceCount\n        = deviceList.filter(d => d.kind === 'videoinput').length;\n    const videoOutputDeviceCount\n        = deviceList.filter(d => d.kind === 'videooutput').length;\n\n    deviceList.forEach(device => {\n        const attributes = {\n            'audio_input_device_count': audioInputDeviceCount,\n            'audio_output_device_count': audioOutputDeviceCount,\n            'video_input_device_count': videoInputDeviceCount,\n            'video_output_device_count': videoOutputDeviceCount,\n            'device_id': device.deviceId,\n            'device_group_id': device.groupId,\n            'device_kind': device.kind,\n            'device_label': device.label\n        };\n\n        Statistics.sendAnalytics(AVAILABLE_DEVICE, attributes);\n    });\n}\n\n\n/**\n * Update known devices.\n *\n * @param {Array<Object>} pds - The new devices.\n * @returns {void}\n *\n * NOTE: Use this function as a shared callback to handle both the devicechange event  and the polling implementations.\n * This prevents duplication and works around a chrome bug (verified to occur on 68) where devicechange fires twice in\n * a row, which can cause async post devicechange processing to collide.\n */\nfunction updateKnownDevices(pds) {\n    if (compareAvailableMediaDevices(pds)) {\n        onMediaDevicesListChanged(pds);\n    }\n}\n\n/**\n * Event handler for the 'devicechange' event.\n *\n * @param {MediaDeviceInfo[]} devices - list of media devices.\n * @emits RTCEvents.DEVICE_LIST_CHANGED\n */\nfunction onMediaDevicesListChanged(devicesReceived) {\n    availableDevices = devicesReceived.slice(0);\n    logger.info('list of media devices has changed:', availableDevices);\n\n    sendDeviceListToAnalytics(availableDevices);\n\n    // Used by tracks to update the real device id before the consumer of lib-jitsi-meet receives the new device list.\n    eventEmitter.emit(RTCEvents.DEVICE_LIST_WILL_CHANGE, availableDevices);\n\n    eventEmitter.emit(RTCEvents.DEVICE_LIST_CHANGED, availableDevices);\n}\n\n/**\n *\n */\nclass RTCUtils extends Listenable {\n    /**\n     *\n     */\n    constructor() {\n        super(eventEmitter);\n    }\n\n    /**\n     * Depending on the browser, sets difference instance methods for\n     * interacting with user media and adds methods to native WebRTC-related\n     * objects. Also creates an instance variable for peer connection\n     * constraints.\n     *\n     * @param {Object} options\n     * @returns {void}\n     */\n    init(options = {}) {\n        if (typeof options.disableAEC === 'boolean') {\n            disableAEC = options.disableAEC;\n            logger.info(`Disable AEC: ${disableAEC}`);\n        }\n        if (typeof options.disableNS === 'boolean') {\n            disableNS = options.disableNS;\n            logger.info(`Disable NS: ${disableNS}`);\n        }\n        if (typeof options.disableAP === 'boolean') {\n            disableAP = options.disableAP;\n            logger.info(`Disable AP: ${disableAP}`);\n        }\n        if (typeof options.disableAGC === 'boolean') {\n            disableAGC = options.disableAGC;\n            logger.info(`Disable AGC: ${disableAGC}`);\n        }\n        if (typeof options.audioQuality?.stereo === 'boolean') {\n            stereo = options.audioQuality.stereo;\n            logger.info(`Stereo: ${stereo}`);\n        }\n\n        window.clearInterval(availableDevicesPollTimer);\n        availableDevicesPollTimer = undefined;\n\n        if (browser.isReactNative()) {\n            this.RTCPeerConnectionType = RTCPeerConnection;\n\n            this.attachMediaStream = undefined; // Unused on React Native.\n\n            this.getStreamID = function({ id }) {\n                // The react-native-webrtc implementation that we use at the\n                // time of this writing returns a number for the id of\n                // MediaStream. Let's just say that a number contains no special\n                // characters.\n                return (\n                    typeof id === 'number'\n                        ? id\n                        : SDPUtil.filterSpecialChars(id));\n            };\n            this.getTrackID = ({ id }) => id;\n        } else {\n            this.RTCPeerConnectionType = RTCPeerConnection;\n\n            this.attachMediaStream\n                = wrapAttachMediaStream((element, stream) => {\n                    if (element) {\n                        element.srcObject = stream;\n                    }\n                });\n\n            this.getStreamID = ({ id }) => id;\n            this.getTrackID = ({ id }) => id;\n        }\n\n        this.pcConstraints = browser.isChromiumBased() || browser.isReactNative()\n            ? { optional: [\n                { googScreencastMinBitrate: 100 },\n                { googCpuOveruseDetection: true }\n            ] }\n            : {};\n\n        screenObtainer.init(options);\n\n        if (this.isDeviceListAvailable()) {\n            this.enumerateDevices(ds => {\n                availableDevices = ds.slice(0);\n\n                logger.debug('Available devices: ', availableDevices);\n                sendDeviceListToAnalytics(availableDevices);\n\n                eventEmitter.emit(\n                    RTCEvents.DEVICE_LIST_AVAILABLE,\n                    availableDevices);\n\n                if (browser.supportsDeviceChangeEvent()) {\n                    navigator.mediaDevices.addEventListener(\n                        'devicechange',\n                        () => this.enumerateDevices(emptyFuncton));\n                } else {\n                    // Periodically poll enumerateDevices() method to check if\n                    // list of media devices has changed.\n                    availableDevicesPollTimer = window.setInterval(\n                        () => this.enumerateDevices(emptyFuncton),\n                        AVAILABLE_DEVICES_POLL_INTERVAL_TIME);\n                }\n            });\n        }\n    }\n\n    /**\n     *\n     * @param {Function} callback\n     */\n    enumerateDevices(callback) {\n        navigator.mediaDevices.enumerateDevices()\n            .then(devices => {\n                updateKnownDevices(devices);\n                callback(devices);\n            })\n            .catch(error => {\n                logger.warn(`Failed to  enumerate devices. ${error}`);\n                updateKnownDevices([]);\n                callback([]);\n            });\n    }\n\n    /**\n     * Acquires a media stream via getUserMedia that\n     * matches the given constraints\n     *\n     * @param {array} umDevices which devices to acquire (e.g. audio, video)\n     * @param {Object} constraints - Stream specifications to use.\n     * @param {number} timeout - The timeout in ms for GUM.\n     * @returns {Promise}\n     */\n    _getUserMedia(umDevices, constraints = {}, timeout = 0) {\n        return new Promise((resolve, reject) => {\n            let gumTimeout, timeoutExpired = false;\n\n            if (typeof timeout === 'number' && !isNaN(timeout) && timeout > 0) {\n                gumTimeout = setTimeout(() => {\n                    timeoutExpired = true;\n                    gumTimeout = undefined;\n                    reject(new JitsiTrackError(JitsiTrackErrors.TIMEOUT));\n                }, timeout);\n            }\n\n            navigator.mediaDevices.getUserMedia(constraints)\n                .then(stream => {\n                    logger.log('onUserMediaSuccess');\n                    updateGrantedPermissions(umDevices, stream);\n                    if (!timeoutExpired) {\n                        if (typeof gumTimeout !== 'undefined') {\n                            clearTimeout(gumTimeout);\n                        }\n                        resolve(stream);\n                    }\n                })\n                .catch(error => {\n                    logger.warn(`Failed to get access to local media. ${error} ${JSON.stringify(constraints)}`);\n                    const jitsiError = new JitsiTrackError(error, constraints, umDevices);\n\n                    if (!timeoutExpired) {\n                        if (typeof gumTimeout !== 'undefined') {\n                            clearTimeout(gumTimeout);\n                        }\n                        reject(jitsiError);\n                    }\n\n                    if (jitsiError.name === JitsiTrackErrors.PERMISSION_DENIED) {\n                        updateGrantedPermissions(umDevices, undefined);\n                    }\n\n                    // else {\n                    // Probably the error is not caused by the lack of permissions and we don't need to update them.\n                    // }\n                });\n        });\n    }\n\n    /**\n     * Acquire a display stream via the screenObtainer. This requires extra\n     * logic compared to use screenObtainer versus normal device capture logic\n     * in RTCUtils#_getUserMedia.\n     *\n     * @returns {Promise} A promise which will be resolved with an object which\n     * contains the acquired display stream. If desktop sharing is not supported\n     * then a rejected promise will be returned.\n     */\n    _getDesktopMedia() {\n        if (!screenObtainer.isSupported()) {\n            return Promise.reject(new Error('Desktop sharing is not supported!'));\n        }\n\n        return new Promise((resolve, reject) => {\n            screenObtainer.obtainStream(\n                stream => {\n                    resolve(stream);\n                },\n                error => {\n                    reject(error);\n                });\n        });\n    }\n\n    /**\n     * Private utility for determining if the passed in MediaStream contains\n     * tracks of the type(s) specified in the requested devices.\n     *\n     * @param {string[]} requestedDevices - The track types that are expected to\n     * be includes in the stream.\n     * @param {MediaStream} stream - The MediaStream to check if it has the\n     * expected track types.\n     * @returns {string[]} An array of string with the missing track types. The\n     * array will be empty if all requestedDevices are found in the stream.\n     */\n    _getMissingTracks(requestedDevices = [], stream) {\n        const missingDevices = [];\n\n        const audioDeviceRequested = requestedDevices.includes('audio');\n        const audioTracksReceived\n            = stream && stream.getAudioTracks().length > 0;\n\n        if (audioDeviceRequested && !audioTracksReceived) {\n            missingDevices.push('audio');\n        }\n\n        const videoDeviceRequested = requestedDevices.includes('video');\n        const videoTracksReceived\n            = stream && stream.getVideoTracks().length > 0;\n\n        if (videoDeviceRequested && !videoTracksReceived) {\n            missingDevices.push('video');\n        }\n\n        return missingDevices;\n    }\n\n    /**\n     * Gets streams from specified device types. This function intentionally\n     * ignores errors for upstream to catch and handle instead.\n     *\n     * @param {Object} options - A hash describing what devices to get and\n     * relevant constraints.\n     * @param {string[]} options.devices - The types of media to capture. Valid\n     * values are \"desktop\", \"audio\", and \"video\".\n     * @param {Object} options.desktopSharingFrameRate\n     * @param {Object} options.desktopSharingFrameRate.min - Minimum fps\n     * @param {Object} options.desktopSharingFrameRate.max - Maximum fps\n     * @param {String} options.desktopSharingSourceDevice - The device id or\n     * label for a video input source that should be used for screensharing.\n     * @returns {Promise} The promise, when successful, will return an array of\n     * meta data for the requested device type, which includes the stream and\n     * track. If an error occurs, it will be deferred to the caller for\n     * handling.\n     */\n    obtainAudioAndVideoPermissions(options) {\n        const {\n            timeout,\n            ...otherOptions\n        } = options;\n\n        const mediaStreamsMetaData = [];\n\n        // Declare private functions to be used in the promise chain below.\n        // These functions are declared in the scope of this function because\n        // they are not being used anywhere else, so only this function needs to\n        // know about them.\n\n        /**\n         * Executes a request for desktop media if specified in options.\n         *\n         * @returns {Promise}\n         */\n        const maybeRequestDesktopDevice = function() {\n            const umDevices = otherOptions.devices || [];\n            const isDesktopDeviceRequested\n                = umDevices.indexOf('desktop') !== -1;\n\n            if (!isDesktopDeviceRequested) {\n                return Promise.resolve();\n            }\n\n            const {\n                desktopSharingSourceDevice\n            } = otherOptions;\n\n            // Attempt to use a video input device as a screenshare source if\n            // the option is defined.\n            if (desktopSharingSourceDevice) {\n                const matchingDevice\n                    = availableDevices && availableDevices.find(device =>\n                        device.kind === 'videoinput'\n                            && (device.deviceId === desktopSharingSourceDevice\n                            || device.label === desktopSharingSourceDevice));\n\n                if (!matchingDevice) {\n                    return Promise.reject(new JitsiTrackError(\n                        { name: 'ConstraintNotSatisfiedError' },\n                        {},\n                        [ desktopSharingSourceDevice ]\n                    ));\n                }\n\n                const requestedDevices = [ 'video' ];\n                const constraints = {\n                    video: {\n                        deviceId: matchingDevice.deviceId\n\n                        // frameRate is omited here on purpose since this is a device that we'll pretend is a screen.\n                    }\n                };\n\n                return this._getUserMedia(requestedDevices, constraints, timeout)\n                    .then(stream => {\n                        return {\n                            sourceType: 'device',\n                            stream\n                        };\n                    });\n            }\n\n            return this._getDesktopMedia();\n        }.bind(this);\n\n        /**\n         * Creates a meta data object about the passed in desktopStream and\n         * pushes the meta data to the internal array mediaStreamsMetaData to be\n         * returned later.\n         *\n         * @param {MediaStreamTrack} desktopStream - A track for a desktop\n         * capture.\n         * @returns {void}\n         */\n        const maybeCreateAndAddDesktopTrack = function(desktopStream) {\n            if (!desktopStream) {\n                return;\n            }\n\n            const { stream, sourceId, sourceType } = desktopStream;\n\n            const desktopAudioTracks = stream.getAudioTracks();\n\n            if (desktopAudioTracks.length) {\n                const desktopAudioStream = new MediaStream(desktopAudioTracks);\n\n                mediaStreamsMetaData.push({\n                    stream: desktopAudioStream,\n                    sourceId,\n                    sourceType,\n                    track: desktopAudioStream.getAudioTracks()[0]\n                });\n            }\n\n            const desktopVideoTracks = stream.getVideoTracks();\n\n            if (desktopVideoTracks.length) {\n                const desktopVideoStream = new MediaStream(desktopVideoTracks);\n\n                mediaStreamsMetaData.push({\n                    stream: desktopVideoStream,\n                    sourceId,\n                    sourceType,\n                    track: desktopVideoStream.getVideoTracks()[0],\n                    videoType: VideoType.DESKTOP\n                });\n            }\n        };\n\n        /**\n         * Executes a request for audio and/or video, as specified in options.\n         * By default both audio and video will be captured if options.devices\n         * is not defined.\n         *\n         * @returns {Promise}\n         */\n        const maybeRequestCaptureDevices = function() {\n            const umDevices = otherOptions.devices || [ 'audio', 'video' ];\n            const requestedCaptureDevices = umDevices.filter(device => device === 'audio' || device === 'video');\n\n            if (!requestedCaptureDevices.length) {\n                return Promise.resolve();\n            }\n\n            const constraints = getConstraints(requestedCaptureDevices, otherOptions);\n\n            logger.info('Got media constraints: ', JSON.stringify(constraints));\n\n            return this._getUserMedia(requestedCaptureDevices, constraints, timeout);\n        }.bind(this);\n\n        /**\n         * Splits the passed in media stream into separate audio and video\n         * streams and creates meta data objects for each and pushes them to the\n         * internal array mediaStreamsMetaData to be returned later.\n         *\n         * @param {MediaStreamTrack} avStream - A track for with audio and/or\n         * video track.\n         * @returns {void}\n         */\n        const maybeCreateAndAddAVTracks = function(avStream) {\n            if (!avStream) {\n                return;\n            }\n\n            const audioTracks = avStream.getAudioTracks();\n\n            if (audioTracks.length) {\n                const audioStream = new MediaStream(audioTracks);\n\n                mediaStreamsMetaData.push({\n                    stream: audioStream,\n                    track: audioStream.getAudioTracks()[0],\n                    effects: otherOptions.effects\n                });\n            }\n\n            const videoTracks = avStream.getVideoTracks();\n\n            if (videoTracks.length) {\n                const videoStream = new MediaStream(videoTracks);\n\n                mediaStreamsMetaData.push({\n                    stream: videoStream,\n                    track: videoStream.getVideoTracks()[0],\n                    videoType: VideoType.CAMERA,\n                    effects: otherOptions.effects\n                });\n            }\n        };\n\n        return maybeRequestDesktopDevice()\n            .then(maybeCreateAndAddDesktopTrack)\n            .then(maybeRequestCaptureDevices)\n            .then(maybeCreateAndAddAVTracks)\n            .then(() => mediaStreamsMetaData)\n            .catch(error => {\n                mediaStreamsMetaData.forEach(({ stream }) => {\n                    this.stopMediaStream(stream);\n                });\n\n                return Promise.reject(error);\n            });\n    }\n\n    /**\n     * Checks whether it is possible to enumerate available cameras/microphones.\n     *\n     * @returns {boolean} {@code true} if the device listing is available;\n     * {@code false}, otherwise.\n     */\n    isDeviceListAvailable() {\n        return Boolean(\n            navigator.mediaDevices\n                && navigator.mediaDevices.enumerateDevices);\n    }\n\n    /**\n     * Returns true if changing the input (camera / microphone) or output\n     * (audio) device is supported and false if not.\n     * @params {string} [deviceType] - type of device to change. Default is\n     *      undefined or 'input', 'output' - for audio output device change.\n     * @returns {boolean} true if available, false otherwise.\n     */\n    isDeviceChangeAvailable(deviceType) {\n        if (deviceType === 'output' || deviceType === 'audiooutput') {\n            return isAudioOutputDeviceChangeAvailable;\n        }\n\n        // Calling getUserMedia again (for preview) kills the track returned by the first getUserMedia call because of\n        // https://bugs.webkit.org/show_bug.cgi?id=179363. Therefore, do not show microphone/camera options on mobile\n        // Safari.\n        if ((deviceType === 'audioinput' || deviceType === 'input') && browser.isIosBrowser()) {\n            return false;\n        }\n\n        return true;\n    }\n\n    /**\n     * A method to handle stopping of the stream.\n     * One point to handle the differences in various implementations.\n     * @param mediaStream MediaStream object to stop.\n     */\n    stopMediaStream(mediaStream) {\n        if (!mediaStream) {\n            return;\n        }\n\n        mediaStream.getTracks().forEach(track => {\n            if (track.stop) {\n                track.stop();\n            }\n        });\n\n        // leave stop for implementation still using it\n        if (mediaStream.stop) {\n            mediaStream.stop();\n        }\n\n        // The MediaStream implementation of the react-native-webrtc project has\n        // an explicit release method that is to be invoked in order to release\n        // used resources such as memory.\n        if (mediaStream.release) {\n            mediaStream.release();\n        }\n    }\n\n    /**\n     * Returns whether the desktop sharing is enabled or not.\n     * @returns {boolean}\n     */\n    isDesktopSharingEnabled() {\n        return screenObtainer.isSupported();\n    }\n\n    /**\n     * Sets current audio output device.\n     * @param {string} deviceId - id of 'audiooutput' device from\n     *      navigator.mediaDevices.enumerateDevices(), 'default' for default\n     *      device\n     * @returns {Promise} - resolves when audio output is changed, is rejected\n     *      otherwise\n     */\n    setAudioOutputDevice(deviceId) {\n        if (!this.isDeviceChangeAvailable('output')) {\n            return Promise.reject(\n                new Error('Audio output device change is not supported'));\n        }\n\n        return featureDetectionAudioEl.setSinkId(deviceId)\n            .then(() => {\n                audioOutputDeviceId = deviceId;\n                audioOutputChanged = true;\n\n                logger.log(`Audio output device set to ${deviceId}`);\n\n                eventEmitter.emit(RTCEvents.AUDIO_OUTPUT_DEVICE_CHANGED,\n                    deviceId);\n            });\n    }\n\n    /**\n     * Sets the capture frame rate for desktop tracks.\n     *\n     * @param {number} maxFps - max fps to be used as the capture frame rate.\n     * @returns {void}\n     */\n    setDesktopSharingFrameRate(maxFps) {\n        screenObtainer.setDesktopSharingFrameRate(maxFps);\n    }\n\n    /**\n     * Returns currently used audio output device id, '' stands for default\n     * device\n     * @returns {string}\n     */\n    getAudioOutputDevice() {\n        return audioOutputDeviceId;\n    }\n\n    /**\n     * Returns list of available media devices if its obtained, otherwise an\n     * empty array is returned/\n     * @returns {Array} list of available media devices.\n     */\n    getCurrentlyAvailableMediaDevices() {\n        return availableDevices;\n    }\n\n    /**\n     * Returns whether available devices have permissions granted\n     * @returns {Boolean}\n     */\n    arePermissionsGrantedForAvailableDevices() {\n        return availableDevices.some(device => Boolean(device.label));\n    }\n\n    /**\n     * Returns event data for device to be reported to stats.\n     * @returns {MediaDeviceInfo} device.\n     */\n    getEventDataForActiveDevice(device) {\n        const deviceList = [];\n        const deviceData = {\n            'deviceId': device.deviceId,\n            'kind': device.kind,\n            'label': device.label,\n            'groupId': device.groupId\n        };\n\n        deviceList.push(deviceData);\n\n        return { deviceList };\n    }\n\n    /**\n     * Configures the given PeerConnection constraints to either enable or\n     * disable (according to the value of the 'enable' parameter) the\n     * 'googSuspendBelowMinBitrate' option.\n     * @param constraints the constraints on which to operate.\n     * @param enable {boolean} whether to enable or disable the suspend video\n     * option.\n     */\n    setSuspendVideo(constraints, enable) {\n        if (!constraints.optional) {\n            constraints.optional = [];\n        }\n\n        // Get rid of all \"googSuspendBelowMinBitrate\" constraints (we assume\n        // that the elements of constraints.optional contain a single property).\n        constraints.optional\n            = constraints.optional.filter(\n                c => !c.hasOwnProperty('googSuspendBelowMinBitrate'));\n\n        if (enable) {\n            constraints.optional.push({ googSuspendBelowMinBitrate: 'true' });\n        }\n    }\n}\n\nconst rtcUtils = new RTCUtils();\n\n/**\n * Wraps original attachMediaStream function to set current audio output device\n * if this is supported.\n * @param {Function} origAttachMediaStream\n * @returns {Function}\n */\nfunction wrapAttachMediaStream(origAttachMediaStream) {\n    return function(element, stream) {\n        // eslint-disable-next-line prefer-rest-params\n        const res = origAttachMediaStream.apply(rtcUtils, arguments);\n\n        if (stream\n                && rtcUtils.isDeviceChangeAvailable('output')\n                && stream.getAudioTracks\n                && stream.getAudioTracks().length\n\n                // we skip setting audio output if there was no explicit change\n                && audioOutputChanged) {\n            element.setSinkId(rtcUtils.getAudioOutputDevice())\n                .catch(function(ex) {\n                    const err\n                        = new JitsiTrackError(ex, null, [ 'audiooutput' ]);\n\n                    GlobalOnErrorHandler.callUnhandledRejectionHandler({\n                        promise: this, // eslint-disable-line no-invalid-this\n                        reason: err\n                    });\n\n                    logger.warn(\n                        'Failed to set audio output device for the element.'\n                            + ' Default audio output device will be used'\n                            + ' instead',\n                        element,\n                        err);\n                });\n        }\n\n        return res;\n    };\n}\n\nexport default rtcUtils;\n","import { getLogger } from '@jitsi/logger';\nimport EventEmitter from 'events';\n\nimport * as JitsiTrackEvents from '../../JitsiTrackEvents';\nimport { MediaType } from '../../service/RTC/MediaType';\nimport browser from '../browser';\n\nimport RTCUtils from './RTCUtils';\n\nconst logger = getLogger(__filename);\n\n/**\n * Maps our handler types to MediaStreamTrack properties.\n */\nconst trackHandler2Prop = {\n    'track_mute': 'onmute', // Not supported on FF\n    'track_unmute': 'onunmute',\n    'track_ended': 'onended'\n};\n\n/**\n * Represents a single media track (either audio or video).\n */\nexport default class JitsiTrack extends EventEmitter {\n    /* eslint-disable max-params */\n    /**\n     * Represents a single media track (either audio or video).\n     * @constructor\n     * @param conference the rtc instance\n     * @param stream the WebRTC MediaStream instance\n     * @param track the WebRTC MediaStreamTrack instance, must be part of\n     * the given <tt>stream</tt>.\n     * @param streamInactiveHandler the function that will handle\n     *        onended/oninactive events of the stream.\n     * @param trackMediaType the media type of the JitsiTrack\n     * @param videoType the VideoType for this track if any\n     */\n    constructor(\n            conference,\n            stream,\n            track,\n            streamInactiveHandler,\n            trackMediaType,\n            videoType) {\n        super();\n\n        // aliases for addListener/removeListener\n        this.addEventListener = this.addListener;\n        this.removeEventListener = this.off = this.removeListener;\n\n        /**\n         * Array with the HTML elements that are displaying the streams.\n         * @type {Array}\n         */\n        this.containers = [];\n        this.conference = conference;\n        this.audioLevel = -1;\n        this.type = trackMediaType;\n        this.track = track;\n        this.videoType = videoType;\n        this.handlers = new Map();\n\n        /**\n         * Indicates whether this JitsiTrack has been disposed. If true, this\n         * JitsiTrack is to be considered unusable and operations involving it\n         * are to fail (e.g. {@link JitsiConference#addTrack(JitsiTrack)},\n         * {@link JitsiConference#removeTrack(JitsiTrack)}).\n         * @type {boolean}\n         */\n        this.disposed = false;\n\n        /**\n         * The inactive handler which will be triggered when the underlying\n         * <tt>MediaStream</tt> ends.\n         *\n         * @private\n         * @type {Function}\n         */\n        this._streamInactiveHandler = streamInactiveHandler;\n\n        this._setStream(stream);\n    }\n\n    /* eslint-enable max-params */\n\n    /**\n     * Adds onended/oninactive handler to a MediaStream or a MediaStreamTrack.\n     * Firefox doesn't fire a inactive event on the MediaStream, instead it fires\n     * a onended event on the MediaStreamTrack.\n     * @param {Function} handler the handler\n     */\n    _addMediaStreamInactiveHandler(handler) {\n        if (browser.isFirefox()) {\n            this.track.onended = handler;\n        } else {\n            this.stream.oninactive = handler;\n        }\n    }\n\n    /**\n     * Sets handler to the WebRTC MediaStream or MediaStreamTrack object\n     * depending on the passed type.\n     * @param {string} type the type of the handler that is going to be set\n     * @param {Function} handler the handler.\n     */\n    _setHandler(type, handler) {\n        if (!trackHandler2Prop.hasOwnProperty(type)) {\n            logger.error(`Invalid handler type ${type}`);\n\n            return;\n        }\n        if (handler) {\n            this.handlers.set(type, handler);\n        } else {\n            this.handlers.delete(type);\n        }\n\n        if (this.stream) {\n            for (const track of this.stream.getTracks()) {\n                track[trackHandler2Prop[type]] = handler;\n            }\n        }\n    }\n\n    /**\n     * Unregisters all event handlers bound to the underlying media stream/track\n     * @private\n     */\n    _unregisterHandlers() {\n        if (!this.stream) {\n            logger.warn(\n                `${this}: unable to unregister handlers - no stream object`);\n\n            return;\n        }\n\n        for (const type of this.handlers.keys()) {\n            // FIXME Why only video tracks?\n            for (const videoTrack of this.stream.getVideoTracks()) {\n                videoTrack[trackHandler2Prop[type]] = undefined;\n            }\n        }\n        if (this._streamInactiveHandler) {\n            this._addMediaStreamInactiveHandler(undefined);\n        }\n    }\n\n    /**\n     * Sets the stream property of JitsiTrack object and sets all stored\n     * handlers to it.\n     *\n     * @param {MediaStream} stream the new stream.\n     * @protected\n     */\n    _setStream(stream) {\n        if (this.stream === stream) {\n            return;\n        }\n\n        this.stream = stream;\n\n        // TODO Practically, that's like the opposite of _unregisterHandlers\n        // i.e. may be abstracted into a function/method called\n        // _registerHandlers for clarity and easing the maintenance of the two\n        // pieces of source code.\n        if (this.stream) {\n            for (const type of this.handlers.keys()) {\n                this._setHandler(type, this.handlers.get(type));\n            }\n            if (this._streamInactiveHandler) {\n                this._addMediaStreamInactiveHandler(this._streamInactiveHandler);\n            }\n        }\n    }\n\n    /**\n     * Returns the video type (camera or desktop) of this track.\n     */\n    getVideoType() {\n        return this.videoType;\n    }\n\n    /**\n     * Returns the type (audio or video) of this track.\n     */\n    getType() {\n        return this.type;\n    }\n\n    /**\n     * Check if this is an audio track.\n     */\n    isAudioTrack() {\n        return this.getType() === MediaType.AUDIO;\n    }\n\n    /**\n     * Checks whether the underlying WebRTC <tt>MediaStreamTrack</tt> is muted\n     * according to it's 'muted' field status.\n     * @return {boolean} <tt>true</tt> if the underlying\n     * <tt>MediaStreamTrack</tt> is muted or <tt>false</tt> otherwise.\n     */\n    isWebRTCTrackMuted() {\n        return this.track && this.track.muted;\n    }\n\n    /**\n     * Check if this is a video track.\n     */\n    isVideoTrack() {\n        return this.getType() === MediaType.VIDEO;\n    }\n\n    /**\n     * Checks whether this is a local track.\n     * @abstract\n     * @return {boolean} 'true' if it's a local track or 'false' otherwise.\n     */\n    isLocal() {\n        throw new Error('Not implemented by subclass');\n    }\n\n    /**\n     * Check whether this is a local audio track.\n     *\n     * @return {boolean} -  true if track represents a local audio track, false otherwise.\n     */\n    isLocalAudioTrack() {\n        return this.isAudioTrack() && this.isLocal();\n    }\n\n    /**\n     * Returns the WebRTC MediaStream instance.\n     */\n    getOriginalStream() {\n        return this.stream;\n    }\n\n    /**\n     * Returns the ID of the underlying WebRTC Media Stream(if any)\n     * @returns {String|null}\n     */\n    getStreamId() {\n        return this.stream ? this.stream.id : null;\n    }\n\n    /**\n     * Return the underlying WebRTC MediaStreamTrack\n     * @returns {MediaStreamTrack}\n     */\n    getTrack() {\n        return this.track;\n    }\n\n    /**\n     * Return the underlying WebRTC MediaStreamTrack label\n     * @returns {string}\n     */\n    getTrackLabel() {\n        return this.track.label;\n    }\n\n    /**\n     * Returns the ID of the underlying WebRTC MediaStreamTrack(if any)\n     * @returns {String|null}\n     */\n    getTrackId() {\n        return this.track ? this.track.id : null;\n    }\n\n    /**\n     * Return meaningful usage label for this track depending on it's media and\n     * eventual video type.\n     * @returns {string}\n     */\n    getUsageLabel() {\n        if (this.isAudioTrack()) {\n            return 'mic';\n        }\n\n        return this.videoType ? this.videoType : 'default';\n    }\n\n    /**\n     * Eventually will trigger RTCEvents.TRACK_ATTACHED event.\n     * @param container the video/audio container to which this stream is\n     *        attached and for which event will be fired.\n     * @private\n     */\n    _maybeFireTrackAttached(container) {\n        if (this.conference && container) {\n            this.conference._onTrackAttach(this, container);\n        }\n    }\n\n    /**\n     * Attaches the MediaStream of this track to an HTML container.\n     * Adds the container to the list of containers that are displaying the\n     * track.\n     *\n     * @param container the HTML container which can be 'video' or 'audio'\n     * element.\n     *\n     * @returns {void}\n     */\n    attach(container) {\n        if (this.stream) {\n            this._onTrackAttach(container);\n            RTCUtils.attachMediaStream(container, this.stream);\n        }\n        this.containers.push(container);\n        this._maybeFireTrackAttached(container);\n        this._attachTTFMTracker(container);\n    }\n\n    /**\n     * Removes this JitsiTrack from the passed HTML container.\n     *\n     * @param container the HTML container to detach from this JitsiTrack. If\n     * <tt>null</tt> or <tt>undefined</tt>, all containers are removed. A\n     * container can be a 'video', 'audio' or 'object' HTML element instance to\n     * which this JitsiTrack is currently attached.\n     */\n    detach(container) {\n        for (let cs = this.containers, i = cs.length - 1; i >= 0; --i) {\n            const c = cs[i];\n\n            if (!container) {\n                this._onTrackDetach(c);\n                RTCUtils.attachMediaStream(c, null);\n            }\n            if (!container || c === container) {\n                cs.splice(i, 1);\n            }\n        }\n\n        if (container) {\n            this._onTrackDetach(container);\n            RTCUtils.attachMediaStream(container, null);\n        }\n    }\n\n    /**\n     * Called when the track has been attached to a new container.\n     *\n     * @param {HTMLElement} container the HTML container which can be 'video' or\n     * 'audio' element.\n     * @private\n     */\n    _onTrackAttach(container) { // eslint-disable-line no-unused-vars\n        // Should be defined by the classes that are extending JitsiTrack\n    }\n\n    /**\n     * Called when the track has been detached from a container.\n     *\n     * @param {HTMLElement} container the HTML container which can be 'video' or\n     * 'audio' element.\n     * @private\n     */\n    _onTrackDetach(container) { // eslint-disable-line no-unused-vars\n        // Should be defined by the classes that are extending JitsiTrack\n    }\n\n    /**\n     * Attach time to first media tracker only if there is conference and only\n     * for the first element.\n     *\n     * @param {HTMLElement} container the HTML container which can be 'video' or\n     * 'audio' element.\n     * @private\n     */\n    _attachTTFMTracker(container) { // eslint-disable-line no-unused-vars\n        // Should be defined by the classes that are extending JitsiTrack\n    }\n\n    /**\n     * Removes attached event listeners.\n     *\n     * @returns {Promise}\n     */\n    dispose() {\n        this.removeAllListeners();\n\n        this.disposed = true;\n\n        return Promise.resolve();\n    }\n\n    /**\n     * Returns true if this is a video track and the source of the video is a\n     * screen capture as opposed to a camera.\n     */\n    isScreenSharing() {\n        // FIXME: Should be fixed or removed.\n    }\n\n    /**\n     * Returns id of the track.\n     * @returns {string|null} id of the track or null if this is fake track.\n     */\n    getId() {\n        if (this.stream) {\n            return RTCUtils.getStreamID(this.stream);\n        }\n\n        return null;\n    }\n\n    /**\n     * Checks whether the MediaStream is active/not ended.\n     * When there is no check for active we don't have information and so\n     * will return that stream is active (in case of FF).\n     * @returns {boolean} whether MediaStream is active.\n     */\n    isActive() {\n        if (typeof this.stream.active !== 'undefined') {\n            return this.stream.active;\n        }\n\n        return true;\n    }\n\n    /**\n     * Sets the audio level for the stream\n     * @param {number} audioLevel value between 0 and 1\n     * @param {TraceablePeerConnection} [tpc] the peerconnection instance which\n     * is source for the audio level. It can be <tt>undefined</tt> for\n     * a local track if the audio level was measured outside of the\n     * peerconnection (see /modules/statistics/LocalStatsCollector.js).\n     */\n    setAudioLevel(audioLevel, tpc) {\n        let newAudioLevel = audioLevel;\n\n        // When using getSynchornizationSources on the audio receiver to gather audio levels for\n        // remote tracks, browser reports last known audio levels even when the remote user is\n        // audio muted, we need to reset the value to zero here so that the audio levels are cleared.\n        // Remote tracks have the tpc info present while local tracks do not.\n        if (browser.supportsReceiverStats() && typeof tpc !== 'undefined' && this.isMuted()) {\n            newAudioLevel = 0;\n        }\n\n        if (this.audioLevel !== newAudioLevel) {\n            this.audioLevel = newAudioLevel;\n            this.emit(\n                JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED,\n                newAudioLevel,\n                tpc);\n\n        // LocalStatsCollector reports a value of 0.008 for muted mics\n        // and a value of 0 when there is no audio input.\n        } else if (this.audioLevel === 0\n            && newAudioLevel === 0\n            && this.isLocal()\n            && !this.isWebRTCTrackMuted()) {\n            this.emit(\n                JitsiTrackEvents.NO_AUDIO_INPUT,\n                newAudioLevel);\n        }\n    }\n\n    /**\n     * Returns the msid of the stream attached to the JitsiTrack object or null\n     * if no stream is attached.\n     */\n    getMSID() {\n        const streamId = this.getStreamId();\n        const trackId = this.getTrackId();\n\n        return streamId && trackId ? `${streamId} ${trackId}` : null;\n    }\n\n    /**\n     * Sets new audio output device for track's DOM elements. Video tracks are\n     * ignored.\n     * @param {string} audioOutputDeviceId - id of 'audiooutput' device from\n     *      navigator.mediaDevices.enumerateDevices(), '' for default device\n     * @emits JitsiTrackEvents.TRACK_AUDIO_OUTPUT_CHANGED\n     * @returns {Promise}\n     */\n    setAudioOutput(audioOutputDeviceId) {\n        if (!RTCUtils.isDeviceChangeAvailable('output')) {\n            return Promise.reject(\n                new Error('Audio output device change is not supported'));\n        }\n\n        // All audio communication is done through audio tracks, so ignore\n        // changing audio output for video tracks at all.\n        if (this.isVideoTrack()) {\n            return Promise.resolve();\n        }\n\n        return (\n            Promise.all(\n                this.containers.map(\n                    element =>\n                        element.setSinkId(audioOutputDeviceId)\n                            .catch(error => {\n                                logger.warn(\n                                    'Failed to change audio output device on'\n                                        + ' element. Default or previously set'\n                                        + ' audio output device will be used.',\n                                    element,\n                                    error);\n                                throw error;\n                            }))\n            )\n                .then(() => {\n                    this.emit(\n                        JitsiTrackEvents.TRACK_AUDIO_OUTPUT_CHANGED,\n                        audioOutputDeviceId);\n                }));\n    }\n}\n","import { getLogger } from '@jitsi/logger';\n\nimport JitsiTrackError from '../../JitsiTrackError';\nimport {\n    TRACK_IS_DISPOSED,\n    TRACK_NO_STREAM_FOUND\n} from '../../JitsiTrackErrors';\nimport {\n    LOCAL_TRACK_STOPPED,\n    NO_DATA_FROM_SOURCE,\n    TRACK_MUTE_CHANGED\n} from '../../JitsiTrackEvents';\nimport CameraFacingMode from '../../service/RTC/CameraFacingMode';\nimport { MediaType } from '../../service/RTC/MediaType';\nimport RTCEvents from '../../service/RTC/RTCEvents';\nimport { VideoType } from '../../service/RTC/VideoType';\nimport {\n    NO_BYTES_SENT,\n    TRACK_UNMUTED,\n    createNoDataFromSourceEvent\n} from '../../service/statistics/AnalyticsEvents';\nimport browser from '../browser';\nimport Statistics from '../statistics/statistics';\n\nimport JitsiTrack from './JitsiTrack';\nimport RTCUtils from './RTCUtils';\n\nconst logger = getLogger(__filename);\n\n/**\n * Represents a single media track(either audio or video).\n * One <tt>JitsiLocalTrack</tt> corresponds to one WebRTC MediaStreamTrack.\n */\nexport default class JitsiLocalTrack extends JitsiTrack {\n    /**\n     * Constructs a new JitsiLocalTrack instance.\n     *\n     * @constructor\n     * @param {Object} trackInfo\n     * @param {number} trackInfo.rtcId - The ID assigned by the RTC module.\n     * @param {Object} trackInfo.stream - The WebRTC MediaStream, parent of the track.\n     * @param {Object} trackInfo.track - The underlying WebRTC MediaStreamTrack for new JitsiLocalTrack.\n     * @param {string} trackInfo.mediaType - The MediaType of the JitsiLocalTrack.\n     * @param {string} trackInfo.videoType - The VideoType of the JitsiLocalTrack.\n     * @param {Array<Object>} trackInfo.effects - The effects to be applied to the JitsiLocalTrack.\n     * @param {number} trackInfo.resolution - The the video resolution if it's a video track\n     * @param {string} trackInfo.deviceId - The ID of the local device for this track.\n     * @param {string} trackInfo.facingMode - Thehe camera facing mode used in getUserMedia call (for mobile only).\n     * @param {sourceId} trackInfo.sourceId - The id of the desktop sharing source. NOTE: defined for desktop sharing\n     * tracks only.\n     */\n    constructor({\n        deviceId,\n        facingMode,\n        mediaType,\n        resolution,\n        rtcId,\n        sourceId,\n        sourceType,\n        stream,\n        track,\n        videoType,\n        effects = []\n    }) {\n        super(\n            /* conference */ null,\n            stream,\n            track,\n            /* streamInactiveHandler */ () => this.emit(LOCAL_TRACK_STOPPED),\n            mediaType,\n            videoType);\n\n        this._setEffectInProgress = false;\n        const effect = effects.find(e => e.isEnabled(this));\n\n        if (effect) {\n            this._startStreamEffect(effect);\n        }\n\n        const displaySurface = videoType === VideoType.DESKTOP\n            ? track.getSettings().displaySurface\n            : null;\n\n        /**\n         * Track metadata.\n         */\n        this.metadata = {\n            timestamp: Date.now(),\n            ...displaySurface ? { displaySurface } : {}\n        };\n\n\n        /**\n         * The ID assigned by the RTC module on instance creation.\n         *\n         * @type {number}\n         */\n        this.rtcId = rtcId;\n        this.sourceId = sourceId;\n        this.sourceType = sourceType;\n\n        // Get the resolution from the track itself because it cannot be\n        // certain which resolution webrtc has fallen back to using.\n        this.resolution = track.getSettings().height;\n        this.maxEnabledResolution = resolution;\n\n        // Cache the constraints of the track in case of any this track\n        // model needs to call getUserMedia again, such as when unmuting.\n        this._constraints = track.getConstraints();\n\n        // Safari returns an empty constraints object, construct the constraints using getSettings.\n        if (!Object.keys(this._constraints).length && videoType === VideoType.CAMERA) {\n            this._constraints = {\n                height: track.getSettings().height,\n                width: track.getSettings().width\n            };\n        }\n\n        this.deviceId = deviceId;\n\n        /**\n         * The <tt>Promise</tt> which represents the progress of a previously\n         * queued/scheduled {@link _setMuted} (from the point of view of\n         * {@link _queueSetMuted}).\n         *\n         * @private\n         * @type {Promise}\n         */\n        this._prevSetMuted = Promise.resolve();\n\n        /**\n         * The facing mode of the camera from which this JitsiLocalTrack\n         * instance was obtained.\n         *\n         * @private\n         * @type {CameraFacingMode|undefined}\n         */\n        this._facingMode = facingMode;\n\n        // Currently there is no way to know the MediaStreamTrack ended due to\n        // to device disconnect in Firefox through e.g. \"readyState\" property.\n        // Instead we will compare current track's label with device labels from\n        // enumerateDevices() list.\n        this._trackEnded = false;\n\n        /**\n         * Indicates whether data has been sent or not.\n         */\n        this._hasSentData = false;\n\n        /**\n         * Used only for detection of audio problems. We want to check only once\n         * whether the track is sending data ot not. This flag is set to false\n         * after the check.\n         */\n        this._testDataSent = true;\n\n        // Currently there is no way to determine with what device track was\n        // created (until getConstraints() support), however we can associate\n        // tracks with real devices obtained from enumerateDevices() call as\n        // soon as it's called.\n        // NOTE: this.deviceId corresponds to the device id specified in GUM constraints and this._realDeviceId seems to\n        // correspond to the id of a matching device from the available device list.\n        this._realDeviceId = this.deviceId === '' ? undefined : this.deviceId;\n\n        // The source name that will be signaled for this track.\n        this._sourceName = null;\n\n        this._trackMutedTS = 0;\n\n        this._onDeviceListWillChange = devices => {\n            const oldRealDeviceId = this._realDeviceId;\n\n            this._setRealDeviceIdFromDeviceList(devices);\n\n            if (\n                // Mark track as ended for those browsers that do not support\n                // \"readyState\" property. We do not touch tracks created with\n                // default device ID \"\".\n                (typeof this.getTrack().readyState === 'undefined'\n                    && typeof this._realDeviceId !== 'undefined'\n                    && !devices.find(d => d.deviceId === this._realDeviceId))\n\n                // If there was an associated realDeviceID and after the device change the realDeviceId is undefined\n                // then the associated device has been disconnected and the _trackEnded flag needs to be set. In\n                // addition on some Chrome versions the readyState property is set after the device change event is\n                // triggered which causes issues in jitsi-meet with the selection of a new device because we don't\n                // detect that the old one was removed.\n                || (typeof oldRealDeviceId !== 'undefined' && typeof this._realDeviceId === 'undefined')\n            ) {\n                this._trackEnded = true;\n            }\n        };\n\n        // Subscribe each created local audio track to\n        // RTCEvents.AUDIO_OUTPUT_DEVICE_CHANGED event. This is different from\n        // handling this event for remote tracks (which are handled in RTC.js),\n        // because there might be local tracks not attached to a conference.\n        if (this.isAudioTrack() && RTCUtils.isDeviceChangeAvailable('output')) {\n            this._onAudioOutputDeviceChanged = this.setAudioOutput.bind(this);\n            RTCUtils.addListener(\n                RTCEvents.AUDIO_OUTPUT_DEVICE_CHANGED,\n                this._onAudioOutputDeviceChanged);\n        }\n\n        RTCUtils.addListener(RTCEvents.DEVICE_LIST_WILL_CHANGE, this._onDeviceListWillChange);\n\n        this._initNoDataFromSourceHandlers();\n    }\n\n    /**\n     * Adds stream to conference and marks it as \"unmute\" operation.\n     *\n     * @private\n     * @returns {Promise}\n     */\n    _addStreamToConferenceAsUnmute() {\n        if (!this.conference) {\n            return Promise.resolve();\n        }\n\n        // FIXME it would be good to not included conference as part of this process. Only TraceablePeerConnections to\n        // which the track is attached should care about this action. The TPCs to which the track is not attached can\n        // sync up when track is re-attached. A problem with that is that the \"modify sources\" queue is part of the\n        // JingleSessionPC and it would be excluded from the process. One solution would be to extract class between\n        // TPC and JingleSessionPC which would contain the queue and would notify the signaling layer when local SSRCs\n        // are changed. This would help to separate XMPP from the RTC module.\n        return new Promise((resolve, reject) => {\n            this.conference._addLocalTrackAsUnmute(this)\n                .then(resolve, error => reject(new Error(error)));\n        });\n    }\n\n    /**\n     * Fires NO_DATA_FROM_SOURCE event and logs it to analytics and callstats.\n     *\n     * @private\n     * @returns {void}\n     */\n    _fireNoDataFromSourceEvent() {\n        const value = !this.isReceivingData();\n\n        this.emit(NO_DATA_FROM_SOURCE, value);\n\n        // FIXME: Should we report all of those events\n        Statistics.sendAnalytics(createNoDataFromSourceEvent(this.getType(), value));\n        Statistics.sendLog(JSON.stringify({\n            name: NO_DATA_FROM_SOURCE,\n            log: value\n        }));\n    }\n\n    /**\n     * Sets handlers to the MediaStreamTrack object that will detect camera issues.\n     *\n     * @private\n     * @returns {void}\n     */\n    _initNoDataFromSourceHandlers() {\n        if (!this._isNoDataFromSourceEventsEnabled()) {\n            return;\n        }\n\n        this._setHandler('track_mute', () => {\n            this._trackMutedTS = window.performance.now();\n            this._fireNoDataFromSourceEvent();\n        });\n\n        this._setHandler('track_unmute', () => {\n            this._fireNoDataFromSourceEvent();\n            Statistics.sendAnalyticsAndLog(\n                TRACK_UNMUTED,\n                {\n                    'media_type': this.getType(),\n                    'track_type': 'local',\n                    value: window.performance.now() - this._trackMutedTS\n                });\n        });\n\n        if (this.isVideoTrack() && this.videoType === VideoType.CAMERA) {\n            this._setHandler('track_ended', () => {\n                if (!this.isReceivingData()) {\n                    this._fireNoDataFromSourceEvent();\n                }\n            });\n        }\n    }\n\n    /**\n     * Returns true if no data from source events are enabled for this JitsiLocalTrack and false otherwise.\n     *\n     * @private\n     * @returns {boolean} - True if no data from source events are enabled for this JitsiLocalTrack and false otherwise.\n     */\n    _isNoDataFromSourceEventsEnabled() {\n        // Disable the events for screen sharing.\n        return !this.isVideoTrack() || this.videoType !== VideoType.DESKTOP;\n    }\n\n    /**\n     * Initializes a new Promise to execute {@link #_setMuted}. May be called multiple times in a row and the\n     * invocations of {@link #_setMuted} and, consequently, {@link #mute} and/or {@link #unmute} will be resolved in a\n     * serialized fashion.\n     *\n     * @param {boolean} muted - The value to invoke <tt>_setMuted</tt> with.\n     * @private\n     * @returns {Promise}\n     */\n    _queueSetMuted(muted) {\n        const setMuted = this._setMuted.bind(this, muted);\n\n        this._prevSetMuted = this._prevSetMuted.then(setMuted, setMuted);\n\n        return this._prevSetMuted;\n    }\n\n    /**\n     * Removes stream from conference and marks it as \"mute\" operation.\n     *\n     * @param {Function} successCallback - Callback that will be called when the operation is successful.\n     * @param {Function} errorCallback - Callback that will be called when the operation fails.\n     * @private\n     * @returns {Promise}\n     */\n    _removeStreamFromConferenceAsMute(successCallback, errorCallback) {\n        if (!this.conference) {\n            successCallback();\n\n            return;\n        }\n        this.conference._removeLocalTrackAsMute(this).then(\n            successCallback,\n            error => errorCallback(new Error(error)));\n    }\n\n    /**\n     * Sends mute status for a track to conference if any.\n     *\n     * @param {boolean} mute - If track is muted.\n     * @private\n     * @returns {void}\n     */\n    _sendMuteStatus(mute) {\n        if (this.conference) {\n            this.conference._setTrackMuteStatus(this.getType(), this, mute) && this.conference.room.sendPresence();\n        }\n    }\n\n    /**\n     * Mutes / unmutes this track.\n     *\n     * @param {boolean} muted - If <tt>true</tt>, this track will be muted; otherwise, this track will be unmuted.\n     * @private\n     * @returns {Promise}\n     */\n    _setMuted(muted) {\n        if (this.isMuted() === muted) {\n            return Promise.resolve();\n        }\n\n        if (this.disposed) {\n            return Promise.reject(new JitsiTrackError(TRACK_IS_DISPOSED));\n        }\n\n        let promise = Promise.resolve();\n\n        // A function that will print info about muted status transition\n        const logMuteInfo = () => logger.info(`Mute ${this}: ${muted}`);\n\n        if (this.isAudioTrack()\n                || this.videoType === VideoType.DESKTOP\n                || !browser.doesVideoMuteByStreamRemove()) {\n            logMuteInfo();\n\n            // If we have a stream effect that implements its own mute functionality, prioritize it before\n            // normal mute e.g. the stream effect that implements system audio sharing has a custom\n            // mute state in which if the user mutes, system audio still has to go through.\n            if (this._streamEffect && this._streamEffect.setMuted) {\n                this._streamEffect.setMuted(muted);\n            } else if (this.track) {\n                this.track.enabled = !muted;\n            }\n        } else if (muted) {\n            promise = new Promise((resolve, reject) => {\n                logMuteInfo();\n                this._removeStreamFromConferenceAsMute(\n                    () => {\n                        if (this._streamEffect) {\n                            this._stopStreamEffect();\n                        }\n\n                        // FIXME: Maybe here we should set the SRC for the\n                        // containers to something\n                        // We don't want any events to be fired on this stream\n                        this._unregisterHandlers();\n                        this.stopStream();\n                        this._setStream(null);\n\n                        resolve();\n                    },\n                    reject);\n            });\n        } else {\n            logMuteInfo();\n\n            // This path is only for camera.\n            const streamOptions = {\n                cameraDeviceId: this.getDeviceId(),\n                devices: [ MediaType.VIDEO ],\n                effects: this._streamEffect ? [ this._streamEffect ] : [],\n                facingMode: this.getCameraFacingMode()\n            };\n\n            promise\n                = RTCUtils.obtainAudioAndVideoPermissions(Object.assign(\n                    {},\n                    streamOptions,\n                    { constraints: { video: this._constraints } }));\n\n            promise = promise.then(streamsInfo => {\n                // The track kind for presenter track is video as well.\n                const mediaType = this.getType() === MediaType.PRESENTER ? MediaType.VIDEO : this.getType();\n                const streamInfo = streamsInfo.find(info => info.track.kind === mediaType);\n\n                if (streamInfo) {\n                    this._setStream(streamInfo.stream);\n                    this.track = streamInfo.track;\n\n                    // This is not good when video type changes after\n                    // unmute, but let's not crash here\n                    if (this.videoType !== streamInfo.videoType) {\n                        logger.warn(\n                            `${this}: video type has changed after unmute!`,\n                            this.videoType, streamInfo.videoType);\n                        this.videoType = streamInfo.videoType;\n                    }\n                } else {\n                    throw new JitsiTrackError(TRACK_NO_STREAM_FOUND);\n                }\n\n                if (this._streamEffect) {\n                    this._startStreamEffect(this._streamEffect);\n                }\n\n                this.containers.map(\n                    cont => RTCUtils.attachMediaStream(cont, this.stream));\n\n                return this._addStreamToConferenceAsUnmute();\n            });\n        }\n\n        return promise\n            .then(() => {\n                this._sendMuteStatus(muted);\n\n                // Send the videoType message to the bridge.\n                this.isVideoTrack() && this.conference && this.conference._sendBridgeVideoTypeMessage(this);\n                this.emit(TRACK_MUTE_CHANGED, this);\n            });\n    }\n\n    /**\n     * Sets real device ID by comparing track information with device information. This is temporary solution until\n     * getConstraints() method will be implemented in browsers.\n     *\n     * @param {MediaDeviceInfo[]} devices - The list of devices obtained from enumerateDevices() call.\n     * @private\n     * @returns {void}\n     */\n    _setRealDeviceIdFromDeviceList(devices) {\n        const track = this.getTrack();\n        const kind = `${track.kind}input`;\n\n        // We need to match by deviceId as well, in case of multiple devices with the same label.\n        let device = devices.find(d => d.kind === kind && d.label === track.label && d.deviceId === this.deviceId);\n\n        if (!device && this._realDeviceId === 'default') { // the default device has been changed.\n            // If the default device was 'A' and the default device is changed to 'B' the label for the track will\n            // remain 'Default - A' but the label for the device in the device list will be updated to 'A'. That's\n            // why in order to match it we need to remove the 'Default - ' part.\n            const label = (track.label || '').replace('Default - ', '');\n\n            device = devices.find(d => d.kind === kind && d.label === label);\n        }\n\n        if (device) {\n            this._realDeviceId = device.deviceId;\n        } else {\n            this._realDeviceId = undefined;\n        }\n    }\n\n    /**\n     * Sets the stream property of JitsiLocalTrack object and sets all stored handlers to it.\n     *\n     * @param {MediaStream} stream - The new MediaStream.\n     * @private\n     * @returns {void}\n     */\n    _setStream(stream) {\n        super._setStream(stream);\n\n        if (stream) {\n            // Store the MSID for video mute/unmute purposes.\n            this.storedMSID = this.getMSID();\n            logger.debug(`Setting new MSID: ${this.storedMSID} on ${this}`);\n        } else {\n            logger.debug(`Setting 'null' stream on ${this}`);\n        }\n    }\n\n    /**\n     * Starts the effect process and returns the modified stream.\n     *\n     * @param {Object} effect - Represents effect instance\n     * @private\n     * @returns {void}\n     */\n    _startStreamEffect(effect) {\n        this._streamEffect = effect;\n        this._originalStream = this.stream;\n        this._setStream(this._streamEffect.startEffect(this._originalStream));\n        this.track = this.stream.getTracks()[0];\n    }\n\n    /**\n     * Stops the effect process and returns the original stream.\n     *\n     * @private\n     * @returns {void}\n     */\n    _stopStreamEffect() {\n        if (this._streamEffect) {\n            this._streamEffect.stopEffect();\n            this._setStream(this._originalStream);\n            this._originalStream = null;\n            this.track = this.stream ? this.stream.getTracks()[0] : null;\n        }\n    }\n\n    /**\n     * Switches the camera facing mode if the WebRTC implementation supports the custom MediaStreamTrack._switchCamera\n     * method. Currently, the method in question is implemented in react-native-webrtc only. When such a WebRTC\n     * implementation is executing, the method is the preferred way to switch between the front/user-facing and the\n     * back/environment-facing cameras because it will likely be (as is the case of react-native-webrtc) noticeably\n     * faster that creating a new MediaStreamTrack via a new getUserMedia call with the switched facingMode constraint\n     * value. Moreover, the approach with a new getUserMedia call may not even work: WebRTC on Android and iOS is\n     * either very slow to open the camera a second time or plainly freezes attempting to do that.\n     *\n     * @returns {void}\n     */\n    _switchCamera() {\n        if (this.isVideoTrack()\n                && this.videoType === VideoType.CAMERA\n                && typeof this.track._switchCamera === 'function') {\n            this.track._switchCamera();\n\n            this._facingMode\n                = this._facingMode === CameraFacingMode.ENVIRONMENT\n                    ? CameraFacingMode.USER\n                    : CameraFacingMode.ENVIRONMENT;\n        }\n    }\n\n    /**\n     * Stops the currently used effect (if there is one) and starts the passed effect (if there is one).\n     *\n     * @param {Object|undefined} effect - The new effect to be set.\n     * @private\n     * @returns {void}\n     */\n    _switchStreamEffect(effect) {\n        if (this._streamEffect) {\n            this._stopStreamEffect();\n            this._streamEffect = undefined;\n        }\n        if (effect) {\n            this._startStreamEffect(effect);\n        }\n    }\n\n    /**\n     * @inheritdoc\n     *\n     * Stops sending the media track. And removes it from the HTML. NOTE: Works for local tracks only.\n     *\n     * @extends JitsiTrack#dispose\n     * @returns {Promise}\n     */\n    dispose() {\n        let promise = Promise.resolve();\n\n        // Remove the effect instead of stopping it so that the original stream is restored\n        // on both the local track and on the peerconnection.\n        if (this._streamEffect) {\n            promise = this.setEffect();\n        }\n\n        if (this.conference) {\n            promise = promise.then(() => this.conference.removeTrack(this));\n        }\n\n        if (this.stream) {\n            this.stopStream();\n            this.detach();\n        }\n\n        RTCUtils.removeListener(RTCEvents.DEVICE_LIST_WILL_CHANGE, this._onDeviceListWillChange);\n\n        if (this._onAudioOutputDeviceChanged) {\n            RTCUtils.removeListener(RTCEvents.AUDIO_OUTPUT_DEVICE_CHANGED,\n                this._onAudioOutputDeviceChanged);\n        }\n\n        return promise.then(() => super.dispose());\n    }\n\n    /**\n     * Returns facing mode for video track from camera. For other cases (e.g. audio track or 'desktop' video track)\n     * returns undefined.\n     *\n     * @returns {CameraFacingMode|undefined}\n     */\n    getCameraFacingMode() {\n        if (this.isVideoTrack() && this.videoType === VideoType.CAMERA) {\n            // MediaStreamTrack#getSettings() is not implemented in many\n            // browsers, so we need feature checking here. Progress on the\n            // respective browser's implementation can be tracked at\n            // https://bugs.chromium.org/p/webrtc/issues/detail?id=2481 for\n            // Chromium and https://bugzilla.mozilla.org/show_bug.cgi?id=1213517\n            // for Firefox. Even if a browser implements getSettings() already,\n            // it might still not return anything for 'facingMode'.\n            const trackSettings = this.track.getSettings?.();\n\n            if (trackSettings && 'facingMode' in trackSettings) {\n                return trackSettings.facingMode;\n            }\n\n            if (typeof this._facingMode !== 'undefined') {\n                return this._facingMode;\n            }\n\n            // In most cases we are showing a webcam. So if we've gotten here,\n            // it should be relatively safe to assume that we are probably\n            // showing the user-facing camera.\n            return CameraFacingMode.USER;\n        }\n\n        return undefined;\n    }\n\n    /**\n     * Returns device id associated with track.\n     *\n     * @returns {string}\n     */\n    getDeviceId() {\n        return this._realDeviceId || this.deviceId;\n    }\n\n    /**\n     * Get the duration of the track.\n     *\n     * @returns {Number} the duration of the track in seconds\n     */\n    getDuration() {\n        return (Date.now() / 1000) - (this.metadata.timestamp / 1000);\n    }\n\n    /**\n     * Returns the participant id which owns the track.\n     *\n     * @returns {string} the id of the participants. It corresponds to the\n     * Colibri endpoint id/MUC nickname in case of Jitsi-meet.\n     */\n    getParticipantId() {\n        return this.conference && this.conference.myUserId();\n    }\n\n    /**\n     * Returns the source name associated with the jitsi track.\n     *\n     * @returns {string | null} source name\n     */\n    getSourceName() {\n        return this._sourceName;\n    }\n\n    /**\n     * Returns if associated MediaStreamTrack is in the 'ended' state\n     *\n     * @returns {boolean}\n     */\n    isEnded() {\n        if (this.isVideoTrack() && this.isMuted()) {\n            // If a video track is muted the readyState will be ended, that's why we need to rely only on the\n            // _trackEnded flag.\n            return this._trackEnded;\n        }\n\n        return this.getTrack().readyState === 'ended' || this._trackEnded;\n    }\n\n    /**\n     * Returns <tt>true</tt>.\n     *\n     * @returns {boolean} <tt>true</tt>\n     */\n    isLocal() {\n        return true;\n    }\n\n    /**\n     * Returns <tt>true</tt> - if the stream is muted and <tt>false</tt> otherwise.\n     *\n     * @returns {boolean} <tt>true</tt> - if the stream is muted and <tt>false</tt> otherwise.\n     */\n    isMuted() {\n        // this.stream will be null when we mute local video on Chrome\n        if (!this.stream) {\n            return true;\n        }\n        if (this.isVideoTrack() && !this.isActive()) {\n            return true;\n        }\n\n        // If currently used stream effect has its own muted state, use that.\n        if (this._streamEffect && this._streamEffect.isMuted) {\n            return this._streamEffect.isMuted();\n        }\n\n        return !this.track || !this.track.enabled;\n    }\n\n    /**\n     * Checks whether the attached MediaStream is receiving data from source or not. If the stream property is null\n     * (because of mute or another reason) this method will return false.\n     * NOTE: This method doesn't indicate problem with the streams directly. For example in case of video mute the\n     * method will return false or if the user has disposed the track.\n     *\n     * @returns {boolean} true if the stream is receiving data and false this otherwise.\n     */\n    isReceivingData() {\n        if (this.isVideoTrack()\n            && (this.isMuted() || this._stopStreamInProgress || this.videoType === VideoType.DESKTOP)) {\n            return true;\n        }\n\n        if (!this.stream) {\n            return false;\n        }\n\n        // In older version of the spec there is no muted property and readyState can have value muted. In the latest\n        // versions readyState can have values \"live\" and \"ended\" and there is muted boolean property. If the stream is\n        // muted that means that we aren't receiving any data from the source. We want to notify the users for error if\n        // the stream is muted or ended on it's creation.\n\n        // For video blur enabled use the original video stream\n        const stream = this._effectEnabled ? this._originalStream : this.stream;\n\n        return stream.getTracks().some(track =>\n            (!('readyState' in track) || track.readyState === 'live')\n                && (!('muted' in track) || track.muted !== true));\n    }\n\n    /**\n     * Asynchronously mutes this track.\n     *\n     * @returns {Promise}\n     */\n    mute() {\n        return this._queueSetMuted(true);\n    }\n\n    /**\n     * Handles bytes sent statistics. NOTE: used only for audio tracks to detect audio issues.\n     *\n     * @param {TraceablePeerConnection} tpc - The peerconnection that is reporting the bytes sent stat.\n     * @param {number} bytesSent - The new value.\n     * @returns {void}\n     */\n    onByteSentStatsReceived(tpc, bytesSent) {\n        if (bytesSent > 0) {\n            this._hasSentData = true;\n        }\n        const iceConnectionState = tpc.getConnectionState();\n\n        if (this._testDataSent && iceConnectionState === 'connected') {\n            setTimeout(() => {\n                if (!this._hasSentData) {\n                    logger.warn(`${this} 'bytes sent' <= 0: \\\n                        ${bytesSent}`);\n\n                    Statistics.analytics.sendEvent(NO_BYTES_SENT, { 'media_type': this.getType() });\n                }\n            }, 3000);\n            this._testDataSent = false;\n        }\n    }\n\n    /**\n     * Sets the JitsiConference object associated with the track. This is temp solution.\n     *\n     * @param conference - JitsiConference object.\n     * @returns {void}\n     */\n    setConference(conference) {\n        this.conference = conference;\n\n        // We want to keep up with postponed events which should have been fired\n        // on \"attach\" call, but for local track we not always have the\n        // conference before attaching. However this may result in duplicated\n        // events if they have been triggered on \"attach\" already.\n        for (let i = 0; i < this.containers.length; i++) {\n            this._maybeFireTrackAttached(this.containers[i]);\n        }\n    }\n\n    /**\n     * Sets the effect and switches between the modified stream and original one.\n     *\n     * @param {Object} effect - Represents the effect instance to be used.\n     * @returns {Promise}\n     */\n    setEffect(effect) {\n        if (typeof this._streamEffect === 'undefined' && typeof effect === 'undefined') {\n            return Promise.resolve();\n        }\n\n        if (typeof effect !== 'undefined' && !effect.isEnabled(this)) {\n            return Promise.reject(new Error('Incompatible effect instance!'));\n        }\n\n        if (this._setEffectInProgress === true) {\n            return Promise.reject(new Error('setEffect already in progress!'));\n        }\n\n        // In case we have an audio track that is being enhanced with an effect, we still want it to be applied,\n        // even if the track is muted. Where as for video the actual track doesn't exists if it's muted.\n        if (this.isMuted() && !this.isAudioTrack()) {\n            this._streamEffect = effect;\n\n            return Promise.resolve();\n        }\n\n        const conference = this.conference;\n\n        if (!conference) {\n            this._switchStreamEffect(effect);\n            if (this.isVideoTrack()) {\n                this.containers.forEach(cont => RTCUtils.attachMediaStream(cont, this.stream));\n            }\n\n            return Promise.resolve();\n        }\n\n        this._setEffectInProgress = true;\n\n        // TODO: Create new JingleSessionPC method for replacing a stream in JitsiLocalTrack without offer answer.\n        return conference.removeTrack(this)\n            .then(() => {\n                this._switchStreamEffect(effect);\n                if (this.isVideoTrack()) {\n                    this.containers.forEach(cont => RTCUtils.attachMediaStream(cont, this.stream));\n                }\n\n                return conference.addTrack(this);\n            })\n            .then(() => {\n                this._setEffectInProgress = false;\n            })\n            .catch(error => {\n                // Any error will be not recovarable and will trigger CONFERENCE_FAILED event. But let's try to cleanup\n                // everyhting related to the effect functionality.\n                this._setEffectInProgress = false;\n                this._switchStreamEffect();\n                logger.error('Failed to switch to the new stream!', error);\n                throw error;\n            });\n    }\n\n    /**\n     * Sets the source name to be used for signaling the jitsi track.\n     *\n     * @param {string} name The source name.\n     */\n    setSourceName(name) {\n        this._sourceName = name;\n    }\n\n    /**\n     * Stops the associated MediaStream.\n     *\n     * @returns {void}\n     */\n    stopStream() {\n        /**\n         * Indicates that we are executing {@link #stopStream} i.e.\n         * {@link RTCUtils#stopMediaStream} for the <tt>MediaStream</tt>\n         * associated with this <tt>JitsiTrack</tt> instance.\n         *\n         * @private\n         * @type {boolean}\n         */\n        this._stopStreamInProgress = true;\n\n        try {\n            RTCUtils.stopMediaStream(this.stream);\n        } finally {\n            this._stopStreamInProgress = false;\n        }\n    }\n\n    /**\n     * Creates a text representation of this local track instance.\n     *\n     * @return {string}\n     */\n    toString() {\n        return `LocalTrack[${this.rtcId},${this.getType()}]`;\n    }\n\n    /**\n     * Asynchronously unmutes this track.\n     *\n     * @returns {Promise}\n     */\n    unmute() {\n        return this._queueSetMuted(false);\n    }\n}\n","/* Copyright @ 2015 - Present, 8x8 Inc\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport transform from 'sdp-transform';\n\n/**\n * Rewrites the source information in the way sdp-transform expects.\n * Source information is split into multiple ssrc objects each containing\n * an id, attribute and value.\n * @param {Object} media - media description to be modified.\n * @returns {void}\n */\nconst write = function(session, opts) {\n    if (typeof session !== 'undefined' && typeof session.media !== 'undefined' && Array.isArray(session.media)) {\n        session.media.forEach(mLine => {\n            if (mLine.sources && mLine.sources.length) {\n                mLine.ssrcs = [];\n                mLine.sources.forEach(source => {\n                    Object.keys(source).forEach(attribute => {\n                        if (attribute === 'id') {\n                            return;\n                        }\n                        mLine.ssrcs.push({\n                            id: source.id,\n                            attribute,\n                            value: source[attribute]\n                        });\n                    });\n                });\n                delete mLine.sources;\n            }\n\n            // join ssrcs in ssrc groups\n            if (mLine.ssrcGroups && mLine.ssrcGroups.length) {\n                mLine.ssrcGroups.forEach(ssrcGroup => {\n                    if (typeof ssrcGroup.ssrcs !== 'undefined'\n                    && Array.isArray(ssrcGroup.ssrcs)) {\n                        ssrcGroup.ssrcs = ssrcGroup.ssrcs.join(' ');\n                    }\n                });\n            }\n        });\n    }\n\n    return transform.write(session, opts);\n};\n\n/**\n * Rewrites the source information that we get from sdp-transform.\n * All the ssrc lines with different attributes that belong to the\n * same ssrc are grouped into a single soure object with multiple key value pairs.\n * @param {Object} media - media description to be modified.\n * @returns {void}\n */\nconst parse = function(sdp) {\n    const session = transform.parse(sdp);\n\n    if (typeof session !== 'undefined' && typeof session.media !== 'undefined' && Array.isArray(session.media)) {\n        session.media.forEach(mLine => {\n            // group sources attributes by ssrc\n            if (typeof mLine.ssrcs !== 'undefined' && Array.isArray(mLine.ssrcs)) {\n                mLine.sources = [];\n                mLine.ssrcs.forEach(ssrc => {\n                    const found = mLine.sources.findIndex(source => source.id === ssrc.id);\n\n                    if (found > -1) {\n                        mLine.sources[found][ssrc.attribute] = ssrc.value;\n                    } else {\n                        const src = { id: ssrc.id };\n\n                        src[ssrc.attribute] = ssrc.value;\n                        mLine.sources.push(src);\n                    }\n                });\n                delete mLine.ssrcs;\n            }\n\n            // split ssrcs in ssrc groups\n            if (typeof mLine.ssrcGroups !== 'undefined' && Array.isArray(mLine.ssrcGroups)) {\n                mLine.ssrcGroups.forEach(ssrcGroup => {\n                    if (typeof ssrcGroup.ssrcs === 'string') {\n                        ssrcGroup.ssrcs = ssrcGroup.ssrcs.split(' ');\n                    }\n                });\n            }\n        });\n    }\n\n    return session;\n};\n\nexport default {\n    write,\n    parse\n};\n","/* Copyright @ 2015 - Present, 8x8 Inc\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport clonedeep from 'lodash.clonedeep';\n\nimport transform from './transform.js';\n\nconst PLAN_B_MIDS = [ 'audio', 'video', 'data' ];\nconst findSimGroup = ssrcGroup => ssrcGroup.find(grp => grp.semantics === 'SIM');\nconst findFidGroup = ssrcGroup => ssrcGroup.find(grp => grp.semantics === 'FID');\n\n/**\n * Add the ssrcs of the SIM group and their corresponding FID group ssrcs\n * to the m-line.\n * @param {Object} mLine - The m-line to which ssrcs have to be added.\n * @param {Object} simGroup - The SIM group whose ssrcs have to be added to\n * the m-line.\n * @param {Object} sourceGroups - inverted source-group map.\n * @param {Array<Object>} sourceList - array containing all the sources.\n */\nfunction addSimGroupSources(mLine, simGroup, sourceGroups, sourceList) {\n    if (!mLine || !simGroup) {\n        return;\n    }\n    const findSourcebyId = src => sourceList.find(source => source.id.toString() === src);\n\n    simGroup.ssrcs.forEach(src => {\n        mLine.sources.push(findSourcebyId(src));\n\n        // find the related FID group member for this ssrc.\n        const relatedFidGroup = sourceGroups[parseInt(src, 10)].find(grp => grp.semantics === 'FID');\n\n        if (relatedFidGroup) {\n            const relatedSsrc = relatedFidGroup.ssrcs.find(s => s !== src);\n\n            mLine.sources.push(findSourcebyId(relatedSsrc));\n            mLine.ssrcGroups.push(relatedFidGroup);\n        }\n    });\n\n    // Add the SIM group last.\n    mLine.ssrcGroups.push(simGroup);\n}\n\n/**\n * Add ssrcs and ssrc-groups to the m-line. When a primary ssrc, i.e., the\n * first ssrc in a SIM group is passed, all the other ssrcs from the SIM\n * group and the other ssrcs from the related FID groups are added to the same\n * m-line since they all belong to the same remote source. Since the ssrcs are\n * not guaranteed to be in the correct order, try to find if a SIM group exists,\n * if not, just add the FID group.\n * @param {Object} mLine - The m-line to which ssrcs have to be added.\n * @param {Object} ssrc - the primary ssrc.\n * @param {Object} sourceGroups - inverted source-group map.\n * @param {Array<Object>} sourceList - array containing all the sources.\n * @returns {void}\n */\nfunction addSourcesToMline(mLine, ssrc, sourceGroups, sourceList) {\n    if (!mLine || !ssrc) {\n        return;\n    }\n    mLine.sources = [];\n    mLine.ssrcGroups = [];\n\n    // If there are no associated ssrc-groups, just add the ssrc and msid.\n    if (!sourceGroups[ssrc.id]) {\n        mLine.sources.push(ssrc);\n        mLine.msid = ssrc.msid;\n\n        return;\n    }\n    const findSourcebyId = src => sourceList.find(source => source.id.toString() === src);\n\n    // Find the SIM and FID groups that this ssrc belongs to.\n    const simGroup = findSimGroup(sourceGroups[ssrc.id]);\n    const fidGroup = findFidGroup(sourceGroups[ssrc.id]);\n\n    // Add the ssrcs for the SIM group and their corresponding FID groups.\n    if (simGroup) {\n        addSimGroupSources(mLine, simGroup, sourceGroups, sourceList);\n    } else if (fidGroup) {\n        // check if the other ssrc from this FID group is part of a SIM group\n        const otherSsrc = fidGroup.ssrcs.find(s => s !== ssrc);\n        const simGroup2 = findSimGroup(sourceGroups[otherSsrc]);\n\n        if (simGroup2) {\n            addSimGroupSources(mLine, simGroup2, sourceGroups, sourceList);\n        } else {\n            // Add the FID group ssrcs.\n            fidGroup.ssrcs.forEach(src => {\n                mLine.sources.push(findSourcebyId(src));\n            });\n            mLine.ssrcGroups.push(fidGroup);\n        }\n    }\n\n    // Set the msid for the media description using the msid attribute of the ssrcs.\n    mLine.msid = mLine.sources[0].msid;\n}\n\n/**\n * Check if a new SDP requests an ICE restart.\n * @param {Object} - the parsed new SDP\n * @param {Object} - the parsed previous SDP\n * @returns {Boolean} - Returns true if an ICE restart is requested otherwise false.\n */\nfunction checkForIceRestart(newDesc, oldDesc) {\n    if (!newDesc || !oldDesc || newDesc.media.length === 0 || oldDesc.media.length === 0) {\n        return false;\n    }\n\n    const newMLine = newDesc.media[0];\n    const oldMLine = oldDesc.media[0];\n\n    return newMLine.iceUfrag !== oldMLine.iceUfrag || newMLine.icePwd !== oldMLine.icePwd;\n}\n\n/**\n * Returns a rejected m-line (with port 0) if its exists in the provided description.\n * @param {Object} desc - the current remote description.\n * @param {String} mediaType - media type.\n * @returns {Object}\n */\nfunction checkForRejectedMlines(desc, mediaType) {\n    if (!desc || !mediaType) {\n        return null;\n    }\n\n    return desc.media.find(m => m.port === 0 && m.type === mediaType);\n}\n\n/**\n * Checks if there is a mline for the given ssrc or its related primary ssrc.\n * We always implode the SIM group to the first ssrc in the SIM group before sRD,\n * so we also check if mline for that ssrc exists.\n * For example:\n * If the following ssrcs are in a SIM group,\n * <ssrc-group xmlns=\\\"urn:xmpp:jingle:apps:rtp:ssma:0\\\" semantics=\\\"SIM\\\">\n *        <source ssrc=\\\"1806330949\\\"/>\n *        <source ssrc=\\\"4173145196\\\"/>\n *        <source ssrc=\\\"2002632207\\\"/>\n * </ssrc-group>\n * This method returns true for any one of the 3 ssrcs if there is a mline for 1806330949.\n * @param {Object} ssrc - ssrc to check.\n * @param {Object} sourceGroups - inverted source-group map.\n * @param {Array<Object>} mlines - mlines in the description\n\n * @returns {Boolean} - Returns true if mline for the given ssrc or the related primary ssrc\n * exists, returns false otherwise.\n */\nfunction checkIfMlineForSsrcExists(ssrc, sourceGroups, mlines) {\n    const findMatchingMline = mline => {\n        if (mline.sources) {\n            return mline.sources.some(source => source.id === ssrc.id);\n        }\n\n        return false;\n    };\n\n    if (!mlines.find(findMatchingMline)) {\n        // check if this ssrc is member of a SIM group. If so, check if there\n        // is a matching m-line for the primary ssrc of the SIM group.\n        if (!sourceGroups[ssrc.id]) {\n            return false;\n        }\n        const simGroup = findSimGroup(sourceGroups[ssrc.id]);\n        const fidGroup = findFidGroup(sourceGroups[ssrc.id]);\n\n        if (simGroup) {\n            return mlines.some(mline => mline.sources\n                && mline.sources.some(src => src.id.toString() === simGroup.ssrcs[0]));\n        } else if (fidGroup && ssrc.id.toString() !== fidGroup.ssrcs[0]) {\n            const otherSsrc = { id: fidGroup.ssrcs[0] };\n\n            return checkIfMlineForSsrcExists(otherSsrc, sourceGroups, mlines);\n\n        }\n\n        return false;\n    }\n\n    return true;\n}\n\n/**\n * Create an inverted sourceGroup map to put all the grouped ssrcs\n * in the same m-line.\n * @param {Array<Object>} sourceGroups\n * @returns {Object} - An inverted sourceGroup map.\n */\nfunction createSourceGroupMap(sourceGroups) {\n    const ssrc2group = {};\n\n    if (!sourceGroups || !Array.isArray(sourceGroups)) {\n        return ssrc2group;\n    }\n    sourceGroups.forEach(group => {\n        if (group.ssrcs && Array.isArray(group.ssrcs)) {\n            group.ssrcs.forEach(ssrc => {\n                if (typeof ssrc2group[ssrc] === 'undefined') {\n                    ssrc2group[ssrc] = [];\n                }\n                ssrc2group[ssrc].push(group);\n            });\n        }\n    });\n\n    return ssrc2group;\n}\n\n/**\n * Interop provides an API for tranforming a Plan B SDP to a Unified Plan SDP and\n * vice versa.\n */\nexport class Interop {\n    /**\n     * This method transforms a Unified Plan SDP to an equivalent Plan B SDP.\n     * @param {RTCSessionDescription} description - The description in Unified plan format.\n     * @returns RTCSessionDescription - The transformed session description.\n     */\n    toPlanB(description) {\n        if (!description || typeof description.sdp !== 'string') {\n            console.warn('An empty description was passed as an argument.');\n\n            return description;\n        }\n\n        // Objectify the SDP for easier manipulation.\n        const session = transform.parse(description.sdp);\n\n        // If the SDP contains no media, there's nothing to transform.\n        if (!session.media || !session.media.length) {\n            console.warn('The description has no media.');\n\n            return description;\n        }\n\n        // Make sure this is a unified plan sdp\n        if (session.media.every(m => PLAN_B_MIDS.indexOf(m.mid) !== -1)) {\n            console.warn('The description does not look like unified plan sdp');\n\n            return description;\n        }\n\n        const media = {};\n        const sessionMedia = session.media;\n\n        session.media = [];\n        sessionMedia.forEach(mLine => {\n            const type = mLine.type;\n\n            if (type === 'application') {\n                mLine.mid = 'data';\n                media[mLine.mid] = mLine;\n\n                return;\n            }\n            if (typeof media[type] === 'undefined') {\n                const bLine = clonedeep(mLine);\n\n                // Copy the msid attribute to all the ssrcs if they belong to the same source group\n                if (bLine.sources && Array.isArray(bLine.sources)) {\n                    bLine.sources.forEach(source => {\n                        mLine.msid ? source.msid = mLine.msid : delete source.msid;\n                    });\n                }\n\n                // Do not signal the FID groups if there is no msid attribute present\n                // on the sources as sesison-accept with this source info will fail strophe\n                // validation and the session will not be established. This behavior is seen\n                // on Firefox (with RTX enabled) when no video source is added at the join time.\n                // FF generates two recvonly ssrcs with no msid and a corresponding FID group in\n                // this case.\n                if (!bLine.ssrcGroups || !mLine.msid) {\n                    bLine.ssrcGroups = [];\n                }\n                delete bLine.msid;\n                bLine.mid = type;\n                media[type] = bLine;\n            } else if (mLine.msid) {\n                // Add sources and source-groups to the existing m-line of the same media type.\n                if (mLine.sources && Array.isArray(mLine.sources)) {\n                    media[type].sources = (media[type].sources || []).concat(mLine.sources);\n                }\n                if (typeof mLine.ssrcGroups !== 'undefined' && Array.isArray(mLine.ssrcGroups)) {\n                    media[type].ssrcGroups = media[type].ssrcGroups.concat(mLine.ssrcGroups);\n                }\n            }\n        });\n        session.media = Object.values(media);\n\n        // Bundle the media only if it is active.\n        const bundle = [];\n\n        Object.values(media).forEach(mline => {\n            if (mline.direction !== 'inactive') {\n                bundle.push(mline.mid);\n            }\n        });\n\n        // We regenerate the BUNDLE group with the new mids.\n        session.groups.forEach(group => {\n            if (group.type === 'BUNDLE') {\n                group.mids = bundle.join(' ');\n            }\n        });\n\n        // msid semantic\n        session.msidSemantic = {\n            semantic: 'WMS',\n            token: '*'\n        };\n        const resStr = transform.write(session);\n\n        return new RTCSessionDescription({\n            type: description.type,\n            sdp: resStr\n        });\n    }\n\n    /**\n     * This method transforms a Plan B SDP to an equivalent Unified Plan SDP.\n     * @param {RTCSessionDescription} description - The description in plan-b format.\n     * @param {RTCSessionDescription} current - The current description set on\n     * the peerconnection in Unified-plan format, i.e., the readonly attribute\n     * remoteDescription on the RTCPeerConnection object.\n     * @returns RTCSessionDescription - The transformed session description.\n     */\n    toUnifiedPlan(description, current = null) {\n        if (!description || typeof description.sdp !== 'string') {\n            console.warn('An empty description was passed as an argument.');\n\n            return description;\n        }\n\n        // Objectify the SDP for easier manipulation.\n        const session = transform.parse(description.sdp);\n\n        // If the SDP contains no media, there's nothing to transform.\n        if (!session.media || !session.media.length) {\n            console.warn('The description has no media.');\n\n            return description;\n        }\n\n        // Make sure this is a plan-b sdp.\n        if (session.media.length > 3 || session.media.every(m => PLAN_B_MIDS.indexOf(m.mid) === -1)) {\n            console.warn('The description does not look like plan-b');\n\n            return description;\n        }\n        const currentDesc = current ? transform.parse(current.sdp) : null;\n        const iceRestart = checkForIceRestart(session, currentDesc);\n        const newIceUfrag = session.media[0].iceUfrag;\n        const newIcePwd = session.media[0].icePwd;\n        const newFingerprint = session.media[0].fingerprint;\n        const media = {};\n\n        session.media.forEach(mLine => {\n            const type = mLine.type;\n\n            if (type === 'application') {\n                if (!currentDesc || !currentDesc.media) {\n                    const newMline = clonedeep(mLine);\n\n                    newMline.mid = Object.keys(media).length.toString();\n                    media[mLine.mid] = newMline;\n\n                    return;\n                }\n                const mLineForData = currentDesc.media.findIndex(m => m.type === type);\n\n                if (mLineForData) {\n                    currentDesc.media[mLineForData] = mLine;\n                    currentDesc.media[mLineForData].mid = mLineForData;\n                }\n\n                return;\n            }\n\n            // Create an inverted sourceGroup map here to put all the grouped SSRCs in the same m-line.\n            const ssrc2group = createSourceGroupMap(mLine.ssrcGroups);\n\n            // If there are no sources advertised for a media type, add the description if this is the first\n            // remote offer, i.e., no current description was passed. Chrome in Unified plan does not produce\n            // recvonly ssrcs unlike Firefox and Safari.\n            if (!mLine.sources) {\n                if (!currentDesc) {\n                    const newMline = clonedeep(mLine);\n\n                    newMline.mid = Object.keys(media).length.toString();\n                    media[mLine.mid] = newMline;\n                }\n\n                return;\n            }\n            mLine.sources.forEach((ssrc, idx) => {\n                // Do not add the receive-only ssrcs that Jicofo sends in the source-add.\n                // These ssrcs do not have the \"msid\" attribute set.\n                if (!ssrc.msid) {\n                    return;\n                }\n\n                // If there is no description set on the peerconnection, create new m-lines.\n                if (!currentDesc || !currentDesc.media) {\n                    if (checkIfMlineForSsrcExists(ssrc, ssrc2group, Object.values(media))) {\n                        return;\n                    }\n                    const newMline = clonedeep(mLine);\n\n                    newMline.mid = Object.keys(media).length.toString();\n                    newMline.direction = idx\n                        ? 'sendonly'\n                        : mLine.direction === 'sendonly' ? 'sendonly' : 'sendrecv';\n                    newMline.bundleOnly = undefined;\n                    addSourcesToMline(newMline, ssrc, ssrc2group, mLine.sources);\n                    media[newMline.mid] = newMline;\n\n                    return;\n                }\n\n                // Create if the m-line for the ssrcs already exists.\n                if (checkIfMlineForSsrcExists(ssrc, ssrc2group, currentDesc.media)) {\n                    return;\n                }\n\n                // Check if a rejected m-line with port 0 exists and recycle it if so.\n                const existingMline = checkForRejectedMlines(currentDesc, type);\n\n                if (existingMline) {\n                    existingMline.port = mLine.port;\n                    existingMline.direction = 'sendonly';\n                    addSourcesToMline(existingMline, ssrc, ssrc2group, mLine.sources);\n\n                    return;\n                }\n\n                // Append a new m-line.\n                const newMline = clonedeep(mLine);\n\n                newMline.mid = currentDesc.media.length.toString();\n                newMline.direction = 'sendonly';\n                addSourcesToMline(newMline, ssrc, ssrc2group, mLine.sources);\n                currentDesc.media.push(newMline);\n            });\n        });\n        session.media = currentDesc ? currentDesc.media : Object.values(media);\n        const mids = [];\n\n        session.media.forEach(mLine => {\n            mids.push(mLine.mid);\n            if (iceRestart) {\n                mLine.iceUfrag = newIceUfrag;\n                mLine.icePwd = newIcePwd;\n                mLine.fingerprint = newFingerprint;\n            }\n        });\n\n        // We regenerate the BUNDLE group (since we regenerated the mids)\n        session.groups.forEach(group => {\n            if (group.type === 'BUNDLE') {\n                group.mids = mids.join(' ');\n            }\n        });\n\n        // msid semantic\n        session.msidSemantic = {\n            semantic: 'WMS',\n            token: '*'\n        };\n\n        // Increment the session version every time.\n        session.origin.sessionVersion++;\n        const resultSdp = transform.write(session);\n\n        return new RTCSessionDescription({\n            type: description.type,\n            sdp: resultSdp\n        });\n    }\n}\n","export enum SignalingEvents {\n    /**\n     * Event triggered when participant's muted status changes.\n     * @param {string} endpointId the track owner's identifier (MUC nickname)\n     * @param {MediaType} mediaType \"audio\" or \"video\"\n     * @param {boolean} isMuted the new muted state\n     */\n    PEER_MUTED_CHANGED = 'signaling.peerMuted',\n\n    /**\n     * Event triggered when participant's video type changes.\n     * @param {string} endpointId the video owner's ID (MUC nickname)\n     * @param {VideoType} videoType the new value\n     */\n    PEER_VIDEO_TYPE_CHANGED = 'signaling.peerVideoType'\n}\n\n// exported for backward compatibility\nexport const PEER_MUTED_CHANGED = SignalingEvents.PEER_MUTED_CHANGED;\nexport const PEER_VIDEO_TYPE_CHANGED = SignalingEvents.PEER_VIDEO_TYPE_CHANGED;\n","\nimport Listenable from '../../modules/util/Listenable';\nimport { MediaType } from '../../service/RTC/MediaType';\n\n/**\n * @typedef {string} EndpointId\n */\n/**\n * @typedef {string} SourceName\n */\n/**\n * @typedef {Object} SourceInfo\n *\n * @property {SourceName} sourceName - Name of the media source.\n * @property {boolean} [muted=false] - Tells if the source is muted (paused?).\n * @property {string} [videoType] - Type of the video for video type.\n */\n\n/**\n * Generates a source name.\n *\n * @param {EndpointId} endpointId - Jitsi Endpoint Id.\n * @param {MediaType} mediaType - the media type string.\n * @param {number} trackIdx - Track index (or sender idx? - to be figured out) starting from 0.\n * @returns {SourceName} eg. endpointA-v0\n */\nexport function getSourceNameForJitsiTrack(endpointId, mediaType, trackIdx) {\n    const firstLetterOfMediaType = mediaType.substring(0, 1);\n\n    return `${endpointId}-${firstLetterOfMediaType}${trackIdx}`;\n}\n\n/**\n * Extracts MediaType from give source name (must be in the correct format as generated by\n * {@link getSourceNameForJitsiTrack}).\n *\n * @param {SourceName} sourceName - the source name.\n * @returns {MediaType}\n */\nexport function getMediaTypeFromSourceName(sourceName) {\n    const firstLetterOfMediaTypeIdx = sourceName.indexOf('-') + 1;\n\n    if (firstLetterOfMediaTypeIdx <= 0) {\n        throw new Error(`Invalid source name: ${sourceName}`);\n    }\n\n    const firstLetterOfMediaType = sourceName.substr(firstLetterOfMediaTypeIdx, 1);\n\n    for (const type of Object.values(MediaType)) {\n        if (type.substr(0, 1) === firstLetterOfMediaType) {\n            return type;\n        }\n    }\n\n    throw new Error(`Invalid source name: ${sourceName}`);\n}\n\n/**\n * An object that carries the info about specific media type advertised by\n * participant in the signaling channel.\n * @typedef {Object} PeerMediaInfo\n * @property {boolean} muted indicates if the media is currently muted\n * @property {VideoType|undefined} videoType the type of the video if applicable\n */\n\n/**\n * Interface used to expose the information carried over the signaling channel\n * which is not available to the RTC module in the media SDP.\n *\n * @interface SignalingLayer\n */\nexport default class SignalingLayer extends Listenable {\n\n    /**\n     * Obtains the endpoint ID for given SSRC.\n     * @param {number} ssrc the SSRC number.\n     * @return {string|null} the endpoint ID for given media SSRC.\n     */\n    getSSRCOwner(ssrc) { // eslint-disable-line no-unused-vars\n        throw new Error('not implemented');\n    }\n\n    /**\n     * Obtains the info about given media advertised in the MUC presence of\n     * the participant identified by the given MUC JID.\n     * @param {string} owner the MUC jid of the participant for whom\n     * {@link PeerMediaInfo} will be obtained.\n     * @param {MediaType} mediaType the type of the media for which presence\n     * info will be obtained.\n     * @return {PeerMediaInfo|null} presenceInfo an object with media presence\n     * info or <tt>null</tt> either if there is no presence available for given\n     * JID or if the media type given is invalid.\n     *\n     * @deprecated This method is to be replaced with getPeerSourceInfo.\n     */\n    getPeerMediaInfo(owner, mediaType) { // eslint-disable-line no-unused-vars\n        throw new Error('not implemented');\n    }\n\n    /**\n     * Obtains the info about a source for given name and endpoint ID.\n     * @param {EndpointId} owner - The owner's endpoint ID.\n     * @param {SourceName} sourceName - The name of the source for which the info is to be obtained.\n     * @returns {SourceInfo | undefined}\n     */\n    getPeerSourceInfo(owner, sourceName) { // eslint-disable-line no-unused-vars\n        throw new Error('not implemented');\n    }\n\n    /**\n     * Obtains the source name for given SSRC.\n     * @param {number} ssrc the track's SSRC identifier.\n     * @returns {SourceName | undefined} the track's source name.\n     */\n    getTrackSourceName(ssrc) { // eslint-disable-line no-unused-vars\n        throw new Error('not implemented');\n    }\n}\n","import * as transform from 'sdp-transform';\n\n/**\n * Parses the primary SSRC of given SSRC group.\n * @param {object} group the SSRC group object as defined by the 'sdp-transform'\n * @return {Number} the primary SSRC number\n */\nexport function parsePrimarySSRC(group) {\n    return parseInt(group.ssrcs.split(' ')[0], 10);\n}\n\n/**\n * Parses the secondary SSRC of given SSRC group.\n * @param {object} group the SSRC group object as defined by the 'sdp-transform'\n * @return {Number} the secondary SSRC number\n */\nexport function parseSecondarySSRC(group) {\n    return parseInt(group.ssrcs.split(' ')[1], 10);\n}\n\n/**\n * Tells how many distinct SSRCs are contained in given media line.\n * @param {Object} mLine the media line object as defined by 'sdp-transform' lib\n * @return {number}\n */\nfunction _getSSRCCount(mLine) {\n    if (!mLine.ssrcs) {\n        return 0;\n    }\n\n    return mLine.ssrcs\n        .map(ssrcInfo => ssrcInfo.id)\n        .filter((ssrc, index, array) => array.indexOf(ssrc) === index)\n        .length;\n}\n\n/**\n * A wrapper around 'sdp-transform' media description object which provides\n * utility methods for common SDP/SSRC related operations.\n */\nclass MLineWrap {\n\n    /**\n     * Creates new <tt>MLineWrap</t>>\n     * @param {Object} mLine the media line object as defined by 'sdp-transform'\n     * lib.\n     */\n    constructor(mLine) {\n        if (!mLine) {\n            throw new Error('mLine is undefined');\n        }\n\n        this.mLine = mLine;\n    }\n\n    /**\n     * Getter for the mLine's \"ssrcs\" array. If the array was undefined an empty\n     * one will be preassigned.\n     *\n     * @return {Array<Object>} an array of 'sdp-transform' SSRC attributes\n     * objects.\n     */\n    get ssrcs() {\n        if (!this.mLine.ssrcs) {\n            this.mLine.ssrcs = [];\n        }\n\n        return this.mLine.ssrcs;\n    }\n\n    /**\n     * Setter for the mLine's \"ssrcs\" array.\n     *\n     * @param {Array<Object>} ssrcs an array of 'sdp-transform' SSRC attributes\n     * objects.\n     */\n    set ssrcs(ssrcs) {\n        this.mLine.ssrcs = ssrcs;\n    }\n\n    /**\n     * Returns the direction of the underlying media description.\n     * @return {string} the media direction name as defined in the SDP.\n     */\n    get direction() {\n        return this.mLine.direction;\n    }\n\n    /**\n     * Modifies the direction of the underlying media description.\n     * @param {string} direction the new direction to be set\n     */\n    set direction(direction) {\n        this.mLine.direction = direction;\n    }\n\n    /**\n     * Exposes the SSRC group array of the underlying media description object.\n     * @return {Array.<Object>}\n     */\n    get ssrcGroups() {\n        if (!this.mLine.ssrcGroups) {\n            this.mLine.ssrcGroups = [];\n        }\n\n        return this.mLine.ssrcGroups;\n    }\n\n    /**\n     * Modifies the SSRC groups array of the underlying media description\n     * object.\n     * @param {Array.<Object>} ssrcGroups\n     */\n    set ssrcGroups(ssrcGroups) {\n        this.mLine.ssrcGroups = ssrcGroups;\n    }\n\n    /**\n     * Obtains value from SSRC attribute.\n     * @param {number} ssrcNumber the SSRC number for which attribute is to be\n     * found\n     * @param {string} attrName the name of the SSRC attribute to be found.\n     * @return {string|undefined} the value of SSRC attribute or\n     * <tt>undefined</tt> if no such attribute exists.\n     */\n    getSSRCAttrValue(ssrcNumber, attrName) {\n        const attribute = this.ssrcs.find(\n            ssrcObj => ssrcObj.id === ssrcNumber\n            && ssrcObj.attribute === attrName);\n\n\n        return attribute && attribute.value;\n    }\n\n    /**\n     * Removes all attributes for given SSRC number.\n     * @param {number} ssrcNum the SSRC number for which all attributes will be\n     * removed.\n     */\n    removeSSRC(ssrcNum) {\n        if (!this.mLine.ssrcs || !this.mLine.ssrcs.length) {\n            return;\n        }\n\n        this.mLine.ssrcs\n            = this.mLine.ssrcs.filter(ssrcObj => ssrcObj.id !== ssrcNum);\n    }\n\n    /**\n     * Adds SSRC attribute\n     * @param {object} ssrcObj the SSRC attribute object as defined in\n     * the 'sdp-transform' lib.\n     */\n    addSSRCAttribute(ssrcObj) {\n        this.ssrcs.push(ssrcObj);\n    }\n\n    /**\n     * Finds a SSRC group matching both semantics and SSRCs in order.\n     * @param {string} semantics the name of the semantics\n     * @param {string} [ssrcs] group SSRCs as a string (like it's defined in\n     * SSRC group object of the 'sdp-transform' lib) e.g. \"1232546 342344 25434\"\n     * @return {object|undefined} the SSRC group object or <tt>undefined</tt> if\n     * not found.\n     */\n    findGroup(semantics, ssrcs) {\n        return this.ssrcGroups.find(\n            group =>\n                group.semantics === semantics\n                    && (!ssrcs || ssrcs === group.ssrcs));\n    }\n\n    /**\n     * Finds all groups matching given semantic's name.\n     * @param {string} semantics the name of the semantics\n     * @return {Array.<object>} an array of SSRC group objects as defined by\n     * the 'sdp-transform' lib.\n     */\n    findGroups(semantics) {\n        return this.ssrcGroups.filter(\n            group => group.semantics === semantics);\n    }\n\n    /**\n     * Finds all groups matching given semantic's name and group's primary SSRC.\n     * @param {string} semantics the name of the semantics\n     * @param {number} primarySSRC the primary SSRC number to be matched\n     * @return {Object} SSRC group object as defined by the 'sdp-transform' lib.\n     */\n    findGroupByPrimarySSRC(semantics, primarySSRC) {\n        return this.ssrcGroups.find(\n            group => group.semantics === semantics\n                && parsePrimarySSRC(group) === primarySSRC);\n    }\n\n    /**\n     * @param {string|null} msid the media stream id or <tt>null</tt> to match\n     * the first SSRC object with any 'msid' value.\n     * @return {Object|undefined} the SSRC object as defined by 'sdp-transform'\n     * lib.\n     */\n    findSSRCByMSID(msid) {\n        return this.ssrcs.find(\n            ssrcObj => ssrcObj.attribute === 'msid'\n                && (msid === null || ssrcObj.value === msid));\n    }\n\n    /**\n     * Gets the SSRC count for the underlying media description.\n     * @return {number}\n     */\n    getSSRCCount() {\n        return _getSSRCCount(this.mLine);\n    }\n\n    /**\n     * Checks whether the underlying media description contains any SSRC groups.\n     * @return {boolean} <tt>true</tt> if there are any SSRC groups or\n     * <tt>false</tt> otherwise.\n     */\n    containsAnySSRCGroups() {\n        return this.mLine.ssrcGroups !== undefined;\n    }\n\n    /**\n     * Finds the primary video SSRC.\n     * @returns {number|undefined} the primary video ssrc\n     * @throws Error if the underlying media description is not a video\n     */\n    getPrimaryVideoSsrc() {\n        const mediaType = this.mLine.type;\n\n        if (mediaType !== 'video') {\n            throw new Error(\n                `getPrimarySsrc doesn't work with '${mediaType}'`);\n        }\n\n        const numSsrcs = _getSSRCCount(this.mLine);\n\n        if (numSsrcs === 1) {\n            // Not using \"ssrcs\" getter on purpose here\n            return this.mLine.ssrcs[0].id;\n        }\n\n        // Look for a SIM, FID, or FEC-FR group\n        if (this.mLine.ssrcGroups) {\n            const simGroup = this.findGroup('SIM');\n\n            if (simGroup) {\n                return parsePrimarySSRC(simGroup);\n            }\n            const fidGroup = this.findGroup('FID');\n\n            if (fidGroup) {\n                return parsePrimarySSRC(fidGroup);\n            }\n            const fecGroup = this.findGroup('FEC-FR');\n\n            if (fecGroup) {\n                return parsePrimarySSRC(fecGroup);\n            }\n        }\n\n    }\n\n    /**\n     * Obtains RTX SSRC from the underlying video description (the\n     * secondary SSRC of the first \"FID\" group found)\n     * @param {number} primarySsrc the video ssrc for which to find the\n     * corresponding rtx ssrc\n     * @returns {number|undefined} the rtx ssrc (or undefined if there isn't\n     * one)\n     */\n    getRtxSSRC(primarySsrc) {\n        const fidGroup = this.findGroupByPrimarySSRC('FID', primarySsrc);\n\n\n        return fidGroup && parseSecondarySSRC(fidGroup);\n    }\n\n    /**\n     * Obtains all SSRCs contained in the underlying media description.\n     * @return {Array.<number>} an array with all SSRC as numbers.\n     */\n    getSSRCs() {\n        return this.ssrcs\n            .map(ssrcInfo => ssrcInfo.id)\n            .filter((ssrc, index, array) => array.indexOf(ssrc) === index);\n    }\n\n    /**\n     * Obtains primary video SSRCs.\n     * @return {Array.<number>} an array of all primary video SSRCs as numbers.\n     * @throws Error if the wrapped media description is not a video.\n     */\n    getPrimaryVideoSSRCs() {\n        const mediaType = this.mLine.type;\n\n        if (mediaType !== 'video') {\n            throw new Error(\n                `getPrimaryVideoSSRCs doesn't work with ${mediaType}`);\n        }\n\n        const videoSSRCs = this.getSSRCs();\n\n        for (const ssrcGroupInfo of this.ssrcGroups) {\n            // Right now, FID and FEC-FR groups are the only ones we parse to\n            // disqualify streams.  If/when others arise we'll\n            // need to add support for them here\n            if (ssrcGroupInfo.semantics === 'FID'\n                    || ssrcGroupInfo.semantics === 'FEC-FR') {\n                // secondary streams should be filtered out\n                const secondarySsrc = parseSecondarySSRC(ssrcGroupInfo);\n\n                videoSSRCs.splice(\n                    videoSSRCs.indexOf(secondarySsrc), 1);\n            }\n        }\n\n        return videoSSRCs;\n    }\n\n    /**\n     * Dumps all SSRC groups of this media description to JSON.\n     */\n    dumpSSRCGroups() {\n        return JSON.stringify(this.mLine.ssrcGroups);\n    }\n\n    /**\n     * Removes all SSRC groups which contain given SSRC number at any position.\n     * @param {number} ssrc the SSRC for which all matching groups are to be\n     * removed.\n     */\n    removeGroupsWithSSRC(ssrc) {\n        if (!this.mLine.ssrcGroups) {\n            return;\n        }\n\n        this.mLine.ssrcGroups = this.mLine.ssrcGroups\n            .filter(groupInfo => groupInfo.ssrcs.indexOf(`${ssrc}`) === -1);\n    }\n\n    /**\n     * Removes groups that match given semantics.\n     * @param {string} semantics e.g. \"SIM\" or \"FID\"\n     */\n    removeGroupsBySemantics(semantics) {\n        if (!this.mLine.ssrcGroups) {\n            return;\n        }\n\n        this.mLine.ssrcGroups\n            = this.mLine.ssrcGroups\n                .filter(groupInfo => groupInfo.semantics !== semantics);\n    }\n\n    /**\n     * Replaces SSRC (does not affect SSRC groups, but only attributes).\n     * @param {number} oldSSRC the old SSRC number\n     * @param {number} newSSRC the new SSRC number\n     */\n    replaceSSRC(oldSSRC, newSSRC) {\n        if (this.mLine.ssrcs) {\n            this.mLine.ssrcs.forEach(ssrcInfo => {\n                if (ssrcInfo.id === oldSSRC) {\n                    ssrcInfo.id = newSSRC;\n                }\n            });\n        }\n    }\n\n    /**\n     * Adds given SSRC group to this media description.\n     * @param {object} group the SSRC group object as defined by\n     * the 'sdp-transform' lib.\n     */\n    addSSRCGroup(group) {\n        this.ssrcGroups.push(group);\n    }\n}\n\n/**\n * Utility class for SDP manipulation using the 'sdp-transform' library.\n *\n * Typical use usage scenario:\n *\n * const transformer = new SdpTransformWrap(rawSdp);\n * const videoMLine = transformer.selectMedia('video);\n * if (videoMLine) {\n *     videoMLiner.addSSRCAttribute({\n *         id: 2342343,\n *         attribute: \"cname\",\n *         value: \"someCname\"\n *     });\n *     rawSdp = transformer.toRawSdp();\n * }\n */\nexport class SdpTransformWrap {\n\n    /**\n     * Creates new instance and parses the raw SDP into objects using\n     * 'sdp-transform' lib.\n     * @param {string} rawSDP the SDP in raw text format.\n     */\n    constructor(rawSDP) {\n        this.parsedSDP = transform.parse(rawSDP);\n    }\n\n    /**\n     * Selects all the m-lines from the SDP for a given media type.\n     *\n     * @param {string} mediaType the name of the media e.g. 'audio', 'video', 'data'.\n     * @return {MLineWrap|null} return {@link MLineWrap} instance for the media line or <tt>null</tt> if not found. The\n     * object returned references the underlying SDP state held by this <tt>SdpTransformWrap</tt> instance (it's not a\n     * copy).\n     */\n    selectMedia(mediaType) {\n        const selectedMLines = this.parsedSDP.media\n            .filter(mLine => mLine.type === mediaType)\n            .map(mLine => new MLineWrap(mLine));\n\n        return selectedMLines ?? null;\n    }\n\n    /**\n     * Converts the currently stored SDP state in this instance to raw text SDP\n     * format.\n     * @return {string}\n     */\n    toRawSDP() {\n        return transform.write(this.parsedSDP);\n    }\n}\n","import { getLogger } from '@jitsi/logger';\n\nimport MediaDirection from '../../service/RTC/MediaDirection';\nimport { MediaType } from '../../service/RTC/MediaType';\nimport { getSourceNameForJitsiTrack } from '../../service/RTC/SignalingLayer';\nimport { VideoType } from '../../service/RTC/VideoType';\nimport FeatureFlags from '../flags/FeatureFlags';\n\nimport { SdpTransformWrap } from './SdpTransformUtil';\n\nconst logger = getLogger(__filename);\n\n/**\n * Fakes local SDP exposed to {@link JingleSessionPC} through the local\n * description getter. Modifies the SDP, so that it will contain muted local\n * video tracks description, even though their underlying {MediaStreamTrack}s\n * are no longer in the WebRTC peerconnection. That prevents from SSRC updates\n * being sent to Jicofo/remote peer and prevents sRD/sLD cycle on the remote\n * side.\n */\nexport default class LocalSdpMunger {\n\n    /**\n     * Creates new <tt>LocalSdpMunger</tt> instance.\n     *\n     * @param {TraceablePeerConnection} tpc\n     * @param {string} localEndpointId - The endpoint id of the local user.\n     */\n    constructor(tpc, localEndpointId) {\n        this.tpc = tpc;\n        this.localEndpointId = localEndpointId;\n    }\n\n    /**\n     * Makes sure that muted local video tracks associated with the parent\n     * {@link TraceablePeerConnection} are described in the local SDP. It's done\n     * in order to prevent from sending 'source-remove'/'source-add' Jingle\n     * notifications when local video track is muted (<tt>MediaStream</tt> is\n     * removed from the peerconnection).\n     *\n     * NOTE 1 video track is assumed\n     *\n     * @param {SdpTransformWrap} transformer the transformer instance which will\n     * be used to process the SDP.\n     * @return {boolean} <tt>true</tt> if there were any modifications to\n     * the SDP wrapped by <tt>transformer</tt>.\n     * @private\n     */\n    _addMutedLocalVideoTracksToSDP(transformer) {\n        // Go over each video tracks and check if the SDP has to be changed\n        const localVideos = this.tpc.getLocalTracks(MediaType.VIDEO);\n\n        if (!localVideos.length) {\n            return false;\n        } else if (localVideos.length !== 1) {\n            logger.error(\n                `${this.tpc} there is more than 1 video track ! `\n                    + 'Strange things may happen !', localVideos);\n        }\n\n        const videoMLine = transformer.selectMedia(MediaType.VIDEO)?.[0];\n\n        if (!videoMLine) {\n            logger.debug(\n                `${this.tpc} unable to hack local video track SDP`\n                    + '- no \"video\" media');\n\n            return false;\n        }\n\n        let modified = false;\n\n        for (const videoTrack of localVideos) {\n            const muted = videoTrack.isMuted();\n            const mediaStream = videoTrack.getOriginalStream();\n            const isCamera = videoTrack.videoType === VideoType.CAMERA;\n\n            // During the mute/unmute operation there are periods of time when\n            // the track's underlying MediaStream is not added yet to\n            // the PeerConnection. The SDP needs to be munged in such case.\n            const isInPeerConnection\n                = mediaStream && this.tpc.isMediaStreamInPc(mediaStream);\n            const shouldFakeSdp = isCamera && (muted || !isInPeerConnection);\n\n            if (!shouldFakeSdp) {\n                continue; // eslint-disable-line no-continue\n            }\n\n            // Inject removed SSRCs\n            const requiredSSRCs\n                = this.tpc.isSimulcastOn()\n                    ? this.tpc.simulcast.ssrcCache\n                    : [ this.tpc.sdpConsistency.cachedPrimarySsrc ];\n\n            if (!requiredSSRCs.length) {\n                logger.error(`No SSRCs stored for: ${videoTrack} in ${this.tpc}`);\n\n                continue; // eslint-disable-line no-continue\n            }\n\n            modified = true;\n\n            // We need to fake sendrecv.\n            // NOTE the SDP produced here goes only to Jicofo and is never set\n            // as localDescription. That's why\n            // TraceablePeerConnection.mediaTransferActive is ignored here.\n            videoMLine.direction = MediaDirection.SENDRECV;\n\n            // Check if the recvonly has MSID\n            const primarySSRC = requiredSSRCs[0];\n\n            // FIXME The cname could come from the stream, but may turn out to\n            // be too complex. It is fine to come up with any value, as long as\n            // we only care about the actual SSRC values when deciding whether\n            // or not an update should be sent.\n            const primaryCname = `injected-${primarySSRC}`;\n\n            for (const ssrcNum of requiredSSRCs) {\n                // Remove old attributes\n                videoMLine.removeSSRC(ssrcNum);\n\n                // Inject\n                videoMLine.addSSRCAttribute({\n                    id: ssrcNum,\n                    attribute: 'cname',\n                    value: primaryCname\n                });\n                videoMLine.addSSRCAttribute({\n                    id: ssrcNum,\n                    attribute: 'msid',\n                    value: videoTrack.storedMSID\n                });\n            }\n            if (requiredSSRCs.length > 1) {\n                const group = {\n                    ssrcs: requiredSSRCs.join(' '),\n                    semantics: 'SIM'\n                };\n\n                if (!videoMLine.findGroup(group.semantics, group.ssrcs)) {\n                    // Inject the group\n                    videoMLine.addSSRCGroup(group);\n                }\n            }\n\n            // Insert RTX\n            // FIXME in P2P RTX is used by Chrome regardless of config option\n            // status. Because of that 'source-remove'/'source-add'\n            // notifications are still sent to remove/add RTX SSRC and FID group\n            if (!this.tpc.options.disableRtx) {\n                this.tpc.rtxModifier.modifyRtxSsrcs2(videoMLine);\n            }\n        }\n\n        return modified;\n    }\n\n    /**\n     * Returns a string that can be set as the MSID attribute for a source.\n     *\n     * @param {string} mediaType - Media type of the source.\n     * @param {string} trackId - Id of the MediaStreamTrack associated with the source.\n     * @param {string} streamId - Id of the MediaStream associated with the source.\n     * @returns {string|null}\n     */\n    _generateMsidAttribute(mediaType, trackId, streamId = null) {\n        if (!(mediaType && trackId)) {\n            logger.warn(`Unable to munge local MSID - track id=${trackId} or media type=${mediaType} is missing`);\n\n            return null;\n        }\n        const pcId = this.tpc.id;\n\n        // Handle a case on Firefox when the browser doesn't produce a 'a:ssrc' line with the 'msid' attribute or has\n        // '-' for the stream id part of the msid line. Jicofo needs an unique identifier to be associated with a ssrc\n        // and uses the msid for that.\n        if (streamId === '-' || !streamId) {\n            return `${this.localEndpointId}-${mediaType}-${pcId} ${trackId}-${pcId}`;\n        }\n\n        return `${streamId}-${pcId} ${trackId}-${pcId}`;\n    }\n\n    /**\n     * Modifies 'cname', 'msid', 'label' and 'mslabel' by appending the id of {@link LocalSdpMunger#tpc} at the end,\n     * preceding by a dash sign.\n     *\n     * @param {MLineWrap} mediaSection - The media part (audio or video) of the session description which will be\n     * modified in place.\n     * @returns {void}\n     * @private\n     */\n    _transformMediaIdentifiers(mediaSection) {\n        const mediaType = mediaSection.mLine?.type;\n        const pcId = this.tpc.id;\n        const sourceToMsidMap = new Map();\n\n        for (const ssrcLine of mediaSection.ssrcs) {\n            switch (ssrcLine.attribute) {\n            case 'cname':\n            case 'label':\n            case 'mslabel':\n                ssrcLine.value = ssrcLine.value && `${ssrcLine.value}-${pcId}`;\n                break;\n            case 'msid': {\n                if (ssrcLine.value) {\n                    const streamAndTrackIDs = ssrcLine.value.split(' ');\n\n                    let streamId = streamAndTrackIDs[0];\n                    const trackId = streamAndTrackIDs[1];\n\n                    // eslint-disable-next-line max-depth\n                    if (FeatureFlags.isMultiStreamSupportEnabled()\n                        && this.tpc.usesUnifiedPlan()\n                        && mediaType === MediaType.VIDEO) {\n\n                        // eslint-disable-next-line max-depth\n                        if (streamId === '-' || !streamId) {\n                            streamId = `${this.localEndpointId}-${mediaType}`;\n                        }\n\n                        // eslint-disable-next-line max-depth\n                        if (!sourceToMsidMap.has(trackId)) {\n                            streamId = `${streamId}-${sourceToMsidMap.size}`;\n                            sourceToMsidMap.set(trackId, streamId);\n                        }\n                    }\n\n                    ssrcLine.value = this._generateMsidAttribute(mediaType, trackId, sourceToMsidMap.get(trackId));\n                } else {\n                    logger.warn(`Unable to munge local MSID - weird format detected: ${ssrcLine.value}`);\n                }\n                break;\n            }\n            }\n        }\n\n        // Additional transformations related to MSID are applicable to Unified-plan implementation only.\n        if (!this.tpc.usesUnifiedPlan()) {\n            return;\n        }\n\n        // If the msid attribute is missing, then remove the ssrc from the transformed description so that a\n        // source-remove is signaled to Jicofo. This happens when the direction of the transceiver (or m-line)\n        // is set to 'inactive' or 'recvonly' on Firefox, Chrome (unified) and Safari.\n        const mediaDirection = mediaSection.mLine?.direction;\n\n        if (mediaDirection === MediaDirection.RECVONLY || mediaDirection === MediaDirection.INACTIVE) {\n            mediaSection.ssrcs = undefined;\n            mediaSection.ssrcGroups = undefined;\n\n        // Add the msid attribute if it is missing when the direction is sendrecv/sendonly. Firefox doesn't produce a\n        // a=ssrc line with msid attribute for p2p connection.\n        } else {\n            const msidLine = mediaSection.mLine?.msid;\n            const trackId = msidLine && msidLine.split(' ')[1];\n            const sources = [ ...new Set(mediaSection.mLine?.ssrcs?.map(s => s.id)) ];\n\n            for (const source of sources) {\n                const msidExists = mediaSection.ssrcs\n                    .find(ssrc => ssrc.id === source && ssrc.attribute === 'msid');\n\n                if (!msidExists) {\n                    const generatedMsid = this._generateMsidAttribute(mediaType, trackId);\n\n                    mediaSection.ssrcs.push({\n                        id: source,\n                        attribute: 'msid',\n                        value: generatedMsid\n                    });\n                }\n            }\n        }\n    }\n\n    /**\n     * Maybe modifies local description to fake local video tracks SDP when\n     * those are muted.\n     *\n     * @param {object} desc the WebRTC SDP object instance for the local\n     * description.\n     * @returns {RTCSessionDescription}\n     */\n    maybeAddMutedLocalVideoTracksToSDP(desc) {\n        if (!desc) {\n            throw new Error('No local description passed in.');\n        }\n\n        const transformer = new SdpTransformWrap(desc.sdp);\n\n        if (this._addMutedLocalVideoTracksToSDP(transformer)) {\n            return new RTCSessionDescription({\n                type: desc.type,\n                sdp: transformer.toRawSDP()\n            });\n        }\n\n        return desc;\n    }\n\n    /**\n     * This transformation will make sure that stream identifiers are unique\n     * across all of the local PeerConnections even if the same stream is used\n     * by multiple instances at the same time.\n     * Each PeerConnection assigns different SSRCs to the same local\n     * MediaStream, but the MSID remains the same as it's used to identify\n     * the stream by the WebRTC backend. The transformation will append\n     * {@link TraceablePeerConnection#id} at the end of each stream's identifier\n     * (\"cname\", \"msid\", \"label\" and \"mslabel\").\n     *\n     * @param {RTCSessionDescription} sessionDesc - The local session\n     * description (this instance remains unchanged).\n     * @return {RTCSessionDescription} - Transformed local session description\n     * (a modified copy of the one given as the input).\n     */\n    transformStreamIdentifiers(sessionDesc) {\n        // FIXME similar check is probably duplicated in all other transformers\n        if (!sessionDesc || !sessionDesc.sdp || !sessionDesc.type) {\n            return sessionDesc;\n        }\n\n        const transformer = new SdpTransformWrap(sessionDesc.sdp);\n        const audioMLine = transformer.selectMedia(MediaType.AUDIO)?.[0];\n\n        if (audioMLine) {\n            this._transformMediaIdentifiers(audioMLine);\n            this._injectSourceNames(audioMLine);\n        }\n\n        const videoMLine = transformer.selectMedia(MediaType.VIDEO)?.[0];\n\n        if (videoMLine) {\n            this._transformMediaIdentifiers(videoMLine);\n            this._injectSourceNames(videoMLine);\n        }\n\n        return new RTCSessionDescription({\n            type: sessionDesc.type,\n            sdp: transformer.toRawSDP()\n        });\n    }\n\n    /**\n     * Injects source names. Source names are need to for multiple streams per endpoint support. The final plan is to\n     * use the \"mid\" attribute for source names, but because the SDP to Jingle conversion still operates in the Plan-B\n     * semantics (one source name per media), a custom \"name\" attribute is injected into SSRC lines..\n     *\n     * @param {MLineWrap} mediaSection - The media part (audio or video) of the session description which will be\n     * modified in place.\n     * @returns {void}\n     * @private\n     */\n    _injectSourceNames(mediaSection) {\n        if (!FeatureFlags.isSourceNameSignalingEnabled()) {\n            return;\n        }\n\n        const sources = [ ...new Set(mediaSection.mLine?.ssrcs?.map(s => s.id)) ];\n        const mediaType = mediaSection.mLine?.type;\n\n        if (!mediaType) {\n            throw new Error('_transformMediaIdentifiers - no media type in mediaSection');\n        }\n\n        for (const source of sources) {\n            const nameExists = mediaSection.ssrcs.find(ssrc => ssrc.id === source && ssrc.attribute === 'name');\n\n            if (!nameExists) {\n                // Inject source names as a=ssrc:3124985624 name:endpointA-v0\n                mediaSection.ssrcs.push({\n                    id: source,\n                    attribute: 'name',\n                    value: getSourceNameForJitsiTrack(this.localEndpointId, mediaType, 0)\n                });\n            }\n        }\n    }\n}\n","import { getLogger } from '@jitsi/logger';\n\nimport MediaDirection from '../../service/RTC/MediaDirection';\nimport { MediaType } from '../../service/RTC/MediaType';\n\nimport SDPUtil from './SDPUtil';\nimport { parseSecondarySSRC, SdpTransformWrap } from './SdpTransformUtil';\n\nconst logger = getLogger(__filename);\n\n/**\n * Begin helper functions\n */\n/**\n * Updates or inserts the appropriate rtx information for primarySsrc with\n *  the given rtxSsrc.  If no rtx ssrc for primarySsrc currently exists, it will\n *  add the appropriate ssrc and ssrc group lines.  If primarySsrc already has\n *  an rtx ssrc, the appropriate ssrc and group lines will be updated\n * @param {MLineWrap} mLine\n * @param {object} primarySsrcInfo the info (ssrc, msid & cname) for the\n *  primary ssrc\n * @param {number} rtxSsrc the rtx ssrc to associate with the primary ssrc\n */\nfunction updateAssociatedRtxStream(mLine, primarySsrcInfo, rtxSsrc) {\n    const primarySsrc = primarySsrcInfo.id;\n    const primarySsrcMsid = primarySsrcInfo.msid;\n    const primarySsrcCname = primarySsrcInfo.cname;\n\n    const previousRtxSSRC = mLine.getRtxSSRC(primarySsrc);\n\n    if (previousRtxSSRC === rtxSsrc) {\n        return;\n    }\n    if (previousRtxSSRC) {\n        // Stream already had an rtx ssrc that is different than the one given,\n        //  remove all trace of the old one\n        mLine.removeSSRC(previousRtxSSRC);\n        mLine.removeGroupsWithSSRC(previousRtxSSRC);\n    }\n    mLine.addSSRCAttribute({\n        id: rtxSsrc,\n        attribute: 'cname',\n        value: primarySsrcCname\n    });\n    mLine.addSSRCAttribute({\n        id: rtxSsrc,\n        attribute: 'msid',\n        value: primarySsrcMsid\n    });\n    mLine.addSSRCGroup({\n        semantics: 'FID',\n        ssrcs: `${primarySsrc} ${rtxSsrc}`\n    });\n}\n\n/**\n * End helper functions\n */\n\n/**\n * Adds any missing RTX streams for video streams\n *  and makes sure that they remain consistent\n */\nexport default class RtxModifier {\n    /**\n     * Constructor\n     */\n    constructor() {\n        /**\n         * Map of video ssrc to corresponding RTX\n         *  ssrc\n         */\n        this.correspondingRtxSsrcs = new Map();\n    }\n\n    /**\n     * Clear the cached map of primary video ssrcs to\n     *  their corresponding rtx ssrcs so that they will\n     *  not be used for the next call to modifyRtxSsrcs\n     */\n    clearSsrcCache() {\n        this.correspondingRtxSsrcs.clear();\n    }\n\n    /**\n     * Explicitly set the primary video ssrc -> rtx ssrc\n     *  mapping to be used in modifyRtxSsrcs\n     * @param {Map} ssrcMapping a mapping of primary video\n     *  ssrcs to their corresponding rtx ssrcs\n     */\n    setSsrcCache(ssrcMapping) {\n        logger.debug('Setting ssrc cache to ', ssrcMapping);\n        this.correspondingRtxSsrcs = ssrcMapping;\n    }\n\n    /**\n     * Adds RTX ssrcs for any video ssrcs that don't already have them.  If the video ssrc has been seen before, and\n     * already had an RTX ssrc generated, the same RTX ssrc will be used again.\n     *\n     * @param {string} sdpStr sdp in raw string format\n     * @returns {string} The modified sdp in raw string format.\n     */\n    modifyRtxSsrcs(sdpStr) {\n        let modified = false;\n        const sdpTransformer = new SdpTransformWrap(sdpStr);\n        const videoMLines = sdpTransformer.selectMedia(MediaType.VIDEO);\n\n        if (!videoMLines?.length) {\n            logger.debug(`No 'video' media found in the sdp: ${sdpStr}`);\n\n            return sdpStr;\n        }\n\n        for (const videoMLine of videoMLines) {\n            if (this.modifyRtxSsrcs2(videoMLine)) {\n                modified = true;\n            }\n        }\n\n        return modified ? sdpTransformer.toRawSDP() : sdpStr;\n    }\n\n    /**\n     * Does the same thing as {@link modifyRtxSsrcs}, but takes the {@link MLineWrap} instance wrapping video media as\n     * an argument.\n     * @param {MLineWrap} videoMLine\n     * @return {boolean} <tt>true</tt> if the SDP wrapped by {@link SdpTransformWrap} has been modified or\n     * <tt>false</tt> otherwise.\n     */\n    modifyRtxSsrcs2(videoMLine) {\n        if (videoMLine.direction === MediaDirection.RECVONLY) {\n            return false;\n        }\n        if (videoMLine.getSSRCCount() < 1) {\n            return false;\n        }\n        const primaryVideoSsrcs = videoMLine.getPrimaryVideoSSRCs();\n\n        for (const ssrc of primaryVideoSsrcs) {\n            const msid = videoMLine.getSSRCAttrValue(ssrc, 'msid');\n            const cname = videoMLine.getSSRCAttrValue(ssrc, 'cname');\n            let correspondingRtxSsrc = this.correspondingRtxSsrcs.get(ssrc);\n\n            if (!correspondingRtxSsrc) {\n                // If there's one in the sdp already for it, we'll just set\n                //  that as the corresponding one\n                const previousAssociatedRtxStream = videoMLine.getRtxSSRC(ssrc);\n\n                if (previousAssociatedRtxStream) {\n                    correspondingRtxSsrc = previousAssociatedRtxStream;\n                } else {\n                    correspondingRtxSsrc = SDPUtil.generateSsrc();\n                }\n                this.correspondingRtxSsrcs.set(ssrc, correspondingRtxSsrc);\n            }\n            updateAssociatedRtxStream(\n                videoMLine,\n                {\n                    id: ssrc,\n                    cname,\n                    msid\n                },\n                correspondingRtxSsrc);\n        }\n\n        // FIXME we're not looking into much details whether the SDP has been\n        // modified or not once the precondition requirements are met.\n        return true;\n    }\n\n    /**\n     * Strip all rtx streams from the given sdp.\n     *\n     * @param {string} sdpStr sdp in raw string format\n     * @returns {string} sdp string with all rtx streams stripped\n     */\n    stripRtx(sdpStr) {\n        const sdpTransformer = new SdpTransformWrap(sdpStr);\n        const videoMLines = sdpTransformer.selectMedia(MediaType.VIDEO);\n\n        if (!videoMLines?.length) {\n            logger.debug(`No 'video' media found in the sdp: ${sdpStr}`);\n\n            return sdpStr;\n        }\n\n        for (const videoMLine of videoMLines) {\n            if (videoMLine.direction !== MediaDirection.RECVONLY\n                && videoMLine.getSSRCCount()\n                && videoMLine.containsAnySSRCGroups()) {\n                const fidGroups = videoMLine.findGroups('FID');\n\n                // Remove the fid groups from the mline\n                videoMLine.removeGroupsBySemantics('FID');\n\n                // Get the rtx ssrcs and remove them from the mline\n                for (const fidGroup of fidGroups) {\n                    const rtxSsrc = parseSecondarySSRC(fidGroup);\n\n                    videoMLine.removeSSRC(rtxSsrc);\n                }\n            }\n        }\n\n        return sdpTransformer.toRawSDP();\n    }\n}\n","import { getLogger } from '@jitsi/logger';\n\nimport { MediaType } from '../../service/RTC/MediaType';\n\nimport {\n    parsePrimarySSRC,\n    parseSecondarySSRC,\n    SdpTransformWrap\n} from './SdpTransformUtil';\n\nconst logger = getLogger(__filename);\n\n/**\n * Handles the work of keeping video ssrcs consistent across multiple\n * o/a cycles, making it such that all stream operations can be\n * kept local and do not need to be signaled.\n * NOTE: This only keeps the 'primary' video ssrc consistent: meaning\n * the primary video stream\n */\nexport default class SdpConsistency {\n    /**\n     * Constructor\n     * @param {string} logPrefix the log prefix appended to every logged\n     * message, currently used to distinguish for which\n     * <tt>TraceablePeerConnection</tt> the instance works.\n     */\n    constructor(logPrefix) {\n        this.clearVideoSsrcCache();\n        this.logPrefix = logPrefix;\n    }\n\n    /**\n     * Clear the cached video primary and primary rtx ssrcs so that\n     *  they will not be used for the next call to\n     *  makeVideoPrimarySsrcsConsistent\n     */\n    clearVideoSsrcCache() {\n        this.cachedPrimarySsrc = null;\n        this.injectRecvOnly = false;\n    }\n\n    /**\n     * Explicitly set the primary ssrc to be used in\n     *  makeVideoPrimarySsrcsConsistent\n     * @param {number} primarySsrc the primarySsrc to be used\n     *  in future calls to makeVideoPrimarySsrcsConsistent\n     * @throws Error if <tt>primarySsrc</tt> is not a number\n     */\n    setPrimarySsrc(primarySsrc) {\n        if (typeof primarySsrc !== 'number') {\n            throw new Error('Primary SSRC must be a number!');\n        }\n        this.cachedPrimarySsrc = primarySsrc;\n    }\n\n    /**\n     * Checks whether or not there is a primary video SSRC cached already.\n     * @return {boolean}\n     */\n    hasPrimarySsrcCached() {\n        return Boolean(this.cachedPrimarySsrc);\n    }\n\n    /**\n     * Given an sdp string, either:\n     *  1) record the primary video and primary rtx ssrcs to be\n     *   used in future calls to makeVideoPrimarySsrcsConsistent or\n     *  2) change the primary and primary rtx ssrcs in the given sdp\n     *   to match the ones previously cached\n     * @param {string} sdpStr the sdp string to (potentially)\n     *  change to make the video ssrcs consistent\n     * @returns {string} a (potentially) modified sdp string\n     *  with ssrcs consistent with this class' cache\n     */\n    makeVideoPrimarySsrcsConsistent(sdpStr) {\n        const sdpTransformer = new SdpTransformWrap(sdpStr);\n        const videoMLine = sdpTransformer.selectMedia(MediaType.VIDEO)?.[0];\n\n        if (!videoMLine) {\n            logger.debug(`${this.logPrefix} no 'video' media found in the sdp: ${sdpStr}`);\n\n            return sdpStr;\n        }\n\n        if (videoMLine.direction === 'recvonly') {\n            // If the mline is recvonly, we'll add the primary\n            //  ssrc as a recvonly ssrc\n            if (this.cachedPrimarySsrc && this.injectRecvOnly) {\n                videoMLine.addSSRCAttribute({\n                    id: this.cachedPrimarySsrc,\n                    attribute: 'cname',\n                    value: `recvonly-${this.cachedPrimarySsrc}`\n                });\n            } else {\n                logger.info(`${this.logPrefix} no SSRC found for the recvonly video stream!`);\n            }\n        } else {\n            const newPrimarySsrc = videoMLine.getPrimaryVideoSsrc();\n\n            if (!newPrimarySsrc) {\n                logger.info(`${this.logPrefix} sdp-consistency couldn't parse new primary ssrc`);\n\n                return sdpStr;\n            }\n            if (this.cachedPrimarySsrc) {\n                videoMLine.replaceSSRC(newPrimarySsrc, this.cachedPrimarySsrc);\n                for (const group of videoMLine.ssrcGroups) {\n                    if (group.semantics === 'FID') {\n                        const primarySsrc = parsePrimarySSRC(group);\n                        const rtxSsrc = parseSecondarySSRC(group);\n\n                        // eslint-disable-next-line max-depth\n                        if (primarySsrc === newPrimarySsrc) {\n                            group.ssrcs\n                                = `${this.cachedPrimarySsrc} ${rtxSsrc}`;\n                        }\n                    }\n                }\n            } else {\n                this.cachedPrimarySsrc = newPrimarySsrc;\n            }\n            this.injectRecvOnly = true;\n        }\n\n        return sdpTransformer.toRawSDP();\n    }\n}\n","import MediaDirection from '../../service/RTC/MediaDirection';\nimport { MediaType } from '../../service/RTC/MediaType';\n\nimport * as transform from 'sdp-transform';\n\nconst DEFAULT_NUM_OF_LAYERS = 3;\n\ninterface Description {\n    type: RTCSdpType;\n    sdp: string;\n}\n\ninterface Options {\n    numOfLayers?: number\n}\n\n/**\n * This class handles SDP munging for enabling simulcast for local video streams in Unified plan. A set of random SSRCs\n * are generated for the higher layer streams and they are cached for a given mid. The cached SSRCs are then reused on\n * the subsequent iterations while munging the local description. This class also handles imploding of the simulcast\n * SSRCs for remote endpoints into the primary FID group in remote description since Jicofo signals all SSRCs relevant\n * to a given endpoint.\n */\nexport default class SdpSimulcast {\n    private _options: Options;\n    private _ssrcCache: Map<string, Array<number>>;\n\n    /**\n     * Creates a new instance.\n     *\n     * @param options\n     */\n    constructor(options: Options) {\n        this._options = options;\n        this._ssrcCache = new Map();\n\n        if (!this._options.numOfLayers) {\n            this._options.numOfLayers = DEFAULT_NUM_OF_LAYERS;\n        }\n    }\n\n    /**\n     * Updates the given media description using the SSRCs that were cached for the mid associated\n     * with the media description and returns the modified media description.\n     *\n     * @param mLine\n     * @returns\n     */\n     _fillSsrcsFromCache(mLine: transform.MediaDescription) : any {\n        const mid = mLine.mid;\n        const cachedSsrcs = this._ssrcCache.get(mid);\n        const newSsrcs = this._parseSimLayers(mLine);\n        const newMsid = this._getSsrcAttribute(mLine, newSsrcs[0], 'msid');\n        const newCname = this._getSsrcAttribute(mLine, newSsrcs[0], 'cname');\n\n        mLine.ssrcs = [];\n        mLine.ssrcGroups = [];\n\n        for (const ssrc of cachedSsrcs) {\n            mLine.ssrcs.push({\n                id: ssrc,\n                attribute: 'msid',\n                value: newMsid\n            });\n            mLine.ssrcs.push({\n                id: ssrc,\n                attribute: 'cname',\n                value: newCname\n            });\n        }\n\n        mLine.ssrcGroups.push({\n            semantics: 'SIM',\n            ssrcs: cachedSsrcs.join(' ')\n        });\n\n        return mLine;\n    }\n\n    /**\n     * Generates a new set of SSRCs for the higher simulcast layers/streams and adds the attributes and SIM group to\n     * the given media description and returns the modified media description.\n     *\n     * @param mLine\n     * @param primarySsrc\n     * @returns\n     */\n    _generateNewSsrcsForSimulcast(mLine: transform.MediaDescription, primarySsrc: number) : any {\n        const cname = this._getSsrcAttribute(mLine, primarySsrc, 'cname');\n        let msid = this._getSsrcAttribute(mLine, primarySsrc, 'msid');\n        const addAssociatedAttributes = (mLine: transform.MediaDescription, ssrc: number) => {\n            mLine.ssrcs.push({\n                id: ssrc,\n                attribute: 'cname',\n                value: cname\n            });\n            mLine.ssrcs.push({\n                id: ssrc,\n                attribute: 'msid',\n                value: msid\n            });\n        }\n\n        // In Unified-plan mode, the a=ssrc lines with the msid attribute are not present (only cname attributes are\n        // present) in the answers that Chrome and Safari generate for an offer received from Jicofo. Generate these\n        // a=ssrc lines using the msid values from the a=msid line.\n        if (!msid) {\n            msid = mLine.msid;\n            const primarySsrcs = mLine.ssrcs;\n\n            primarySsrcs.forEach(ssrc => {\n                mLine.ssrcs.push({\n                    id: ssrc.id,\n                    attribute: 'msid',\n                    value: msid\n                });\n            })\n        }\n\n        // Generate SIM layers.\n        const simSsrcs = [];\n\n        for (let i = 0; i < this._options.numOfLayers - 1; ++i) {\n            const simSsrc = this._generateSsrc();\n\n            addAssociatedAttributes(mLine, simSsrc);\n            simSsrcs.push(simSsrc);\n        }\n\n        mLine.ssrcGroups = mLine.ssrcGroups || [];\n        mLine.ssrcGroups.push({\n            semantics: 'SIM',\n            ssrcs: primarySsrc + ' ' + simSsrcs.join(' ')\n        });\n\n        return mLine;\n    }\n\n    /**\n     * Returns a random number to be used for the SSRC.\n     *\n     * @returns\n     */\n    _generateSsrc() : number {\n        const max = 0xffffffff;\n\n        return Math.floor(Math.random() * max);\n    }\n\n    /**\n     * Returns the requested attribute value for a SSRC from a given media description.\n     *\n     * @param mLine\n     * @param ssrc\n     * @param attributeName\n     * @returns\n     */\n    _getSsrcAttribute(mLine: transform.MediaDescription, ssrc: number, attributeName: string) : string | undefined {\n        return mLine.ssrcs?.find(\n            ssrcInfo => Number(ssrcInfo.id) === ssrc\n            && ssrcInfo.attribute === attributeName)?.value;\n    }\n\n    /**\n     * Returns an array of all the primary SSRCs in the SIM group for a given media description.\n     *\n     * @param mLine\n     * @returns\n     */\n    _parseSimLayers(mLine: transform.MediaDescription) : Array<number> | null {\n        const simGroup = mLine.ssrcGroups?.find(group => group.semantics === 'SIM');\n\n        if (simGroup) {\n            return simGroup.ssrcs.split(' ').map(ssrc => Number(ssrc));\n        }\n\n        if (mLine.ssrcs?.length) {\n            return [ Number(mLine.ssrcs[0].id) ];\n        }\n\n        return null;\n    }\n\n    /**\n     * Munges the given media description to enable simulcast for the video media sections that are in either have\n     * SENDRECV or SENDONLY as the media direction thereby ignoring all the RECVONLY transceivers created for remote\n     * endpoints.\n     * NOTE: This needs to be called only when simulcast is enabled.\n     *\n     * @param description\n     * @returns\n     */\n    mungeLocalDescription(description: Description) : Description {\n        if (!description || !description.sdp) {\n            return description;\n        }\n        const session = transform.parse(description.sdp);\n\n        for (let media of session.media) {\n            // Ignore recvonly and inactive transceivers created for remote sources.\n            if (media.direction === MediaDirection.RECVONLY || media.direction === MediaDirection.INACTIVE) {\n                continue;\n            }\n\n            // Ignore audio m-lines.\n            if (media.type !== MediaType.VIDEO) {\n                continue;\n            }\n            const mid = media.mid;\n            const numSsrcs = new Set(media.ssrcs?.map(ssrcInfo => ssrcInfo.id));\n            const numGroups = media.ssrcGroups?.length ?? 0;\n            let primarySsrc: number;\n\n            // Do not munge if the description has no ssrcs or if simulcast is already enabled.\n            if (numSsrcs.size === 0 || numSsrcs.size > 2 || (numSsrcs.size === 2 && numGroups === 0)) {\n                continue;\n            }\n            if (numSsrcs.size === 1) {\n                primarySsrc = Number(media.ssrcs[0]?.id);\n            } else {\n                const fidGroup = media.ssrcGroups.find(group => group.semantics === 'FID');\n\n                if (fidGroup) {\n                    primarySsrc = Number(fidGroup.ssrcs.split(' ')[0]);\n                }\n            }\n\n            if (this._ssrcCache.has(mid)) {\n                media = this._fillSsrcsFromCache(media);\n            } else {\n                media = this._generateNewSsrcsForSimulcast(media, primarySsrc);\n                const simulcastSsrcs = this._parseSimLayers(media);\n\n                // Update the SSRCs in the cache so that they can re-used for the same mid again.\n                this._ssrcCache.set(mid, simulcastSsrcs);\n            }\n        }\n\n        return new RTCSessionDescription({\n            type: description.type,\n            sdp: transform.write(session)\n        });\n    }\n\n    /**\n     * Munges the given media description by removing the SSRCs and related FID groups for the higher layer streams.\n     *\n     * @param description\n     * @returns\n     */\n    mungeRemoteDescription(description: Description) : Description {\n        if (!description || !description.sdp) {\n            return description;\n        }\n\n        const session = transform.parse(description.sdp);\n\n        for (const media of session.media) {\n            if (media.type !== MediaType.VIDEO) {\n                continue;\n            }\n\n            if (media.direction !== MediaDirection.SENDONLY) {\n                continue;\n            }\n\n            // Ignore m-lines that do not have any SSRCs or SSRC groups. These are the ones associated with remote\n            // sources that have left the call. These will be recycled when a new remote source joins the call.\n            if (!media.ssrcGroups?.length || !media?.ssrcs.length) {\n                continue;\n            }\n\n            // Cache the SSRCs and the source groups.\n            const mungedSsrcs = new Set(media.ssrcs.slice());\n            const mungedSsrcGroups = new Set(media.ssrcGroups.slice());\n            const fidGroups = media.ssrcGroups.filter(group => group.semantics === 'FID');\n            const simGroup = media.ssrcGroups.find(group => group.semantics === 'SIM');\n            const primarySsrc = simGroup?.ssrcs.split(' ')[0];;\n\n            // When simulcast and RTX are both enabled.\n            if (fidGroups.length && simGroup) {\n                const fidGroup = fidGroups.find(group => group.ssrcs.includes(primarySsrc));\n                const secondarySsrc = fidGroup.ssrcs.split(' ')[1];\n\n                for (const ssrcGroup of media.ssrcGroups) {\n                    if (ssrcGroup !== fidGroup) {\n                        mungedSsrcGroups.delete(ssrcGroup);\n                    }\n                }\n                for (const ssrc of media.ssrcs) {\n                    if (ssrc.id.toString() !== primarySsrc\n                        && ssrc.id.toString() !== secondarySsrc) {\n                        mungedSsrcs.delete(ssrc);\n                    }\n                }\n\n            // When simulcast is enabled but RTX is disabled.\n            } else if (simGroup) {\n                mungedSsrcGroups.delete(simGroup);\n\n                for (const ssrc of media.ssrcs) {\n                    if (ssrc.id.toString() !== primarySsrc) {\n                        mungedSsrcs.delete(ssrc);\n                    }\n                }\n            }\n\n            media.ssrcs = Array.from(mungedSsrcs);\n            media.ssrcGroups = Array.from(mungedSsrcGroups);\n        }\n\n        return new RTCSessionDescription ({\n            type: description.type,\n            sdp: transform.write(session)\n        });\n    }\n}\n","import { getLogger } from '@jitsi/logger';\n\nimport { JitsiConferenceEvents } from '../../JitsiConferenceEvents';\nimport * as JitsiTrackEvents from '../../JitsiTrackEvents';\nimport RTCEvents from '../../service/RTC/RTCEvents';\nimport { createTrackStreamingStatusEvent } from '../../service/statistics/AnalyticsEvents';\nimport JitsiConference from '../../types/hand-crafted/JitsiConference';\nimport JitsiRemoteTrack from '../../types/hand-crafted/modules/RTC/JitsiRemoteTrack';\nimport RTC from '../../types/hand-crafted/modules/RTC/RTC';\nimport { VideoType } from '../../types/hand-crafted/service/RTC/VideoType';\nimport browser from '../browser';\nimport Statistics from '../statistics/statistics';\n\n/** Track streaming statuses. */\nexport enum TrackStreamingStatus {\n\n    /**\n     * Status indicating that streaming is currently active.\n     */\n    ACTIVE = 'active',\n\n    /**\n     * Status indicating that streaming is currently inactive.\n     * Inactive means the streaming was stopped on purpose from the bridge, like exiting forwarded sources or\n     * adaptivity decided to drop video because of not enough bandwidth.\n     */\n    INACTIVE = 'inactive',\n\n    /**\n     * Status indicating that streaming is currently interrupted.\n     */\n    INTERRUPTED = 'interrupted',\n\n    /**\n     * Status indicating that streaming is currently restoring.\n     */\n    RESTORING = 'restoring',\n  }\n\ntype StreamingStatusMap = {\n    // TODO: Replace this hand crafted VideoType when we convert VideoType.js to Typescript.\n    videoType?: VideoType, \n    startedMs?: number,\n    p2p?: boolean,\n    streamingStatus?: string,\n    value?: number\n};\n\nconst logger = getLogger(__filename);\n\n/**\n * Default value of 500 milliseconds for {@link TrackStreamingStatusImpl.outOfForwardedSourcesTimeout}.\n */\nconst DEFAULT_NOT_IN_FORWARDED_SOURCES_TIMEOUT = 500;\n\n/**\n * Default value of 2500 milliseconds for {@link TrackStreamingStatusImpl.p2pRtcMuteTimeout}.\n */\nconst DEFAULT_P2P_RTC_MUTE_TIMEOUT = 2500;\n\n/**\n * Default value of 10000 milliseconds for {@link TrackStreamingStatusImpl.rtcMuteTimeout}.\n */\nconst DEFAULT_RTC_MUTE_TIMEOUT = 10000;\n\n/**\n * The time to wait a track to be restored. Track which was out of forwarded sources should be inactive and when\n * entering forwarded sources it becomes restoring and when data is received from bridge it will become active, but if\n * no data is received for some time we set status of that track streaming to interrupted.\n */\nconst DEFAULT_RESTORING_TIMEOUT = 10000;\n\n/**\n * Class is responsible for emitting JitsiTrackEvents.TRACK_STREAMING_STATUS_CHANGED events.\n */\nexport class TrackStreamingStatusImpl {\n    rtc: RTC;\n    conference: JitsiConference;\n    track: JitsiRemoteTrack;\n\n    /**  This holds the timeout callback ID scheduled using window.setTimeout. */\n    trackTimer: number | null;\n\n    /**\n     * If video track frozen detection through RTC mute event is supported, we wait some time until video track is\n     * considered frozen. But because when the track falls out of forwarded sources it is expected for the video to\n     * freeze this timeout must be significantly reduced in \"out of forwarded sources\" case.\n     *\n     * Basically this value is used instead of {@link rtcMuteTimeout} when track is not in forwarded sources.\n     */\n    outOfForwardedSourcesTimeout: number;\n\n    /**\n     * How long we are going to wait for the corresponding signaling mute event after the RTC video track muted\n     * event is fired on the Media stream, before the connection interrupted is fired. The default value is\n     * {@link DEFAULT_P2P_RTC_MUTE_TIMEOUT}.\n     */\n    p2pRtcMuteTimeout: number;\n\n    /**\n     * How long we're going to wait after the RTC video track muted event for the corresponding signalling mute\n     * event, before the connection interrupted is fired. The default value is {@link DEFAULT_RTC_MUTE_TIMEOUT}.\n     *\n     * @returns amount of time in milliseconds\n     */\n    rtcMuteTimeout: number;\n\n    /**\n     * This holds a timestamp indicating  when remote video track was RTC muted. The purpose of storing the\n     * timestamp is to avoid the transition to disconnected status in case of legitimate video mute operation where\n     * the signalling video muted event can arrive shortly after RTC muted event.\n     *\n     * The timestamp is measured in milliseconds obtained with <tt>Date.now()</tt>.\n     *\n     * FIXME merge this logic with NO_DATA_FROM_SOURCE event implemented in JitsiLocalTrack by extending the event\n     * to the remote track and allowing to set different timeout for local and remote tracks.\n     */\n    rtcMutedTimestamp: number | null;\n\n    /** This holds the restoring timeout callback ID scheduled using window.setTimeout. */\n    restoringTimer: ReturnType<typeof setTimeout> | null;\n\n    /**\n     * This holds the current streaming status (along with all the internal events that happen while in that\n     * state).\n     *\n     * The goal is to send this information to the analytics backend for post-mortem analysis.\n     */\n    streamingStatusMap: StreamingStatusMap;\n\n    _onP2PStatus: () => void;\n    _onUserLeft: () => void;\n    _onTrackRtcMuted: () => void;\n    _onTrackRtcUnmuted: () => void;\n    _onSignallingMuteChanged: () => void;\n    _onTrackVideoTypeChanged: () => void;\n    _onLastNValueChanged: () => void;\n    _onForwardedSourcesChanged: () => void;\n\n    /* eslint-disable max-params*/\n    /**\n     * Calculates the new {@link TrackStreamingStatus} based on the values given for some specific remote track. It is\n     * assumed that the conference is currently in the JVB mode (in contrary to the P2P mode)\n     * @param isInForwardedSources - indicates whether the track is in the forwarded sources set. When set to\n     * false it means that JVB is not sending any video for the track.\n     * @param isRestoringTimedout - if true it means that the track has been outside of forwarded sources too\n     * long to be considered {@link TrackStreamingStatus.RESTORING}.\n     * @param isVideoMuted - true if the track is video muted and we should not expect to receive any video.\n     * @param isVideoTrackFrozen - if the current browser support video frozen detection then it will be set to\n     * true when the video track is frozen. If the current browser does not support frozen detection the it's always\n     * false.\n     * @return {TrackStreamingStatus} the new streaming status for the track for whom the values above were provided.\n     * @private\n     */\n    static _getNewStateForJvbMode(\n            isInForwardedSources: boolean,\n            isRestoringTimedout: boolean,\n            isVideoMuted: boolean,\n            isVideoTrackFrozen: boolean): TrackStreamingStatus {\n\n        // We are currently not checking the endpoint connection status received from the JVB.\n        if (isVideoMuted) {\n            // If the connection is active according to JVB and the track is video muted there is no way for the\n            // connection to be inactive, because the detection logic below only makes sense for video.\n            return TrackStreamingStatus.ACTIVE;\n        }\n\n        // Logic when isVideoTrackFrozen is supported\n        if (browser.supportsVideoMuteOnConnInterrupted()) {\n            if (!isVideoTrackFrozen) {\n                // If the video is playing we're good\n                return TrackStreamingStatus.ACTIVE;\n            } else if (isInForwardedSources) {\n                return isRestoringTimedout ? TrackStreamingStatus.INTERRUPTED : TrackStreamingStatus.RESTORING;\n            }\n\n            return TrackStreamingStatus.INACTIVE;\n        }\n\n        // Because this browser is incapable of detecting frozen video we must rely on the forwarded sources value\n        return isInForwardedSources ? TrackStreamingStatus.ACTIVE : TrackStreamingStatus.INACTIVE;\n    }\n\n    /* eslint-enable max-params*/\n\n    /**\n     * In P2P mode we don't care about any values coming from the JVB and the streaming status can be only active or\n     * interrupted.\n     * @param isVideoMuted - true if video muted\n     * @param isVideoTrackFrozen - true if the video track for the remote track is currently frozen. If the\n     * current browser does not support video frozen detection then it's always false.\n     * @return {TrackStreamingStatus}\n     * @private\n     */\n    static _getNewStateForP2PMode(isVideoMuted: boolean, isVideoTrackFrozen: boolean): TrackStreamingStatus {\n        if (!browser.supportsVideoMuteOnConnInterrupted()) {\n            // There's no way to detect problems in P2P when there's no video track frozen detection...\n            return TrackStreamingStatus.ACTIVE;\n        }\n\n        return isVideoMuted || !isVideoTrackFrozen\n            ? TrackStreamingStatus.ACTIVE : TrackStreamingStatus.INTERRUPTED;\n    }\n\n    /**\n     * Creates new instance of <tt>TrackStreamingStatus</tt>.\n     *\n     * @constructor\n     * @param rtc - the RTC service instance\n     * @param conference - parent conference instance\n     * @param {Object} options\n     * @param {number} [options.p2pRtcMuteTimeout=2500] custom value for\n     * {@link TrackStreamingStatusImpl.p2pRtcMuteTimeout}.\n     * @param {number} [options.rtcMuteTimeout=2000] custom value for\n     * {@link TrackStreamingStatusImpl.rtcMuteTimeout}.\n     * @param {number} [options.outOfForwardedSourcesTimeout=500] custom value for\n     * {@link TrackStreamingStatusImpl.outOfForwardedSourcesTimeout}.\n     */\n    constructor(rtc: RTC, conference: JitsiConference, track: JitsiRemoteTrack, options: {\n        outOfForwardedSourcesTimeout: number,\n        p2pRtcMuteTimeout: number,\n        rtcMuteTimeout: number\n    }) {\n        this.rtc = rtc;\n        this.conference = conference;\n        this.track = track;\n\n        this.restoringTimer = null;\n        this.rtcMutedTimestamp = null;\n        this.streamingStatusMap = {};\n        this.trackTimer = null;\n\n        this.outOfForwardedSourcesTimeout = typeof options.outOfForwardedSourcesTimeout === 'number'\n            ? options.outOfForwardedSourcesTimeout : DEFAULT_NOT_IN_FORWARDED_SOURCES_TIMEOUT;\n\n        this.p2pRtcMuteTimeout = typeof options.p2pRtcMuteTimeout === 'number'\n            ? options.p2pRtcMuteTimeout : DEFAULT_P2P_RTC_MUTE_TIMEOUT;\n\n        this.rtcMuteTimeout = typeof options.rtcMuteTimeout === 'number'\n            ? options.rtcMuteTimeout : DEFAULT_RTC_MUTE_TIMEOUT;\n        logger.info(`RtcMuteTimeout set to: ${this.rtcMuteTimeout}`);\n    }\n\n    /**\n     * Gets the video frozen timeout for given source name.\n     * @return how long are we going to wait since RTC video muted even, before a video track is considered\n     * frozen.\n     * @private\n     */\n    _getVideoFrozenTimeout(): number {\n        const sourceName = this.track.getSourceName();\n\n        return this.rtc.isInForwardedSources(sourceName)\n            ? this.rtcMuteTimeout\n            : this.conference.isP2PActive() ? this.p2pRtcMuteTimeout : this.outOfForwardedSourcesTimeout;\n    }\n\n    /**\n     * Initializes <tt>TrackStreamingStatus</tt> and bind required event listeners.\n     */\n    init(): void {\n        // Handles P2P status changes\n        this._onP2PStatus = this.figureOutStreamingStatus.bind(this);\n        this.conference.on(JitsiConferenceEvents.P2P_STATUS, this._onP2PStatus);\n\n        // Used to send analytics events for the participant that left the call.\n        this._onUserLeft = this.onUserLeft.bind(this);\n        this.conference.on(JitsiConferenceEvents.USER_LEFT, this._onUserLeft);\n\n        // On some browsers MediaStreamTrack trigger \"onmute\"/\"onunmute\" events for video type tracks when they stop\n        // receiving data which is often a sign that remote user is having connectivity issues.\n        if (browser.supportsVideoMuteOnConnInterrupted()) {\n\n            this._onTrackRtcMuted = this.onTrackRtcMuted.bind(this);\n            this.rtc.addListener(RTCEvents.REMOTE_TRACK_MUTE, this._onTrackRtcMuted);\n\n            this._onTrackRtcUnmuted = this.onTrackRtcUnmuted.bind(this);\n            this.rtc.addListener(RTCEvents.REMOTE_TRACK_UNMUTE, this._onTrackRtcUnmuted);\n\n            // Listened which will be bound to JitsiRemoteTrack to listen for signalling mute/unmute events.\n            this._onSignallingMuteChanged = this.onSignallingMuteChanged.bind(this);\n            this.track.on(JitsiTrackEvents.TRACK_MUTE_CHANGED, this._onSignallingMuteChanged);\n\n            // Used to send an analytics event when the video type changes.\n            this._onTrackVideoTypeChanged = this.onTrackVideoTypeChanged.bind(this);\n            this.track.on(JitsiTrackEvents.TRACK_VIDEOTYPE_CHANGED, this._onTrackVideoTypeChanged);\n        }\n\n        this._onForwardedSourcesChanged = this.onForwardedSourcesChanged.bind(this);\n        this.conference.on(JitsiConferenceEvents.FORWARDED_SOURCES_CHANGED, this._onForwardedSourcesChanged);\n\n        this._onLastNValueChanged = this.figureOutStreamingStatus.bind(this);\n        this.rtc.on(RTCEvents.LASTN_VALUE_CHANGED, this._onLastNValueChanged);\n    }\n\n    /**\n     * Removes all event listeners and disposes of all resources held by this instance.\n     */\n    dispose(): void {\n        if (browser.supportsVideoMuteOnConnInterrupted()) {\n            this.rtc.removeListener(RTCEvents.REMOTE_TRACK_MUTE, this._onTrackRtcMuted);\n            this.rtc.removeListener(RTCEvents.REMOTE_TRACK_UNMUTE, this._onTrackRtcUnmuted);\n\n            this.track.off(JitsiTrackEvents.TRACK_MUTE_CHANGED, this._onSignallingMuteChanged);\n        }\n\n        this.conference.off(JitsiConferenceEvents.FORWARDED_SOURCES_CHANGED, this._onForwardedSourcesChanged);\n        this.conference.off(JitsiConferenceEvents.P2P_STATUS, this._onP2PStatus);\n        this.conference.off(JitsiConferenceEvents.USER_LEFT, this._onUserLeft);\n        this.rtc.removeListener(RTCEvents.LASTN_VALUE_CHANGED, this._onLastNValueChanged);\n\n        this.clearTimeout();\n        this.clearRtcMutedTimestamp();\n        this.maybeSendTrackStreamingStatusEvent(Date.now());\n        this.figureOutStreamingStatus();\n    }\n\n    /**\n     * Changes streaming status.\n     * @param newStatus\n     */\n    _changeStreamingStatus(newStatus: TrackStreamingStatus): void {\n        if (this.track.getTrackStreamingStatus() !== newStatus) {\n\n            const sourceName = this.track.getSourceName();\n\n            this.track._setTrackStreamingStatus(newStatus);\n\n            logger.debug(`Emit track streaming status(${Date.now()}) ${sourceName}: ${newStatus}`);\n\n            // Log the event on CallStats\n            Statistics.sendLog(\n                JSON.stringify({\n                    id: 'track.streaming.status',\n                    track: sourceName,\n                    status: newStatus\n                }));\n\n            this.track.emit(JitsiTrackEvents.TRACK_STREAMING_STATUS_CHANGED, newStatus);\n        }\n    }\n\n    /**\n     * Reset the postponed \"streaming interrupted\" event which was previously scheduled as a timeout on RTC 'onmute'\n     * event.\n     */\n    clearTimeout(): void {\n        if (this.trackTimer) {\n            window.clearTimeout(this.trackTimer);\n            this.trackTimer = null;\n        }\n    }\n\n    /**\n     * Clears the timestamp of the RTC muted event for remote video track.\n     */\n    clearRtcMutedTimestamp(): void {\n        this.rtcMutedTimestamp = null;\n    }\n\n    /**\n     * Checks if track is considered frozen.\n     * @return <tt>true</tt> if the video has frozen or <tt>false</tt> when it's either not considered frozen\n     * (yet) or if freeze detection is not supported by the current browser.\n     *\n     * FIXME merge this logic with NO_DATA_FROM_SOURCE event implemented in JitsiLocalTrack by extending the event to\n     *       the remote track and allowing to set different timeout for local and remote tracks.\n     */\n    isVideoTrackFrozen(): boolean {\n        if (!browser.supportsVideoMuteOnConnInterrupted()) {\n            return false;\n        }\n\n        const isVideoRTCMuted = this.track.isWebRTCTrackMuted();\n        const rtcMutedTimestamp = this.rtcMutedTimestamp;\n        const timeout = this._getVideoFrozenTimeout();\n\n        return isVideoRTCMuted && typeof rtcMutedTimestamp === 'number' && (Date.now() - rtcMutedTimestamp) >= timeout;\n    }\n\n    /**\n     * Figures out (and updates) the current streaming status for the track identified by the source name.\n     */\n    figureOutStreamingStatus(): void {\n        const sourceName = this.track.getSourceName();\n        const inP2PMode = this.conference.isP2PActive();\n        const isRestoringTimedOut = this._isRestoringTimedout();\n        const audioOnlyMode = this.conference.getLastN() === 0;\n\n        // NOTE Overriding videoMuted to true for audioOnlyMode should disable any detection based on video playback or\n        // forwarded sources.\n        const isVideoMuted = this.track.isMuted() || audioOnlyMode;\n        const isVideoTrackFrozen = this.isVideoTrackFrozen();\n        const isInForwardedSources = this.rtc.isInForwardedSources(sourceName);\n\n        const newState\n            = inP2PMode\n                ? TrackStreamingStatusImpl._getNewStateForP2PMode(\n                    isVideoMuted,\n                    isVideoTrackFrozen)\n                : TrackStreamingStatusImpl._getNewStateForJvbMode(\n                    isInForwardedSources,\n                    isRestoringTimedOut,\n                    isVideoMuted,\n                    isVideoTrackFrozen);\n\n        // if the new state is not restoring clear timers and timestamps that we use to track the restoring state\n        if (newState !== TrackStreamingStatus.RESTORING) {\n            this._clearRestoringTimer();\n        }\n\n        logger.debug(\n            `Figure out conn status for ${sourceName}, is video muted: ${\n                isVideoMuted} video track frozen: ${\n                isVideoTrackFrozen} p2p mode: ${\n                inP2PMode} is in forwarded sources: ${\n                isInForwardedSources} currentStatus => newStatus: ${\n                this.track.getTrackStreamingStatus()} => ${newState}`);\n\n        const oldStreamingStatus = this.streamingStatusMap || {};\n\n        // Send an analytics event (guard on either the p2p flag or the streaming status has changed since the last\n        // time this code block run).\n        if (!('p2p' in oldStreamingStatus)\n            || !('streamingStatus' in oldStreamingStatus)\n            || oldStreamingStatus.p2p !== inP2PMode\n            || oldStreamingStatus.streamingStatus !== newState) {\n\n            const nowMs = Date.now();\n\n            this.maybeSendTrackStreamingStatusEvent(nowMs);\n\n            this.streamingStatusMap = {\n                ...oldStreamingStatus,\n                streamingStatus: newState,\n                p2p: inP2PMode,\n                startedMs: nowMs\n            };\n\n            // sometimes (always?) we're late to hook the TRACK_VIDEOTYPE_CHANGED event and the video type is not in\n            // oldStreamingStatus.\n            if (!('videoType' in this.streamingStatusMap)) {\n                this.streamingStatusMap.videoType = this.track.getVideoType();\n            }\n        }\n        this._changeStreamingStatus(newState);\n    }\n\n    /**\n     * Computes the duration of the current streaming status for the track (i.e. 15 seconds in the INTERRUPTED state)\n     * and sends a track streaming status event.\n     * @param nowMs - The current time (in millis).\n     */\n    maybeSendTrackStreamingStatusEvent(nowMs: number): void {\n        const trackStreamingStatus = this.streamingStatusMap;\n\n        if (trackStreamingStatus\n            && 'startedMs' in trackStreamingStatus\n            && 'videoType' in trackStreamingStatus\n            && 'streamingStatus' in trackStreamingStatus\n            && 'p2p' in trackStreamingStatus) {\n            trackStreamingStatus.value = nowMs - trackStreamingStatus.startedMs;\n            Statistics.sendAnalytics(createTrackStreamingStatusEvent(trackStreamingStatus));\n        }\n    }\n\n    /**\n     * On change in forwarded sources set check all leaving and entering track to change their corresponding statuses.\n     *\n     * @param leavingForwardedSources - The array of sourceName leaving forwarded sources.\n     * @param enteringForwardedSources - The array of sourceName entering forwarded sources.\n     * @param timestamp - The time in millis\n     * @private\n     */\n    onForwardedSourcesChanged(\n            leavingForwardedSources: string[] = [],\n            enteringForwardedSources: string[] = [],\n            timestamp: number): void {\n\n        const sourceName = this.track.getSourceName();\n\n        logger.debug(`Fowarded sources changed leaving=${leavingForwardedSources}, entering=${\n            enteringForwardedSources} at ${timestamp}`);\n\n        // If the browser doesn't fire the mute/onmute events when the remote peer stops/starts sending media,\n        // calculate the streaming status for all the tracks since it won't get triggered automatically on the track\n        // that has started/stopped receiving media.\n        if (!browser.supportsVideoMuteOnConnInterrupted()) {\n            this.figureOutStreamingStatus();\n        }\n\n        if (leavingForwardedSources.includes(sourceName)) {\n            this.track._clearEnteredForwardedSourcesTimestamp();\n            this._clearRestoringTimer();\n            browser.supportsVideoMuteOnConnInterrupted() && this.figureOutStreamingStatus();\n        }\n\n        if (enteringForwardedSources.includes(sourceName)) {\n            // store the timestamp this track is entering forwarded sources\n            this.track._setEnteredForwardedSourcesTimestamp(timestamp);\n            browser.supportsVideoMuteOnConnInterrupted() && this.figureOutStreamingStatus();\n        }\n    }\n\n    /**\n     * Clears the restoring timer for video track and the timestamp for entering forwarded sources.\n     */\n    _clearRestoringTimer(): void {\n        const rTimer = this.restoringTimer;\n\n        if (rTimer) {\n            clearTimeout(rTimer);\n            this.restoringTimer = null;\n        }\n    }\n\n    /**\n     * Checks whether a track had stayed enough in restoring state, compares current time and the time the track\n     * entered in forwarded sources. If it hasn't timedout and there is no timer added, add new timer in order to give\n     * it more time to become active or mark it as interrupted on next check.\n     *\n     * @returns <tt>true</tt> if the track was in restoring state more than the timeout\n     * ({@link DEFAULT_RESTORING_TIMEOUT}.) in order to set its status to interrupted.\n     * @private\n     */\n    _isRestoringTimedout(): boolean {\n        const enteredForwardedSourcesTimestamp = this.track._getEnteredForwardedSourcesTimestamp();\n\n        if (enteredForwardedSourcesTimestamp\n            && (Date.now() - enteredForwardedSourcesTimestamp) >= DEFAULT_RESTORING_TIMEOUT) {\n            return true;\n        }\n\n        // still haven't reached timeout, if there is no timer scheduled, schedule one so we can track the restoring\n        // state and change it after reaching the timeout\n        const rTimer = this.restoringTimer;\n\n        if (!rTimer) {\n            this.restoringTimer = setTimeout(() => this.figureOutStreamingStatus(), DEFAULT_RESTORING_TIMEOUT);\n        }\n\n        return false;\n    }\n\n    /** Checks whether a track is the current track. */\n    _isCurrentTrack(track: JitsiRemoteTrack): boolean {\n        return track.getSourceName() === this.track.getSourceName();\n    }\n\n    /**\n     * Sends a last/final track streaming status event for the track of the user that left the conference.\n     * @param id - The id of the participant that left the conference.\n     */\n    onUserLeft(id: string): void {\n        if (this.track.getParticipantId() === id) {\n            this.maybeSendTrackStreamingStatusEvent(Date.now());\n            this.streamingStatusMap = {};\n        }\n    }\n\n    /**\n     * Handles RTC 'onmute' event for the video track.\n     *\n     * @param track - The video track for which 'onmute' event will be processed.\n     */\n    onTrackRtcMuted(track: JitsiRemoteTrack): void {\n        if (!this._isCurrentTrack(track)) {\n            return;\n        }\n\n        const sourceName = track.getSourceName();\n\n        logger.debug(`Detector track RTC muted: ${sourceName}`, Date.now());\n\n        this.rtcMutedTimestamp = Date.now();\n        if (!track.isMuted()) {\n            // If the user is not muted according to the signalling we'll give it some time, before the streaming\n            // interrupted event is triggered.\n            this.clearTimeout();\n\n            // The timeout is reduced when track is not in the forwarded sources\n            const timeout = this._getVideoFrozenTimeout();\n\n            this.trackTimer = window.setTimeout(() => {\n                logger.debug(`Set RTC mute timeout for: ${sourceName} of ${timeout} ms`);\n                this.clearTimeout();\n                this.figureOutStreamingStatus();\n            }, timeout);\n        }\n    }\n\n    /**\n     * Handles RTC 'onunmute' event for the video track.\n     *\n     * @param track - The video track for which 'onunmute' event will be processed.\n     */\n    onTrackRtcUnmuted(track: JitsiRemoteTrack): void {\n        if (!this._isCurrentTrack(track)) {\n            return;\n        }\n\n        const sourceName = this.track.getSourceName();\n\n        logger.debug(`Detector track RTC unmuted: ${sourceName}`, Date.now());\n\n        this.clearTimeout();\n        this.clearRtcMutedTimestamp();\n\n        this.figureOutStreamingStatus();\n    }\n\n    /**\n     * Here the signalling \"mute\"/\"unmute\" events are processed.\n     *\n     * @param track - The remote video track for which the signalling mute/unmute event will be\n     * processed.\n     */\n    onSignallingMuteChanged(track: JitsiRemoteTrack): void {\n        if (!this._isCurrentTrack(track)) {\n            return;\n        }\n\n        const sourceName = this.track.getSourceName();\n\n        logger.debug(`Detector on track signalling mute changed: ${sourceName}`, track.isMuted());\n\n        this.figureOutStreamingStatus();\n    }\n\n    /**\n     * Sends a track streaming status event as a result of the video type changing.\n     * @deprecated this will go away with full multiple streams support\n     * @param type - The video type.\n     */\n    onTrackVideoTypeChanged(type: VideoType): void {\n        const nowMs = Date.now();\n\n        this.maybeSendTrackStreamingStatusEvent(nowMs);\n\n        this.streamingStatusMap = {\n            ...this.streamingStatusMap || {},\n            videoType: type,\n            startedMs: nowMs\n        };\n    }\n}\n\nexport default TrackStreamingStatusImpl;\n","import * as JitsiTrackEvents from '../../JitsiTrackEvents';\nimport { createTtfmEvent } from '../../service/statistics/AnalyticsEvents';\nimport TrackStreamingStatusImpl, { TrackStreamingStatus } from '../connectivity/TrackStreamingStatus';\nimport FeatureFlags from '../flags/FeatureFlags';\nimport Statistics from '../statistics/statistics';\n\nimport JitsiTrack from './JitsiTrack';\n\nconst logger = require('@jitsi/logger').getLogger(__filename);\n\nconst RTCEvents = require('../../service/RTC/RTCEvents');\n\nlet ttfmTrackerAudioAttached = false;\nlet ttfmTrackerVideoAttached = false;\n\n/**\n * List of container events that we are going to process. _onContainerEventHandler will be added as listener to the\n * container for every event in the list.\n */\nconst containerEvents = [ 'abort', 'canplaythrough', 'ended', 'error' ];\n\n/* eslint-disable max-params */\n\n/**\n * Represents a single media track (either audio or video).\n */\nexport default class JitsiRemoteTrack extends JitsiTrack {\n    /**\n     * Creates new JitsiRemoteTrack instance.\n     * @param {RTC} rtc the RTC service instance.\n     * @param {JitsiConference} conference the conference to which this track\n     *        belongs to\n     * @param {string} ownerEndpointId the endpoint ID of the track owner\n     * @param {MediaStream} stream WebRTC MediaStream, parent of the track\n     * @param {MediaStreamTrack} track underlying WebRTC MediaStreamTrack for\n     *        the new JitsiRemoteTrack\n     * @param {MediaType} mediaType the type of the media\n     * @param {VideoType} videoType the type of the video if applicable\n     * @param {number} ssrc the SSRC number of the Media Stream\n     * @param {boolean} muted the initial muted state\n     * @param {boolean} isP2P indicates whether or not this track belongs to a\n     * P2P session\n     * @param {String} sourceName the source name signaled for the track\n     * @throws {TypeError} if <tt>ssrc</tt> is not a number.\n     * @constructor\n     */\n    constructor(\n            rtc,\n            conference,\n            ownerEndpointId,\n            stream,\n            track,\n            mediaType,\n            videoType,\n            ssrc,\n            muted,\n            isP2P,\n            sourceName) {\n        super(\n            conference,\n            stream,\n            track,\n            () => {\n                // Nothing to do if the track is inactive.\n            },\n            mediaType,\n            videoType);\n        this.rtc = rtc;\n\n        // Prevent from mixing up type of SSRC which should be a number\n        if (typeof ssrc !== 'number') {\n            throw new TypeError(`SSRC ${ssrc} is not a number`);\n        }\n        this.ssrc = ssrc;\n        this.ownerEndpointId = ownerEndpointId;\n        this.muted = muted;\n        this.isP2P = isP2P;\n        this._sourceName = sourceName;\n        this._trackStreamingStatus = null;\n        this._trackStreamingStatusImpl = null;\n\n        /**\n         * This holds the timestamp indicating when remote video track entered forwarded sources set. Track entering\n         * forwardedSources will have streaming status restoring and when we start receiving video will become active,\n         * but if video is not received for certain time {@link DEFAULT_RESTORING_TIMEOUT} that track streaming status\n         * will become interrupted.\n         */\n        this._enteredForwardedSourcesTimestamp = null;\n\n        this.addEventListener = this.on = this._addEventListener.bind(this);\n        this.removeEventListener = this.off = this._removeEventListener.bind(this);\n\n        logger.debug(`New remote track added: ${this}`);\n\n        // we want to mark whether the track has been ever muted\n        // to detect ttfm events for startmuted conferences, as it can\n        // significantly increase ttfm values\n        this.hasBeenMuted = muted;\n\n        // Bind 'onmute' and 'onunmute' event handlers\n        if (this.rtc && this.track) {\n            this._bindTrackHandlers();\n        }\n        this._containerHandlers = {};\n        containerEvents.forEach(event => {\n            this._containerHandlers[event] = this._containerEventHandler.bind(this, event);\n        });\n    }\n\n    /* eslint-enable max-params */\n    /**\n     * Attaches the track handlers.\n     *\n     * @returns {void}\n     */\n    _bindTrackHandlers() {\n        this.track.addEventListener('mute', () => this._onTrackMute());\n        this.track.addEventListener('unmute', () => this._onTrackUnmute());\n        this.track.addEventListener('ended', () => {\n            logger.debug(`\"onended\" event(${Date.now()}): ${this}`);\n        });\n    }\n\n    /**\n     * Overrides addEventListener method to init TrackStreamingStatus instance when there are listeners for the\n     * {@link JitsiTrackEvents.TRACK_STREAMING_STATUS_CHANGED} event.\n     *\n     * @param {string} event - event name\n     * @param {function} handler - event handler\n     */\n    _addEventListener(event, handler) {\n        super.addListener(event, handler);\n\n        if (FeatureFlags.isSourceNameSignalingEnabled()\n            && event === JitsiTrackEvents.TRACK_STREAMING_STATUS_CHANGED\n            && this.listenerCount(JitsiTrackEvents.TRACK_STREAMING_STATUS_CHANGED)\n            && !this._trackStreamingStatusImpl\n        ) {\n            this._initTrackStreamingStatus();\n            logger.debug(`Initializing track streaming status: ${this._sourceName}`);\n        }\n    }\n\n    /**\n     * Overrides removeEventListener method to dispose TrackStreamingStatus instance.\n     *\n     * @param {string} event - event name\n     * @param {function} handler - event handler\n     */\n    _removeEventListener(event, handler) {\n        super.removeListener(event, handler);\n\n        if (FeatureFlags.isSourceNameSignalingEnabled()\n            && event === JitsiTrackEvents.TRACK_STREAMING_STATUS_CHANGED\n            && !this.listenerCount(JitsiTrackEvents.TRACK_STREAMING_STATUS_CHANGED)\n        ) {\n            this._disposeTrackStreamingStatus();\n            logger.debug(`Disposing track streaming status: ${this._sourceName}`);\n        }\n    }\n\n    /**\n     * Callback invoked when the track is muted. Emits an event notifying\n     * listeners of the mute event.\n     *\n     * @private\n     * @returns {void}\n     */\n    _onTrackMute() {\n        logger.debug(`\"onmute\" event(${Date.now()}): ${this}`);\n\n        this.rtc.eventEmitter.emit(RTCEvents.REMOTE_TRACK_MUTE, this);\n    }\n\n    /**\n     * Callback invoked when the track is unmuted. Emits an event notifying\n     * listeners of the mute event.\n     *\n     * @private\n     * @returns {void}\n     */\n    _onTrackUnmute() {\n        logger.debug(`\"onunmute\" event(${Date.now()}): ${this}`);\n\n        this.rtc.eventEmitter.emit(RTCEvents.REMOTE_TRACK_UNMUTE, this);\n    }\n\n    /**\n     * Removes attached event listeners and dispose TrackStreamingStatus .\n     *\n     * @returns {Promise}\n     */\n    dispose() {\n        if (FeatureFlags.isSourceNameSignalingEnabled()) {\n            this._disposeTrackStreamingStatus();\n        }\n\n        return super.dispose();\n    }\n\n    /**\n     * Sets current muted status and fires an events for the change.\n     * @param value the muted status.\n     */\n    setMute(value) {\n        if (this.muted === value) {\n            return;\n        }\n\n        if (value) {\n            this.hasBeenMuted = true;\n        }\n\n        // we can have a fake video stream\n        if (this.stream) {\n            this.stream.muted = value;\n        }\n\n        this.muted = value;\n        this.emit(JitsiTrackEvents.TRACK_MUTE_CHANGED, this);\n    }\n\n    /**\n     * Returns the current muted status of the track.\n     * @returns {boolean|*|JitsiRemoteTrack.muted} <tt>true</tt> if the track is\n     * muted and <tt>false</tt> otherwise.\n     */\n    isMuted() {\n        return this.muted;\n    }\n\n    /**\n     * Returns the participant id which owns the track.\n     *\n     * @returns {string} the id of the participants. It corresponds to the\n     * Colibri endpoint id/MUC nickname in case of Jitsi-meet.\n     */\n    getParticipantId() {\n        return this.ownerEndpointId;\n    }\n\n    /**\n     * Return false;\n     */\n    isLocal() {\n        return false;\n    }\n\n    /**\n     * Returns the synchronization source identifier (SSRC) of this remote\n     * track.\n     *\n     * @returns {number} the SSRC of this remote track.\n     */\n    getSSRC() {\n        return this.ssrc;\n    }\n\n\n    /**\n     * Returns the tracks source name\n     *\n     * @returns {string} the track's source name\n     */\n    getSourceName() {\n        return this._sourceName;\n    }\n\n    /**\n     * Changes the video type of the track.\n     *\n     * @param {string} type - The new video type(\"camera\", \"desktop\").\n     */\n    _setVideoType(type) {\n        if (this.videoType === type) {\n            return;\n        }\n        this.videoType = type;\n        this.emit(JitsiTrackEvents.TRACK_VIDEOTYPE_CHANGED, type);\n    }\n\n    /**\n     * Handles track play events.\n     */\n    _playCallback() {\n        if (!this.conference.room) {\n            return;\n        }\n\n        const type = this.isVideoTrack() ? 'video' : 'audio';\n\n        const now = window.performance.now();\n\n        console.log(`(TIME) Render ${type}:\\t`, now);\n        this.conference.getConnectionTimes()[`${type}.render`] = now;\n\n        // The conference can be started without calling GUM\n        // FIXME if there would be a module for connection times this kind\n        // of logic (gumDuration or ttfm) should end up there\n        const gumStart = window.connectionTimes['obtainPermissions.start'];\n        const gumEnd = window.connectionTimes['obtainPermissions.end'];\n        const gumDuration\n            = !isNaN(gumEnd) && !isNaN(gumStart) ? gumEnd - gumStart : 0;\n\n        // Subtract the muc.joined-to-session-initiate duration because jicofo\n        // waits until there are 2 participants to start Jingle sessions.\n        const ttfm = now\n            - (this.conference.getConnectionTimes()['session.initiate']\n                - this.conference.getConnectionTimes()['muc.joined'])\n            - gumDuration;\n\n        this.conference.getConnectionTimes()[`${type}.ttfm`] = ttfm;\n        console.log(`(TIME) TTFM ${type}:\\t`, ttfm);\n\n        Statistics.sendAnalytics(createTtfmEvent(\n            {\n                'media_type': type,\n                muted: this.hasBeenMuted,\n                value: ttfm\n            }));\n\n    }\n\n    /**\n     * Attach time to first media tracker only if there is conference and only\n     * for the first element.\n     * @param container the HTML container which can be 'video' or 'audio'\n     * element.\n     * @private\n     */\n    _attachTTFMTracker(container) {\n        if ((ttfmTrackerAudioAttached && this.isAudioTrack())\n            || (ttfmTrackerVideoAttached && this.isVideoTrack())) {\n            return;\n        }\n\n        if (this.isAudioTrack()) {\n            ttfmTrackerAudioAttached = true;\n        }\n        if (this.isVideoTrack()) {\n            ttfmTrackerVideoAttached = true;\n        }\n\n        container.addEventListener('canplay', this._playCallback.bind(this));\n    }\n\n    /**\n     * Called when the track has been attached to a new container.\n     *\n     * @param {HTMLElement} container the HTML container which can be 'video' or 'audio' element.\n     * @private\n     */\n    _onTrackAttach(container) {\n        containerEvents.forEach(event => {\n            container.addEventListener(event, this._containerHandlers[event]);\n        });\n    }\n\n    /**\n     * Called when the track has been detached from a container.\n     *\n     * @param {HTMLElement} container the HTML container which can be 'video' or 'audio' element.\n     * @private\n     */\n    _onTrackDetach(container) {\n        containerEvents.forEach(event => {\n            container.removeEventListener(event, this._containerHandlers[event]);\n        });\n    }\n\n    /**\n     * An event handler for events triggered by the attached container.\n     *\n     * @param {string} type - The type of the event.\n     */\n    _containerEventHandler(type) {\n        logger.debug(`${type} handler was called for a container with attached ${this}`);\n    }\n\n    /**\n     * Returns a string with a description of the current status of the track.\n     *\n     * @returns {string}\n     */\n    _getStatus() {\n        const { enabled, muted, readyState } = this.track;\n\n        return `readyState: ${readyState}, muted: ${muted}, enabled: ${enabled}`;\n    }\n\n    /**\n     * Initializes trackStreamingStatusImpl.\n     */\n    _initTrackStreamingStatus() {\n        const config = this.conference.options.config;\n\n        this._trackStreamingStatus = TrackStreamingStatus.ACTIVE;\n\n        this._trackStreamingStatusImpl = new TrackStreamingStatusImpl(\n            this.rtc,\n            this.conference,\n            this,\n            {\n                // These options are not public API, leaving it here only as an entry point through config for\n                // tuning up purposes. Default values should be adjusted as soon as optimal values are discovered.\n                p2pRtcMuteTimeout: config._p2pConnStatusRtcMuteTimeout,\n                rtcMuteTimeout: config._peerConnStatusRtcMuteTimeout,\n                outOfForwardedSourcesTimeout: config._peerConnStatusOutOfLastNTimeout\n            });\n\n        this._trackStreamingStatusImpl.init();\n    }\n\n    /**\n     * Disposes trackStreamingStatusImpl and clears trackStreamingStatus.\n     */\n    _disposeTrackStreamingStatus() {\n        if (this._trackStreamingStatusImpl) {\n            this._trackStreamingStatusImpl.dispose();\n            this._trackStreamingStatusImpl = null;\n            this._trackStreamingStatus = null;\n        }\n    }\n\n    /**\n     * Updates track's streaming status.\n     *\n     * @param {string} state the current track streaming state. {@link TrackStreamingStatus}.\n     */\n    _setTrackStreamingStatus(status) {\n        this._trackStreamingStatus = status;\n    }\n\n    /**\n     * Returns track's streaming status.\n     *\n     * @returns {string} the streaming status <tt>TrackStreamingStatus</tt> of the track. Returns null\n     * if trackStreamingStatusImpl hasn't been initialized.\n     *\n     * {@link TrackStreamingStatus}.\n     */\n    getTrackStreamingStatus() {\n        return this._trackStreamingStatus;\n    }\n\n    /**\n     * Clears the timestamp of when the track entered forwarded sources.\n     */\n    _clearEnteredForwardedSourcesTimestamp() {\n        this._enteredForwardedSourcesTimestamp = null;\n    }\n\n    /**\n     * Updates the timestamp of when the track entered forwarded sources.\n     *\n     * @param {number} timestamp the time in millis\n     */\n    _setEnteredForwardedSourcesTimestamp(timestamp) {\n        this._enteredForwardedSourcesTimestamp = timestamp;\n    }\n\n    /**\n     * Returns the timestamp of when the track entered forwarded sources.\n     *\n     * @returns {number} the time in millis\n     */\n    _getEnteredForwardedSourcesTimestamp() {\n        return this._enteredForwardedSourcesTimestamp;\n    }\n\n    /**\n     * Creates a text representation of this remote track instance.\n     * @return {string}\n     */\n    toString() {\n        return `RemoteTrack[userID: ${this.getParticipantId()}, type: ${this.getType()}, ssrc: ${\n            this.getSSRC()}, p2p: ${this.isP2P}, sourceName: ${this._sourceName}, status: ${this._getStatus()}]`;\n    }\n}\n","import { getLogger } from '@jitsi/logger';\nimport transform from 'sdp-transform';\n\nimport MediaDirection from '../../service/RTC/MediaDirection';\nimport { MediaType } from '../../service/RTC/MediaType';\nimport { VideoType } from '../../service/RTC/VideoType';\nimport browser from '../browser';\nimport FeatureFlags from '../flags/FeatureFlags';\n\nconst logger = getLogger(__filename);\nconst DESKTOP_SHARE_RATE = 500000;\nconst LD_BITRATE = 200000;\nconst SD_BITRATE = 700000;\nconst SIM_LAYER_1_RID = '1';\nconst SIM_LAYER_2_RID = '2';\nconst SIM_LAYER_3_RID = '3';\n\nexport const HD_BITRATE = 2500000;\nexport const HD_SCALE_FACTOR = 1;\nexport const LD_SCALE_FACTOR = 4;\nexport const SD_SCALE_FACTOR = 2;\nexport const SIM_LAYER_RIDS = [ SIM_LAYER_1_RID, SIM_LAYER_2_RID, SIM_LAYER_3_RID ];\n\n/**\n * Handles track related operations on TraceablePeerConnection when browser is\n * running in unified plan mode.\n */\nexport class TPCUtils {\n    /**\n     * Creates a new instance for a given TraceablePeerConnection\n     *\n     * @param peerconnection - the tpc instance for which we have utility functions.\n     */\n    constructor(peerconnection) {\n        this.pc = peerconnection;\n        const bitrateSettings = this.pc.options?.videoQuality?.maxBitratesVideo;\n        const standardBitrates = {\n            low: LD_BITRATE,\n            standard: SD_BITRATE,\n            high: HD_BITRATE\n        };\n\n        // Check if the max. bitrates for video are specified through config.js videoQuality settings.\n        // Right now only VP8 bitrates are configured on the simulcast encodings, VP9 bitrates have to be\n        // configured on the SDP using b:AS line.\n        this.videoBitrates = bitrateSettings ?? standardBitrates;\n        const encodingBitrates = this.videoBitrates.VP8 ?? this.videoBitrates;\n\n        /**\n         * The startup configuration for the stream encodings that are applicable to\n         * the video stream when a new sender is created on the peerconnection. The initial\n         * config takes into account the differences in browser's simulcast implementation.\n         *\n         * Encoding parameters:\n         * active - determine the on/off state of a particular encoding.\n         * maxBitrate - max. bitrate value to be applied to that particular encoding\n         *  based on the encoding's resolution and config.js videoQuality settings if applicable.\n         * rid - Rtp Stream ID that is configured for a particular simulcast stream.\n         * scaleResolutionDownBy - the factor by which the encoding is scaled down from the\n         *  original resolution of the captured video.\n         */\n        this.localStreamEncodingsConfig = [\n            {\n                active: true,\n                maxBitrate: browser.isFirefox() ? encodingBitrates.high : encodingBitrates.low,\n                rid: SIM_LAYER_1_RID,\n                scaleResolutionDownBy: browser.isFirefox() ? HD_SCALE_FACTOR : LD_SCALE_FACTOR\n            },\n            {\n                active: true,\n                maxBitrate: encodingBitrates.standard,\n                rid: SIM_LAYER_2_RID,\n                scaleResolutionDownBy: SD_SCALE_FACTOR\n            },\n            {\n                active: true,\n                maxBitrate: browser.isFirefox() ? encodingBitrates.low : encodingBitrates.high,\n                rid: SIM_LAYER_3_RID,\n                scaleResolutionDownBy: browser.isFirefox() ? LD_SCALE_FACTOR : HD_SCALE_FACTOR\n            }\n        ];\n    }\n\n    /**\n     * Obtains stream encodings that need to be configured on the given track based\n     * on the track media type and the simulcast setting.\n     * @param {JitsiLocalTrack} localTrack\n     */\n    _getStreamEncodings(localTrack) {\n        if (this.pc.isSimulcastOn() && localTrack.isVideoTrack()) {\n            return this.localStreamEncodingsConfig;\n        }\n\n        return localTrack.isVideoTrack()\n            ? [ {\n                active: true,\n                maxBitrate: this.videoBitrates.high\n            } ]\n            : [ { active: true } ];\n    }\n\n    /**\n     * Ensures that the ssrcs associated with a FID ssrc-group appear in the correct order, i.e.,\n     * the primary ssrc first and the secondary rtx ssrc later. This is important for unified\n     * plan since we have only one FID group per media description.\n     * @param {Object} description the webRTC session description instance for the remote\n     * description.\n     * @private\n     */\n    ensureCorrectOrderOfSsrcs(description) {\n        const parsedSdp = transform.parse(description.sdp);\n\n        parsedSdp.media.forEach(mLine => {\n            if (mLine.type === MediaType.AUDIO) {\n                return;\n            }\n            if (!mLine.ssrcGroups || !mLine.ssrcGroups.length) {\n                return;\n            }\n            let reorderedSsrcs = [];\n\n            const ssrcs = new Set();\n\n            mLine.ssrcGroups.map(group =>\n                group.ssrcs\n                    .split(' ')\n                    .filter(Boolean)\n                    .forEach(ssrc => ssrcs.add(ssrc))\n            );\n\n            ssrcs.forEach(ssrc => {\n                const sources = mLine.ssrcs.filter(source => source.id.toString() === ssrc);\n\n                reorderedSsrcs = reorderedSsrcs.concat(sources);\n            });\n            mLine.ssrcs = reorderedSsrcs;\n        });\n\n        return new RTCSessionDescription({\n            type: description.type,\n            sdp: transform.write(parsedSdp)\n        });\n    }\n\n    /**\n     * Returns the transceiver associated with a given RTCRtpSender/RTCRtpReceiver.\n     *\n     * @param {string} mediaType - type of track associated with the transceiver 'audio' or 'video'.\n     * @param {JitsiLocalTrack} localTrack - local track to be used for lookup.\n     * @returns {RTCRtpTransceiver}\n     */\n    findTransceiver(mediaType, localTrack = null) {\n        const transceiver = localTrack?.track && localTrack.getOriginalStream()\n            ? this.pc.peerconnection.getTransceivers().find(t => t.sender?.track?.id === localTrack.getTrackId())\n            : this.pc.peerconnection.getTransceivers().find(t => t.receiver?.track?.kind === mediaType);\n\n        return transceiver;\n    }\n\n    /**\n     * Takes in a *unified plan* offer and inserts the appropriate\n     * parameters for adding simulcast receive support.\n     * @param {Object} desc - A session description object\n     * @param {String} desc.type - the type (offer/answer)\n     * @param {String} desc.sdp - the sdp content\n     *\n     * @return {Object} A session description (same format as above) object\n     * with its sdp field modified to advertise simulcast receive support\n     */\n    insertUnifiedPlanSimulcastReceive(desc) {\n        // a=simulcast line is not needed on browsers where we SDP munging is used for enabling on simulcast.\n        // Remove this check when the client switches to RID/MID based simulcast on all browsers.\n        if (browser.usesSdpMungingForSimulcast()) {\n            return desc;\n        }\n        const sdp = transform.parse(desc.sdp);\n        const idx = sdp.media.findIndex(mline => mline.type === MediaType.VIDEO);\n\n        if (sdp.media[idx].rids && (sdp.media[idx].simulcast_03 || sdp.media[idx].simulcast)) {\n            // Make sure we don't have the simulcast recv line on video descriptions other than\n            // the first video description.\n            sdp.media.forEach((mline, i) => {\n                if (mline.type === MediaType.VIDEO && i !== idx) {\n                    sdp.media[i].rids = undefined;\n                    sdp.media[i].simulcast = undefined;\n\n                    // eslint-disable-next-line camelcase\n                    sdp.media[i].simulcast_03 = undefined;\n                }\n            });\n\n            return new RTCSessionDescription({\n                type: desc.type,\n                sdp: transform.write(sdp)\n            });\n        }\n\n        // In order of highest to lowest spatial quality\n        sdp.media[idx].rids = [\n            {\n                id: SIM_LAYER_1_RID,\n                direction: 'recv'\n            },\n            {\n                id: SIM_LAYER_2_RID,\n                direction: 'recv'\n            },\n            {\n                id: SIM_LAYER_3_RID,\n                direction: 'recv'\n            }\n        ];\n\n        // Firefox 72 has stopped parsing the legacy rid= parameters in simulcast attributes.\n        // eslint-disable-next-line max-len\n        // https://www.fxsitecompat.dev/en-CA/docs/2019/pt-and-rid-in-webrtc-simulcast-attributes-are-no-longer-supported/\n        const simulcastLine = browser.isFirefox() && browser.isVersionGreaterThan(71)\n            ? `recv ${SIM_LAYER_RIDS.join(';')}`\n            : `recv rid=${SIM_LAYER_RIDS.join(';')}`;\n\n        // eslint-disable-next-line camelcase\n        sdp.media[idx].simulcast_03 = {\n            value: simulcastLine\n        };\n\n        return new RTCSessionDescription({\n            type: desc.type,\n            sdp: transform.write(sdp)\n        });\n    }\n\n    /**\n    * Adds {@link JitsiLocalTrack} to the WebRTC peerconnection for the first time.\n    * @param {JitsiLocalTrack} track - track to be added to the peerconnection.\n    * @param {boolean} isInitiator - boolean that indicates if the endpoint is offerer in a p2p connection.\n    * @returns {void}\n    */\n    addTrack(localTrack, isInitiator) {\n        const track = localTrack.getTrack();\n\n        if (isInitiator) {\n            const streams = [];\n\n            if (localTrack.getOriginalStream()) {\n                streams.push(localTrack.getOriginalStream());\n            }\n\n            // Use pc.addTransceiver() for the initiator case when local tracks are getting added\n            // to the peerconnection before a session-initiate is sent over to the peer.\n            const transceiverInit = {\n                direction: MediaDirection.SENDRECV,\n                streams,\n                sendEncodings: []\n            };\n\n            if (!browser.isFirefox()) {\n                transceiverInit.sendEncodings = this._getStreamEncodings(localTrack);\n            }\n            this.pc.peerconnection.addTransceiver(track, transceiverInit);\n        } else {\n            // Use pc.addTrack() for responder case so that we can re-use the m-lines that were created\n            // when setRemoteDescription was called. pc.addTrack() automatically  attaches to any existing\n            // unused \"recv-only\" transceiver.\n            this.pc.peerconnection.addTrack(track);\n        }\n    }\n\n    /**\n     * Returns the calculated active state of the simulcast encodings based on the frame height requested for the send\n     * stream. All the encodings that have a resolution lower than the frame height requested will be enabled.\n     *\n     * @param {JitsiLocalTrack} localVideoTrack The local video track.\n     * @param {number} newHeight The resolution requested for the video track.\n     * @returns {Array<boolean>}\n     */\n    calculateEncodingsActiveState(localVideoTrack, newHeight) {\n        const localTrack = localVideoTrack.getTrack();\n        const { height } = localTrack.getSettings();\n        const encodingsState = this.localStreamEncodingsConfig\n        .map(encoding => height / encoding.scaleResolutionDownBy)\n        .map((frameHeight, idx) => {\n            let active = localVideoTrack.getVideoType() === VideoType.CAMERA\n\n                // Keep the LD stream enabled even when the LD stream's resolution is higher than of the requested\n                // resolution. This can happen when camera is captured at resolutions higher than 720p but the\n                // requested resolution is 180. Since getParameters doesn't give us information about the resolutions\n                // of the simulcast encodings, we have to rely on our initial config for the simulcast streams.\n                ? newHeight > 0 && this.localStreamEncodingsConfig[idx]?.scaleResolutionDownBy === LD_SCALE_FACTOR\n                    ? true\n                    : frameHeight <= newHeight\n\n                // Keep all the encodings for desktop track active.\n                : true;\n\n            // Disable the lower spatial layers for screensharing in Unified plan when low fps screensharing is in\n            // progress. Sending all three streams often results in the browser suspending the high resolution in low\n            // b/w and cpu cases, especially on the low end machines. Suspending the low resolution streams ensures\n            // that the highest resolution stream is available always. Safari is an exception here since it does not\n            // send the desktop stream at all if only the high resolution stream is enabled.\n            if (this.pc.isSharingLowFpsScreen()\n                && this.pc.usesUnifiedPlan()\n                && !browser.isWebKitBased()\n                && this.localStreamEncodingsConfig[idx].scaleResolutionDownBy !== HD_SCALE_FACTOR) {\n                active = false;\n            }\n\n            return active;\n        });\n\n        return encodingsState;\n    }\n\n    /**\n     * Returns the calculates max bitrates that need to be configured on the simulcast encodings based on the video\n     * type and other considerations associated with screenshare.\n     *\n     * @param {JitsiLocalTrack} localVideoTrack The local video track.\n     * @returns {Array<number>}\n     */\n    calculateEncodingsBitrates(localVideoTrack) {\n        const videoType = localVideoTrack.getVideoType();\n        const desktopShareBitrate = this.pc.options?.videoQuality?.desktopBitrate || DESKTOP_SHARE_RATE;\n        const presenterEnabled = localVideoTrack._originalStream\n            && localVideoTrack._originalStream.id !== localVideoTrack.getStreamId();\n\n        const encodingsBitrates = this.localStreamEncodingsConfig\n        .map(encoding => {\n            const bitrate = this.pc.isSharingLowFpsScreen() && !browser.isWebKitBased()\n\n                // For low fps screensharing, set a max bitrate of 500 Kbps when presenter is not turned on, 2500 Kbps\n                // otherwise.\n                ? presenterEnabled ? HD_BITRATE : desktopShareBitrate\n\n                // For high fps screenshare, 'maxBitrate' setting must be cleared on Chrome in plan-b, because\n                // if simulcast is enabled for screen and maxBitrates are set then Chrome will not send the\n                // desktop stream.\n                : videoType === VideoType.DESKTOP && browser.isChromiumBased() && !this.pc.usesUnifiedPlan()\n                    ? undefined\n                    : encoding.maxBitrate;\n\n            return bitrate;\n        });\n\n        return encodingsBitrates;\n    }\n\n    /**\n     * Replaces the existing track on a RTCRtpSender with the given track.\n     *\n     * @param {JitsiLocalTrack} oldTrack - existing track on the sender that needs to be removed.\n     * @param {JitsiLocalTrack} newTrack - new track that needs to be added to the sender.\n     * @returns {Promise<RTCRtpTransceiver>} - resolved with the associated transceiver when done, rejected otherwise.\n     */\n    replaceTrack(oldTrack, newTrack) {\n        const mediaType = newTrack?.getType() ?? oldTrack?.getType();\n        const track = newTrack?.getTrack() ?? null;\n        let transceiver;\n\n        // If old track exists, replace the track on the corresponding sender.\n        if (oldTrack && !oldTrack.isMuted()) {\n            transceiver = this.pc.peerconnection.getTransceivers().find(t => t.sender.track === oldTrack.getTrack());\n\n        // Find the first recvonly transceiver when more than one track of the same media type is being added to the pc.\n        // As part of the track addition, a new m-line was added to the remote description with direction set to\n        // recvonly.\n        } else if (FeatureFlags.isMultiStreamSupportEnabled()\n            && this.pc.getLocalTracks(mediaType)?.length\n            && !newTrack.conference) {\n            transceiver = this.pc.peerconnection.getTransceivers().find(\n                t => t.receiver.track.kind === mediaType\n                && t.direction === MediaDirection.RECVONLY\n                && t.currentDirection === MediaDirection.INACTIVE);\n\n        // For unmute operations, find the transceiver based on the track index in the source name if present, otherwise\n        // it is assumed to be the first local track that was added to the peerconnection.\n        } else {\n            transceiver = this.pc.peerconnection.getTransceivers().find(t => t.receiver.track.kind === mediaType);\n\n            const sourceName = newTrack?.getSourceName();\n\n            if (sourceName) {\n                const trackIndex = Number(sourceName.split('-')[1].substring(1));\n\n                if (trackIndex) {\n                    transceiver = this.pc.peerconnection.getTransceivers()\n                        .filter(t => t.receiver.track.kind === mediaType\n                            && t.direction !== MediaDirection.RECVONLY)[trackIndex];\n                }\n            }\n        }\n\n        if (!transceiver) {\n            return Promise.reject(new Error('replace track failed'));\n        }\n        logger.debug(`${this.pc} Replacing ${oldTrack} with ${newTrack}`);\n\n        return transceiver.sender.replaceTrack(track)\n            .then(() => Promise.resolve(transceiver));\n    }\n\n    /**\n    * Enables/disables audio transmission on the peer connection. When\n    * disabled the audio transceiver direction will be set to 'inactive'\n    * which means that no data will be sent nor accepted, but\n    * the connection should be kept alive.\n    * @param {boolean} active - true to enable audio media transmission or\n    * false to disable.\n    * @returns {void}\n    */\n    setAudioTransferActive(active) {\n        this.setMediaTransferActive(MediaType.AUDIO, active);\n    }\n\n    /**\n     * Set the simulcast stream encoding properties on the RTCRtpSender.\n     * @param {JitsiLocalTrack} track - the current track in use for which\n     * the encodings are to be set.\n     * @returns {Promise<void>} - resolved when done.\n     */\n    setEncodings(track) {\n        const mediaType = track.getType();\n        const transceiver = this.findTransceiver(mediaType, track);\n        const parameters = transceiver?.sender?.getParameters();\n\n        // Resolve if the encodings are not available yet. This happens immediately after the track is added to the\n        // peerconnection on chrome in unified-plan. It is ok to ignore and not report the error here since the\n        // action that triggers 'addTrack' (like unmute) will also configure the encodings and set bitrates after that.\n        if (!parameters?.encodings?.length) {\n            return Promise.resolve();\n        }\n        parameters.encodings = this._getStreamEncodings(track);\n\n        return transceiver.sender.setParameters(parameters);\n    }\n\n    /**\n     * Enables/disables media transmission on the peerconnection by changing the direction\n     * on the transceiver for the specified media type.\n     * @param {String} mediaType - 'audio' or 'video'\n     * @param {boolean} active - true to enable media transmission or false\n     * to disable.\n     * @returns {void}\n     */\n    setMediaTransferActive(mediaType, active) {\n        const transceivers = this.pc.peerconnection.getTransceivers()\n            .filter(t => t.receiver && t.receiver.track && t.receiver.track.kind === mediaType);\n        const localTracks = this.pc.getLocalTracks(mediaType);\n\n        logger.info(`${this.pc} ${active ? 'Enabling' : 'Suspending'} ${mediaType} media transfer.`);\n        transceivers.forEach((transceiver, idx) => {\n            if (active) {\n                // The first transceiver is for the local track and only this one can be set to 'sendrecv'\n                if (idx === 0 && localTracks.length) {\n                    transceiver.direction = MediaDirection.SENDRECV;\n                } else {\n                    transceiver.direction = MediaDirection.RECVONLY;\n                }\n            } else {\n                transceiver.direction = MediaDirection.INACTIVE;\n            }\n        });\n    }\n\n    /**\n    * Enables/disables video media transmission on the peer connection. When\n    * disabled the SDP video media direction in the local SDP will be adjusted to\n    * 'inactive' which means that no data will be sent nor accepted, but\n    * the connection should be kept alive.\n    * @param {boolean} active - true to enable video media transmission or\n    * false to disable.\n    * @returns {void}\n    */\n    setVideoTransferActive(active) {\n        this.setMediaTransferActive(MediaType.VIDEO, active);\n    }\n\n    /**\n     * Ensures that the resolution of the stream encodings are consistent with the values\n     * that were configured on the RTCRtpSender when the source was added to the peerconnection.\n     * This should prevent us from overriding the default values if the browser returns\n     * erroneous values when RTCRtpSender.getParameters is used for getting the encodings info.\n     * @param {Object} parameters - the RTCRtpEncodingParameters obtained from the browser.\n     * @returns {void}\n     */\n    updateEncodingsResolution(parameters) {\n        if (!(browser.isWebKitBased() && parameters.encodings && Array.isArray(parameters.encodings))) {\n            return;\n        }\n        const allEqualEncodings\n            = encodings => encodings.every(encoding => typeof encoding.scaleResolutionDownBy !== 'undefined'\n                && encoding.scaleResolutionDownBy === encodings[0].scaleResolutionDownBy);\n\n        // Implement the workaround only when all the encodings report the same resolution.\n        if (allEqualEncodings(parameters.encodings)) {\n            parameters.encodings.forEach((encoding, idx) => {\n                encoding.scaleResolutionDownBy = this.localStreamEncodingsConfig[idx].scaleResolutionDownBy;\n            });\n        }\n    }\n}\n","import { getLogger } from '@jitsi/logger';\nimport { Interop } from '@jitsi/sdp-interop';\nimport transform from 'sdp-transform';\n\nimport CodecMimeType from '../../service/RTC/CodecMimeType';\nimport MediaDirection from '../../service/RTC/MediaDirection';\nimport { MediaType } from '../../service/RTC/MediaType';\nimport RTCEvents from '../../service/RTC/RTCEvents';\nimport * as SignalingEvents from '../../service/RTC/SignalingEvents';\nimport { getSourceNameForJitsiTrack } from '../../service/RTC/SignalingLayer';\nimport { VideoType } from '../../service/RTC/VideoType';\nimport { SS_DEFAULT_FRAME_RATE } from '../RTC/ScreenObtainer';\nimport browser from '../browser';\nimport FeatureFlags from '../flags/FeatureFlags';\nimport LocalSdpMunger from '../sdp/LocalSdpMunger';\nimport RtxModifier from '../sdp/RtxModifier';\nimport SDP from '../sdp/SDP';\nimport SDPUtil from '../sdp/SDPUtil';\nimport SdpConsistency from '../sdp/SdpConsistency';\nimport SdpSimulcast from '../sdp/SdpSimulcast';\nimport { SdpTransformWrap } from '../sdp/SdpTransformUtil';\nimport * as GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';\n\nimport JitsiRemoteTrack from './JitsiRemoteTrack';\nimport RTC from './RTC';\nimport RTCUtils from './RTCUtils';\nimport {\n    HD_BITRATE,\n    HD_SCALE_FACTOR,\n    SIM_LAYER_RIDS,\n    TPCUtils\n} from './TPCUtils';\n\n// FIXME SDP tools should end up in some kind of util module\n\nconst logger = getLogger(__filename);\nconst DEGRADATION_PREFERENCE_CAMERA = 'maintain-framerate';\nconst DEGRADATION_PREFERENCE_DESKTOP = 'maintain-resolution';\n\n/* eslint-disable max-params */\n\n/**\n * Creates new instance of 'TraceablePeerConnection'.\n *\n * @param {RTC} rtc the instance of <tt>RTC</tt> service\n * @param {number} id the peer connection id assigned by the parent RTC module.\n * @param {SignalingLayer} signalingLayer the signaling layer instance\n * @param {object} pcConfig The {@code RTCConfiguration} to use for the WebRTC peer connection.\n * @param {object} constraints WebRTC 'PeerConnection' constraints\n * @param {boolean} isP2P indicates whether or not the new instance will be used in a peer to peer connection.\n * @param {object} options <tt>TracablePeerConnection</tt> config options.\n * @param {boolean} options.disableSimulcast if set to 'true' will disable the simulcast.\n * @param {boolean} options.disableRtx if set to 'true' will disable the RTX.\n * @param {string} options.disabledCodec the mime type of the code that should not be negotiated on the peerconnection.\n * @param {string} options.preferredCodec the mime type of the codec that needs to be made the preferred codec for the\n * peerconnection.\n * @param {boolean} options.startSilent If set to 'true' no audio will be sent or received.\n * @param {boolean} options.usesUnifiedPlan Indicates if the  browser is running in unified plan mode.\n *\n * FIXME: initially the purpose of TraceablePeerConnection was to be able to\n * debug the peer connection. Since many other responsibilities have been added\n * it would make sense to extract a separate class from it and come up with\n * a more suitable name.\n *\n * @constructor\n */\nexport default function TraceablePeerConnection(\n        rtc,\n        id,\n        signalingLayer,\n        pcConfig,\n        constraints,\n        isP2P,\n        options) {\n\n    /**\n     * Indicates whether or not this peer connection instance is actively\n     * sending/receiving audio media. When set to <tt>false</tt> the SDP audio\n     * media direction will be adjusted to 'inactive' in order to suspend\n     * the transmission.\n     * @type {boolean}\n     * @private\n     */\n    this.audioTransferActive = !(options.startSilent === true);\n\n    /**\n     * The DTMF sender instance used to send DTMF tones.\n     *\n     * @type {RTCDTMFSender|undefined}\n     * @private\n     */\n    this._dtmfSender = undefined;\n\n    /**\n     * @typedef {Object} TouchToneRequest\n     * @property {string} tones - The DTMF tones string as defined by\n     * {@code RTCDTMFSender.insertDTMF}, 'tones' argument.\n     * @property {number} duration - The amount of time in milliseconds that\n     * each DTMF should last.\n     * @property {string} interToneGap - The length of time in miliseconds to\n     * wait between tones.\n     */\n    /**\n     * TouchToneRequests which are waiting to be played. This queue is filled\n     * if there are touch tones currently being played.\n     *\n     * @type {Array<TouchToneRequest>}\n     * @private\n     */\n    this._dtmfTonesQueue = [];\n\n    /**\n     * Indicates whether or not this peer connection instance is actively\n     * sending/receiving video media. When set to <tt>false</tt> the SDP video\n     * media direction will be adjusted to 'inactive' in order to suspend\n     * the transmission.\n     * @type {boolean}\n     * @private\n     */\n    this.videoTransferActive = true;\n\n    /**\n     * The parent instance of RTC service which created this\n     * <tt>TracablePeerConnection</tt>.\n     * @type {RTC}\n     */\n    this.rtc = rtc;\n\n    /**\n     * The peer connection identifier assigned by the RTC module.\n     * @type {number}\n     */\n    this.id = id;\n\n    /**\n     * Indicates whether or not this instance is used in a peer to peer\n     * connection.\n     * @type {boolean}\n     */\n    this.isP2P = isP2P;\n\n    /**\n     * The map holds remote tracks associated with this peer connection. It maps user's JID to media type and a set of\n     * remote tracks.\n     * @type {Map<string, Map<MediaType, Set<JitsiRemoteTrack>>>}\n     */\n    this.remoteTracks = new Map();\n\n    /**\n     * A map which stores local tracks mapped by {@link JitsiLocalTrack.rtcId}\n     * @type {Map<number, JitsiLocalTrack>}\n     */\n    this.localTracks = new Map();\n\n    /**\n     * Keeps tracks of the WebRTC <tt>MediaStream</tt>s that have been added to\n     * the underlying WebRTC PeerConnection.\n     * @type {Array}\n     * @private\n     */\n    this._addedStreams = [];\n\n    /**\n     * @typedef {Object} TPCGroupInfo\n     * @property {string} semantics the SSRC groups semantics\n     * @property {Array<number>} ssrcs group's SSRCs in order where the first\n     * one is group's primary SSRC, the second one is secondary (RTX) and so\n     * on...\n     */\n    /**\n     * @typedef {Object} TPCSSRCInfo\n     * @property {Array<number>} ssrcs an array which holds all track's SSRCs\n     * @property {Array<TPCGroupInfo>} groups an array stores all track's SSRC\n     * groups\n     */\n    /**\n     * Holds the info about local track's SSRCs mapped per their\n     * {@link JitsiLocalTrack.rtcId}\n     * @type {Map<number, TPCSSRCInfo>}\n     */\n    this.localSSRCs = new Map();\n\n    /**\n     * The local ICE username fragment for this session.\n     */\n    this.localUfrag = null;\n\n    /**\n     * The remote ICE username fragment for this session.\n     */\n    this.remoteUfrag = null;\n\n    /**\n     * The DTLS transport object for the PeerConnection.\n     * Note: this assume only one shared transport exists because we bundled\n     *       all streams on the same underlying transport.\n     */\n    this._dtlsTransport = null;\n\n    /**\n     * The signaling layer which operates this peer connection.\n     * @type {SignalingLayer}\n     */\n    this.signalingLayer = signalingLayer;\n\n    // SignalingLayer listeners\n    this._peerVideoTypeChanged = this._peerVideoTypeChanged.bind(this);\n    this.signalingLayer.on(\n        SignalingEvents.PEER_VIDEO_TYPE_CHANGED,\n        this._peerVideoTypeChanged);\n\n    this._peerMutedChanged = this._peerMutedChanged.bind(this);\n    this.signalingLayer.on(\n        SignalingEvents.PEER_MUTED_CHANGED,\n        this._peerMutedChanged);\n    this.options = options;\n\n    // Make sure constraints is properly formatted in order to provide information about whether or not this\n    // connection is P2P to rtcstats.\n    const safeConstraints = constraints || {};\n\n    safeConstraints.optional = safeConstraints.optional || [];\n\n    // The `optional` parameter needs to be of type array, otherwise chrome will throw an error.\n    // Firefox and Safari just ignore it.\n    if (Array.isArray(safeConstraints.optional)) {\n        safeConstraints.optional.push({ rtcStatsSFUP2P: this.isP2P });\n    } else {\n        logger.warn('Optional param is not an array, rtcstats p2p data is omitted.');\n    }\n\n    this.peerconnection = new RTCUtils.RTCPeerConnectionType(pcConfig, safeConstraints);\n\n    this.tpcUtils = new TPCUtils(this);\n    this.updateLog = [];\n    this.stats = {};\n    this.statsinterval = null;\n\n    /**\n     * Flag used to indicate if simulcast is turned off and a cap of 500 Kbps is applied on screensharing.\n     */\n    this._capScreenshareBitrate = this.options.capScreenshareBitrate;\n\n    /**\n    * Flag used to indicate if the browser is running in unified  plan mode.\n    */\n    this._usesUnifiedPlan = options.usesUnifiedPlan;\n\n    /**\n     * Flag used to indicate if RTCRtpTransceiver#setCodecPreferences is to be used instead of SDP\n     * munging for codec selection.\n     */\n    this._usesTransceiverCodecPreferences = browser.supportsCodecPreferences() && this._usesUnifiedPlan;\n    this._usesTransceiverCodecPreferences\n        && logger.info('Using RTCRtpTransceiver#setCodecPreferences for codec selection');\n\n    /**\n     * @type {number} The max number of stats to keep in this.stats. Limit to\n     * 300 values, i.e. 5 minutes; set to 0 to disable\n     */\n    this.maxstats = options.maxstats;\n\n    this.interop = new Interop();\n\n    if (this._usesUnifiedPlan) {\n        this.simulcast = new SdpSimulcast({ numOfLayers: SIM_LAYER_RIDS.length });\n    } else {\n        const Simulcast = require('@jitsi/sdp-simulcast');\n\n        this.simulcast = new Simulcast(\n            {\n                numOfLayers: SIM_LAYER_RIDS.length,\n                explodeRemoteSimulcast: false,\n                usesUnifiedPlan: false\n            });\n    }\n\n    this.sdpConsistency = new SdpConsistency(this.toString());\n\n    /**\n     * Munges local SDP provided to the Jingle Session in order to prevent from\n     * sending SSRC updates on attach/detach and mute/unmute (for video).\n     * @type {LocalSdpMunger}\n     */\n    this.localSdpMunger = new LocalSdpMunger(this, this.rtc.getLocalEndpointId());\n\n    /**\n     * TracablePeerConnection uses RTC's eventEmitter\n     * @type {EventEmitter}\n     */\n    this.eventEmitter = rtc.eventEmitter;\n    this.rtxModifier = new RtxModifier();\n\n    /**\n     * The height constraint applied on the video sender. The default value is 2160 (4K) when layer suspension is\n     * explicitly disabled.\n     */\n    this._senderVideoMaxHeight = 2160;\n\n    /**\n     * The height constraints to be applied on the sender per local video source (source name as the key).\n     * @type {Map<string, number>}\n     */\n    this._senderMaxHeights = new Map();\n\n    // override as desired\n    this.trace = (what, info) => {\n        logger.debug(what, info);\n\n        this.updateLog.push({\n            time: new Date(),\n            type: what,\n            value: info || ''\n        });\n    };\n    this.onicecandidate = null;\n    this.peerconnection.onicecandidate = event => {\n        this.trace(\n            'onicecandidate',\n            JSON.stringify(event.candidate, null, ' '));\n\n        if (this.onicecandidate !== null) {\n            this.onicecandidate(event);\n        }\n    };\n\n    // Use track events when browser is running in unified plan mode and stream events in plan-b mode.\n    if (this._usesUnifiedPlan) {\n        this.onTrack = evt => {\n            const stream = evt.streams[0];\n\n            this._remoteTrackAdded(stream, evt.track, evt.transceiver);\n            stream.addEventListener('removetrack', e => {\n                this._remoteTrackRemoved(stream, e.track);\n            });\n        };\n        this.peerconnection.addEventListener('track', this.onTrack);\n    } else {\n        this.peerconnection.onaddstream = event => this._remoteStreamAdded(event.stream);\n        this.peerconnection.onremovestream = event => this._remoteStreamRemoved(event.stream);\n    }\n    this.onsignalingstatechange = null;\n    this.peerconnection.onsignalingstatechange = event => {\n        this.trace('onsignalingstatechange', this.signalingState);\n        if (this.onsignalingstatechange !== null) {\n            this.onsignalingstatechange(event);\n        }\n    };\n    this.oniceconnectionstatechange = null;\n    this.peerconnection.oniceconnectionstatechange = event => {\n        this.trace('oniceconnectionstatechange', this.iceConnectionState);\n        if (this.oniceconnectionstatechange !== null) {\n            this.oniceconnectionstatechange(event);\n        }\n    };\n    this.onnegotiationneeded = null;\n    this.peerconnection.onnegotiationneeded = event => {\n        this.trace('onnegotiationneeded');\n        if (this.onnegotiationneeded !== null) {\n            this.onnegotiationneeded(event);\n        }\n    };\n    this.onconnectionstatechange = null;\n    this.peerconnection.onconnectionstatechange = event => {\n        this.trace('onconnectionstatechange', this.connectionState);\n        if (this.onconnectionstatechange !== null) {\n            this.onconnectionstatechange(event);\n        }\n    };\n    this.ondatachannel = null;\n    this.peerconnection.ondatachannel = event => {\n        this.trace('ondatachannel');\n        if (this.ondatachannel !== null) {\n            this.ondatachannel(event);\n        }\n    };\n\n    if (this.maxstats) {\n        this.statsinterval = window.setInterval(() => {\n            this.getStats().then(stats => {\n                if (typeof stats?.result === 'function') {\n                    const results = stats.result();\n\n                    for (let i = 0; i < results.length; ++i) {\n                        const res = results[i];\n\n                        res.names().forEach(name => {\n                            this._processStat(res, name, res.stat(name));\n                        });\n                    }\n                } else {\n                    stats.forEach(r => this._processStat(r, '', r));\n                }\n            });\n        }, 1000);\n    }\n\n    logger.info(`Create new ${this}`);\n}\n\n/* eslint-enable max-params */\n\n/**\n * Process stat and adds it to the array of stats we store.\n * @param report the current stats report.\n * @param name the name of the report, if available\n * @param statValue the value to add.\n * @private\n */\nTraceablePeerConnection.prototype._processStat\n    = function(report, name, statValue) {\n        const id = `${report.id}-${name}`;\n        let s = this.stats[id];\n        const now = new Date();\n\n        if (!s) {\n            this.stats[id] = s = {\n                startTime: now,\n                endTime: now,\n                values: [],\n                times: []\n            };\n        }\n        s.values.push(statValue);\n        s.times.push(now.getTime());\n        if (s.values.length > this.maxstats) {\n            s.values.shift();\n            s.times.shift();\n        }\n        s.endTime = now;\n    };\n\n/**\n * Returns a string representation of a SessionDescription object.\n */\nconst dumpSDP = function(description) {\n    if (typeof description === 'undefined' || description === null) {\n        return '';\n    }\n\n    return `type: ${description.type}\\r\\n${description.sdp}`;\n};\n\n\n/**\n * Forwards the {@link peerconnection.iceConnectionState} state except that it\n * will convert \"completed\" into \"connected\" where both mean that the ICE has\n * succeeded and is up and running. We never see \"completed\" state for\n * the JVB connection, but it started appearing for the P2P one. This method\n * allows to adapt old logic to this new situation.\n * @return {string}\n */\nTraceablePeerConnection.prototype.getConnectionState = function() {\n    const state = this.peerconnection.iceConnectionState;\n\n    if (state === 'completed') {\n        return 'connected';\n    }\n\n    return state;\n};\n\n/**\n * Obtains the media direction for given {@link MediaType}. The method takes\n * into account whether or not there are any local tracks for media and\n * the {@link audioTransferActive} and {@link videoTransferActive} flags.\n * @param {MediaType} mediaType\n * @param {boolean} isAddOperation whether the direction is to be calculated after a source-add action.\n * @return {string} one of the SDP direction constants ('sendrecv, 'recvonly'\n * etc.) which should be used when setting local description on the peer\n * connection.\n * @private\n */\nTraceablePeerConnection.prototype.getDesiredMediaDirection = function(mediaType, isAddOperation = false) {\n    const hasLocalSource = this.hasAnyTracksOfType(mediaType);\n\n    if (this._usesUnifiedPlan) {\n        return isAddOperation\n            ? hasLocalSource ? MediaDirection.SENDRECV : MediaDirection.SENDONLY\n            : hasLocalSource ? MediaDirection.RECVONLY : MediaDirection.INACTIVE;\n    }\n\n    const mediaTransferActive = mediaType === MediaType.AUDIO ? this.audioTransferActive : this.videoTransferActive;\n\n    if (mediaTransferActive) {\n        return hasLocalSource ? MediaDirection.SENDRECV : MediaDirection.RECVONLY;\n    }\n\n    return MediaDirection.INACTIVE;\n};\n\n/**\n * Returns the list of RTCRtpReceivers created for the source of the given media type associated with\n * the set of remote endpoints specified.\n * @param {Array<string>} endpoints list of the endpoints\n * @param {string} mediaType 'audio' or 'video'\n * @returns {Array<RTCRtpReceiver>} list of receivers created by the peerconnection.\n */\nTraceablePeerConnection.prototype._getReceiversByEndpointIds = function(endpoints, mediaType) {\n    let remoteTracks = [];\n    let receivers = [];\n\n    for (const endpoint of endpoints) {\n        remoteTracks = remoteTracks.concat(this.getRemoteTracks(endpoint, mediaType));\n    }\n\n    // Get the ids of the MediaStreamTracks associated with each of these remote tracks.\n    const remoteTrackIds = remoteTracks.map(remote => remote.track?.id);\n\n    receivers = this.peerconnection.getReceivers()\n        .filter(receiver => receiver.track\n            && receiver.track.kind === mediaType\n            && remoteTrackIds.find(trackId => trackId === receiver.track.id));\n\n    return receivers;\n};\n\n/**\n * Tells whether or not this TPC instance is using Simulcast.\n * @return {boolean} <tt>true</tt> if simulcast is enabled and active or\n * <tt>false</tt> if it's turned off.\n */\nTraceablePeerConnection.prototype.isSimulcastOn = function() {\n    return !this.options.disableSimulcast;\n};\n\n/**\n * Handles {@link SignalingEvents.PEER_VIDEO_TYPE_CHANGED}\n * @param {string} endpointId the video owner's ID (MUC nickname)\n * @param {VideoType} videoType the new value\n * @private\n */\nTraceablePeerConnection.prototype._peerVideoTypeChanged = function(\n        endpointId,\n        videoType) {\n    // Check if endpointId has a value to avoid action on random track\n    if (!endpointId) {\n        logger.error(`${this} No endpointID on peerVideoTypeChanged`);\n\n        return;\n    }\n    const videoTrack = this.getRemoteTracks(endpointId, MediaType.VIDEO);\n\n    if (videoTrack.length) {\n        // NOTE 1 track per media type is assumed\n        videoTrack[0]._setVideoType(videoType);\n    }\n};\n\n/**\n * Handles remote track mute / unmute events.\n * @param {string} endpointId the track owner's identifier (MUC nickname)\n * @param {MediaType} mediaType \"audio\" or \"video\"\n * @param {boolean} isMuted the new mute state\n * @private\n */\nTraceablePeerConnection.prototype._peerMutedChanged = function(\n        endpointId,\n        mediaType,\n        isMuted) {\n    // Check if endpointId is a value to avoid doing action on all remote tracks\n    if (!endpointId) {\n        logger.error(`${this} On peerMuteChanged - no endpoint ID`);\n\n        return;\n    }\n    const track = this.getRemoteTracks(endpointId, mediaType);\n\n    if (track.length) {\n        // NOTE 1 track per media type is assumed\n        track[0].setMute(isMuted);\n    }\n};\n\n/**\n * Obtains audio levels of the remote audio tracks by getting the source information on the RTCRtpReceivers.\n * The information relevant to the ssrc is updated each time a RTP packet constaining the ssrc is received.\n * @param {Array<string>} speakerList list of endpoint ids for which audio levels are to be gathered.\n * @returns {Object} containing ssrc and audio level information as a key-value pair.\n */\nTraceablePeerConnection.prototype.getAudioLevels = function(speakerList = []) {\n    const audioLevels = {};\n    const audioReceivers = speakerList.length\n        ? this._getReceiversByEndpointIds(speakerList, MediaType.AUDIO)\n        : this.peerconnection.getReceivers()\n            .filter(receiver => receiver.track && receiver.track.kind === MediaType.AUDIO && receiver.track.enabled);\n\n    audioReceivers.forEach(remote => {\n        const ssrc = remote.getSynchronizationSources();\n\n        if (ssrc && ssrc.length) {\n            // As per spec, this audiolevel is a value between 0..1 (linear), where 1.0\n            // represents 0 dBov, 0 represents silence, and 0.5 represents approximately\n            // 6 dBSPL change in the sound pressure level from 0 dBov.\n            // https://www.w3.org/TR/webrtc/#dom-rtcrtpcontributingsource-audiolevel\n            audioLevels[ssrc[0].source] = ssrc[0].audioLevel;\n        }\n    });\n\n    return audioLevels;\n};\n\n/**\n * Obtains local tracks for given {@link MediaType}. If the <tt>mediaType</tt>\n * argument is omitted the list of all local tracks will be returned.\n * @param {MediaType} [mediaType]\n * @return {Array<JitsiLocalTrack>}\n */\nTraceablePeerConnection.prototype.getLocalTracks = function(mediaType) {\n    let tracks = Array.from(this.localTracks.values());\n\n    if (mediaType !== undefined) {\n        tracks = tracks.filter(track => track.getType() === mediaType);\n    }\n\n    return tracks;\n};\n\n/**\n * Retrieves the local video tracks.\n *\n * @returns {JitsiLocalTrack[]|undefined} - local video tracks.\n */\nTraceablePeerConnection.prototype.getLocalVideoTracks = function() {\n    return this.getLocalTracks(MediaType.VIDEO);\n};\n\n/**\n * Checks whether or not this {@link TraceablePeerConnection} instance contains any local tracks for given\n * <tt>mediaType</tt>.\n *\n * @param {MediaType} mediaType - The media type.\n * @return {boolean}\n */\nTraceablePeerConnection.prototype.hasAnyTracksOfType = function(mediaType) {\n    if (!mediaType) {\n        throw new Error('\"mediaType\" is required');\n    }\n\n    return this.getLocalTracks(mediaType).length > 0;\n};\n\n/**\n * Obtains all remote tracks currently known to this PeerConnection instance.\n *\n * @param {string} [endpointId] - The track owner's identifier (MUC nickname)\n * @param {MediaType} [mediaType] - The remote tracks will be filtered by their media type if this argument is\n * specified.\n * @return {Array<JitsiRemoteTrack>}\n */\nTraceablePeerConnection.prototype.getRemoteTracks = function(endpointId, mediaType) {\n    let remoteTracks = [];\n    const endpoints = endpointId ? [ endpointId ] : this.remoteTracks.keys();\n\n    for (const endpoint of endpoints) {\n        const endpointTracksByMediaType = this.remoteTracks.get(endpoint);\n\n        if (endpointTracksByMediaType) {\n            for (const trackMediaType of endpointTracksByMediaType.keys()) {\n                // per media type filtering\n                if (!mediaType || mediaType === trackMediaType) {\n                    remoteTracks = remoteTracks.concat(Array.from(endpointTracksByMediaType.get(trackMediaType)));\n                }\n            }\n        }\n    }\n\n    return remoteTracks;\n};\n\n/**\n * Parses the remote description and returns the sdp lines of the sources associated with a remote participant.\n *\n * @param {string} id Endpoint id of the remote participant.\n * @returns {Array<string>} The sdp lines that have the ssrc information.\n */\nTraceablePeerConnection.prototype.getRemoteSourceInfoByParticipant = function(id) {\n    const removeSsrcInfo = [];\n    const remoteTracks = this.getRemoteTracks(id);\n\n    if (!remoteTracks?.length) {\n        return removeSsrcInfo;\n    }\n    const primarySsrcs = remoteTracks.map(track => track.getSSRC());\n    const sdp = new SDP(this.remoteDescription.sdp);\n\n    primarySsrcs.forEach((ssrc, idx) => {\n        for (const media of sdp.media) {\n            let lines = '';\n            let ssrcLines = SDPUtil.findLines(media, `a=ssrc:${ssrc}`);\n\n            if (ssrcLines.length) {\n                if (!removeSsrcInfo[idx]) {\n                    removeSsrcInfo[idx] = '';\n                }\n\n                // Check if there are any FID groups present for the primary ssrc.\n                const fidLines = SDPUtil.findLines(media, `a=ssrc-group:FID ${ssrc}`);\n\n                if (fidLines.length) {\n                    const secondarySsrc = fidLines[0].split(' ')[2];\n\n                    lines += `${fidLines[0]}\\r\\n`;\n                    ssrcLines = ssrcLines.concat(SDPUtil.findLines(media, `a=ssrc:${secondarySsrc}`));\n                }\n                removeSsrcInfo[idx] += `${ssrcLines.join('\\r\\n')}\\r\\n`;\n                removeSsrcInfo[idx] += lines;\n            }\n        }\n    });\n\n    return removeSsrcInfo;\n};\n\n/**\n * Returns the target bitrates configured for the local video source.\n *\n * @returns {Object}\n */\nTraceablePeerConnection.prototype.getTargetVideoBitrates = function() {\n    const currentCodec = this.getConfiguredVideoCodec();\n\n    return this.tpcUtils.videoBitrates[currentCodec.toUpperCase()] || this.tpcUtils.videoBitrates;\n};\n\n/**\n * Tries to find {@link JitsiTrack} for given SSRC number. It will search both\n * local and remote tracks bound to this instance.\n * @param {number} ssrc\n * @return {JitsiTrack|null}\n */\nTraceablePeerConnection.prototype.getTrackBySSRC = function(ssrc) {\n    if (typeof ssrc !== 'number') {\n        throw new Error(`SSRC ${ssrc} is not a number`);\n    }\n    for (const localTrack of this.localTracks.values()) {\n        if (this.getLocalSSRC(localTrack) === ssrc) {\n            return localTrack;\n        }\n    }\n    for (const remoteTrack of this.getRemoteTracks()) {\n        if (remoteTrack.getSSRC() === ssrc) {\n            return remoteTrack;\n        }\n    }\n\n    return null;\n};\n\n/**\n * Tries to find SSRC number for given {@link JitsiTrack} id. It will search\n * both local and remote tracks bound to this instance.\n * @param {string} id\n * @return {number|null}\n */\nTraceablePeerConnection.prototype.getSsrcByTrackId = function(id) {\n\n    const findTrackById = track => track.getTrack().id === id;\n    const localTrack = this.getLocalTracks().find(findTrackById);\n\n    if (localTrack) {\n        return this.getLocalSSRC(localTrack);\n    }\n\n    const remoteTrack = this.getRemoteTracks().find(findTrackById);\n\n    if (remoteTrack) {\n        return remoteTrack.getSSRC();\n    }\n\n    return null;\n};\n\n/**\n * Called when new remote MediaStream is added to the PeerConnection.\n * @param {MediaStream} stream the WebRTC MediaStream for remote participant\n */\nTraceablePeerConnection.prototype._remoteStreamAdded = function(stream) {\n    const streamId = RTC.getStreamID(stream);\n\n    if (!RTC.isUserStreamById(streamId)) {\n        logger.info(`${this} ignored remote 'stream added' event for non-user stream[id=${streamId}]`);\n\n        return;\n    }\n\n    // Bind 'addtrack'/'removetrack' event handlers\n    if (browser.isChromiumBased()) {\n        stream.onaddtrack = event => {\n            this._remoteTrackAdded(stream, event.track);\n        };\n        stream.onremovetrack = event => {\n            this._remoteTrackRemoved(stream, event.track);\n        };\n    }\n\n    // Call remoteTrackAdded for each track in the stream\n    const streamAudioTracks = stream.getAudioTracks();\n\n    for (const audioTrack of streamAudioTracks) {\n        this._remoteTrackAdded(stream, audioTrack);\n    }\n    const streamVideoTracks = stream.getVideoTracks();\n\n    for (const videoTrack of streamVideoTracks) {\n        this._remoteTrackAdded(stream, videoTrack);\n    }\n};\n\n\n/**\n * Called on \"track added\" and \"stream added\" PeerConnection events (because we\n * handle streams on per track basis). Finds the owner and the SSRC for\n * the track and passes that to ChatRoom for further processing.\n * @param {MediaStream} stream the WebRTC MediaStream instance which is\n * the parent of the track\n * @param {MediaStreamTrack} track the WebRTC MediaStreamTrack added for remote\n * participant.\n * @param {RTCRtpTransceiver} transceiver the WebRTC transceiver that is created\n * for the remote participant in unified plan.\n */\nTraceablePeerConnection.prototype._remoteTrackAdded = function(stream, track, transceiver = null) {\n    const streamId = RTC.getStreamID(stream);\n    const mediaType = track.kind;\n\n    if (!this.isP2P && !RTC.isUserStreamById(streamId)) {\n        logger.info(`${this} ignored remote 'stream added' event for non-user stream[id=${streamId}]`);\n\n        return;\n    }\n    logger.info(`${this} adding remote track for stream[id=${streamId},type=${mediaType}]`);\n\n    // look up an associated JID for a stream id\n    if (!mediaType) {\n        GlobalOnErrorHandler.callErrorHandler(\n            new Error(\n                `MediaType undefined for remote track, stream id: ${streamId}`\n            ));\n\n        // Abort\n        return;\n    }\n\n    const remoteSDP = this._usesUnifiedPlan\n        ? new SDP(this.peerconnection.remoteDescription.sdp)\n        : new SDP(this.remoteDescription.sdp);\n    let mediaLines;\n\n    // In unified plan mode, find the matching mline using 'mid' if its availble, otherwise use the\n    // 'msid' attribute of the stream.\n    if (this._usesUnifiedPlan) {\n        if (transceiver && transceiver.mid) {\n            const mid = transceiver.mid;\n\n            mediaLines = remoteSDP.media.filter(mls => SDPUtil.findLine(mls, `a=mid:${mid}`));\n        } else {\n            mediaLines = remoteSDP.media.filter(mls => {\n                const msid = SDPUtil.findLine(mls, 'a=msid:');\n\n                return typeof msid === 'string' && streamId === msid.substring(7).split(' ')[0];\n            });\n        }\n    } else {\n        mediaLines = remoteSDP.media.filter(mls => mls.startsWith(`m=${mediaType}`));\n    }\n\n    if (!mediaLines.length) {\n        GlobalOnErrorHandler.callErrorHandler(\n            new Error(`No media lines found in remote SDP for remote stream[id=${streamId},type=${mediaType}]`));\n\n        // Abort\n        return;\n    }\n\n    let ssrcLines = SDPUtil.findLines(mediaLines[0], 'a=ssrc:');\n\n    ssrcLines\n        = ssrcLines.filter(line => line.indexOf(`msid:${streamId}`) !== -1);\n    if (!ssrcLines.length) {\n        GlobalOnErrorHandler.callErrorHandler(\n            new Error(`No SSRC lines found in remote SDP for remote stream[msid=${streamId},type=${mediaType}]`));\n\n        // Abort\n        return;\n    }\n\n    // FIXME the length of ssrcLines[0] not verified, but it will fail\n    // with global error handler anyway\n    const ssrcStr = ssrcLines[0].substring(7).split(' ')[0];\n    const trackSsrc = Number(ssrcStr);\n    const ownerEndpointId = this.signalingLayer.getSSRCOwner(trackSsrc);\n\n    if (isNaN(trackSsrc) || trackSsrc < 0) {\n        GlobalOnErrorHandler.callErrorHandler(\n            new Error(\n                `Invalid SSRC for remote stream[ssrc=${trackSsrc},id=${streamId},type=${mediaType}]`));\n\n        // Abort\n        return;\n    } else if (!ownerEndpointId) {\n        GlobalOnErrorHandler.callErrorHandler(\n            new Error(\n                `No SSRC owner known for remote stream[ssrc=${trackSsrc},id=${streamId},type=${mediaType}]`));\n\n        // Abort\n        return;\n    }\n\n\n    let sourceName;\n\n    if (FeatureFlags.isSourceNameSignalingEnabled()) {\n        sourceName = this.signalingLayer.getTrackSourceName(trackSsrc);\n\n        // If source name was not signaled, we'll generate one which allows testing signaling\n        // when mixing legacy(mobile) with new clients.\n        if (!sourceName) {\n            sourceName = getSourceNameForJitsiTrack(ownerEndpointId, mediaType, 0);\n        }\n    }\n\n    // eslint-disable-next-line no-undef\n    logger.info(`${this} creating remote track[endpoint=${ownerEndpointId},ssrc=${trackSsrc},`\n        + `type=${mediaType},sourceName=${sourceName}]`);\n\n    const peerMediaInfo\n        = this.signalingLayer.getPeerMediaInfo(ownerEndpointId, mediaType);\n\n    if (!peerMediaInfo) {\n        GlobalOnErrorHandler.callErrorHandler(\n            new Error(`${this}: no peer media info available for ${ownerEndpointId}`));\n\n        return;\n    }\n\n    const muted = peerMediaInfo.muted;\n    const videoType = peerMediaInfo.videoType; // can be undefined\n\n    // eslint-disable-next-line no-undef\n    this._createRemoteTrack(\n        ownerEndpointId, stream, track, mediaType, videoType, trackSsrc, muted, sourceName);\n};\n\n// FIXME cleanup params\n/* eslint-disable max-params */\n\n/**\n * Initializes a new JitsiRemoteTrack instance with the data provided by\n * the signaling layer and SDP.\n *\n * @param {string} ownerEndpointId the owner's endpoint ID (MUC nickname)\n * @param {MediaStream} stream the WebRTC stream instance\n * @param {MediaStreamTrack} track the WebRTC track instance\n * @param {MediaType} mediaType the track's type of the media\n * @param {VideoType} [videoType] the track's type of the video (if applicable)\n * @param {number} ssrc the track's main SSRC number\n * @param {boolean} muted the initial muted status\n * @param {String} sourceName the track's source name\n */\nTraceablePeerConnection.prototype._createRemoteTrack = function(\n        ownerEndpointId,\n        stream,\n        track,\n        mediaType,\n        videoType,\n        ssrc,\n        muted,\n        sourceName) {\n    let remoteTracksMap = this.remoteTracks.get(ownerEndpointId);\n\n    if (!remoteTracksMap) {\n        remoteTracksMap = new Map();\n        remoteTracksMap.set(MediaType.AUDIO, new Set());\n        remoteTracksMap.set(MediaType.VIDEO, new Set());\n        this.remoteTracks.set(ownerEndpointId, remoteTracksMap);\n    }\n\n    const userTracksByMediaType = remoteTracksMap.get(mediaType);\n\n    if (userTracksByMediaType?.size\n        && Array.from(userTracksByMediaType).find(jitsiTrack => jitsiTrack.getTrack() === track)) {\n        // Ignore duplicated event which can originate either from 'onStreamAdded' or 'onTrackAdded'.\n        logger.info(`${this} ignored duplicated track event for track[endpoint=${ownerEndpointId},type=${mediaType}]`);\n\n        return;\n    } else if (userTracksByMediaType?.size && !FeatureFlags.isSourceNameSignalingEnabled()) {\n        logger.error(`${this} received a second remote track for track[endpoint=${ownerEndpointId},type=${mediaType}]`\n            + 'deleting the existing track');\n        const existingTrack = Array.from(userTracksByMediaType)[0];\n\n        // The exisiting track needs to be removed here. This happens on Safari sometimes when a SSRC is removed from\n        // the remote description and the browser doesn't fire a 'removetrack' event on the associated MediaStream.\n        this._remoteTrackRemoved(existingTrack.getOriginalStream(), existingTrack.getTrack());\n    }\n\n    const remoteTrack\n        = new JitsiRemoteTrack(\n                this.rtc,\n                this.rtc.conference,\n                ownerEndpointId,\n                stream,\n                track,\n                mediaType,\n                videoType,\n                ssrc,\n                muted,\n                this.isP2P,\n                sourceName);\n\n    userTracksByMediaType.add(remoteTrack);\n    this.eventEmitter.emit(RTCEvents.REMOTE_TRACK_ADDED, remoteTrack, this);\n};\n\n/* eslint-enable max-params */\n\n/**\n * Handles remote stream removal.\n * @param stream the WebRTC MediaStream object which is being removed from the\n * PeerConnection\n */\nTraceablePeerConnection.prototype._remoteStreamRemoved = function(stream) {\n    if (!RTC.isUserStream(stream)) {\n        const id = RTC.getStreamID(stream);\n\n        logger.info(`Ignored remote 'stream removed' event for stream[id=${id}]`);\n\n        return;\n    }\n\n    // Call remoteTrackRemoved for each track in the stream\n    const streamVideoTracks = stream.getVideoTracks();\n\n    for (const videoTrack of streamVideoTracks) {\n        this._remoteTrackRemoved(stream, videoTrack);\n    }\n    const streamAudioTracks = stream.getAudioTracks();\n\n    for (const audioTrack of streamAudioTracks) {\n        this._remoteTrackRemoved(stream, audioTrack);\n    }\n};\n\n/**\n * Handles remote media track removal.\n *\n * @param {MediaStream} stream - WebRTC MediaStream instance which is the parent of the track.\n * @param {MediaStreamTrack} track - WebRTC MediaStreamTrack which has been removed from the PeerConnection.\n * @returns {void}\n */\nTraceablePeerConnection.prototype._remoteTrackRemoved = function(stream, track) {\n    const streamId = RTC.getStreamID(stream);\n    const trackId = track && RTC.getTrackID(track);\n\n    if (!RTC.isUserStreamById(streamId)) {\n        logger.info(`${this} ignored remote 'stream removed' event for non-user stream[id=${streamId}]`);\n\n        return;\n    }\n\n    if (!streamId) {\n        GlobalOnErrorHandler.callErrorHandler(new Error(`${this} remote track removal failed - no stream ID`));\n\n        return;\n    }\n\n    if (!trackId) {\n        GlobalOnErrorHandler.callErrorHandler(new Error(`${this} remote track removal failed - no track ID`));\n\n        return;\n    }\n\n    const toBeRemoved = this.getRemoteTracks().find(\n        remoteTrack => remoteTrack.getStreamId() === streamId\n        && remoteTrack.getTrackId() === trackId);\n\n    if (!toBeRemoved) {\n        GlobalOnErrorHandler.callErrorHandler(new Error(`${this} remote track removal failed - track not found`));\n\n        return;\n    }\n\n    logger.info(`${this} remote track removed stream[id=${streamId},trackId=${trackId}]`);\n    this._removeRemoteTrack(toBeRemoved);\n};\n\n/**\n * Removes all JitsiRemoteTracks associated with given MUC nickname (resource part of the JID).\n *\n * @param {string} owner - The resource part of the MUC JID.\n * @returns {JitsiRemoteTrack[]} - The array of removed tracks.\n */\nTraceablePeerConnection.prototype.removeRemoteTracks = function(owner) {\n    let removedTracks = [];\n    const remoteTracksByMedia = this.remoteTracks.get(owner);\n\n    if (remoteTracksByMedia) {\n        removedTracks = removedTracks.concat(Array.from(remoteTracksByMedia.get(MediaType.AUDIO)));\n        removedTracks = removedTracks.concat(Array.from(remoteTracksByMedia.get(MediaType.VIDEO)));\n        this.remoteTracks.delete(owner);\n    }\n    logger.debug(`${this} removed remote tracks[endpoint=${owner},count=${removedTracks.length}`);\n\n    return removedTracks;\n};\n\n/**\n * Removes and disposes given <tt>JitsiRemoteTrack</tt> instance. Emits {@link RTCEvents.REMOTE_TRACK_REMOVED}.\n *\n * @param {JitsiRemoteTrack} toBeRemoved - The remote track to be removed.\n * @returns {void}\n */\nTraceablePeerConnection.prototype._removeRemoteTrack = function(toBeRemoved) {\n    toBeRemoved.dispose();\n    const participantId = toBeRemoved.getParticipantId();\n    const userTracksByMediaType = this.remoteTracks.get(participantId);\n\n    if (!userTracksByMediaType) {\n        logger.error(`${this} removeRemoteTrack: no remote tracks map for endpoint=${participantId}`);\n    } else if (!userTracksByMediaType.get(toBeRemoved.getType())?.delete(toBeRemoved)) {\n        logger.error(`${this} Failed to remove ${toBeRemoved} - type mapping messed up ?`);\n    }\n    this.eventEmitter.emit(RTCEvents.REMOTE_TRACK_REMOVED, toBeRemoved);\n};\n\n/**\n * Returns a map with keys msid/mediaType and <tt>TrackSSRCInfo</tt> values.\n * @param {RTCSessionDescription} desc the local description.\n * @return {Map<string,TrackSSRCInfo>}\n */\nTraceablePeerConnection.prototype._extractSSRCMap = function(desc) {\n    /**\n     * Track SSRC infos mapped by stream ID (msid) or mediaType (unfied-plan)\n     * @type {Map<string,TrackSSRCInfo>}\n     */\n    const ssrcMap = new Map();\n\n    /**\n     * Groups mapped by primary SSRC number\n     * @type {Map<number,Array<SSRCGroupInfo>>}\n     */\n    const groupsMap = new Map();\n\n    if (typeof desc !== 'object' || desc === null\n        || typeof desc.sdp !== 'string') {\n        logger.warn('An empty description was passed as an argument');\n\n        return ssrcMap;\n    }\n\n    const session = transform.parse(desc.sdp);\n\n    if (!Array.isArray(session.media)) {\n        return ssrcMap;\n    }\n\n    let media = session.media;\n\n    // For unified plan clients, only the first audio and video mlines will have ssrcs for the local sources.\n    // The rest of the m-lines are for the recv-only sources, one for each remote source.\n    if (this._usesUnifiedPlan) {\n        media = [];\n        [ MediaType.AUDIO, MediaType.VIDEO ].forEach(mediaType => {\n            const mLine = session.media.find(m => m.type === mediaType);\n\n            mLine && media.push(mLine);\n        });\n    }\n\n    for (const mLine of media) {\n        if (!Array.isArray(mLine.ssrcs)) {\n            continue; // eslint-disable-line no-continue\n        }\n\n        if (Array.isArray(mLine.ssrcGroups)) {\n            for (const group of mLine.ssrcGroups) {\n                if (typeof group.semantics !== 'undefined'\n                    && typeof group.ssrcs !== 'undefined') {\n                    // Parse SSRCs and store as numbers\n                    const groupSSRCs = group.ssrcs.split(' ').map(ssrcStr => parseInt(ssrcStr, 10));\n                    const primarySSRC = groupSSRCs[0];\n\n                    // Note that group.semantics is already present\n                    group.ssrcs = groupSSRCs;\n\n                    // eslint-disable-next-line max-depth\n                    if (!groupsMap.has(primarySSRC)) {\n                        groupsMap.set(primarySSRC, []);\n                    }\n                    groupsMap.get(primarySSRC).push(group);\n                }\n            }\n        }\n\n        let ssrcs = mLine.ssrcs;\n\n        // Filter the ssrcs with 'msid' attribute for plan-b clients and 'cname' for unified-plan clients.\n        ssrcs = this._usesUnifiedPlan\n            ? ssrcs.filter(s => s.attribute === 'cname')\n            : ssrcs.filter(s => s.attribute === 'msid');\n\n        for (const ssrc of ssrcs) {\n            // Use the mediaType as key for the source map for unified plan clients since msids are not part of\n            // the standard and the unified plan SDPs do not have a proper msid attribute for the sources.\n            // Also the ssrcs for sources do not change for Unified plan clients since RTCRtpSender#replaceTrack is\n            // used for switching the tracks so it is safe to use the mediaType as the key for the TrackSSRCInfo map.\n            const key = this._usesUnifiedPlan ? mLine.type : ssrc.value;\n            const ssrcNumber = ssrc.id;\n            let ssrcInfo = ssrcMap.get(key);\n\n            if (!ssrcInfo) {\n                ssrcInfo = {\n                    ssrcs: [],\n                    groups: [],\n                    msid: key\n                };\n                ssrcMap.set(key, ssrcInfo);\n            }\n            ssrcInfo.ssrcs.push(ssrcNumber);\n\n            if (groupsMap.has(ssrcNumber)) {\n                const ssrcGroups = groupsMap.get(ssrcNumber);\n\n                for (const group of ssrcGroups) {\n                    ssrcInfo.groups.push(group);\n                }\n            }\n        }\n    }\n\n    return ssrcMap;\n};\n\n/**\n * Takes a SessionDescription object and returns a \"normalized\" version.\n * Currently it takes care of ordering the a=ssrc lines and denoting receive\n * only SSRCs.\n */\nconst normalizePlanB = function(desc) {\n    if (typeof desc !== 'object' || desc === null\n        || typeof desc.sdp !== 'string') {\n        logger.warn('An empty description was passed as an argument');\n\n        return desc;\n    }\n\n    // eslint-disable-next-line no-shadow\n    const transform = require('sdp-transform');\n    const session = transform.parse(desc.sdp);\n\n    if (typeof session !== 'undefined'\n            && typeof session.media !== 'undefined'\n            && Array.isArray(session.media)) {\n        session.media.forEach(mLine => {\n\n            // Chrome appears to be picky about the order in which a=ssrc lines\n            // are listed in an m-line when rtx is enabled (and thus there are\n            // a=ssrc-group lines with FID semantics). Specifically if we have\n            // \"a=ssrc-group:FID S1 S2\" and the \"a=ssrc:S2\" lines appear before\n            // the \"a=ssrc:S1\" lines, SRD fails.\n            // So, put SSRC which appear as the first SSRC in an FID ssrc-group\n            // first.\n            const firstSsrcs = [];\n            const newSsrcLines = [];\n\n            if (typeof mLine.ssrcGroups !== 'undefined'\n                && Array.isArray(mLine.ssrcGroups)) {\n                mLine.ssrcGroups.forEach(group => {\n                    if (typeof group.semantics !== 'undefined'\n                        && group.semantics === 'FID') {\n                        if (typeof group.ssrcs !== 'undefined') {\n                            firstSsrcs.push(Number(group.ssrcs.split(' ')[0]));\n                        }\n                    }\n                });\n            }\n\n            if (Array.isArray(mLine.ssrcs)) {\n                let i;\n\n                for (i = 0; i < mLine.ssrcs.length; i++) {\n                    if (typeof mLine.ssrcs[i] === 'object'\n                        && typeof mLine.ssrcs[i].id !== 'undefined'\n                        && firstSsrcs.indexOf(mLine.ssrcs[i].id) >= 0) {\n                        newSsrcLines.push(mLine.ssrcs[i]);\n                        delete mLine.ssrcs[i];\n                    }\n                }\n\n                for (i = 0; i < mLine.ssrcs.length; i++) {\n                    if (typeof mLine.ssrcs[i] !== 'undefined') {\n                        newSsrcLines.push(mLine.ssrcs[i]);\n                    }\n                }\n\n                mLine.ssrcs = replaceDefaultUnifiedPlanMsid(newSsrcLines);\n            }\n        });\n    }\n\n    const resStr = transform.write(session);\n\n\n    return new RTCSessionDescription({\n        type: desc.type,\n        sdp: resStr\n    });\n};\n\n/**\n * Unified plan differentiates a remote track not associated with a stream using\n * the msid \"-\", which can incorrectly trigger an onaddstream event in plan-b.\n * For jitsi, these tracks are actually receive-only ssrcs. To prevent\n * onaddstream from firing, remove the ssrcs with msid \"-\" except the cname\n * line. Normally the ssrcs are not used by the client, as the bridge controls\n * media flow, but keep one reference to the ssrc for the p2p case.\n *\n * @param {Array<Object>} ssrcLines - The ssrc lines from a remote description.\n * @private\n * @returns {Array<Object>} ssrcLines with removed lines referencing msid \"-\".\n */\nfunction replaceDefaultUnifiedPlanMsid(ssrcLines = []) {\n    if (!browser.isChrome() || !browser.isVersionGreaterThan(70)) {\n        return ssrcLines;\n    }\n\n    let filteredLines = [ ...ssrcLines ];\n\n    const problematicSsrcIds = ssrcLines.filter(ssrcLine =>\n        ssrcLine.attribute === 'mslabel' && ssrcLine.value === '-')\n        .map(ssrcLine => ssrcLine.id);\n\n    problematicSsrcIds.forEach(ssrcId => {\n        // Find the cname which is to be modified and left in.\n        const cnameLine = filteredLines.find(line =>\n            line.id === ssrcId && line.attribute === 'cname');\n\n        cnameLine.value = `${MediaDirection.RECVONLY}-${ssrcId}`;\n\n        // Remove all of lines for the ssrc.\n        filteredLines\n            = filteredLines.filter(line => line.id !== ssrcId);\n\n        // But re-add the cname line so there is a reference kept to the ssrc\n        // in the SDP.\n        filteredLines.push(cnameLine);\n    });\n\n    return filteredLines;\n}\n\n/**\n * Makes sure that both audio and video directions are configured as 'sendrecv'.\n * @param {Object} localDescription the SDP object as defined by WebRTC.\n * @param {object} options <tt>TracablePeerConnection</tt> config options.\n */\nconst enforceSendRecv = function(localDescription, options) {\n    if (!localDescription) {\n        throw new Error('No local description passed in.');\n    }\n\n    const transformer = new SdpTransformWrap(localDescription.sdp);\n    const audioMedia = transformer.selectMedia(MediaType.AUDIO)?.[0];\n    let changed = false;\n\n    if (audioMedia && audioMedia.direction !== MediaDirection.SENDRECV) {\n        if (options.startSilent) {\n            audioMedia.direction = MediaDirection.INACTIVE;\n        } else {\n            audioMedia.direction = MediaDirection.SENDRECV;\n        }\n\n        changed = true;\n    }\n\n    const videoMedia = transformer.selectMedia(MediaType.VIDEO)?.[0];\n\n    if (videoMedia && videoMedia.direction !== MediaDirection.SENDRECV) {\n        videoMedia.direction = MediaDirection.SENDRECV;\n        changed = true;\n    }\n\n    if (changed) {\n        return new RTCSessionDescription({\n            type: localDescription.type,\n            sdp: transformer.toRawSDP()\n        });\n    }\n\n    return localDescription;\n};\n\n/**\n *\n * @param {JitsiLocalTrack} localTrack\n */\nTraceablePeerConnection.prototype.getLocalSSRC = function(localTrack) {\n    const ssrcInfo = this._getSSRC(localTrack.rtcId);\n\n    return ssrcInfo && ssrcInfo.ssrcs[0];\n};\n\n/**\n * When doing unified plan simulcast, we'll have a set of ssrcs with the\n * same msid but no ssrc-group, since unified plan signals the simulcast\n * group via the a=simulcast line.  Unfortunately, Jicofo will complain\n * if it sees ssrcs with matching msids but no ssrc-group, so we'll inject\n * an ssrc-group line to make Jicofo happy.\n * @param desc A session description object (with 'type' and 'sdp' fields)\n * @return A session description object with its sdp field modified to\n * contain an inject ssrc-group for simulcast\n */\nTraceablePeerConnection.prototype._injectSsrcGroupForUnifiedSimulcast\n    = function(desc) {\n        const sdp = transform.parse(desc.sdp);\n        const video = sdp.media.find(mline => mline.type === 'video');\n\n        // Check if the browser supports RTX, add only the primary ssrcs to the SIM group if that is the case.\n        video.ssrcGroups = video.ssrcGroups || [];\n        const fidGroups = video.ssrcGroups.filter(group => group.semantics === 'FID');\n\n        if (video.simulcast || video.simulcast_03) {\n            const ssrcs = [];\n\n            if (fidGroups && fidGroups.length) {\n                fidGroups.forEach(group => {\n                    ssrcs.push(group.ssrcs.split(' ')[0]);\n                });\n            } else {\n                video.ssrcs.forEach(ssrc => {\n                    if (ssrc.attribute === 'msid') {\n                        ssrcs.push(ssrc.id);\n                    }\n                });\n            }\n            if (video.ssrcGroups.find(group => group.semantics === 'SIM')) {\n                // Group already exists, no need to do anything\n                return desc;\n            }\n\n            video.ssrcGroups.push({\n                semantics: 'SIM',\n                ssrcs: ssrcs.join(' ')\n            });\n        }\n\n        return new RTCSessionDescription({\n            type: desc.type,\n            sdp: transform.write(sdp)\n        });\n    };\n\n/* eslint-disable-next-line vars-on-top */\nconst getters = {\n    signalingState() {\n        return this.peerconnection.signalingState;\n    },\n    iceConnectionState() {\n        return this.peerconnection.iceConnectionState;\n    },\n    connectionState() {\n        return this.peerconnection.connectionState;\n    },\n    localDescription() {\n        let desc = this.peerconnection.localDescription;\n\n        if (!desc) {\n            logger.debug(`${this} getLocalDescription no localDescription found`);\n\n            return {};\n        }\n\n        this.trace('getLocalDescription::preTransform', dumpSDP(desc));\n\n        // If the browser is running in unified plan mode and this is a jvb connection,\n        // transform the SDP to Plan B first.\n        if (this._usesUnifiedPlan && !this.isP2P) {\n            desc = this.interop.toPlanB(desc);\n            this.trace('getLocalDescription::postTransform (Plan B)',\n                dumpSDP(desc));\n\n            desc = this._injectSsrcGroupForUnifiedSimulcast(desc);\n            this.trace('getLocalDescription::postTransform (inject ssrc group)',\n                dumpSDP(desc));\n        } else if (!this._usesUnifiedPlan) {\n            if (browser.doesVideoMuteByStreamRemove()) {\n                desc = this.localSdpMunger.maybeAddMutedLocalVideoTracksToSDP(desc);\n                logger.debug(\n                    'getLocalDescription::postTransform (munge local SDP)', desc);\n            }\n\n            // What comes out of this getter will be signalled over Jingle to\n            // the other peer, so we need to make sure the media direction is\n            // 'sendrecv' because we won't change the direction later and don't want\n            // the other peer to think we can't send or receive.\n            //\n            // Note that the description we set in chrome does have the accurate\n            // direction (e.g. 'recvonly'), since that is technically what is\n            // happening (check setLocalDescription impl).\n            desc = enforceSendRecv(desc, this.options);\n        }\n\n        // See the method's doc for more info about this transformation.\n        desc = this.localSdpMunger.transformStreamIdentifiers(desc);\n\n        return desc;\n    },\n    remoteDescription() {\n        let desc = this.peerconnection.remoteDescription;\n\n        if (!desc) {\n            logger.debug(`${this} getRemoteDescription no remoteDescription found`);\n\n            return {};\n        }\n        this.trace('getRemoteDescription::preTransform', dumpSDP(desc));\n\n        if (this._usesUnifiedPlan) {\n            if (this.isP2P) {\n                // Adjust the media direction for p2p based on whether a local source has been added.\n                desc = this._adjustRemoteMediaDirection(desc);\n            } else {\n                // If this is a jvb connection, transform the SDP to Plan B first.\n                desc = this.interop.toPlanB(desc);\n                this.trace('getRemoteDescription::postTransform (Plan B)', dumpSDP(desc));\n            }\n        }\n\n        return desc;\n    }\n};\n\nObject.keys(getters).forEach(prop => {\n    Object.defineProperty(\n        TraceablePeerConnection.prototype,\n        prop, {\n            get: getters[prop]\n        }\n    );\n});\n\nTraceablePeerConnection.prototype._getSSRC = function(rtcId) {\n    return this.localSSRCs.get(rtcId);\n};\n\n/**\n * Checks if low fps screensharing is in progress.\n *\n * @private\n * @returns {boolean} Returns true if 5 fps screensharing is in progress, false otherwise.\n */\nTraceablePeerConnection.prototype.isSharingLowFpsScreen = function() {\n    return this._isSharingScreen() && this._capScreenshareBitrate;\n};\n\n/**\n * Checks if screensharing is in progress.\n *\n * @returns {boolean}  Returns true if a desktop track has been added to the peerconnection, false otherwise.\n */\nTraceablePeerConnection.prototype._isSharingScreen = function() {\n    const tracks = this.getLocalVideoTracks();\n\n    return Boolean(tracks.find(track => track.videoType === VideoType.DESKTOP));\n};\n\n/**\n * Munges the order of the codecs in the SDP passed based on the preference\n * set through config.js settings. All instances of the specified codec are\n * moved up to the top of the list when it is preferred. The specified codec\n * is deleted from the list if the configuration specifies that the codec be\n * disabled.\n * @param {RTCSessionDescription} description that needs to be munged.\n * @returns {RTCSessionDescription} the munged description.\n */\nTraceablePeerConnection.prototype._mungeCodecOrder = function(description) {\n    if (!this.codecPreference) {\n        return description;\n    }\n\n    const parsedSdp = transform.parse(description.sdp);\n\n    // Only the m-line that defines the source the browser will be sending should need to change.\n    // This is typically the first m-line with the matching media type.\n    const mLine = parsedSdp.media.find(m => m.type === this.codecPreference.mediaType);\n\n    if (!mLine) {\n        return description;\n    }\n\n    if (this.codecPreference.enable) {\n        SDPUtil.preferCodec(mLine, this.codecPreference.mimeType);\n\n        // Strip the high profile H264 codecs on mobile clients for p2p connection.\n        // High profile codecs give better quality at the expense of higher load which\n        // we do not want on mobile clients.\n        // Jicofo offers only the baseline code for the jvb connection.\n        // TODO - add check for mobile browsers once js-utils provides that check.\n        if (this.codecPreference.mimeType === CodecMimeType.H264 && browser.isReactNative() && this.isP2P) {\n            SDPUtil.stripCodec(mLine, this.codecPreference.mimeType, true /* high profile */);\n        }\n\n        // Set the max bitrate here on the SDP so that the configured max. bitrate is effective\n        // as soon as the browser switches to VP9.\n        if (this.codecPreference.mimeType === CodecMimeType.VP9\n            && this.getConfiguredVideoCodec() === CodecMimeType.VP9) {\n            const bitrates = this.tpcUtils.videoBitrates.VP9 || this.tpcUtils.videoBitrates;\n            const hdBitrate = bitrates.high ? bitrates.high : HD_BITRATE;\n            const limit = Math.floor((this._isSharingScreen() ? HD_BITRATE : hdBitrate) / 1000);\n\n            // Use only the HD bitrate for now as there is no API available yet for configuring\n            // the bitrates on the individual SVC layers.\n            mLine.bandwidth = [ {\n                type: 'AS',\n                limit\n            } ];\n        } else {\n            // Clear the bandwidth limit in SDP when VP9 is no longer the preferred codec.\n            // This is needed on react native clients as react-native-webrtc returns the\n            // SDP that the application passed instead of returning the SDP off the native side.\n            // This line automatically gets cleared on web on every renegotiation.\n            mLine.bandwidth = undefined;\n        }\n    } else {\n        SDPUtil.stripCodec(mLine, this.codecPreference.mimeType);\n    }\n\n    return new RTCSessionDescription({\n        type: description.type,\n        sdp: transform.write(parsedSdp)\n    });\n};\n\n/**\n * Add {@link JitsiLocalTrack} to this TPC.\n * @param {JitsiLocalTrack} track\n * @param {boolean} isInitiator indicates if the endpoint is the offerer.\n * @returns {Promise<void>} - resolved when done.\n */\nTraceablePeerConnection.prototype.addTrack = function(track, isInitiator = false) {\n    const rtcId = track.rtcId;\n\n    logger.info(`${this} adding ${track}`);\n\n    if (this.localTracks.has(rtcId)) {\n\n        return Promise.reject(new Error(`${track} is already in ${this}`));\n    }\n\n    this.localTracks.set(rtcId, track);\n    const webrtcStream = track.getOriginalStream();\n\n    if (this._usesUnifiedPlan) {\n        logger.debug(`${this} TPC.addTrack using unified plan`);\n        try {\n            this.tpcUtils.addTrack(track, isInitiator);\n        } catch (error) {\n            logger.error(`${this} Adding track=${track} failed: ${error?.message}`);\n\n            return Promise.reject(error);\n        }\n    } else {\n        // Use addStream API for the plan-b case.\n        if (webrtcStream) {\n            this._addStream(webrtcStream);\n\n        // It's not ok for a track to not have a WebRTC stream if:\n        } else if (!browser.doesVideoMuteByStreamRemove()\n                    || track.isAudioTrack()\n                    || (track.isVideoTrack() && !track.isMuted())) {\n            return Promise.reject(new Error(`${this} no WebRTC stream for track=${track}`));\n        }\n\n        // Muted video tracks do not have WebRTC stream\n        if (browser.doesVideoMuteByStreamRemove() && track.isVideoTrack() && track.isMuted()) {\n            const ssrcInfo = this.generateNewStreamSSRCInfo(track);\n\n            this.sdpConsistency.setPrimarySsrc(ssrcInfo.ssrcs[0]);\n            const simGroup\n                = ssrcInfo.groups.find(groupInfo => groupInfo.semantics === 'SIM');\n\n            if (simGroup) {\n                this.simulcast.setSsrcCache(simGroup.ssrcs);\n            }\n            const fidGroups\n                = ssrcInfo.groups.filter(\n                    groupInfo => groupInfo.semantics === 'FID');\n\n            if (fidGroups) {\n                const rtxSsrcMapping = new Map();\n\n                fidGroups.forEach(fidGroup => {\n                    const primarySsrc = fidGroup.ssrcs[0];\n                    const rtxSsrc = fidGroup.ssrcs[1];\n\n                    rtxSsrcMapping.set(primarySsrc, rtxSsrc);\n                });\n                this.rtxModifier.setSsrcCache(rtxSsrcMapping);\n            }\n        }\n    }\n    let promiseChain = Promise.resolve();\n\n    // On Firefox, the encodings have to be configured on the sender only after the transceiver is created.\n    if (browser.isFirefox()) {\n        promiseChain = promiseChain.then(() => webrtcStream && this.tpcUtils.setEncodings(track));\n    }\n\n    return promiseChain;\n};\n\n/**\n * Adds local track as part of the unmute operation.\n * @param {JitsiLocalTrack} track the track to be added as part of the unmute operation.\n *\n * @return {Promise<boolean>} Promise that resolves to true if the underlying PeerConnection's\n * state has changed and renegotiation is required, false if no renegotiation is needed or\n * Promise is rejected when something goes wrong.\n */\nTraceablePeerConnection.prototype.addTrackUnmute = function(track) {\n    logger.info(`${this} Adding track=${track} as unmute`);\n\n    if (!this._assertTrackBelongs('addTrackUnmute', track)) {\n        // Abort\n\n        return Promise.reject('Track not found on the peerconnection');\n    }\n\n    const webRtcStream = track.getOriginalStream();\n\n    if (!webRtcStream) {\n        logger.error(`${this} Unable to add track=${track} as unmute - no WebRTC stream`);\n\n        return Promise.reject('Stream not found');\n    }\n\n    if (this._usesUnifiedPlan) {\n        return this.tpcUtils.replaceTrack(null, track).then(() => false);\n    }\n\n    this._addStream(webRtcStream);\n\n    return Promise.resolve(true);\n};\n\n/**\n * Adds WebRTC media stream to the underlying PeerConnection\n * @param {MediaStream} mediaStream\n * @private\n */\nTraceablePeerConnection.prototype._addStream = function(mediaStream) {\n    this.peerconnection.addStream(mediaStream);\n    this._addedStreams.push(mediaStream);\n};\n\n/**\n * Removes WebRTC media stream from the underlying PeerConection\n * @param {MediaStream} mediaStream\n */\nTraceablePeerConnection.prototype._removeStream = function(mediaStream) {\n    this.peerconnection.removeStream(mediaStream);\n    this._addedStreams\n        = this._addedStreams.filter(stream => stream !== mediaStream);\n};\n\n/**\n * This method when called will check if given <tt>localTrack</tt> belongs to\n * this TPC (that it has been previously added using {@link addTrack}). If the\n * track does not belong an error message will be logged.\n * @param {string} methodName the method name that will be logged in an error\n * message\n * @param {JitsiLocalTrack} localTrack\n * @return {boolean} <tt>true</tt> if given local track belongs to this TPC or\n * <tt>false</tt> otherwise.\n * @private\n */\nTraceablePeerConnection.prototype._assertTrackBelongs = function(\n        methodName,\n        localTrack) {\n    const doesBelong = this.localTracks.has(localTrack?.rtcId);\n\n    if (!doesBelong) {\n        logger.error(`${this} ${methodName}: track=${localTrack} does not belong to pc`);\n    }\n\n    return doesBelong;\n};\n\n/**\n * Returns the codec that is configured on the client as the preferred video codec.\n * This takes into account the current order of codecs in the local description sdp.\n *\n * @returns {CodecMimeType} The codec that is set as the preferred codec to receive\n * video in the local SDP.\n */\nTraceablePeerConnection.prototype.getConfiguredVideoCodec = function() {\n    const sdp = this.peerconnection.localDescription?.sdp;\n    const defaultCodec = CodecMimeType.VP8;\n\n    if (!sdp) {\n        return defaultCodec;\n    }\n    const parsedSdp = transform.parse(sdp);\n    const mLine = parsedSdp.media.find(m => m.type === MediaType.VIDEO);\n    const codec = mLine.rtp[0].codec;\n\n    if (codec) {\n        return Object.values(CodecMimeType).find(value => value === codec.toLowerCase());\n    }\n\n    return defaultCodec;\n};\n\n/**\n * Enables or disables simulcast for screenshare based on the frame rate requested for desktop track capture.\n *\n * @param {number} maxFps framerate to be used for desktop track capture.\n */\nTraceablePeerConnection.prototype.setDesktopSharingFrameRate = function(maxFps) {\n    const lowFps = maxFps <= SS_DEFAULT_FRAME_RATE;\n\n    this._capScreenshareBitrate = this.isSimulcastOn() && lowFps;\n};\n\n/**\n * Sets the codec preference on the peerconnection. The codec preference goes into effect when\n * the next renegotiation happens.\n *\n * @param {CodecMimeType} preferredCodec the preferred codec.\n * @param {CodecMimeType} disabledCodec the codec that needs to be disabled.\n * @returns {void}\n */\nTraceablePeerConnection.prototype.setVideoCodecs = function(preferredCodec = null, disabledCodec = null) {\n    // If both enable and disable are set, disable settings will prevail.\n    const enable = disabledCodec === null;\n    const mimeType = disabledCodec ? disabledCodec : preferredCodec;\n\n    if (this.codecPreference && (preferredCodec || disabledCodec)) {\n        this.codecPreference.enable = enable;\n        this.codecPreference.mimeType = mimeType;\n    } else if (preferredCodec || disabledCodec) {\n        this.codecPreference = {\n            enable,\n            mediaType: MediaType.VIDEO,\n            mimeType\n        };\n    } else {\n        logger.warn(`${this} Invalid codec settings[preferred=${preferredCodec},disabled=${disabledCodec}],\n            atleast one value is needed`);\n    }\n};\n\n/**\n * Tells if the given WebRTC <tt>MediaStream</tt> has been added to\n * the underlying WebRTC PeerConnection.\n * @param {MediaStream} mediaStream\n * @returns {boolean}\n */\nTraceablePeerConnection.prototype.isMediaStreamInPc = function(mediaStream) {\n    return this._addedStreams.indexOf(mediaStream) > -1;\n};\n\n/**\n * Remove local track from this TPC.\n * @param {JitsiLocalTrack} localTrack the track to be removed from this TPC.\n *\n * FIXME It should probably remove a boolean just like {@link removeTrackMute}\n *       The same applies to addTrack.\n */\nTraceablePeerConnection.prototype.removeTrack = function(localTrack) {\n    const webRtcStream = localTrack.getOriginalStream();\n\n    this.trace(\n        'removeStream',\n        localTrack.rtcId, webRtcStream ? webRtcStream.id : undefined);\n\n    if (!this._assertTrackBelongs('removeStream', localTrack)) {\n        // Abort - nothing to be done here\n        return;\n    }\n    this.localTracks.delete(localTrack.rtcId);\n    this.localSSRCs.delete(localTrack.rtcId);\n\n    if (webRtcStream) {\n        this.peerconnection.removeStream(webRtcStream);\n    }\n};\n\n/**\n * Returns the sender corresponding to the given media type.\n * @param {MEDIA_TYPE} mediaType - The media type 'audio' or 'video' to be used for the search.\n * @returns {RTPSender|undefined} - The found sender or undefined if no sender\n * was found.\n */\nTraceablePeerConnection.prototype.findSenderByKind = function(mediaType) {\n    if (this.peerconnection.getSenders) {\n        return this.peerconnection.getSenders().find(s => s.track && s.track.kind === mediaType);\n    }\n};\n\n/**\n * Returns the receiver corresponding to the given MediaStreamTrack.\n *\n * @param {MediaSreamTrack} track - The media stream track used for the search.\n * @returns {RTCRtpReceiver|undefined} - The found receiver or undefined if no receiver\n * was found.\n */\nTraceablePeerConnection.prototype.findReceiverForTrack = function(track) {\n    return this.peerconnection.getReceivers().find(r => r.track === track);\n};\n\n/**\n * Returns the sender corresponding to the given MediaStreamTrack.\n *\n * @param {MediaSreamTrack} track - The media stream track used for the search.\n * @returns {RTCRtpSender|undefined} - The found sender or undefined if no sender\n * was found.\n */\nTraceablePeerConnection.prototype.findSenderForTrack = function(track) {\n    if (this.peerconnection.getSenders) {\n        return this.peerconnection.getSenders().find(s => s.track === track);\n    }\n};\n\n/**\n * Replaces <tt>oldTrack</tt> with <tt>newTrack</tt> from the peer connection.\n * Either <tt>oldTrack</tt> or <tt>newTrack</tt> can be null; replacing a valid\n * <tt>oldTrack</tt> with a null <tt>newTrack</tt> effectively just removes\n * <tt>oldTrack</tt>\n *\n * @param {JitsiLocalTrack|null} oldTrack - The current track in use to be replaced on the pc.\n * @param {JitsiLocalTrack|null} newTrack - The new track to be used.\n *\n * @returns {Promise<boolean>} - If the promise resolves with true, renegotiation will be needed.\n * Otherwise no renegotiation is needed.\n */\nTraceablePeerConnection.prototype.replaceTrack = function(oldTrack, newTrack) {\n    if (!(oldTrack || newTrack)) {\n        logger.info(`${this} replaceTrack called with no new track and no old track`);\n\n        return Promise.resolve();\n    }\n\n    // If a track is being added to the peerconnection for the first time, we want the source signaling to be sent to\n    // Jicofo before the mute state is sent over presence. Therefore, trigger a renegotiation in this case. If we\n    // rely on \"negotiationneeded\" fired by the browser to signal new ssrcs, the mute state in presence will be sent\n    // before the source signaling which is undesirable.\n    const negotiationNeeded = Boolean(!oldTrack || !this.localTracks.has(oldTrack?.rtcId));\n\n    if (this._usesUnifiedPlan) {\n        logger.debug(`${this} TPC.replaceTrack using unified plan`);\n        const mediaType = newTrack?.getType() ?? oldTrack?.getType();\n        const stream = newTrack?.getOriginalStream();\n        const promise = newTrack && !stream\n\n            // Ignore cases when the track is replaced while the device is in a muted state.\n            // The track will be replaced again on the peerconnection when the user unmutes.\n            ? Promise.resolve()\n            : this.tpcUtils.replaceTrack(oldTrack, newTrack);\n\n        return promise\n            .then(transceiver => {\n                oldTrack && this.localTracks.delete(oldTrack.rtcId);\n                newTrack && this.localTracks.set(newTrack.rtcId, newTrack);\n                const mediaActive = mediaType === MediaType.AUDIO\n                    ? this.audioTransferActive\n                    : this.videoTransferActive;\n\n                // Set the transceiver direction only if media is not suspended on the connection. This happens when\n                // the client is using the p2p connection. Transceiver direction is updated when media is resumed on\n                // this connection again.\n                if (transceiver && mediaActive) {\n                    transceiver.direction = newTrack ? MediaDirection.SENDRECV : MediaDirection.RECVONLY;\n                }\n\n                // Avoid configuring the encodings on Chromium/Safari until simulcast is configured\n                // for the newly added track using SDP munging which happens during the renegotiation.\n                const configureEncodingsPromise = browser.usesSdpMungingForSimulcast() || !newTrack\n                    ? Promise.resolve()\n                    : this.tpcUtils.setEncodings(newTrack);\n\n                // Force renegotiation only when the source is added for the first time.\n                return configureEncodingsPromise.then(() => negotiationNeeded);\n            });\n    }\n\n    logger.debug(`${this} TPC.replaceTrack using plan B`);\n\n    let promiseChain = Promise.resolve();\n\n    if (oldTrack) {\n        this.removeTrack(oldTrack);\n    }\n    if (newTrack) {\n        promiseChain = this.addTrack(newTrack);\n    }\n\n    return promiseChain.then(() => true);\n};\n\n/**\n * Removes local track as part of the mute operation.\n * @param {JitsiLocalTrack} localTrack the local track to be remove as part of\n * the mute operation.\n * @return {Promise<boolean>} Promise that resolves to true if the underlying PeerConnection's\n * state has changed and renegotiation is required, false if no renegotiation is needed or\n * Promise is rejected when something goes wrong.\n */\nTraceablePeerConnection.prototype.removeTrackMute = function(localTrack) {\n    const webRtcStream = localTrack.getOriginalStream();\n\n    this.trace(\n        'removeStreamMute',\n        localTrack.rtcId, webRtcStream ? webRtcStream.id : null);\n\n    if (!this._assertTrackBelongs('removeStreamMute', localTrack)) {\n        // Abort - nothing to be done here\n        return Promise.reject('Track not found in the peerconnection');\n    }\n\n    if (this._usesUnifiedPlan) {\n        return this.tpcUtils.replaceTrack(localTrack, null).then(() => false);\n    }\n\n    if (webRtcStream) {\n        logger.info(`${this} Removing track=${localTrack} as mute`);\n        this._removeStream(webRtcStream);\n\n        return Promise.resolve(true);\n    }\n\n    logger.error(`${this} removeStreamMute - no WebRTC stream for track=${localTrack}`);\n\n    return Promise.reject('Stream not found');\n};\n\nTraceablePeerConnection.prototype.createDataChannel = function(label, opts) {\n    this.trace('createDataChannel', label, opts);\n\n    return this.peerconnection.createDataChannel(label, opts);\n};\n\n/**\n * Ensures that the simulcast ssrc-group appears after any other ssrc-groups\n * in the SDP so that simulcast is properly activated.\n *\n * @param {Object} localSdp the WebRTC session description instance for\n * the local description.\n * @private\n */\nTraceablePeerConnection.prototype._ensureSimulcastGroupIsLast = function(localSdp) {\n    let sdpStr = localSdp.sdp;\n\n    const videoStartIndex = sdpStr.indexOf('m=video');\n    const simStartIndex = sdpStr.indexOf('a=ssrc-group:SIM', videoStartIndex);\n    let otherStartIndex = sdpStr.lastIndexOf('a=ssrc-group');\n\n    if (simStartIndex === -1\n        || otherStartIndex === -1\n        || otherStartIndex === simStartIndex) {\n        return localSdp;\n    }\n\n    const simEndIndex = sdpStr.indexOf('\\r\\n', simStartIndex);\n    const simStr = sdpStr.substring(simStartIndex, simEndIndex + 2);\n\n    sdpStr = sdpStr.replace(simStr, '');\n    otherStartIndex = sdpStr.lastIndexOf('a=ssrc-group');\n    const otherEndIndex = sdpStr.indexOf('\\r\\n', otherStartIndex);\n    const sdpHead = sdpStr.slice(0, otherEndIndex);\n    const simStrTrimmed = simStr.trim();\n    const sdpTail = sdpStr.slice(otherEndIndex);\n\n    sdpStr = `${sdpHead}\\r\\n${simStrTrimmed}${sdpTail}`;\n\n    return new RTCSessionDescription({\n        type: localSdp.type,\n        sdp: sdpStr\n    });\n};\n\n/**\n * Will adjust audio and video media direction in the given SDP object to\n * reflect the current status of the {@link audioTransferActive} and\n * {@link videoTransferActive} flags.\n * @param {RTCSessionDescription} localDescription the WebRTC session description instance for\n * the local description.\n * @private\n */\nTraceablePeerConnection.prototype._adjustLocalMediaDirection = function(localDescription) {\n    const transformer = new SdpTransformWrap(localDescription.sdp);\n    let modifiedDirection = false;\n    const audioMedia = transformer.selectMedia(MediaType.AUDIO)?.[0];\n\n    if (audioMedia) {\n        const desiredAudioDirection = this.getDesiredMediaDirection(MediaType.AUDIO);\n\n        if (audioMedia.direction !== desiredAudioDirection) {\n            audioMedia.direction = desiredAudioDirection;\n            logger.info(`${this} Adjusted local audio direction to ${desiredAudioDirection}`);\n            modifiedDirection = true;\n        }\n    } else {\n        logger.warn(`${this} No \"audio\" media found in the local description`);\n    }\n\n    const videoMedia = transformer.selectMedia(MediaType.VIDEO)?.[0];\n\n    if (videoMedia) {\n        const desiredVideoDirection = this.getDesiredMediaDirection(MediaType.VIDEO);\n\n        if (videoMedia.direction !== desiredVideoDirection) {\n            videoMedia.direction = desiredVideoDirection;\n            logger.info(`${this} Adjusted local video direction to ${desiredVideoDirection}`);\n            modifiedDirection = true;\n        }\n    } else {\n        logger.warn(`${this} No \"video\" media found in the local description`);\n    }\n\n    if (modifiedDirection) {\n        return new RTCSessionDescription({\n            type: localDescription.type,\n            sdp: transformer.toRawSDP()\n        });\n    }\n\n    return localDescription;\n};\n\n/**\n * Adjusts the media direction on the remote description based on availability of local and remote sources in a p2p\n * media connection.\n *\n * @param {RTCSessionDescription} remoteDescription the WebRTC session description instance for the remote description.\n * @returns the transformed remoteDescription.\n * @private\n */\nTraceablePeerConnection.prototype._adjustRemoteMediaDirection = function(remoteDescription) {\n    const transformer = new SdpTransformWrap(remoteDescription.sdp);\n\n    [ MediaType.AUDIO, MediaType.VIDEO ].forEach(mediaType => {\n        const media = transformer.selectMedia(mediaType)?.[0];\n        const hasLocalSource = this.hasAnyTracksOfType(mediaType);\n        const hasRemoteSource = this.getRemoteTracks(null, mediaType).length > 0;\n\n        media.direction = hasLocalSource && hasRemoteSource\n            ? MediaDirection.SENDRECV\n            : hasLocalSource\n                ? MediaDirection.RECVONLY\n                : hasRemoteSource ? MediaDirection.SENDONLY : MediaDirection.INACTIVE;\n    });\n\n    return new RTCSessionDescription({\n        type: remoteDescription.type,\n        sdp: transformer.toRawSDP()\n    });\n};\n\n/**\n * Munges the stereo flag as well as the opusMaxAverageBitrate in the SDP, based\n * on values set through config.js, if present.\n *\n * @param {RTCSessionDescription} description that needs to be munged.\n * @returns {RTCSessionDescription} the munged description.\n */\nTraceablePeerConnection.prototype._mungeOpus = function(description) {\n    const { audioQuality } = this.options;\n\n    if (!audioQuality?.stereo && !audioQuality?.opusMaxAverageBitrate) {\n        return description;\n    }\n\n    const parsedSdp = transform.parse(description.sdp);\n    const mLines = parsedSdp.media;\n\n    for (const mLine of mLines) {\n        if (mLine.type === 'audio') {\n            const { payload } = mLine.rtp.find(protocol => protocol.codec === CodecMimeType.OPUS);\n\n            if (!payload) {\n                // eslint-disable-next-line no-continue\n                continue;\n            }\n\n            let fmtpOpus = mLine.fmtp.find(protocol => protocol.payload === payload);\n\n            if (!fmtpOpus) {\n                fmtpOpus = {\n                    payload,\n                    config: ''\n                };\n            }\n\n            const fmtpConfig = transform.parseParams(fmtpOpus.config);\n            let sdpChanged = false;\n\n            if (audioQuality?.stereo) {\n                fmtpConfig.stereo = 1;\n                sdpChanged = true;\n            }\n\n            if (audioQuality?.opusMaxAverageBitrate) {\n                fmtpConfig.maxaveragebitrate = audioQuality.opusMaxAverageBitrate;\n                sdpChanged = true;\n            }\n\n            if (!sdpChanged) {\n                // eslint-disable-next-line no-continue\n                continue;\n            }\n\n            let mungedConfig = '';\n\n            for (const key of Object.keys(fmtpConfig)) {\n                mungedConfig += `${key}=${fmtpConfig[key]}; `;\n            }\n\n            fmtpOpus.config = mungedConfig.trim();\n        }\n    }\n\n    return new RTCSessionDescription({\n        type: description.type,\n        sdp: transform.write(parsedSdp)\n    });\n};\n\n/**\n * Sets up the _dtlsTransport object and initializes callbacks for it.\n */\nTraceablePeerConnection.prototype._initializeDtlsTransport = function() {\n    // We are assuming here that we only have one bundled transport here\n    if (!this.peerconnection.getSenders || this._dtlsTransport) {\n        return;\n    }\n\n    const senders = this.peerconnection.getSenders();\n\n    if (senders.length !== 0 && senders[0].transport) {\n        this._dtlsTransport = senders[0].transport;\n\n        this._dtlsTransport.onerror = error => {\n            logger.error(`${this} DtlsTransport error: ${error}`);\n        };\n\n        this._dtlsTransport.onstatechange = () => {\n            this.trace('dtlsTransport.onstatechange', this._dtlsTransport.state);\n        };\n    }\n};\n\n\n/**\n * Configures the stream encodings depending on the video type and the bitrates configured.\n *\n * @param {JitsiLocalTrack} - The local track for which the sender encodings have to configured.\n * @returns {Promise} promise that will be resolved when the operation is successful and rejected otherwise.\n */\nTraceablePeerConnection.prototype.configureSenderVideoEncodings = function(localVideoTrack = null) {\n    if (FeatureFlags.isSourceNameSignalingEnabled()) {\n        if (localVideoTrack) {\n            return this.setSenderVideoConstraints(\n                this._senderMaxHeights.get(localVideoTrack.getSourceName()),\n                localVideoTrack);\n        }\n        const promises = [];\n\n        for (const track of this.getLocalVideoTracks()) {\n            promises.push(this.setSenderVideoConstraints(this._senderMaxHeights.get(track.getSourceName()), track));\n        }\n\n        return Promise.allSettled(promises);\n    }\n\n    let localTrack = localVideoTrack;\n\n    if (!localTrack) {\n        localTrack = this.getLocalVideoTracks()[0];\n    }\n\n    return this.setSenderVideoConstraints(this._senderVideoMaxHeight, localTrack);\n};\n\nTraceablePeerConnection.prototype.setLocalDescription = function(description) {\n    let localDescription = description;\n\n    this.trace('setLocalDescription::preTransform', dumpSDP(localDescription));\n\n    // Munge stereo flag and opusMaxAverageBitrate based on config.js\n    localDescription = this._mungeOpus(localDescription);\n\n    if (!this._usesUnifiedPlan) {\n        localDescription = this._adjustLocalMediaDirection(localDescription);\n        localDescription = this._ensureSimulcastGroupIsLast(localDescription);\n    }\n\n    // Munge the order of the codecs based on the preferences set through config.js if we are using SDP munging.\n    if (!this._usesTransceiverCodecPreferences) {\n        localDescription = this._mungeCodecOrder(localDescription);\n    }\n\n    this.trace('setLocalDescription::postTransform', dumpSDP(localDescription));\n\n    return new Promise((resolve, reject) => {\n        this.peerconnection.setLocalDescription(localDescription)\n            .then(() => {\n                this.trace('setLocalDescriptionOnSuccess');\n                const localUfrag = SDPUtil.getUfrag(localDescription.sdp);\n\n                if (localUfrag !== this.localUfrag) {\n                    this.localUfrag = localUfrag;\n                    this.eventEmitter.emit(RTCEvents.LOCAL_UFRAG_CHANGED, this, localUfrag);\n                }\n\n                this._initializeDtlsTransport();\n\n                resolve();\n            }, err => {\n                this.trace('setLocalDescriptionOnFailure', err);\n                this.eventEmitter.emit(RTCEvents.SET_LOCAL_DESCRIPTION_FAILED, err, this);\n                reject(err);\n            });\n    });\n};\n\n/**\n * Enables/disables audio media transmission on this peer connection. When\n * disabled the SDP audio media direction in the local SDP will be adjusted to\n * 'inactive' which means that no data will be sent nor accepted, but\n * the connection should be kept alive.\n * @param {boolean} active <tt>true</tt> to enable audio media transmission or\n * <tt>false</tt> to disable. If the value is not a boolean the call will have\n * no effect.\n * @return {boolean} <tt>true</tt> if the value has changed and sRD/sLD cycle\n * needs to be executed in order for the changes to take effect or\n * <tt>false</tt> if the given value was the same as the previous one.\n * @public\n */\nTraceablePeerConnection.prototype.setAudioTransferActive = function(active) {\n    logger.debug(`${this} audio transfer active: ${active}`);\n    const changed = this.audioTransferActive !== active;\n\n    this.audioTransferActive = active;\n\n    if (this._usesUnifiedPlan) {\n        this.tpcUtils.setAudioTransferActive(active);\n\n        // false means no renegotiation up the chain which is not needed in the Unified mode\n        return false;\n    }\n\n    return changed;\n};\n\nTraceablePeerConnection.prototype.setRemoteDescription = function(description) {\n    let remoteDescription = description;\n\n    this.trace('setRemoteDescription::preTransform', dumpSDP(description));\n\n    // Munge stereo flag and opusMaxAverageBitrate based on config.js\n    remoteDescription = this._mungeOpus(remoteDescription);\n\n    if (this._usesUnifiedPlan) {\n        // Translate the SDP to Unified plan format first for the jvb case, p2p case will only have 2 m-lines.\n        if (!this.isP2P) {\n            const currentDescription = this.peerconnection.remoteDescription;\n\n            remoteDescription = this.interop.toUnifiedPlan(remoteDescription, currentDescription);\n            this.trace('setRemoteDescription::postTransform (Unified)', dumpSDP(remoteDescription));\n        }\n        if (this.isSimulcastOn()) {\n            // Implode the simulcast ssrcs so that the remote sdp has only the first ssrc in the SIM group.\n            remoteDescription = this.simulcast.mungeRemoteDescription(remoteDescription);\n            this.trace('setRemoteDescription::postTransform (simulcast)', dumpSDP(remoteDescription));\n\n            remoteDescription = this.tpcUtils.insertUnifiedPlanSimulcastReceive(remoteDescription);\n            this.trace('setRemoteDescription::postTransform (sim receive)', dumpSDP(remoteDescription));\n        }\n        remoteDescription = this.tpcUtils.ensureCorrectOrderOfSsrcs(remoteDescription);\n        this.trace('setRemoteDescription::postTransform (correct ssrc order)', dumpSDP(remoteDescription));\n    } else {\n        if (this.isSimulcastOn()) {\n            // Implode the simulcast ssrcs so that the remote sdp has only the first ssrc in the SIM group.\n            remoteDescription = this.simulcast.mungeRemoteDescription(\n                remoteDescription,\n                true /* add x-google-conference flag */);\n            this.trace('setRemoteDescription::postTransform (simulcast)', dumpSDP(remoteDescription));\n        }\n        remoteDescription = normalizePlanB(remoteDescription);\n    }\n\n    // Munge the order of the codecs based on the preferences set through config.js.\n    remoteDescription = this._mungeCodecOrder(remoteDescription);\n    this.trace('setRemoteDescription::postTransform (munge codec order)', dumpSDP(remoteDescription));\n\n    return new Promise((resolve, reject) => {\n        this.peerconnection.setRemoteDescription(remoteDescription)\n            .then(() => {\n                this.trace('setRemoteDescriptionOnSuccess');\n                const remoteUfrag = SDPUtil.getUfrag(remoteDescription.sdp);\n\n                if (remoteUfrag !== this.remoteUfrag) {\n                    this.remoteUfrag = remoteUfrag;\n                    this.eventEmitter.emit(RTCEvents.REMOTE_UFRAG_CHANGED, this, remoteUfrag);\n                }\n\n                this._initializeDtlsTransport();\n\n                resolve();\n            }, err => {\n                this.trace('setRemoteDescriptionOnFailure', err);\n                this.eventEmitter.emit(RTCEvents.SET_REMOTE_DESCRIPTION_FAILED, err, this);\n                reject(err);\n            });\n    });\n};\n\n/**\n * Changes the resolution of the video stream that is sent to the peer based on the resolution requested by the peer\n * and user preference, sets the degradation preference on the sender based on the video type, configures the maximum\n * bitrates on the send stream.\n *\n * @param {number} frameHeight - The max frame height to be imposed on the outgoing video stream.\n * @param {JitsiLocalTrack} - The local track for which the sender constraints have to be applied.\n * @returns {Promise} promise that will be resolved when the operation is successful and rejected otherwise.\n */\nTraceablePeerConnection.prototype.setSenderVideoConstraints = function(frameHeight, localVideoTrack) {\n    if (frameHeight < 0) {\n        throw new Error(`Invalid frameHeight: ${frameHeight}`);\n    }\n\n    // XXX: This is not yet supported on mobile.\n    if (browser.isReactNative()) {\n        return Promise.resolve();\n    }\n\n    if (FeatureFlags.isSourceNameSignalingEnabled()) {\n        this._senderMaxHeights.set(localVideoTrack.getSourceName(), frameHeight);\n    } else {\n        this._senderVideoMaxHeight = frameHeight;\n    }\n\n    if (!localVideoTrack || localVideoTrack.isMuted()) {\n        return Promise.resolve();\n    }\n    const videoSender = this.findSenderForTrack(localVideoTrack.getTrack());\n\n    if (!videoSender) {\n        return Promise.resolve();\n    }\n    const parameters = videoSender.getParameters();\n\n    if (!parameters?.encodings?.length) {\n        return Promise.resolve();\n    }\n\n    // Set the degradation preference.\n    const preference = this.isSharingLowFpsScreen()\n        ? DEGRADATION_PREFERENCE_DESKTOP // Prefer resolution for low fps share.\n        : DEGRADATION_PREFERENCE_CAMERA; // Prefer frame-rate for high fps share and camera.\n\n    parameters.degradationPreference = preference;\n    logger.info(`${this} Setting degradation preference [preference=${preference},track=${localVideoTrack}`);\n\n    // Calculate the encodings active state based on the resolution requested by the bridge.\n    this.encodingsEnabledState = this.tpcUtils.calculateEncodingsActiveState(localVideoTrack, frameHeight);\n    const maxBitrates = this.tpcUtils.calculateEncodingsBitrates(localVideoTrack);\n    const videoType = localVideoTrack.getVideoType();\n\n    if (this.isSimulcastOn()) {\n        for (const encoding in parameters.encodings) {\n            if (parameters.encodings.hasOwnProperty(encoding)) {\n                parameters.encodings[encoding].active = this.encodingsEnabledState[encoding];\n\n                // Firefox doesn't follow the spec and lets application specify the degradation preference on the\n                // encodings.\n                browser.isFirefox() && (parameters.encodings[encoding].degradationPreference = preference);\n\n                // Max bitrates are configured on the encodings only for VP8.\n                if (this.getConfiguredVideoCodec() === CodecMimeType.VP8\n                    && (this.options?.videoQuality?.maxBitratesVideo\n                        || this.isSharingLowFpsScreen()\n                        || this._usesUnifiedPlan)) {\n                    parameters.encodings[encoding].maxBitrate = maxBitrates[encoding];\n                }\n            }\n        }\n        this.tpcUtils.updateEncodingsResolution(parameters);\n\n    // For p2p and cases and where simulcast is explicitly disabled.\n    } else if (frameHeight > 0) {\n        let scaleFactor = HD_SCALE_FACTOR;\n\n        // Do not scale down encodings for desktop tracks for non-simulcast case.\n        if (videoType === VideoType.CAMERA && localVideoTrack.resolution > frameHeight) {\n            scaleFactor = Math.floor(localVideoTrack.resolution / frameHeight);\n        }\n\n        parameters.encodings[0].active = true;\n        parameters.encodings[0].scaleResolutionDownBy = scaleFactor;\n\n        // Firefox doesn't follow the spec and lets application specify the degradation preference on the encodings.\n        browser.isFirefox() && (parameters.encodings[0].degradationPreference = preference);\n\n        // Configure the bitrate.\n        if (this.getConfiguredVideoCodec() === CodecMimeType.VP8 && this.options?.videoQuality?.maxBitratesVideo) {\n            let bitrate = this.getTargetVideoBitrates()?.high;\n\n            if (videoType === VideoType.CAMERA) {\n                bitrate = this.tpcUtils.localStreamEncodingsConfig\n                    .find(layer => layer.scaleResolutionDownBy === scaleFactor)?.maxBitrate ?? bitrate;\n            }\n            parameters.encodings[0].maxBitrate = bitrate;\n        }\n    } else {\n        parameters.encodings[0].active = false;\n    }\n\n    logger.info(`${this} setting max height=${frameHeight},encodings=${JSON.stringify(parameters.encodings)}`);\n\n    return videoSender.setParameters(parameters).then(() => {\n        localVideoTrack.maxEnabledResolution = frameHeight;\n        this.eventEmitter.emit(RTCEvents.LOCAL_TRACK_MAX_ENABLED_RESOLUTION_CHANGED, localVideoTrack);\n    });\n};\n\n/**\n * Enables/disables video media transmission on this peer connection. When\n * disabled the SDP video media direction in the local SDP will be adjusted to\n * 'inactive' which means that no data will be sent nor accepted, but\n * the connection should be kept alive.\n * @param {boolean} active <tt>true</tt> to enable video media transmission or\n * <tt>false</tt> to disable. If the value is not a boolean the call will have\n * no effect.\n * @return {boolean} <tt>true</tt> if the value has changed and sRD/sLD cycle\n * needs to be executed in order for the changes to take effect or\n * <tt>false</tt> if the given value was the same as the previous one.\n * @public\n */\nTraceablePeerConnection.prototype.setVideoTransferActive = function(active) {\n    logger.debug(`${this} video transfer active: ${active}`);\n    const changed = this.videoTransferActive !== active;\n\n    this.videoTransferActive = active;\n\n    if (this._usesUnifiedPlan) {\n        this.tpcUtils.setVideoTransferActive(active);\n\n        // false means no renegotiation up the chain which is not needed in the Unified mode\n        return false;\n    }\n\n    return changed;\n};\n\n/**\n * Sends DTMF tones if possible.\n *\n * @param {string} tones - The DTMF tones string as defined by {@code RTCDTMFSender.insertDTMF}, 'tones' argument.\n * @param {number} duration - The amount of time in milliseconds that each DTMF should last. It's 200ms by default.\n * @param {number} interToneGap - The length of time in miliseconds to wait between tones. It's 200ms by default.\n *\n * @returns {void}\n */\nTraceablePeerConnection.prototype.sendTones = function(tones, duration = 200, interToneGap = 200) {\n    if (!this._dtmfSender) {\n        if (this.peerconnection.getSenders) {\n            const rtpSender = this.peerconnection.getSenders().find(s => s.dtmf);\n\n            this._dtmfSender = rtpSender && rtpSender.dtmf;\n            this._dtmfSender && logger.info(`${this} initialized DTMFSender using getSenders`);\n        }\n\n        if (!this._dtmfSender) {\n            const localAudioTrack = Array.from(this.localTracks.values()).find(t => t.isAudioTrack());\n\n            if (this.peerconnection.createDTMFSender && localAudioTrack) {\n                this._dtmfSender = this.peerconnection.createDTMFSender(localAudioTrack.getTrack());\n            }\n            this._dtmfSender && logger.info(`${this} initialized DTMFSender using deprecated createDTMFSender`);\n        }\n\n        if (this._dtmfSender) {\n            this._dtmfSender.ontonechange = this._onToneChange.bind(this);\n        }\n    }\n\n    if (this._dtmfSender) {\n        if (this._dtmfSender.toneBuffer) {\n            this._dtmfTonesQueue.push({\n                tones,\n                duration,\n                interToneGap\n            });\n\n            return;\n        }\n\n        this._dtmfSender.insertDTMF(tones, duration, interToneGap);\n    } else {\n        logger.warn(`${this} sendTones - failed to select DTMFSender`);\n    }\n};\n\n/**\n * Callback ivoked by {@code this._dtmfSender} when it has finished playing\n * a single tone.\n *\n * @param {Object} event - The tonechange event which indicates what characters\n * are left to be played for the current tone.\n * @private\n * @returns {void}\n */\nTraceablePeerConnection.prototype._onToneChange = function(event) {\n    // An empty event.tone indicates the current tones have finished playing.\n    // Automatically start playing any queued tones on finish.\n    if (this._dtmfSender && event.tone === '' && this._dtmfTonesQueue.length) {\n        const { tones, duration, interToneGap } = this._dtmfTonesQueue.shift();\n\n        this._dtmfSender.insertDTMF(tones, duration, interToneGap);\n    }\n};\n\n/**\n * Makes the underlying TraceablePeerConnection generate new SSRC for\n * the recvonly video stream.\n */\nTraceablePeerConnection.prototype.generateRecvonlySsrc = function() {\n    const newSSRC = SDPUtil.generateSsrc();\n\n    logger.info(`${this} generated new recvonly SSRC=${newSSRC}`);\n    this.sdpConsistency.setPrimarySsrc(newSSRC);\n};\n\n/**\n * Makes the underlying TraceablePeerConnection forget the current primary video\n * SSRC.\n */\nTraceablePeerConnection.prototype.clearRecvonlySsrc = function() {\n    logger.info(`${this} Clearing primary video SSRC!`);\n    this.sdpConsistency.clearVideoSsrcCache();\n};\n\n/**\n * Closes underlying WebRTC PeerConnection instance and removes all remote\n * tracks by emitting {@link RTCEvents.REMOTE_TRACK_REMOVED} for each one of\n * them.\n */\nTraceablePeerConnection.prototype.close = function() {\n    this.trace('stop');\n\n    // Off SignalingEvents\n    this.signalingLayer.off(SignalingEvents.PEER_MUTED_CHANGED, this._peerMutedChanged);\n    this.signalingLayer.off(SignalingEvents.PEER_VIDEO_TYPE_CHANGED, this._peerVideoTypeChanged);\n    this._usesUnifiedPlan && this.peerconnection.removeEventListener('track', this.onTrack);\n\n    for (const peerTracks of this.remoteTracks.values()) {\n        for (const remoteTracks of peerTracks.values()) {\n            for (const remoteTrack of remoteTracks) {\n                this._removeRemoteTrack(remoteTrack);\n            }\n        }\n    }\n    this.remoteTracks.clear();\n\n    this._addedStreams = [];\n\n    this._dtmfSender = null;\n    this._dtmfTonesQueue = [];\n\n    if (!this.rtc._removePeerConnection(this)) {\n        logger.error(`${this} RTC._removePeerConnection returned false`);\n    }\n    if (this.statsinterval !== null) {\n        window.clearInterval(this.statsinterval);\n        this.statsinterval = null;\n    }\n    logger.info(`${this} Closing peerconnection`);\n    this.peerconnection.close();\n};\n\nTraceablePeerConnection.prototype.createAnswer = function(constraints) {\n    return this._createOfferOrAnswer(false /* answer */, constraints);\n};\n\nTraceablePeerConnection.prototype.createOffer = function(constraints) {\n    return this._createOfferOrAnswer(true /* offer */, constraints);\n};\n\nTraceablePeerConnection.prototype._createOfferOrAnswer = function(\n        isOffer,\n        constraints) {\n    const logName = isOffer ? 'Offer' : 'Answer';\n\n    this.trace(`create${logName}`, JSON.stringify(constraints, null, ' '));\n\n    const handleSuccess = (resultSdp, resolveFn, rejectFn) => {\n        try {\n            this.trace(\n                `create${logName}OnSuccess::preTransform`, dumpSDP(resultSdp));\n\n            if (!this._usesUnifiedPlan) {\n                // If there are no local video tracks, then a \"recvonly\"\n                // SSRC needs to be generated\n                if (!this.hasAnyTracksOfType(MediaType.VIDEO)\n                    && !this.sdpConsistency.hasPrimarySsrcCached()) {\n                    this.generateRecvonlySsrc();\n                }\n\n                // eslint-disable-next-line no-param-reassign\n                resultSdp = new RTCSessionDescription({\n                    type: resultSdp.type,\n                    sdp: this.sdpConsistency.makeVideoPrimarySsrcsConsistent(\n                        resultSdp.sdp)\n                });\n\n                this.trace(\n                    `create${logName}OnSuccess::postTransform `\n                         + '(make primary audio/video ssrcs consistent)',\n                    dumpSDP(resultSdp));\n            }\n\n            const localVideoTrack = this.getLocalVideoTracks()[0];\n\n            // Configure simulcast for camera tracks and for desktop tracks that need simulcast.\n            if (this.isSimulcastOn() && browser.usesSdpMungingForSimulcast()\n                && (localVideoTrack?.getVideoType() === VideoType.CAMERA\n                || this._usesUnifiedPlan\n                || !this.isSharingLowFpsScreen())) {\n                // eslint-disable-next-line no-param-reassign\n                resultSdp = this.simulcast.mungeLocalDescription(resultSdp);\n                this.trace(`create${logName} OnSuccess::postTransform (simulcast)`, dumpSDP(resultSdp));\n            }\n\n            if (!this.options.disableRtx && browser.usesSdpMungingForSimulcast()) {\n                // eslint-disable-next-line no-param-reassign\n                resultSdp = new RTCSessionDescription({\n                    type: resultSdp.type,\n                    sdp: this.rtxModifier.modifyRtxSsrcs(resultSdp.sdp)\n                });\n\n                this.trace(\n                    `create${logName}`\n                         + 'OnSuccess::postTransform (rtx modifier)',\n                    dumpSDP(resultSdp));\n            }\n\n            const ssrcMap = this._extractSSRCMap(resultSdp);\n\n            this._processLocalSSRCsMap(ssrcMap);\n\n            resolveFn(resultSdp);\n        } catch (e) {\n            this.trace(`create${logName}OnError`, e);\n            this.trace(`create${logName}OnError`, dumpSDP(resultSdp));\n            logger.error(`${this} create${logName}OnError`, e, dumpSDP(resultSdp));\n\n            rejectFn(e);\n        }\n    };\n\n    const handleFailure = (err, rejectFn) => {\n        this.trace(`create${logName}OnFailure`, err);\n        const eventType\n            = isOffer\n                ? RTCEvents.CREATE_OFFER_FAILED\n                : RTCEvents.CREATE_ANSWER_FAILED;\n\n        this.eventEmitter.emit(eventType, err, this);\n\n        rejectFn(err);\n    };\n\n    // Set the codec preference before creating an offer or answer so that the generated SDP will have\n    // the correct preference order.\n    if (this._usesTransceiverCodecPreferences) {\n        const transceiver = this.peerconnection.getTransceivers()\n            .find(t => t.receiver && t.receiver?.track?.kind === MediaType.VIDEO);\n\n        if (transceiver) {\n            let capabilities = RTCRtpReceiver.getCapabilities(MediaType.VIDEO)?.codecs;\n            const mimeType = this.codecPreference?.mimeType;\n            const enable = this.codecPreference?.enable;\n\n            if (capabilities && mimeType && enable) {\n                // Move the desired codec (all variations of it as well) to the beginning of the list.\n                /* eslint-disable-next-line arrow-body-style */\n                capabilities.sort(caps => {\n                    return caps.mimeType.toLowerCase() === `${MediaType.VIDEO}/${mimeType}` ? -1 : 1;\n                });\n            } else if (capabilities && mimeType) {\n                capabilities = capabilities\n                    .filter(caps => caps.mimeType.toLowerCase() !== `${MediaType.VIDEO}/${mimeType}`);\n            }\n\n            // Disable ulpfec on Google Chrome and derivatives because\n            // https://bugs.chromium.org/p/chromium/issues/detail?id=1276427\n            if (browser.isChromiumBased()) {\n                capabilities = capabilities\n                    .filter(caps => caps.mimeType.toLowerCase() !== `${MediaType.VIDEO}/${CodecMimeType.ULPFEC}`);\n            }\n\n            try {\n                transceiver.setCodecPreferences(capabilities);\n            } catch (err) {\n                logger.warn(`${this} Setting codec[preference=${mimeType},enable=${enable}] failed`, err);\n            }\n        }\n    }\n\n    return new Promise((resolve, reject) => {\n        let oaPromise;\n\n        if (isOffer) {\n            oaPromise = this.peerconnection.createOffer(constraints);\n        } else {\n            oaPromise = this.peerconnection.createAnswer(constraints);\n        }\n\n        oaPromise\n            .then(\n                sdp => handleSuccess(sdp, resolve, reject),\n                error => handleFailure(error, reject));\n    });\n};\n\n/**\n * Extract primary SSRC from given {@link TrackSSRCInfo} object.\n * @param {TrackSSRCInfo} ssrcObj\n * @return {number|null} the primary SSRC or <tt>null</tt>\n */\nTraceablePeerConnection.prototype._extractPrimarySSRC = function(ssrcObj) {\n    if (ssrcObj && ssrcObj.groups && ssrcObj.groups.length) {\n        return ssrcObj.groups[0].ssrcs[0];\n    } else if (ssrcObj && ssrcObj.ssrcs && ssrcObj.ssrcs.length) {\n        return ssrcObj.ssrcs[0];\n    }\n\n    return null;\n};\n\n/**\n * Goes over the SSRC map extracted from the latest local description and tries\n * to match them with the local tracks (by MSID). Will update the values\n * currently stored in the {@link TraceablePeerConnection.localSSRCs} map.\n * @param {Map<string,TrackSSRCInfo>} ssrcMap\n * @private\n */\nTraceablePeerConnection.prototype._processLocalSSRCsMap = function(ssrcMap) {\n    for (const track of this.localTracks.values()) {\n        const sourceIdentifier = this._usesUnifiedPlan ? track.getType() : track.storedMSID;\n\n        if (ssrcMap.has(sourceIdentifier)) {\n            const newSSRC = ssrcMap.get(sourceIdentifier);\n\n            if (!newSSRC) {\n                logger.error(`${this} No SSRC found for stream=${sourceIdentifier}`);\n\n                return;\n            }\n            const oldSSRC = this.localSSRCs.get(track.rtcId);\n            const newSSRCNum = this._extractPrimarySSRC(newSSRC);\n            const oldSSRCNum = this._extractPrimarySSRC(oldSSRC);\n\n            // eslint-disable-next-line no-negated-condition\n            if (newSSRCNum !== oldSSRCNum) {\n                oldSSRCNum && logger.error(`${this} Overwriting SSRC for track=${track}] with ssrc=${newSSRC}`);\n                this.localSSRCs.set(track.rtcId, newSSRC);\n                this.eventEmitter.emit(RTCEvents.LOCAL_TRACK_SSRC_UPDATED, track, newSSRCNum);\n            }\n        } else if (!track.isVideoTrack() && !track.isMuted()) {\n            // It is normal to find no SSRCs for a muted video track in\n            // the local SDP as the recv-only SSRC is no longer munged in.\n            // So log the warning only if it's not a muted video track.\n            logger.warn(`${this} No SSRCs found in the local SDP for track=${track}, stream=${sourceIdentifier}`);\n        }\n    }\n};\n\nTraceablePeerConnection.prototype.addIceCandidate = function(candidate) {\n    this.trace('addIceCandidate', JSON.stringify({\n        candidate: candidate.candidate,\n        sdpMid: candidate.sdpMid,\n        sdpMLineIndex: candidate.sdpMLineIndex,\n        usernameFragment: candidate.usernameFragment\n    }, null, ' '));\n\n    return this.peerconnection.addIceCandidate(candidate);\n};\n\n/**\n * Returns the number of simulcast streams that are currently enabled on the peerconnection.\n *\n * @returns {number} The number of simulcast streams currently enabled or 1 when simulcast is disabled.\n */\nTraceablePeerConnection.prototype.getActiveSimulcastStreams = function() {\n    let activeStreams = 1;\n\n    if (this.isSimulcastOn() && this.encodingsEnabledState) {\n        activeStreams = this.encodingsEnabledState.filter(stream => Boolean(stream))?.length;\n    } else if (this.isSimulcastOn()) {\n        activeStreams = SIM_LAYER_RIDS.length;\n    }\n\n    return activeStreams;\n};\n\n/**\n * Obtains call-related stats from the peer connection.\n *\n * @returns {Promise<Object>} Promise which resolves with data providing statistics about\n * the peerconnection.\n */\nTraceablePeerConnection.prototype.getStats = function() {\n    return this.peerconnection.getStats();\n};\n\n/**\n * Generates and stores new SSRC info object for given local track.\n * The method should be called only for a video track being added to this TPC\n * in the muted state (given that the current browser uses this strategy).\n * @param {JitsiLocalTrack} track\n * @return {TPCSSRCInfo}\n */\nTraceablePeerConnection.prototype.generateNewStreamSSRCInfo = function(track) {\n    const rtcId = track.rtcId;\n    let ssrcInfo = this._getSSRC(rtcId);\n\n    if (ssrcInfo) {\n        logger.error(`${this} Overwriting local SSRCs for track id=${rtcId}`);\n    }\n\n    // Configure simulcast for camera tracks and desktop tracks that need simulcast.\n    if (this.isSimulcastOn()\n        && (track.getVideoType() === VideoType.CAMERA || !this.isSharingLowFpsScreen())) {\n        ssrcInfo = {\n            ssrcs: [],\n            groups: []\n        };\n        for (let i = 0; i < SIM_LAYER_RIDS.length; i++) {\n            ssrcInfo.ssrcs.push(SDPUtil.generateSsrc());\n        }\n        ssrcInfo.groups.push({\n            ssrcs: ssrcInfo.ssrcs.slice(),\n            semantics: 'SIM'\n        });\n    } else {\n        ssrcInfo = {\n            ssrcs: [ SDPUtil.generateSsrc() ],\n            groups: []\n        };\n    }\n    if (!this.options.disableRtx) {\n        // Specifically use a for loop here because we'll\n        //  be adding to the list we're iterating over, so we\n        //  only want to iterate through the items originally\n        //  on the list\n        const currNumSsrcs = ssrcInfo.ssrcs.length;\n\n        for (let i = 0; i < currNumSsrcs; ++i) {\n            const primarySsrc = ssrcInfo.ssrcs[i];\n            const rtxSsrc = SDPUtil.generateSsrc();\n\n            ssrcInfo.ssrcs.push(rtxSsrc);\n            ssrcInfo.groups.push({\n                ssrcs: [ primarySsrc, rtxSsrc ],\n                semantics: 'FID'\n            });\n        }\n    }\n    ssrcInfo.msid = track.storedMSID;\n    this.localSSRCs.set(rtcId, ssrcInfo);\n\n    return ssrcInfo;\n};\n\n/**\n * Returns if the peer connection uses Unified plan implementation.\n *\n * @returns {boolean} True if the pc uses Unified plan, false otherwise.\n */\nTraceablePeerConnection.prototype.usesUnifiedPlan = function() {\n    return this._usesUnifiedPlan;\n};\n\n/**\n * Creates a text representation of this <tt>TraceablePeerConnection</tt>\n * instance.\n * @return {string}\n */\nTraceablePeerConnection.prototype.toString = function() {\n    return `TPC[id=${this.id},type=${this.isP2P ? 'P2P' : 'JVB'}]`;\n};\n","import { getLogger } from '@jitsi/logger';\n\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\nimport BridgeVideoType from '../../service/RTC/BridgeVideoType';\nimport { MediaType } from '../../service/RTC/MediaType';\nimport RTCEvents from '../../service/RTC/RTCEvents';\nimport browser from '../browser';\nimport FeatureFlags from '../flags/FeatureFlags';\nimport Statistics from '../statistics/statistics';\nimport GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';\nimport Listenable from '../util/Listenable';\nimport { safeCounterIncrement } from '../util/MathUtil';\n\nimport BridgeChannel from './BridgeChannel';\nimport JitsiLocalTrack from './JitsiLocalTrack';\nimport RTCUtils from './RTCUtils';\nimport TraceablePeerConnection from './TraceablePeerConnection';\n\n\nconst logger = getLogger(__filename);\n\n/**\n * The counter used to generated id numbers assigned to peer connections\n * @type {number}\n */\nlet peerConnectionIdCounter = 0;\n\n/**\n * The counter used to generate id number for the local\n * <code>MediaStreamTrack</code>s.\n * @type {number}\n */\nlet rtcTrackIdCounter = 0;\n\n/**\n * Creates {@code JitsiLocalTrack} instances from the passed in meta information\n * about MedieaTracks.\n *\n * @param {Object[]} mediaStreamMetaData - An array of meta information with\n * MediaTrack instances. Each can look like:\n * {{\n *     stream: MediaStream instance that holds a track with audio or video,\n *     track: MediaTrack within the MediaStream,\n *     videoType: \"camera\" or \"desktop\" or falsy,\n *     sourceId: ID of the desktopsharing source,\n *     sourceType: The desktopsharing source type,\n *     effects: Array of effect types\n * }}\n */\nfunction _createLocalTracks(mediaStreamMetaData = []) {\n    return mediaStreamMetaData.map(metaData => {\n        const {\n            sourceId,\n            sourceType,\n            stream,\n            track,\n            videoType,\n            effects\n        } = metaData;\n\n        const { deviceId, facingMode } = track.getSettings();\n\n        // FIXME Move rtcTrackIdCounter to a static method in JitsiLocalTrack\n        // so RTC does not need to handle ID management. This move would be\n        // safer to do once the old createLocalTracks is removed.\n        rtcTrackIdCounter = safeCounterIncrement(rtcTrackIdCounter);\n\n        return new JitsiLocalTrack({\n            deviceId,\n            facingMode,\n            mediaType: track.kind,\n            rtcId: rtcTrackIdCounter,\n            sourceId,\n            sourceType,\n            stream,\n            track,\n            videoType: videoType || null,\n            effects\n        });\n    });\n}\n\n/**\n *\n */\nexport default class RTC extends Listenable {\n    /**\n     *\n     * @param conference\n     * @param options\n     */\n    constructor(conference, options = {}) {\n        super();\n        this.conference = conference;\n\n        /**\n         * A map of active <tt>TraceablePeerConnection</tt>.\n         * @type {Map.<number, TraceablePeerConnection>}\n         */\n        this.peerConnections = new Map();\n\n        this.localTracks = [];\n\n        this.options = options;\n\n        // BridgeChannel instance.\n        // @private\n        // @type {BridgeChannel}\n        this._channel = null;\n\n        /**\n         * The value specified to the last invocation of setLastN before the\n         * channel completed opening. If non-null, the value will be sent\n         * through a channel (once) as soon as it opens and will then be\n         * discarded.\n         * @private\n         * @type {number}\n         */\n        this._lastN = undefined;\n\n        /**\n         * Defines the last N endpoints list. It can be null or an array once\n         * initialised with a channel last N event.\n         * @type {Array<string>|null}\n         * @private\n         */\n        this._lastNEndpoints = null;\n\n        /**\n         * Defines the forwarded sources list. It can be null or an array once initialised with a channel forwarded\n         * sources event.\n         *\n         * @type {Array<string>|null}\n         * @private\n         */\n        this._forwardedSources = null;\n\n        /**\n         * The number representing the maximum video height the local client\n         * should receive from the bridge.\n         *\n         * @type {number|undefined}\n         * @private\n         */\n        this._maxFrameHeight = undefined;\n\n        /**\n         * The endpoint IDs of currently selected participants.\n         *\n         * @type {Array}\n         * @private\n         */\n        this._selectedEndpoints = null;\n\n        // The last N change listener.\n        this._lastNChangeListener = this._onLastNChanged.bind(this);\n\n        // The forwarded sources change listener.\n        this._forwardedSourcesChangeListener = this._onForwardedSourcesChanged.bind(this);\n\n        this._onDeviceListChanged = this._onDeviceListChanged.bind(this);\n        this._updateAudioOutputForAudioTracks\n            = this._updateAudioOutputForAudioTracks.bind(this);\n\n        /**\n         * The default video type assumed by the bridge.\n         * @deprecated this will go away with multiple streams support\n         * @type {BridgeVideoType}\n         * @private\n         */\n        this._videoType = BridgeVideoType.NONE;\n\n        // Switch audio output device on all remote audio tracks. Local audio\n        // tracks handle this event by themselves.\n        if (RTCUtils.isDeviceChangeAvailable('output')) {\n            RTCUtils.addListener(\n                RTCEvents.AUDIO_OUTPUT_DEVICE_CHANGED,\n                this._updateAudioOutputForAudioTracks\n            );\n\n            RTCUtils.addListener(\n                RTCEvents.DEVICE_LIST_CHANGED,\n                this._onDeviceListChanged\n            );\n        }\n    }\n\n    /**\n     * Removes any listeners and stored state from this {@code RTC} instance.\n     *\n     * @returns {void}\n     */\n    destroy() {\n        RTCUtils.removeListener(RTCEvents.AUDIO_OUTPUT_DEVICE_CHANGED, this._updateAudioOutputForAudioTracks);\n        RTCUtils.removeListener(RTCEvents.DEVICE_LIST_CHANGED, this._onDeviceListChanged);\n\n        if (this._channelOpenListener) {\n            this.removeListener(\n                RTCEvents.DATA_CHANNEL_OPEN,\n                this._channelOpenListener\n            );\n        }\n    }\n\n    /**\n     * Exposes the private helper for converting a WebRTC MediaStream to a\n     * JitsiLocalTrack.\n     *\n     * @param {Array<Object>} tracksInfo\n     * @returns {Array<JitsiLocalTrack>}\n     */\n    static createLocalTracks(tracksInfo) {\n        return _createLocalTracks(tracksInfo);\n    }\n\n    /**\n     * Creates the local MediaStreams.\n     * @param {object} [options] Optional parameters.\n     * @param {array} options.devices The devices that will be requested.\n     * @param {string} options.resolution Resolution constraints.\n     * @param {string} options.cameraDeviceId\n     * @param {string} options.micDeviceId\n     * @returns {*} Promise object that will receive the new JitsiTracks\n     */\n    static obtainAudioAndVideoPermissions(options) {\n        return RTCUtils.obtainAudioAndVideoPermissions(options)\n            .then(tracksInfo => _createLocalTracks(tracksInfo));\n    }\n\n    /**\n     * Initializes the bridge channel of this instance.\n     * At least one of both, peerconnection or wsUrl parameters, must be\n     * given.\n     * @param {RTCPeerConnection} [peerconnection] WebRTC peer connection\n     * instance.\n     * @param {string} [wsUrl] WebSocket URL.\n     */\n    initializeBridgeChannel(peerconnection, wsUrl) {\n        this._channel = new BridgeChannel(peerconnection, wsUrl, this.eventEmitter);\n\n        this._channelOpenListener = () => {\n            const logError = (error, msgType, value) => {\n                GlobalOnErrorHandler.callErrorHandler(error);\n                logger.error(`Cannot send ${msgType}(${JSON.stringify(value)}) endpoint message`, error);\n            };\n\n            // When the channel becomes available, tell the bridge about video selections so that it can do adaptive\n            // simulcast, we want the notification to trigger even if userJid is undefined, or null.\n            if (this._receiverVideoConstraints) {\n                try {\n                    this._channel.sendNewReceiverVideoConstraintsMessage(this._receiverVideoConstraints);\n                } catch (error) {\n                    logError(error, 'ReceiverVideoConstraints', this._receiverVideoConstraints);\n                }\n            }\n            if (this._selectedEndpoints) {\n                try {\n                    this._channel.sendSelectedEndpointsMessage(this._selectedEndpoints);\n                } catch (error) {\n                    logError(error, 'SelectedEndpointsChangedEvent', this._selectedEndpoints);\n                }\n            }\n            if (typeof this._maxFrameHeight !== 'undefined') {\n                try {\n                    this._channel.sendReceiverVideoConstraintMessage(this._maxFrameHeight);\n                } catch (error) {\n                    logError(error, 'ReceiverVideoConstraint', this._maxFrameHeight);\n                }\n            }\n            if (typeof this._lastN !== 'undefined' && this._lastN !== -1) {\n                try {\n                    this._channel.sendSetLastNMessage(this._lastN);\n                } catch (error) {\n                    logError(error, 'LastNChangedEvent', this._lastN);\n                }\n            }\n            if (!FeatureFlags.isSourceNameSignalingEnabled()) {\n                try {\n                    this._channel.sendVideoTypeMessage(this._videoType);\n                } catch (error) {\n                    logError(error, 'VideoTypeMessage', this._videoType);\n                }\n            }\n\n            this.removeListener(RTCEvents.DATA_CHANNEL_OPEN, this._channelOpenListener);\n            this._channelOpenListener = null;\n        };\n        this.addListener(RTCEvents.DATA_CHANNEL_OPEN, this._channelOpenListener);\n\n        // Add Last N change listener.\n        this.addListener(RTCEvents.LASTN_ENDPOINT_CHANGED, this._lastNChangeListener);\n\n        if (FeatureFlags.isSourceNameSignalingEnabled()) {\n            // Add forwarded sources change listener.\n            this.addListener(RTCEvents.FORWARDED_SOURCES_CHANGED, this._forwardedSourcesChangeListener);\n        }\n    }\n\n    /**\n     * Callback invoked when the list of known audio and video devices has\n     * been updated. Attempts to update the known available audio output\n     * devices.\n     *\n     * @private\n     * @returns {void}\n     */\n    _onDeviceListChanged() {\n        this._updateAudioOutputForAudioTracks(RTCUtils.getAudioOutputDevice());\n    }\n\n    /**\n     * Receives events when Last N had changed.\n     * @param {array} lastNEndpoints The new Last N endpoints.\n     * @private\n     */\n    _onLastNChanged(lastNEndpoints = []) {\n        const oldLastNEndpoints = this._lastNEndpoints || [];\n        let leavingLastNEndpoints = [];\n        let enteringLastNEndpoints = [];\n\n        this._lastNEndpoints = lastNEndpoints;\n\n        leavingLastNEndpoints = oldLastNEndpoints.filter(\n            id => !this.isInLastN(id));\n\n        enteringLastNEndpoints = lastNEndpoints.filter(\n            id => oldLastNEndpoints.indexOf(id) === -1);\n\n        this.conference.eventEmitter.emit(\n            JitsiConferenceEvents.LAST_N_ENDPOINTS_CHANGED,\n            leavingLastNEndpoints,\n            enteringLastNEndpoints);\n    }\n\n    /**\n     * Receives events when forwarded sources had changed.\n     *\n     * @param {array} forwardedSources The new forwarded sources.\n     * @private\n     */\n    _onForwardedSourcesChanged(forwardedSources = []) {\n        const oldForwardedSources = this._forwardedSources || [];\n        let leavingForwardedSources = [];\n        let enteringForwardedSources = [];\n\n        this._forwardedSources = forwardedSources;\n\n        leavingForwardedSources = oldForwardedSources.filter(sourceName => !this.isInForwardedSources(sourceName));\n\n        enteringForwardedSources = forwardedSources.filter(\n            sourceName => oldForwardedSources.indexOf(sourceName) === -1);\n\n        this.conference.eventEmitter.emit(\n            JitsiConferenceEvents.FORWARDED_SOURCES_CHANGED,\n            leavingForwardedSources,\n            enteringForwardedSources,\n            Date.now());\n    }\n\n    /**\n     * Should be called when current media session ends and after the\n     * PeerConnection has been closed using PeerConnection.close() method.\n     */\n    onCallEnded() {\n        if (this._channel) {\n            // The BridgeChannel is not explicitly closed as the PeerConnection\n            // is closed on call ended which triggers datachannel onclose\n            // events. If using a WebSocket, the channel must be closed since\n            // it is not managed by the PeerConnection.\n            // The reference is cleared to disable any logic related to the\n            // channel.\n            if (this._channel && this._channel.mode === 'websocket') {\n                this._channel.close();\n            }\n\n            this._channel = null;\n        }\n    }\n\n    /**\n     * Sets the capture frame rate to be used for desktop tracks.\n     *\n     * @param {number} maxFps framerate to be used for desktop track capture.\n     */\n    setDesktopSharingFrameRate(maxFps) {\n        RTCUtils.setDesktopSharingFrameRate(maxFps);\n    }\n\n    /**\n     * Sets the receiver video constraints that determine how bitrate is allocated to each of the video streams\n     * requested from the bridge. The constraints are cached and sent through the bridge channel once the channel\n     * is established.\n     * @param {*} constraints\n     */\n    setNewReceiverVideoConstraints(constraints) {\n        this._receiverVideoConstraints = constraints;\n\n        if (this._channel && this._channel.isOpen()) {\n            this._channel.sendNewReceiverVideoConstraintsMessage(constraints);\n        }\n    }\n\n    /**\n     * Sets the maximum video size the local participant should receive from\n     * remote participants. Will cache the value and send it through the channel\n     * once it is created.\n     *\n     * @param {number} maxFrameHeightPixels the maximum frame height, in pixels,\n     * this receiver is willing to receive.\n     * @returns {void}\n     */\n    setReceiverVideoConstraint(maxFrameHeight) {\n        this._maxFrameHeight = maxFrameHeight;\n\n        if (this._channel && this._channel.isOpen()) {\n            this._channel.sendReceiverVideoConstraintMessage(maxFrameHeight);\n        }\n    }\n\n    /**\n     * Sets the video type and availability for the local video source.\n     *\n     * @param {string} videoType 'camera' for camera, 'desktop' for screenshare and\n     * 'none' for when local video source is muted or removed from the peerconnection.\n     * @returns {void}\n     */\n    setVideoType(videoType) {\n        if (this._videoType !== videoType) {\n            this._videoType = videoType;\n\n            if (this._channel && this._channel.isOpen()) {\n                this._channel.sendVideoTypeMessage(videoType);\n            }\n        }\n    }\n\n    /**\n     * Sends the track's  video type to the JVB.\n     * @param {SourceName} sourceName - the track's source name.\n     * @param {BridgeVideoType} videoType - the track's video type.\n     */\n    sendSourceVideoType(sourceName, videoType) {\n        if (this._channel && this._channel.isOpen()) {\n            this._channel.sendSourceVideoTypeMessage(sourceName, videoType);\n        }\n    }\n\n    /**\n     * Elects the participants with the given ids to be the selected\n     * participants in order to always receive video for this participant (even\n     * when last n is enabled). If there is no channel we store it and send it\n     * through the channel once it is created.\n     *\n     * @param {Array<string>} ids - The user ids.\n     * @throws NetworkError or InvalidStateError or Error if the operation\n     * fails.\n     * @returns {void}\n     */\n    selectEndpoints(ids) {\n        this._selectedEndpoints = ids;\n\n        if (this._channel && this._channel.isOpen()) {\n            this._channel.sendSelectedEndpointsMessage(ids);\n        }\n    }\n\n    /**\n     *\n     * @param eventType\n     * @param listener\n     */\n    static addListener(eventType, listener) {\n        RTCUtils.addListener(eventType, listener);\n    }\n\n    /**\n     *\n     * @param eventType\n     * @param listener\n     */\n    static removeListener(eventType, listener) {\n        RTCUtils.removeListener(eventType, listener);\n    }\n\n    /**\n     *\n     * @param options\n     */\n    static init(options = {}) {\n        this.options = options;\n\n        return RTCUtils.init(this.options);\n    }\n\n    /* eslint-disable max-params */\n\n    /**\n     * Creates new <tt>TraceablePeerConnection</tt>\n     * @param {SignalingLayer} signaling The signaling layer that will provide information about the media or\n     * participants which is not carried over SDP.\n     * @param {object} pcConfig The {@code RTCConfiguration} to use for the WebRTC peer connection.\n     * @param {boolean} isP2P Indicates whether or not the new TPC will be used in a peer to peer type of session.\n     * @param {object} options The config options.\n     * @param {boolean} options.enableInsertableStreams - Set to true when the insertable streams constraints is to be\n     * enabled on the PeerConnection.\n     * @param {boolean} options.disableSimulcast If set to 'true' will disable the simulcast.\n     * @param {boolean} options.disableRtx If set to 'true' will disable the RTX.\n     * @param {boolean} options.startSilent If set to 'true' no audio will be sent or received.\n     * @return {TraceablePeerConnection}\n     */\n    createPeerConnection(signaling, pcConfig, isP2P, options) {\n        const pcConstraints = JSON.parse(JSON.stringify(RTCUtils.pcConstraints));\n\n        if (typeof options.abtestSuspendVideo !== 'undefined') {\n            RTCUtils.setSuspendVideo(pcConstraints, options.abtestSuspendVideo);\n\n            Statistics.analytics.addPermanentProperties(\n                { abtestSuspendVideo: options.abtestSuspendVideo });\n        }\n\n        if (options.enableInsertableStreams) {\n            logger.debug('E2EE - setting insertable streams constraints');\n            pcConfig.encodedInsertableStreams = true;\n        }\n\n        const supportsSdpSemantics = browser.isReactNative()\n            || (browser.isChromiumBased() && !options.usesUnifiedPlan);\n\n        if (supportsSdpSemantics) {\n            logger.debug('WebRTC application is running in plan-b mode');\n            pcConfig.sdpSemantics = 'plan-b';\n        }\n\n        if (options.forceTurnRelay) {\n            pcConfig.iceTransportPolicy = 'relay';\n        }\n\n        // Set the RTCBundlePolicy to max-bundle so that only one set of ice candidates is generated.\n        // The default policy generates separate ice candidates for audio and video connections.\n        // This change is necessary for Unified plan to work properly on Chrome and Safari.\n        pcConfig.bundlePolicy = 'max-bundle';\n\n        peerConnectionIdCounter = safeCounterIncrement(peerConnectionIdCounter);\n\n        const newConnection\n            = new TraceablePeerConnection(\n                this,\n                peerConnectionIdCounter,\n                signaling,\n                pcConfig, pcConstraints,\n                isP2P, options);\n\n        this.peerConnections.set(newConnection.id, newConnection);\n\n        return newConnection;\n    }\n\n    /* eslint-enable max-params */\n\n    /**\n     * Removed given peer connection from this RTC module instance.\n     * @param {TraceablePeerConnection} traceablePeerConnection\n     * @return {boolean} <tt>true</tt> if the given peer connection was removed\n     * successfully or <tt>false</tt> if there was no peer connection mapped in\n     * this RTC instance.\n     */\n    _removePeerConnection(traceablePeerConnection) {\n        const id = traceablePeerConnection.id;\n\n        if (this.peerConnections.has(id)) {\n            // NOTE Remote tracks are not removed here.\n            this.peerConnections.delete(id);\n\n            return true;\n        }\n\n        return false;\n\n    }\n\n    /**\n     *\n     * @param track\n     */\n    addLocalTrack(track) {\n        if (!track) {\n            throw new Error('track must not be null nor undefined');\n        }\n\n        this.localTracks.push(track);\n\n        track.conference = this.conference;\n    }\n\n    /**\n     * Get forwarded sources list.\n     * @returns {Array<string>|null}\n     */\n    getForwardedSources() {\n        return this._forwardedSources;\n    }\n\n    /**\n     * Get local video track.\n     * @returns {JitsiLocalTrack|undefined}\n     */\n    getLocalVideoTrack() {\n        const localVideo = this.getLocalTracks(MediaType.VIDEO);\n\n\n        return localVideo.length ? localVideo[0] : undefined;\n    }\n\n    /**\n     * Returns all the local video tracks.\n     * @returns {Array<JitsiLocalTrack>}\n     */\n    getLocalVideoTracks() {\n        return this.getLocalTracks(MediaType.VIDEO);\n    }\n\n    /**\n     * Get local audio track.\n     * @returns {JitsiLocalTrack|undefined}\n     */\n    getLocalAudioTrack() {\n        const localAudio = this.getLocalTracks(MediaType.AUDIO);\n\n\n        return localAudio.length ? localAudio[0] : undefined;\n    }\n\n    /**\n     * Returns the endpoint id for the local user.\n     * @returns {string}\n     */\n    getLocalEndpointId() {\n        return this.conference.myUserId();\n    }\n\n    /**\n     * Returns the local tracks of the given media type, or all local tracks if\n     * no specific type is given.\n     * @param {MediaType} [mediaType] Optional media type filter.\n     * (audio or video).\n     */\n    getLocalTracks(mediaType) {\n        let tracks = this.localTracks.slice();\n\n        if (mediaType !== undefined) {\n            tracks = tracks.filter(\n                track => track.getType() === mediaType);\n        }\n\n        return tracks;\n    }\n\n    /**\n     * Obtains all remote tracks currently known to this RTC module instance.\n     * @param {MediaType} [mediaType] The remote tracks will be filtered\n     *      by their media type if this argument is specified.\n     * @return {Array<JitsiRemoteTrack>}\n     */\n    getRemoteTracks(mediaType) {\n        let remoteTracks = [];\n\n        for (const tpc of this.peerConnections.values()) {\n            const pcRemoteTracks = tpc.getRemoteTracks(undefined, mediaType);\n\n            if (pcRemoteTracks) {\n                remoteTracks = remoteTracks.concat(pcRemoteTracks);\n            }\n        }\n\n        return remoteTracks;\n    }\n\n    /**\n     * Set mute for all local audio streams attached to the conference.\n     * @param value The mute value.\n     * @returns {Promise}\n     */\n    setAudioMute(value) {\n        const mutePromises = [];\n\n        this.getLocalTracks(MediaType.AUDIO).forEach(audioTrack => {\n            // this is a Promise\n            mutePromises.push(value ? audioTrack.mute() : audioTrack.unmute());\n        });\n\n        // We return a Promise from all Promises so we can wait for their\n        // execution.\n        return Promise.all(mutePromises);\n    }\n\n    /**\n    * Set mute for all local video streams attached to the conference.\n    * @param value The mute value.\n    * @returns {Promise}\n    */\n    setVideoMute(value) {\n        const mutePromises = [];\n\n        this.getLocalTracks(MediaType.VIDEO).concat(this.getLocalTracks(MediaType.PRESENTER))\n            .forEach(videoTrack => {\n                // this is a Promise\n                mutePromises.push(value ? videoTrack.mute() : videoTrack.unmute());\n            });\n\n        // We return a Promise from all Promises so we can wait for their\n        // execution.\n        return Promise.all(mutePromises);\n    }\n\n    /**\n     *\n     * @param track\n     */\n    removeLocalTrack(track) {\n        const pos = this.localTracks.indexOf(track);\n\n        if (pos === -1) {\n            return;\n        }\n\n        this.localTracks.splice(pos, 1);\n    }\n\n    /**\n     *\n     * @param elSelector\n     * @param stream\n     */\n    static attachMediaStream(elSelector, stream) {\n        return RTCUtils.attachMediaStream(elSelector, stream);\n    }\n\n    /**\n     * Returns the id of the given stream.\n     * @param {MediaStream} stream\n     */\n    static getStreamID(stream) {\n        return RTCUtils.getStreamID(stream);\n    }\n\n    /**\n     * Returns the id of the given track.\n     * @param {MediaStreamTrack} track\n     */\n    static getTrackID(track) {\n        return RTCUtils.getTrackID(track);\n    }\n\n    /**\n     * Returns true if retrieving the list of input devices is supported\n     * and false if not.\n     */\n    static isDeviceListAvailable() {\n        return RTCUtils.isDeviceListAvailable();\n    }\n\n    /**\n     * Returns true if changing the input (camera / microphone) or output\n     * (audio) device is supported and false if not.\n     * @param {string} [deviceType] Type of device to change. Default is\n     *      undefined or 'input', 'output' - for audio output device change.\n     * @returns {boolean} true if available, false otherwise.\n     */\n    static isDeviceChangeAvailable(deviceType) {\n        return RTCUtils.isDeviceChangeAvailable(deviceType);\n    }\n\n    /**\n     * Returns whether the current execution environment supports WebRTC (for\n     * use within this library).\n     *\n     * @returns {boolean} {@code true} if WebRTC is supported in the current\n     * execution environment (for use within this library); {@code false},\n     * otherwise.\n     */\n    static isWebRtcSupported() {\n        return browser.isSupported();\n    }\n\n    /**\n     * Returns currently used audio output device id, '' stands for default\n     * device\n     * @returns {string}\n     */\n    static getAudioOutputDevice() {\n        return RTCUtils.getAudioOutputDevice();\n    }\n\n    /**\n     * Returns list of available media devices if its obtained, otherwise an\n     * empty array is returned/\n     * @returns {array} list of available media devices.\n     */\n    static getCurrentlyAvailableMediaDevices() {\n        return RTCUtils.getCurrentlyAvailableMediaDevices();\n    }\n\n    /**\n     * Returns whether available devices have permissions granted\n     * @returns {Boolean}\n     */\n    static arePermissionsGrantedForAvailableDevices() {\n        return RTCUtils.arePermissionsGrantedForAvailableDevices();\n    }\n\n    /**\n     * Returns event data for device to be reported to stats.\n     * @returns {MediaDeviceInfo} device.\n     */\n    static getEventDataForActiveDevice(device) {\n        return RTCUtils.getEventDataForActiveDevice(device);\n    }\n\n    /**\n     * Sets current audio output device.\n     * @param {string} deviceId Id of 'audiooutput' device from\n     *      navigator.mediaDevices.enumerateDevices().\n     * @returns {Promise} resolves when audio output is changed, is rejected\n     *      otherwise\n     */\n    static setAudioOutputDevice(deviceId) {\n        return RTCUtils.setAudioOutputDevice(deviceId);\n    }\n\n    /**\n     * Returns <tt>true<tt/> if given WebRTC MediaStream is considered a valid\n     * \"user\" stream which means that it's not a \"receive only\" stream nor a\n     * \"mixed\" JVB stream.\n     *\n     * Clients that implement Unified Plan, such as Firefox use recvonly\n     * \"streams/channels/tracks\" for receiving remote stream/tracks, as opposed\n     * to Plan B where there are only 3 channels: audio, video and data.\n     *\n     * @param {MediaStream} stream The WebRTC MediaStream instance.\n     * @returns {boolean}\n     */\n    static isUserStream(stream) {\n        return RTC.isUserStreamById(RTCUtils.getStreamID(stream));\n    }\n\n    /**\n     * Returns <tt>true<tt/> if a WebRTC MediaStream identified by given stream\n     * ID is considered a valid \"user\" stream which means that it's not a\n     * \"receive only\" stream nor a \"mixed\" JVB stream.\n     *\n     * Clients that implement Unified Plan, such as Firefox use recvonly\n     * \"streams/channels/tracks\" for receiving remote stream/tracks, as opposed\n     * to Plan B where there are only 3 channels: audio, video and data.\n     *\n     * @param {string} streamId The id of WebRTC MediaStream.\n     * @returns {boolean}\n     */\n    static isUserStreamById(streamId) {\n        return streamId && streamId !== 'mixedmslabel'\n            && streamId !== 'default';\n    }\n\n    /**\n     * Allows to receive list of available cameras/microphones.\n     * @param {function} callback Would receive array of devices as an\n     *      argument.\n     */\n    static enumerateDevices(callback) {\n        RTCUtils.enumerateDevices(callback);\n    }\n\n    /**\n     * A method to handle stopping of the stream.\n     * One point to handle the differences in various implementations.\n     * @param {MediaStream} mediaStream MediaStream object to stop.\n     */\n    static stopMediaStream(mediaStream) {\n        RTCUtils.stopMediaStream(mediaStream);\n    }\n\n    /**\n     * Returns whether the desktop sharing is enabled or not.\n     * @returns {boolean}\n     */\n    static isDesktopSharingEnabled() {\n        return RTCUtils.isDesktopSharingEnabled();\n    }\n\n    /**\n     * Closes the currently opened bridge channel.\n     */\n    closeBridgeChannel() {\n        if (this._channel) {\n            this._channel.close();\n            this._channel = null;\n\n            this.removeListener(RTCEvents.LASTN_ENDPOINT_CHANGED, this._lastNChangeListener);\n        }\n    }\n\n    /* eslint-disable max-params */\n    /**\n     *\n     * @param {TraceablePeerConnection} tpc\n     * @param {number} ssrc\n     * @param {number} audioLevel\n     * @param {boolean} isLocal\n     */\n    setAudioLevel(tpc, ssrc, audioLevel, isLocal) {\n        const track = tpc.getTrackBySSRC(ssrc);\n\n        if (!track) {\n            return;\n        } else if (!track.isAudioTrack()) {\n            logger.warn(`Received audio level for non-audio track: ${ssrc}`);\n\n            return;\n        } else if (track.isLocal() !== isLocal) {\n            logger.error(\n                `${track} was expected to ${isLocal ? 'be' : 'not be'} local`);\n        }\n\n        track.setAudioLevel(audioLevel, tpc);\n    }\n\n    /**\n     * Sends message via the bridge channel.\n     * @param {string} to The id of the endpoint that should receive the\n     *      message. If \"\" the message will be sent to all participants.\n     * @param {object} payload The payload of the message.\n     * @throws NetworkError or InvalidStateError or Error if the operation\n     * fails or there is no data channel created.\n     */\n    sendChannelMessage(to, payload) {\n        if (this._channel) {\n            this._channel.sendMessage(to, payload);\n        } else {\n            throw new Error('Channel support is disabled!');\n        }\n    }\n\n    /**\n     * Sends the local stats via the bridge channel.\n     * @param {Object} payload The payload of the message.\n     * @throws NetworkError/InvalidStateError/Error if the operation fails or if there is no data channel created.\n     */\n    sendEndpointStatsMessage(payload) {\n        if (this._channel && this._channel.isOpen()) {\n            this._channel.sendEndpointStatsMessage(payload);\n        }\n    }\n\n    /**\n     * Selects a new value for \"lastN\". The requested amount of videos are going\n     * to be delivered after the value is in effect. Set to -1 for unlimited or\n     * all available videos.\n     * @param {number} value the new value for lastN.\n     */\n    setLastN(value) {\n        if (this._lastN !== value) {\n            this._lastN = value;\n            if (this._channel && this._channel.isOpen()) {\n                this._channel.sendSetLastNMessage(value);\n            }\n            this.eventEmitter.emit(RTCEvents.LASTN_VALUE_CHANGED, value);\n        }\n    }\n\n    /**\n     * Indicates if the endpoint id is currently included in the last N.\n     * @param {string} id The endpoint id that we check for last N.\n     * @returns {boolean} true if the endpoint id is in the last N or if we\n     * don't have bridge channel support, otherwise we return false.\n     */\n    isInLastN(id) {\n        return !this._lastNEndpoints // lastNEndpoints not initialised yet.\n            || this._lastNEndpoints.indexOf(id) > -1;\n    }\n\n    /**\n     * Indicates if the source name is currently included in the forwarded sources.\n     *\n     * @param {string} sourceName The source name that we check for forwarded sources.\n     * @returns {boolean} true if the source name is in the forwarded sources or if we don't have bridge channel\n     * support, otherwise we return false.\n     */\n    isInForwardedSources(sourceName) {\n        return !this._forwardedSources // forwardedSources not initialised yet.\n            || this._forwardedSources.indexOf(sourceName) > -1;\n    }\n\n    /**\n     * Updates the target audio output device for all remote audio tracks.\n     *\n     * @param {string} deviceId - The device id of the audio ouput device to\n     * use for all remote tracks.\n     * @private\n     * @returns {void}\n     */\n    _updateAudioOutputForAudioTracks(deviceId) {\n        const remoteAudioTracks = this.getRemoteTracks(MediaType.AUDIO);\n\n        for (const track of remoteAudioTracks) {\n            track.setAudioOutput(deviceId);\n        }\n    }\n}\n","export enum ConnectionQualityEvents {\n    /**\n     * Indicates that the local connection statistics were updated.\n     */\n    LOCAL_STATS_UPDATED = 'cq.local_stats_updated',\n\n    /**\n     * Indicates that the connection statistics for a particular remote participant\n     * were updated.\n     */\n    REMOTE_STATS_UPDATED = 'cq.remote_stats_updated'\n};\n\n// exported for backward compatibility\nexport const LOCAL_STATS_UPDATED = ConnectionQualityEvents.LOCAL_STATS_UPDATED;\nexport const REMOTE_STATS_UPDATED = ConnectionQualityEvents.REMOTE_STATS_UPDATED;\n\n","import { getLogger } from '@jitsi/logger';\n\nimport * as ConferenceEvents from '../../JitsiConferenceEvents';\nimport CodecMimeType from '../../service/RTC/CodecMimeType';\nimport RTCEvents from '../../service/RTC/RTCEvents';\nimport * as ConnectionQualityEvents from '../../service/connectivity/ConnectionQualityEvents';\nimport browser from '../browser';\n\nconst Resolutions = require('../../service/RTC/Resolutions');\nconst { VideoType } = require('../../service/RTC/VideoType');\nconst { XMPPEvents } = require('../../service/xmpp/XMPPEvents');\n\nconst logger = getLogger(__filename);\n\n/**\n * The value to use for the \"type\" field for messages sent by ConnectionQuality\n * over the data channel.\n */\nconst STATS_MESSAGE_TYPE = 'stats';\n\n/**\n * The value to use for the \"type\" field for messages sent\n * over the data channel that contain facial expression.\n */\nconst FACIAL_EXPRESSION_MESSAGE_TYPE = 'facial_expression';\n\nconst kSimulcastFormats = [\n    { width: 1920,\n        height: 1080,\n        layers: 3,\n        target: 'high',\n        targetRN: 4000000 },\n    { width: 1280,\n        height: 720,\n        layers: 3,\n        target: 'high',\n        targetRN: 2500000 },\n    { width: 960,\n        height: 540,\n        layers: 3,\n        target: 'standard',\n        targetRN: 900000 },\n    { width: 640,\n        height: 360,\n        layers: 2,\n        target: 'standard',\n        targetRN: 500000 },\n    { width: 480,\n        height: 270,\n        layers: 2,\n        target: 'low',\n        targetRN: 350000 },\n    { width: 320,\n        height: 180,\n        layers: 1,\n        target: 'low',\n        targetRN: 150000 }\n];\n\n/**\n * The maximum bitrate to use as a measurement against the participant's current\n * bitrate. This cap helps in the cases where the participant's bitrate is high\n * but not enough to fulfill high targets, such as with 1080p.\n */\nconst MAX_TARGET_BITRATE = 2500;\n\n/**\n * The initial bitrate for video in kbps.\n */\nlet startBitrate = 800;\n\n/**\n * Gets the expected bitrate (in kbps) in perfect network conditions.\n * @param simulcast {boolean} whether simulcast is enabled or not.\n * @param resolution {Resolution} the resolution.\n * @param millisSinceStart {number} the number of milliseconds since sending video started.\n * @param videoQualitySettings {Object} the bitrate and codec settings for the local video source.\n */\nfunction getTarget(simulcast, resolution, millisSinceStart, videoQualitySettings) {\n    let target = 0;\n    let height = Math.min(resolution.height, resolution.width);\n\n    // Find the first format with height no bigger than ours.\n    let simulcastFormat = kSimulcastFormats.find(f => f.height <= height);\n\n    if (simulcastFormat && simulcast && videoQualitySettings.codec === CodecMimeType.VP8) {\n        // Sum the target fields from all simulcast layers for the given\n        // resolution (e.g. 720p + 360p + 180p) for VP8 simulcast.\n        for (height = simulcastFormat.height; height >= 180; height /= 2) {\n            const targetHeight = height;\n\n            simulcastFormat = kSimulcastFormats.find(f => f.height === targetHeight);\n            if (simulcastFormat) {\n                target += browser.isReactNative()\n                    ? simulcastFormat.targetRN\n                    : videoQualitySettings[simulcastFormat.target];\n            } else {\n                break;\n            }\n        }\n    } else if (simulcastFormat) {\n        // For VP9 SVC, H.264 (simulcast automatically disabled) and p2p, target bitrate will be\n        // same as that of the individual stream bitrate.\n        target = browser.isReactNative()\n            ? simulcastFormat.targetRN\n            : videoQualitySettings[simulcastFormat.target];\n    }\n\n    // Allow for an additional 1 second for ramp up -- delay any initial drop\n    // of connection quality by 1 second. Convert target from bps to kbps.\n    return Math.min(target / 1000, rampUp(Math.max(0, millisSinceStart - 1000)));\n}\n\n/**\n * Gets the bitrate to which GCC would have ramped up in perfect network\n * conditions after millisSinceStart milliseconds.\n * @param millisSinceStart {number} the number of milliseconds since sending\n * video was enabled.\n */\nfunction rampUp(millisSinceStart) {\n    if (millisSinceStart > 60000) {\n        return Number.MAX_SAFE_INTEGER;\n    }\n\n    // According to GCC the send side bandwidth estimation grows with at most\n    // 8% per second.\n    // https://tools.ietf.org/html/draft-ietf-rmcat-gcc-02#section-5.5\n    return startBitrate * Math.pow(1.08, millisSinceStart / 1000);\n}\n\n/**\n * A class which monitors the local statistics coming from the RTC modules, and\n * calculates a \"connection quality\" value, in percent, for the media\n * connection. A value of 100% indicates a very good network connection, and a\n * value of 0% indicates a poor connection.\n */\nexport default class ConnectionQuality {\n    /**\n     *\n     * @param conference\n     * @param eventEmitter\n     * @param options\n     */\n    constructor(conference, eventEmitter, options) {\n        this.eventEmitter = eventEmitter;\n\n        /**\n         * The owning JitsiConference.\n         */\n        this._conference = conference;\n\n        /**\n         * Holds statistics about the local connection quality.\n         */\n        this._localStats = {\n            connectionQuality: 100,\n            jvbRTT: undefined\n        };\n\n        /**\n         * The time this._localStats.connectionQuality was last updated.\n         */\n        this._lastConnectionQualityUpdate = -1;\n\n        /**\n         * Conference options.\n         */\n        this._options = options;\n\n        /**\n         * Maps a participant ID to an object holding connection quality\n         * statistics received from this participant.\n         */\n        this._remoteStats = {};\n\n        /**\n         * The time that the ICE state last changed to CONNECTED. We use this\n         * to calculate how much time we as a sender have had to ramp-up.\n         */\n        this._timeIceConnected = -1;\n\n        /**\n         * The time that local video was unmuted. We use this to calculate how\n         * much time we as a sender have had to ramp-up.\n         */\n        this._timeVideoUnmuted = -1;\n\n        // We assume a global startBitrate value for the sake of simplicity.\n        if (this._options.config?.startBitrate > 0) {\n            startBitrate = this._options.config.startBitrate;\n        }\n\n        // TODO: consider ignoring these events and letting the user of\n        // lib-jitsi-meet handle these separately.\n        conference.on(\n            ConferenceEvents.CONNECTION_INTERRUPTED,\n            () => {\n                this._updateLocalConnectionQuality(0);\n                this.eventEmitter.emit(\n                    ConnectionQualityEvents.LOCAL_STATS_UPDATED,\n                    this._localStats);\n                this._broadcastLocalStats();\n            });\n\n        conference.room.addListener(\n            XMPPEvents.ICE_CONNECTION_STATE_CHANGED,\n            (jingleSession, newState) => {\n                if (!jingleSession.isP2P && newState === 'connected') {\n                    this._timeIceConnected = window.performance.now();\n                }\n            });\n\n        // Listen to DataChannel message from other participants in the\n        // conference, and update the _remoteStats field accordingly.\n        // TODO - Delete this when all the mobile endpoints switch to using the new Colibri\n        // message format for sending the endpoint stats.\n        conference.on(\n            ConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,\n            (participant, payload) => {\n                if (payload.type === STATS_MESSAGE_TYPE) {\n                    this._updateRemoteStats(\n                        participant.getId(), payload.values);\n                }\n            });\n\n        conference.on(\n            ConferenceEvents.ENDPOINT_STATS_RECEIVED,\n            (participant, payload) => {\n                this._updateRemoteStats(participant.getId(), payload);\n            });\n\n        conference.on(\n            ConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,\n            (participant, payload) => {\n                if (payload.type === FACIAL_EXPRESSION_MESSAGE_TYPE) {\n                    this.eventEmitter.emit(\n                        ConferenceEvents.FACIAL_EXPRESSION_ADDED,\n                        participant.getId(),\n                        payload);\n                }\n            });\n\n        // Listen to local statistics events originating from the RTC module and update the _localStats field.\n        conference.statistics.addConnectionStatsListener(this._updateLocalStats.bind(this));\n\n        // Save the last time we were unmuted.\n        conference.on(\n            ConferenceEvents.TRACK_MUTE_CHANGED,\n            track => {\n                if (track.isVideoTrack()) {\n                    if (track.isMuted()) {\n                        this._timeVideoUnmuted = -1;\n                    } else {\n                        this._maybeUpdateUnmuteTime();\n                    }\n                }\n            });\n        conference.on(\n            ConferenceEvents.TRACK_ADDED,\n            track => {\n                if (track.isVideoTrack() && !track.isMuted()) {\n                    this._maybeUpdateUnmuteTime();\n                }\n            });\n        conference.rtc.on(\n            RTCEvents.LOCAL_TRACK_MAX_ENABLED_RESOLUTION_CHANGED,\n            track => {\n                this._localStats.maxEnabledResolution = track.maxEnabledResolution;\n            });\n\n        conference.on(\n            ConferenceEvents.SERVER_REGION_CHANGED,\n            serverRegion => {\n                this._localStats.serverRegion = serverRegion;\n            });\n\n        conference.on(\n            ConferenceEvents.PROPERTIES_CHANGED,\n            properties => {\n                this._localStats.bridgeCount\n                    = Number((properties || {})['bridge-count']);\n            }\n        );\n    }\n\n    /**\n     * Sets _timeVideoUnmuted if it was previously unset. If it was already set,\n     * doesn't change it.\n     */\n    _maybeUpdateUnmuteTime() {\n        if (this._timeVideoUnmuted < 0) {\n            this._timeVideoUnmuted = window.performance.now();\n        }\n    }\n\n    /**\n     * Calculates a new \"connection quality\" value.\n     * @param videoType {VideoType} the type of the video source (camera or a screen capture).\n     * @param isMuted {boolean} whether the local video is muted.\n     * @param resolutionName {Resolution} the input resolution used by the camera.\n     * @returns {*} the newly calculated connection quality.\n     */\n    _calculateConnectionQuality(videoType, isMuted, resolutionName) {\n\n        // resolutionName is an index into Resolutions (where \"720\" is\n        // \"1280x720\" and \"960\" is \"960x720\" ...).\n        const resolution = Resolutions[resolutionName];\n\n        let quality = 100;\n        let packetLoss;\n\n        // TODO: take into account packet loss for received streams\n\n        if (this._localStats.packetLoss) {\n            packetLoss = this._localStats.packetLoss.upload;\n\n            // Ugly Hack Alert (UHA):\n            // The packet loss for the upload direction is calculated based on\n            // incoming RTCP Receiver Reports. Since we don't have RTCP\n            // termination for audio, these reports come from the actual\n            // receivers in the conference and therefore the reported packet\n            // loss includes loss from the bridge to the receiver.\n            // When we are sending video this effect is small, because the\n            // number of video packets is much larger than the number of audio\n            // packets (and our calculation is based on the total number of\n            // received and lost packets).\n            // When video is muted, however, the effect might be significant,\n            // but we don't know what it is. We do know that it is positive, so\n            // as a temporary solution, until RTCP termination is implemented\n            // for the audio streams, we relax the packet loss checks here.\n            if (isMuted) {\n                packetLoss *= 0.5;\n            }\n        }\n\n        if (isMuted || !resolution || videoType === VideoType.DESKTOP\n            || this._timeIceConnected < 0\n            || this._timeVideoUnmuted < 0) {\n\n            // Calculate a value based on packet loss only.\n            if (packetLoss === undefined) {\n                logger.error('Cannot calculate connection quality, unknown '\n                    + 'packet loss.');\n                quality = 100;\n            } else if (packetLoss <= 2) {\n                quality = 100; // Full 5 bars.\n            } else if (packetLoss <= 4) {\n                quality = 70; // 4 bars\n            } else if (packetLoss <= 6) {\n                quality = 50; // 3 bars\n            } else if (packetLoss <= 8) {\n                quality = 30; // 2 bars\n            } else if (packetLoss <= 12) {\n                quality = 10; // 1 bars\n            } else {\n                quality = 0; // Still 1 bar, but slower climb-up.\n            }\n        } else {\n            // Calculate a value based on the send video bitrate on the active TPC.\n            const activeTPC = this._conference.getActivePeerConnection();\n\n            if (activeTPC) {\n                const isSimulcastOn = activeTPC.isSimulcastOn();\n                const videoQualitySettings = activeTPC.getTargetVideoBitrates();\n\n                // Add the codec info as well.\n                videoQualitySettings.codec = activeTPC.getConfiguredVideoCodec();\n\n                // Time since sending of video was enabled.\n                const millisSinceStart = window.performance.now()\n                    - Math.max(this._timeVideoUnmuted, this._timeIceConnected);\n                const statsInterval = this._options.config?.pcStatsInterval ?? 10000;\n\n                // Expected sending bitrate in perfect conditions.\n                let target = getTarget(isSimulcastOn, resolution, millisSinceStart, videoQualitySettings);\n\n                target = Math.min(target, MAX_TARGET_BITRATE);\n\n                // Calculate the quality only after the stats are available (after video was enabled).\n                if (millisSinceStart > statsInterval) {\n                    quality = 100 * this._localStats.bitrate.upload / target;\n                }\n            }\n\n            // Whatever the bitrate, drop early if there is significant loss\n            if (packetLoss && packetLoss >= 10) {\n                quality = Math.min(quality, 30);\n            }\n        }\n\n        // Make sure that the quality doesn't climb quickly\n        if (this._lastConnectionQualityUpdate > 0) {\n            const maxIncreasePerSecond = 2;\n            const prevConnectionQuality = this._localStats.connectionQuality;\n            const diffSeconds = (window.performance.now() - this._lastConnectionQualityUpdate) / 1000;\n\n            quality = Math.min(quality, prevConnectionQuality + (diffSeconds * maxIncreasePerSecond));\n        }\n\n        return Math.min(100, quality);\n    }\n\n    /**\n     * Updates the localConnectionQuality value\n     * @param values {number} the new value. Should be in [0, 100].\n     */\n    _updateLocalConnectionQuality(value) {\n        this._localStats.connectionQuality = value;\n        this._lastConnectionQualityUpdate = window.performance.now();\n    }\n\n    /**\n     * Broadcasts the local statistics to all other participants in the\n     * conference.\n     */\n    _broadcastLocalStats() {\n        // Send only the data that remote participants care about.\n        const data = {\n            bitrate: this._localStats.bitrate,\n            packetLoss: this._localStats.packetLoss,\n            connectionQuality: this._localStats.connectionQuality,\n            jvbRTT: this._localStats.jvbRTT,\n            serverRegion: this._localStats.serverRegion,\n            maxEnabledResolution: this._localStats.maxEnabledResolution,\n            avgAudioLevels: this._localStats.localAvgAudioLevels\n        };\n\n        try {\n            this._conference.sendEndpointStatsMessage(data);\n        } catch (err) {\n            // Ignore the error as we might hit it in the beginning of the call before the channel is ready.\n            // The statistics will be sent again after few seconds and error is logged elseware as well.\n        }\n    }\n\n    /**\n     * Updates the local statistics\n     * @param {TraceablePeerConnection} tpc the peerconnection which emitted\n     * the stats\n     * @param data new statistics\n     */\n    _updateLocalStats(tpc, data) {\n        // Update jvbRTT\n        if (!tpc.isP2P) {\n            const jvbRTT\n                = data.transport\n                    && data.transport.length && data.transport[0].rtt;\n\n            this._localStats.jvbRTT = jvbRTT ? jvbRTT : undefined;\n        }\n\n        // Do not continue with processing of other stats if they do not\n        // originate from the active peerconnection\n        if (tpc !== this._conference.getActivePeerConnection()) {\n            return;\n        }\n\n        let key;\n        const updateLocalConnectionQuality\n            = !this._conference.isConnectionInterrupted();\n        const localVideoTrack\n            = this._conference.getLocalVideoTrack();\n        const videoType\n            = localVideoTrack ? localVideoTrack.videoType : undefined;\n        const isMuted = localVideoTrack ? localVideoTrack.isMuted() : true;\n        const resolution = localVideoTrack\n            ? Math.min(localVideoTrack.resolution, localVideoTrack.maxEnabledResolution) : null;\n\n        if (!isMuted) {\n            this._maybeUpdateUnmuteTime();\n        }\n\n        // Copy the fields already in 'data'.\n        for (key in data) {\n            if (data.hasOwnProperty(key)) {\n                this._localStats[key] = data[key];\n            }\n        }\n\n        // And re-calculate the connectionQuality field.\n        if (updateLocalConnectionQuality) {\n            this._updateLocalConnectionQuality(\n                this._calculateConnectionQuality(\n                    videoType,\n                    isMuted,\n                    resolution));\n        }\n\n        this.eventEmitter.emit(\n            ConnectionQualityEvents.LOCAL_STATS_UPDATED,\n            this._localStats);\n        this._broadcastLocalStats();\n    }\n\n    /**\n     * Updates remote statistics\n     * @param id the id of the remote participant\n     * @param data the statistics received\n     */\n    _updateRemoteStats(id, data) {\n        // Use only the fields we need\n        this._remoteStats[id] = {\n            bitrate: data.bitrate,\n            packetLoss: data.packetLoss,\n            connectionQuality: data.connectionQuality,\n            jvbRTT: data.jvbRTT,\n            serverRegion: data.serverRegion,\n            maxEnabledResolution: data.maxEnabledResolution,\n            avgAudioLevels: data.avgAudioLevels\n        };\n\n        this.eventEmitter.emit(\n            ConnectionQualityEvents.REMOTE_STATS_UPDATED,\n            id,\n            this._remoteStats[id]);\n    }\n\n    /**\n     * Returns the local statistics.\n     * Exported only for use in jitsi-meet-torture.\n     */\n    getStats() {\n        return this._localStats;\n    }\n}\n","import { getLogger } from '@jitsi/logger';\n\nimport * as JitsiConferenceErrors from '../../JitsiConferenceErrors';\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\n\nconst logger = getLogger(__filename);\n\n/**\n * This class deals with shenanigans around JVB media session's ICE failed status handling.\n *\n * If ICE restarts are NOT explicitly enabled by the {@code enableIceRestart} config option, then the conference will\n * delay emitting the {@JitsiConferenceErrors.ICE_FAILED} event by 15 seconds. If the network info module reports\n * the internet offline status then the time will start counting after the internet comes back online.\n *\n * If ICE restart are enabled, then a delayed ICE failed notification to Jicofo will be sent, only if the ICE connection\n * does not recover soon after or before the XMPP connection is restored (if it was ever broken). If ICE fails while\n * the XMPP connection is not broken then the notifications will be sent after 2 seconds delay.\n */\nexport default class IceFailedHandling {\n    /**\n     * Creates new {@code DelayedIceFailed} task.\n     * @param {JitsiConference} conference\n     */\n    constructor(conference) {\n        this._conference = conference;\n    }\n\n    /**\n     * After making sure there's no way for the ICE connection to recover this method either sends ICE failed\n     * notification to Jicofo or emits the ice failed conference event.\n     * @private\n     * @returns {void}\n     */\n    _actOnIceFailed() {\n        if (!this._conference.room) {\n            return;\n        }\n\n        const { enableForcedReload, enableIceRestart } = this._conference.options.config;\n        const explicitlyDisabled = typeof enableIceRestart !== 'undefined' && !enableIceRestart;\n        const supportsRestartByTerminate = this._conference.room.supportsRestartByTerminate();\n        const useTerminateForRestart = supportsRestartByTerminate && !enableIceRestart;\n\n        logger.info('ICE failed,'\n            + ` enableForcedReload: ${enableForcedReload},`\n            + ` enableIceRestart: ${enableIceRestart},`\n            + ` supports restart by terminate: ${supportsRestartByTerminate}`);\n\n        if (explicitlyDisabled || (!enableIceRestart && !supportsRestartByTerminate) || enableForcedReload) {\n            logger.info('ICE failed, but ICE restarts are disabled');\n            const reason = enableForcedReload\n                ? JitsiConferenceErrors.CONFERENCE_RESTARTED\n                : JitsiConferenceErrors.ICE_FAILED;\n\n            this._conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_FAILED, reason);\n\n            return;\n        }\n\n        const jvbConnection = this._conference.jvbJingleSession;\n        const jvbConnIceState = jvbConnection && jvbConnection.getIceConnectionState();\n\n        if (!jvbConnection) {\n            logger.warn('Not sending ICE failed - no JVB connection');\n        } else if (jvbConnIceState === 'connected') {\n            logger.info('ICE connection restored - not sending ICE failed');\n        } else {\n            logger.info('Sending ICE failed - the connection did not recover, '\n                + `ICE state: ${jvbConnIceState}, `\n                + `use 'session-terminate': ${useTerminateForRestart}`);\n            if (useTerminateForRestart) {\n                this._conference.jvbJingleSession.terminate(\n                    () => {\n                        logger.info('session-terminate for ice restart - done');\n                    },\n                    error => {\n                        logger.error(`session-terminate for ice restart - error: ${error.message}`);\n                    }, {\n                        reason: 'connectivity-error',\n                        reasonDescription: 'ICE FAILED',\n                        requestRestart: true,\n                        sendSessionTerminate: true\n                    });\n            } else {\n                this._conference.jvbJingleSession.sendIceFailedNotification();\n            }\n        }\n    }\n\n    /**\n     * Starts the task.\n     */\n    start() {\n        //  Using xmpp.ping allows to handle both XMPP being disconnected and internet offline cases. The ping function\n        // uses sendIQ2 method which is resilient to XMPP connection disconnected state and will patiently wait until it\n        // gets reconnected.\n        //  This also handles the case about waiting for the internet to come back online, because ping\n        // will only succeed when the internet is online and then there's a chance for the ICE to recover from FAILED to\n        // CONNECTED which is the extra 2 second timeout after ping.\n        //  The 65 second timeout is given on purpose as there's no chance for XMPP to recover after 65 seconds of no\n        // communication with the server. Such resume attempt will result in unrecoverable conference failed event due\n        // to 'item-not-found' error returned by the server.\n        this._conference.xmpp.ping(65000).then(\n            () => {\n                if (!this._canceled) {\n                    this._iceFailedTimeout = window.setTimeout(() => {\n                        this._iceFailedTimeout = undefined;\n                        this._actOnIceFailed();\n                    }, 2000);\n                }\n            },\n            error => {\n                logger.error('PING error/timeout - not sending ICE failed', error);\n            });\n    }\n\n    /**\n     * Cancels the task.\n     */\n    cancel() {\n        this._canceled = true;\n        window.clearTimeout(this._iceFailedTimeout);\n    }\n}\n","export enum DetectionEvents {\n    /**\n     * Event triggered by a audio detector indicating that its active state has changed from active to inactive or vice\n     * versa.\n     * @event\n     * @type {boolean} - true when service has changed to active false otherwise.\n     */\n    DETECTOR_STATE_CHANGE = 'detector_state_change',\n\n    /** Event triggered by {@link NoAudioSignalDetector} when the local audio device associated with a JitsiConference\n     * starts receiving audio levels with the value of 0 meaning no audio is being captured on that device, or when\n     * it starts receiving audio levels !== 0 after being in a state of no audio.\n     * @event\n     * @type {boolean} - true when the current conference audio track has audio input false otherwise.\n     */\n    AUDIO_INPUT_STATE_CHANGE = 'audio_input_state_changed',\n\n    /** Event triggered by NoAudioSignalDetector when the local audio device associated with a JitsiConference goes silent\n     * for a period of time, meaning that the device is either broken or hardware/software muted.\n     * @event\n     * @type {void}\n     */\n    NO_AUDIO_INPUT = 'no_audio_input_detected',\n\n    /**\n     *  Event generated by {@link VADNoiseDetection} when the tracked device is considered noisy.\n     *  @event\n     *  @type {Object}\n     */\n    VAD_NOISY_DEVICE = 'detection.vad_noise_device',\n\n    /**\n     * Event generated by VADReportingService when if finishes creating a VAD report for the monitored devices.\n     * The generated objects are of type Array<Object>, one score for each monitored device.\n     * @event VAD_REPORT_PUBLISHED\n     * @type Array<Object> with the following structure:\n     * @property {Date} timestamp - Timestamp at which the compute took place.\n     * @property {number} avgVAD - Average VAD score over monitored period of time.\n     * @property {string} deviceId - Associate local audio device ID.\n     */\n    VAD_REPORT_PUBLISHED = 'vad-report-published',\n\n    /**\n     * Event generated by {@link TrackVADEmitter} when PCM sample VAD score is available.\n     *\n     * @event\n     * @type {Object}\n     * @property {Date}   timestamp - Exact time at which processed PCM sample was generated.\n     * @property {number} score - VAD score on a scale from 0 to 1 (i.e. 0.7)\n     * @property {Float32Array} pcmData - Raw PCM data with which the VAD score was calculated.\n     * @property {string} deviceId - Device id of the associated track.\n     */\n    VAD_SCORE_PUBLISHED = 'detection.vad_score_published',\n\n    /**\n     *  Event generated by {@link VADTalkMutedDetection} when a user is talking while the mic is muted.\n     *\n     *  @event\n     *  @type {Object}\n     */\n    VAD_TALK_WHILE_MUTED = 'detection.vad_talk_while_muted'\n};\n\n// exported for backward compatibility\nexport const DETECTOR_STATE_CHANGE = DetectionEvents.DETECTOR_STATE_CHANGE;\nexport const AUDIO_INPUT_STATE_CHANGE = DetectionEvents.AUDIO_INPUT_STATE_CHANGE;\nexport const NO_AUDIO_INPUT = DetectionEvents.NO_AUDIO_INPUT;\nexport const VAD_NOISY_DEVICE = DetectionEvents.VAD_NOISY_DEVICE;\nexport const VAD_REPORT_PUBLISHED = DetectionEvents.VAD_REPORT_PUBLISHED;\nexport const VAD_SCORE_PUBLISHED = DetectionEvents.VAD_SCORE_PUBLISHED;\nexport const VAD_TALK_WHILE_MUTED = DetectionEvents.VAD_TALK_WHILE_MUTED;\n","import EventEmitter from 'events';\n\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\nimport * as JitsiTrackEvents from '../../JitsiTrackEvents';\nimport browser from '../browser';\n\nimport * as DetectionEvents from './DetectionEvents';\n\n// We wait a certain time interval for constant silence input from the current device to account for\n// potential abnormalities and for a better use experience i.e. don't generate event the instant\n// an audio track is added to the tcr.\n// Potential improvement - add this as a configurable parameter.\nconst SILENCE_PERIOD_MS = 4000;\n\n/**\n * Detect if there is no audio input on the current TraceAblePeerConnection selected track. The no audio\n * state must be constant for a configured amount of time in order for the event to be triggered.\n * @fires DetectionEvents.AUDIO_INPUT_STATE_CHANGE\n * @fires DetectionEvents.NO_AUDIO_INPUT\n */\nexport default class NoAudioSignalDetection extends EventEmitter {\n    /**\n     * Creates new NoAudioSignalDetection.\n     *\n     * @param conference the JitsiConference instance that created us.\n     * @constructor\n     */\n    constructor(conference) {\n        super();\n\n        this._conference = conference;\n        this._timeoutTrigger = null;\n        this._hasAudioInput = null;\n\n        if (!browser.supportsReceiverStats()) {\n            conference.statistics.addAudioLevelListener(this._audioLevel.bind(this));\n        }\n        conference.on(JitsiConferenceEvents.TRACK_ADDED, this._trackAdded.bind(this));\n    }\n\n    /**\n     * Clear the timeout state.\n     */\n    _clearTriggerTimeout() {\n        clearTimeout(this._timeoutTrigger);\n        this._timeoutTrigger = null;\n    }\n\n\n    /**\n     * Generated event triggered by a change in the current conference audio input state.\n     *\n     * @param {*} audioLevel - The audio level of the ssrc.\n     * @fires DetectionEvents.AUDIO_INPUT_STATE_CHANGE\n     */\n    _handleAudioInputStateChange(audioLevel) {\n        // Current audio input state of the active local track in the conference, true for audio input false for no\n        // audio input.\n        const status = audioLevel !== 0;\n\n        // If this is the first audio event picked up or the current status is different from the previous trigger\n        // the event.\n        if (this._hasAudioInput === null || this._hasAudioInput !== status) {\n            this._hasAudioInput = status;\n            this.emit(DetectionEvents.AUDIO_INPUT_STATE_CHANGE, this._hasAudioInput);\n        }\n    }\n\n    /**\n     * Generate event triggered by a prolonged period of no audio input.\n     *\n     * @param {number} audioLevel - The audio level of the ssrc.\n     * @fires DetectionEvents.NO_AUDIO_INPUT\n     */\n    _handleNoAudioInputDetection(audioLevel) {\n        if (this._eventFired) {\n            return;\n        }\n\n        if (audioLevel === 0 && !this._timeoutTrigger) {\n            this._timeoutTrigger = setTimeout(() => {\n                this._eventFired = true;\n\n                this.emit(DetectionEvents.NO_AUDIO_INPUT);\n            }, SILENCE_PERIOD_MS);\n        } else if (audioLevel !== 0 && this._timeoutTrigger) {\n            this._clearTriggerTimeout();\n        }\n    }\n\n    /**\n     * Receives audio level events for all send and receive streams on the current TraceablePeerConnection.\n     *\n     * @param {TraceablePeerConnection} tpc - TraceablePeerConnection of the owning conference.\n     * @param {number} ssrc - The synchronization source identifier (SSRC) of the endpoint/participant/stream\n     * being reported.\n     * @param {number} audioLevel - The audio level of the ssrc.\n     * @param {boolean} isLocal - true for local/send streams or false for remote/receive streams.\n     */\n    _audioLevel(tpc, ssrc, audioLevel, isLocal) {\n        // We are interested in the local audio streams\n        if (!isLocal || !this._audioTrack) {\n            return;\n        }\n\n        // Get currently active local tracks from the TraceablePeerConnection\n        const localSSRCs = tpc.localSSRCs.get(this._audioTrack.rtcId);\n\n        // Only target the current active track in the tpc. For some reason audio levels for previous\n        // devices are also picked up from the PeerConnection so we filter them out.\n        if (!localSSRCs || !localSSRCs.ssrcs.includes(ssrc)) {\n            return;\n        }\n\n        // First handle audio input state change. In case the state changed to no input the no audio input event\n        // can try to fire again.\n        this._handleAudioInputStateChange(audioLevel);\n        this._handleNoAudioInputDetection(audioLevel);\n    }\n\n    /**\n     * Notifies NoAudioSignalDetection that a JitsiTrack was added to the associated JitsiConference.\n     * Only take into account local audio tracks.\n     *\n     * @param {JitsiTrack} track - The added JitsiTrack.\n     */\n    _trackAdded(track) {\n        if (track.isLocalAudioTrack()) {\n            // Reset state for the new track.\n            this._audioTrack = track;\n            this._eventFired = false;\n            this._clearTriggerTimeout();\n\n            // Listen for the audio levels on the newly added audio track\n            if (browser.supportsReceiverStats()) {\n                track.on(\n                    JitsiTrackEvents.NO_AUDIO_INPUT,\n                    audioLevel => {\n                        this._handleNoAudioInputDetection(audioLevel);\n                    }\n                );\n                track.on(\n                    JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED,\n                    audioLevel => {\n                        this._handleNoAudioInputDetection(audioLevel);\n                        this._handleAudioInputStateChange(audioLevel);\n                    }\n                );\n            }\n        }\n    }\n}\n","import * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\nimport RTCEvents from '../../service/RTC/RTCEvents';\n\n/**\n * The value which we use to say, every sound over this threshold\n * is talking on the mic.\n * @type {number}\n */\nconst SPEECH_DETECT_THRESHOLD = 0.6;\n\n/**\n * The <tt>P2PDominantSpeakerDetection</tt> is activated only when p2p is\n * currently used.\n * Listens for changes in the audio level changes of the local p2p audio track\n * or remote p2p one and fires dominant speaker events to be able to use\n * features depending on those events (speaker stats), to make them work without\n * the video bridge.\n */\nexport default class P2PDominantSpeakerDetection {\n    /**\n     * Creates P2PDominantSpeakerDetection\n     * @param conference the JitsiConference instance that created us.\n     * @constructor\n     */\n    constructor(conference) {\n        this.conference = conference;\n\n        conference.addEventListener(\n            JitsiConferenceEvents.TRACK_AUDIO_LEVEL_CHANGED,\n            this._audioLevel.bind(this));\n\n        this.myUserID = this.conference.myUserId();\n    }\n\n    /**\n     * Receives audio level events for all streams in the conference.\n     *\n     * @param {String} id - The participant id\n     * @param {number} audioLevel - The audio level.\n     */\n    _audioLevel(id, audioLevel) {\n\n        // we do not process if p2p is not active\n        // or audio level is under certain threshold\n        // or if the audio level is for local audio track which is muted\n        if (!this.conference.isP2PActive()\n            || audioLevel <= SPEECH_DETECT_THRESHOLD\n            || (id === this.myUserID\n                    && this.conference.getLocalAudioTrack().isMuted())) {\n            return;\n        }\n\n        this.conference.rtc.eventEmitter.emit(\n            RTCEvents.DOMINANT_SPEAKER_CHANGED,\n            id);\n    }\n}\n","/**\n * Adapter that creates AudioContext objects depending on the browser.\n *\n * @returns {AudioContext} - Return a new AudioContext or undefined if the browser does not support it.\n */\nexport function createAudioContext(options) {\n    const AudioContextImpl = window.AudioContext || window.webkitAudioContext;\n\n    if (!AudioContextImpl) {\n        return undefined;\n    }\n\n    return new AudioContextImpl(options);\n}\n","import EventEmitter from 'events';\n\nimport RTC from '../RTC/RTC';\nimport { createAudioContext } from '../webaudio/WebAudioUtils';\n\nimport { VAD_SCORE_PUBLISHED } from './DetectionEvents';\n\n/**\n * Connects an audio JitsiLocalTrack to a vadProcessor using WebAudio ScriptProcessorNode.\n * Once an object is created audio from the local track flows through the ScriptProcessorNode as raw PCM.\n * The PCM is processed by the injected vad module and a voice activity detection score is obtained, the\n * score is published to consumers via an EventEmitter.\n * After work is done with this service the destroy method needs to be called for a proper cleanup.\n *\n * @fires VAD_SCORE_PUBLISHED\n */\nexport default class TrackVADEmitter extends EventEmitter {\n    /**\n     * Constructor.\n     *\n     * @param {number} procNodeSampleRate - Sample rate of the ScriptProcessorNode. Possible values  256, 512, 1024,\n     *  2048, 4096, 8192, 16384. Passing other values will default to closes neighbor.\n     * @param {Object} vadProcessor - VAD processor that allows us to calculate VAD score for PCM samples.\n     * @param {JitsiLocalTrack} jitsiLocalTrack - JitsiLocalTrack corresponding to micDeviceId.\n     */\n    constructor(procNodeSampleRate, vadProcessor, jitsiLocalTrack) {\n        super();\n\n        /**\n         * Sample rate of the ScriptProcessorNode.\n         */\n        this._procNodeSampleRate = procNodeSampleRate;\n\n        /**\n         * VAD Processor that allows us to calculate VAD score for PCM samples\n         */\n        this._vadProcessor = vadProcessor;\n\n        /**\n         * The JitsiLocalTrack instance.\n         */\n        this._localTrack = jitsiLocalTrack;\n\n        /**\n         * Buffer to hold residue PCM resulting after a ScriptProcessorNode callback\n         */\n        this._bufferResidue = new Float32Array([]);\n\n        /**\n         * The AudioContext instance with the preferred sample frequency.\n         */\n        this._audioContext = createAudioContext({ sampleRate: vadProcessor.getRequiredPCMFrequency() });\n\n        /**\n         * PCM Sample size expected by the VAD Processor instance. We cache it here as this value is used extensively,\n         * saves a couple of function calls.\n         */\n        this._vadSampleSize = vadProcessor.getSampleLength();\n\n        /**\n         * Event listener function that will be called by the ScriptProcessNode with raw PCM data, depending on the set\n         * sample rate.\n         */\n        this._onAudioProcess = this._onAudioProcess.bind(this);\n\n        this._initializeAudioContext();\n    }\n\n    /**\n     * Factory method that sets up all the necessary components for the creation of the TrackVADEmitter.\n     *\n     * @param {string} micDeviceId - Target microphone device id.\n     * @param {number} procNodeSampleRate - Sample rate of the proc node.\n     * @param {Object} vadProcessor -Module that calculates the voice activity score for a certain audio PCM sample.\n     * The processor needs to implement the following functions:\n     * - <tt>getSampleLength()</tt> - Returns the sample size accepted by getSampleLength.\n     * - <tt>getRequiredPCMFrequency()</tt> - Returns the PCM frequency at which the processor operates.\n     * - <tt>calculateAudioFrameVAD(pcmSample)</tt> - Process a 32 float pcm sample of getSampleLength size.\n     * @returns {Promise<TrackVADEmitter>} - Promise resolving in a new instance of TrackVADEmitter.\n     */\n    static create(micDeviceId, procNodeSampleRate, vadProcessor) {\n        return RTC.obtainAudioAndVideoPermissions({\n            devices: [ 'audio' ],\n            micDeviceId\n        }).then(localTrack => {\n            // We only expect one audio track when specifying a device id.\n            if (!localTrack[0]) {\n                throw new Error(`Failed to create jitsi local track for device id: ${micDeviceId}`);\n            }\n\n            return new TrackVADEmitter(procNodeSampleRate, vadProcessor, localTrack[0]);\n\n            // We have no exception handling at this point as there is nothing to clean up, the vadProcessor\n            // life cycle is handled by whoever created this instance.\n        });\n    }\n\n    /**\n     * Sets up the audio graph in the AudioContext.\n     *\n     * @returns {void}\n     */\n    _initializeAudioContext() {\n        this._audioSource = this._audioContext.createMediaStreamSource(this._localTrack.stream);\n\n        // TODO AudioProcessingNode is deprecated in the web audio specifications and the recommended replacement\n        // is audio worklet, however at the point of implementation AudioProcessingNode was still de de facto way\n        // of achieving this functionality and supported in all major browsers as opposed to audio worklet which\n        // was only available in Chrome. This todo is just a reminder that we should replace AudioProcessingNode\n        // with audio worklet when it's mature enough and has more browser support.\n        // We don't need stereo for determining the VAD score so we create a single channel processing node.\n        this._audioProcessingNode = this._audioContext.createScriptProcessor(this._procNodeSampleRate, 1, 1);\n    }\n\n    /**\n     * ScriptProcessorNode callback, the input parameters contains the PCM audio that is then sent to rnnoise.\n     * Rnnoise only accepts PCM samples of 480 bytes whereas the webaudio processor node can't sample at a multiple\n     * of 480 thus after each _onAudioProcess callback there will remain and PCM buffer residue equal\n     * to _procNodeSampleRate / 480 which will be added to the next sample buffer and so on.\\\n     *\n     *\n     * @param {AudioProcessingEvent} audioEvent - Audio event.\n     * @returns {void}\n     * @fires VAD_SCORE_PUBLISHED\n     */\n    _onAudioProcess(audioEvent) {\n        // Prepend the residue PCM buffer from the previous process callback.\n        const inData = audioEvent.inputBuffer.getChannelData(0);\n        const completeInData = [ ...this._bufferResidue, ...inData ];\n        const sampleTimestamp = Date.now();\n\n        let i = 0;\n\n        for (; i + this._vadSampleSize < completeInData.length; i += this._vadSampleSize) {\n            const pcmSample = completeInData.slice(i, i + this._vadSampleSize);\n\n            // The VAD processor might change the values inside the array so we make a copy.\n            const vadScore = this._vadProcessor.calculateAudioFrameVAD(pcmSample.slice());\n\n            this.emit(VAD_SCORE_PUBLISHED, {\n                timestamp: sampleTimestamp,\n                score: vadScore,\n                pcmData: pcmSample,\n                deviceId: this._localTrack.getDeviceId()\n            });\n        }\n\n        this._bufferResidue = completeInData.slice(i, completeInData.length);\n    }\n\n    /**\n     * Connects the nodes in the AudioContext to start the flow of audio data.\n     *\n     * @returns {void}\n     */\n    _connectAudioGraph() {\n        this._audioProcessingNode.onaudioprocess = this._onAudioProcess;\n        this._audioSource.connect(this._audioProcessingNode);\n        this._audioProcessingNode.connect(this._audioContext.destination);\n    }\n\n    /**\n     * Disconnects the nodes in the AudioContext.\n     *\n     * @returns {void}\n     */\n    _disconnectAudioGraph() {\n        // Even thought we disconnect the processing node it seems that some callbacks remain queued,\n        // resulting in calls with and uninitialized context.\n        // eslint-disable-next-line no-empty-function\n        this._audioProcessingNode.onaudioprocess = () => {};\n        this._audioProcessingNode.disconnect();\n        this._audioSource.disconnect();\n    }\n\n    /**\n     * Cleanup potentially acquired resources.\n     *\n     * @returns {void}\n     */\n    _cleanupResources() {\n        this._disconnectAudioGraph();\n        this._localTrack.stopStream();\n    }\n\n    /**\n     * Get the associated track device ID.\n     *\n     * @returns {string}\n     */\n    getDeviceId() {\n        return this._localTrack.getDeviceId();\n    }\n\n\n    /**\n     * Get the associated track label.\n     *\n     * @returns {string}\n     */\n    getTrackLabel() {\n        return this._localTrack.getDeviceLabel();\n    }\n\n    /**\n     * Start the emitter by connecting the audio graph.\n     *\n     * @returns {void}\n     */\n    start() {\n        this._connectAudioGraph();\n    }\n\n    /**\n     * Stops the emitter by disconnecting the audio graph.\n     *\n     * @returns {void}\n     */\n    stop() {\n        this._disconnectAudioGraph();\n        this._bufferResidue = [];\n    }\n\n    /**\n     * Destroy TrackVADEmitter instance (release resources and stop callbacks).\n     *\n     * @returns {void}\n     */\n    destroy() {\n        if (this._destroyed) {\n            return;\n        }\n\n        this._cleanupResources();\n        this._destroyed = true;\n    }\n}\n","import { getLogger } from '@jitsi/logger';\nimport { EventEmitter } from 'events';\n\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\n\nimport { VAD_SCORE_PUBLISHED, DETECTOR_STATE_CHANGE } from './DetectionEvents';\nimport TrackVADEmitter from './TrackVADEmitter';\n\nconst logger = getLogger(__filename);\n\n/**\n * Sample rate of TrackVADEmitter, it defines how many audio samples are processed at a time.\n * @type {number}\n */\nconst VAD_EMITTER_SAMPLE_RATE = 4096;\n\n/**\n * Connects a TrackVADEmitter to the target conference local audio track and manages various services that use\n * the data to produce audio analytics (VADTalkMutedDetection and VADNoiseDetection).\n */\nexport default class VADAudioAnalyser extends EventEmitter {\n    /**\n     * Creates <tt>VADAudioAnalyser</tt>\n     * @param {JitsiConference} conference - JitsiConference instance that created us.\n     * @param {Object} createVADProcessor - Function that creates a Voice activity detection processor. The processor\n     * needs to implement the following functions:\n     * - <tt>getSampleLength()</tt> - Returns the sample size accepted by getSampleLength.\n     * - <tt>getRequiredPCMFrequency()</tt> - Returns the PCM frequency at which the processor operates.\n     * - <tt>calculateAudioFrameVAD(pcmSample)</tt> - Process a 32 float pcm sample of getSampleLength size.\n     * @constructor\n     */\n    constructor(conference, createVADProcessor) {\n        super();\n\n        /**\n         * Member function that instantiates a VAD processor.\n         */\n        this._createVADProcessor = createVADProcessor;\n\n        /**\n         * Current {@link TrackVADEmitter}. VAD Emitter uses a {@link JitsiLocalTrack} and VAD processor to generate\n         * period voice probability scores.\n         */\n        this._vadEmitter = null;\n\n        /**\n         * Current state of the _vadEmitter\n         */\n        this._isVADEmitterRunning = false;\n\n        /**\n         * Array of currently attached VAD processing services.\n         */\n        this._detectionServices = [];\n\n        /**\n         * Promise used to chain create and destroy operations associated with TRACK_ADDED and TRACK_REMOVED events\n         * coming from the conference.\n         * Because we have an async created component (VAD Processor) we need to make sure that it's initialized before\n         * we destroy it ( when changing the device for instance), or when we use it from an external point of entry\n         * i.e. (TRACK_MUTE_CHANGED event callback).\n         */\n        this._vadInitTracker = Promise.resolve();\n\n        /**\n         * Listens for {@link TrackVADEmitter} events and processes them.\n         */\n        this._processVADScore = this._processVADScore.bind(this);\n\n        conference.on(JitsiConferenceEvents.TRACK_ADDED, this._trackAdded.bind(this));\n        conference.on(JitsiConferenceEvents.TRACK_REMOVED, this._trackRemoved.bind(this));\n        conference.on(JitsiConferenceEvents.TRACK_MUTE_CHANGED, this._trackMuteChanged.bind(this));\n    }\n\n    /**\n     * Attach a VAD detector service to the analyser and handle it's state changes.\n     *\n     * @param {Object} vadTMDetector\n     */\n    addVADDetectionService(vadService) {\n        this._detectionServices.push(vadService);\n        vadService.on(DETECTOR_STATE_CHANGE, () => {\n            // When the state of a detector changes check if there are any active detectors attached so that\n            // the _vadEmitter doesn't run needlessly.\n            const activeDetector = this._detectionServices.filter(detector => detector.isActive() === true);\n\n            // If there are no active detectors running and the vadEmitter is running then stop the emitter as it is\n            // uses a considerable amount of CPU. Otherwise start the service if it's stopped and there is a detector\n            // that needs it.\n            if (!activeDetector.length && this._isVADEmitterRunning) {\n                this._stopVADEmitter();\n            } else if (!this._isVADEmitterRunning) {\n                this._startVADEmitter();\n            }\n        });\n    }\n\n    /**\n     * Start the {@link TrackVADEmitter} and attach the event listener.\n     * @returns {void}\n     */\n    _startVADEmitter() {\n        if (this._vadEmitter) {\n            this._vadEmitter.on(VAD_SCORE_PUBLISHED, this._processVADScore);\n            this._vadEmitter.start();\n            this._isVADEmitterRunning = true;\n        }\n    }\n\n    /**\n     * Stop the {@link TrackVADEmitter} and detach the event listener.\n     * @returns {void}\n     */\n    _stopVADEmitter() {\n        if (this._vadEmitter) {\n            this._vadEmitter.removeListener(VAD_SCORE_PUBLISHED, this._processVADScore);\n            this._vadEmitter.stop();\n        }\n        this._isVADEmitterRunning = false;\n    }\n\n    /**\n     * Listens for {@link TrackVADEmitter} events and directs them to attached services as needed.\n     *\n     * @param {Object} vadScore -VAD score emitted by {@link TrackVADEmitter}\n     * @param {Date}   vadScore.timestamp - Exact time at which processed PCM sample was generated.\n     * @param {number} vadScore.score - VAD score on a scale from 0 to 1 (i.e. 0.7)\n     * @param {Float32Array} pcmData - Raw PCM data with which the VAD score was calculated.\n     * @param {string} vadScore.deviceId - Device id of the associated track.\n     * @listens VAD_SCORE_PUBLISHED\n     */\n    _processVADScore(vadScore) {\n        for (const detector of this._detectionServices) {\n            detector.processVADScore(vadScore);\n        }\n    }\n\n    /**\n     * Change the isMuted state of all attached detection services.\n     *\n     * @param {boolean} isMuted\n     */\n    _changeDetectorsMuteState(isMuted) {\n        for (const detector of this._detectionServices) {\n            detector.changeMuteState(isMuted);\n        }\n    }\n\n    /**\n     * Notifies the detector that a track was added to the associated {@link JitsiConference}.\n     * Only take into account local audio tracks.\n     * @param {JitsiTrack} track - The added track.\n     * @returns {void}\n     * @listens TRACK_ADDED\n     */\n    _trackAdded(track) {\n        if (track.isLocalAudioTrack()) {\n            // Keep a track promise so we take into account successive TRACK_ADD events being generated so that we\n            // destroy/create the processing context in the proper order.\n            this._vadInitTracker = this._vadInitTracker.then(() => this._createVADProcessor())\n                .then(vadProcessor =>\n                    TrackVADEmitter.create(track.getDeviceId(), VAD_EMITTER_SAMPLE_RATE, vadProcessor)\n                )\n                .then(vadEmitter => {\n                    logger.debug('Created VAD emitter for track: ', track.getTrackLabel());\n\n                    this._vadEmitter = vadEmitter;\n\n                    // Iterate through the detection services and set their appropriate mute state, depending on\n                    // service this will trigger a DETECTOR_STATE_CHANGE which in turn might start the _vadEmitter.\n                    this._changeDetectorsMuteState(track.isMuted());\n                })\n                .catch(error => {\n                    logger.warn('Failed to start VADAudioAnalyser', error);\n                });\n        }\n    }\n\n    /**\n     * Notifies the detector that the mute state of a {@link JitsiConference} track has changed. Only takes into account\n     * local audio tracks.\n     * @param {JitsiTrack} track - The track whose mute state has changed.\n     * @returns {void}\n     * @listens TRACK_MUTE_CHANGED\n     */\n    _trackMuteChanged(track) {\n        if (track.isLocalAudioTrack()) {\n            // On a mute toggle reset the state.\n            this._vadInitTracker = this._vadInitTracker.then(() => {\n                // Set mute status for the attached detection services.\n                this._changeDetectorsMuteState(track.isMuted());\n            });\n        }\n    }\n\n    /**\n     * Notifies the detector that a track associated with the {@link JitsiConference} was removed. Only takes into\n     * account local audio tracks. Cleans up resources associated with the track and resets the processing context.\n     *\n     * @param {JitsiTrack} track - The removed track.\n     * @returns {void}\n     * @listens TRACK_REMOVED\n     */\n    _trackRemoved(track) {\n        if (track.isLocalAudioTrack()) {\n            // Use the promise to make sure operations are in sequence.\n            this._vadInitTracker = this._vadInitTracker.then(() => {\n                logger.debug('Removing track from VAD detection - ', track.getTrackLabel());\n\n                // Track was removed, clean up and set appropriate states.\n                if (this._vadEmitter) {\n                    this._stopVADEmitter();\n                    this._vadEmitter.destroy();\n                    this._vadEmitter = null;\n                }\n\n                // Reset state of detectors when active track is removed.\n                for (const detector of this._detectionServices) {\n                    detector.reset();\n                }\n            });\n        }\n    }\n\n\n}\n","import { EventEmitter } from 'events';\n\nimport { calculateAverage, filterPositiveValues } from '../util/MathUtil';\n\nimport { VAD_NOISY_DEVICE, DETECTOR_STATE_CHANGE } from './DetectionEvents';\n\n/**\n * The average value VAD needs to be under over a period of time to be considered noise.\n * @type {number}\n */\nconst VAD_NOISE_AVG_THRESHOLD = 0.2;\n\n/**\n * The average values that audio input need to be over to be considered loud.\n * @type {number}\n */\nconst NOISY_AUDIO_LEVEL_THRESHOLD = 0.040;\n\n/**\n * The value that a VAD score needs to be under in order for processing to begin.\n * @type {number}\n */\nconst VAD_SCORE_TRIGGER = 0.2;\n\n/**\n * The value that a VAD score needs to be under in order for processing to begin.\n * @type {number}\n */\nconst AUDIO_LEVEL_SCORE_TRIGGER = 0.020;\n\n/**\n * Time span over which we calculate an average score used to determine if we trigger the event.\n * @type {number}\n */\nconst PROCESS_TIME_FRAME_SPAN_MS = 1500;\n\n/**\n * Detect if provided VAD score and PCM data is considered noise.\n */\nexport default class VADNoiseDetection extends EventEmitter {\n    /**\n     * Creates <tt>VADNoiseDetection</tt>\n     *\n     * @constructor\n     */\n    constructor() {\n        super();\n\n        /**\n         * Flag which denotes the current state of the detection service i.e.if there is already a processing operation\n         * ongoing.\n         */\n        this._processing = false;\n\n        /**\n         * Buffer that keeps the VAD scores for a period of time.\n         */\n        this._scoreArray = [];\n\n        /**\n         * Buffer that keeps audio level samples for a period of time.\n         */\n        this._audioLvlArray = [];\n\n        /**\n         * Current state of the service, if it's not active no processing will occur.\n         */\n        this._active = false;\n\n        this._calculateNoisyScore = this._calculateNoisyScore.bind(this);\n    }\n\n    /**\n     * Compute cumulative VAD score and PCM audio levels once the PROCESS_TIME_FRAME_SPAN_MS timeout has elapsed.\n     * If the score is above the set threshold fire the event.\n     * @returns {void}\n     * @fires VAD_NOISY_DEVICE\n     */\n    _calculateNoisyScore() {\n        const scoreAvg = calculateAverage(this._scoreArray);\n        const audioLevelAvg = calculateAverage(this._audioLvlArray);\n\n        if (scoreAvg < VAD_NOISE_AVG_THRESHOLD && audioLevelAvg > NOISY_AUDIO_LEVEL_THRESHOLD) {\n            this.emit(VAD_NOISY_DEVICE);\n\n            this._setActiveState(false);\n        }\n\n        // We reset the context in case a new process phase needs to be triggered.\n        this.reset();\n    }\n\n    /**\n     * Record the vad score and average volume in the appropriate buffers.\n     *\n     * @param {number} vadScore\n     * @param {number} avgAudioLvl - average audio level of the PCM sample associated with the VAD score.s\n     */\n    _recordValues(vadScore, avgAudioLvl) {\n        this._scoreArray.push(vadScore);\n        this._audioLvlArray.push(avgAudioLvl);\n    }\n\n    /**\n     * Set the active state of the detection service and notify any listeners.\n     *\n     * @param {boolean} active\n     * @fires DETECTOR_STATE_CHANGE\n     */\n    _setActiveState(active) {\n        this._active = active;\n        this.emit(DETECTOR_STATE_CHANGE, this._active);\n    }\n\n    /**\n     * Change the state according to the muted status of the tracked device.\n     *\n     * @param {boolean} isMuted - Is the device muted or not.\n     */\n    changeMuteState(isMuted) {\n        // This service only needs to run when the microphone is not muted.\n        this._setActiveState(!isMuted);\n        this.reset();\n    }\n\n    /**\n     * Check whether or not the service is active or not.\n     *\n     * @returns {boolean}\n     */\n    isActive() {\n        return this._active;\n    }\n\n    /**\n     * Reset the processing context, clear buffers, cancel the timeout trigger.\n     *\n     * @returns {void}\n     */\n    reset() {\n        this._processing = false;\n        this._scoreArray = [];\n        this._audioLvlArray = [];\n        clearTimeout(this._processTimeout);\n    }\n\n    /**\n     * Listens for {@link TrackVADEmitter} events and processes them.\n     *\n     * @param {Object} vadScore -VAD score emitted by {@link TrackVADEmitter}\n     * @param {Date}   vadScore.timestamp - Exact time at which processed PCM sample was generated.\n     * @param {number} vadScore.score - VAD score on a scale from 0 to 1 (i.e. 0.7)\n     * @param {Float32Array} vadScore.pcmData - Raw PCM Data associated with the VAD score.\n     * @param {string} vadScore.deviceId - Device id of the associated track.\n     * @listens VAD_SCORE_PUBLISHED\n     */\n    processVADScore(vadScore) {\n        if (!this._active) {\n            return;\n        }\n\n        // There is a processing phase on going, add score to buffer array.\n        if (this._processing) {\n            // Filter and calculate sample average so we don't have to process one large array at a time.\n            const posAudioLevels = filterPositiveValues(vadScore.pcmData);\n\n            this._recordValues(vadScore.score, calculateAverage(posAudioLevels));\n\n            return;\n        }\n\n        // If the VAD score for the sample is low and audio level has a high enough level we can start listening for\n        // noise\n        if (vadScore.score < VAD_SCORE_TRIGGER) {\n            const posAudioLevels = filterPositiveValues(vadScore.pcmData);\n            const avgAudioLvl = calculateAverage(posAudioLevels);\n\n            if (avgAudioLvl > AUDIO_LEVEL_SCORE_TRIGGER) {\n                this._processing = true;\n                this._recordValues(vadScore.score, avgAudioLvl);\n\n                // Once the preset timeout executes the final score will be calculated.\n                this._processTimeout = setTimeout(this._calculateNoisyScore, PROCESS_TIME_FRAME_SPAN_MS);\n            }\n        }\n    }\n}\n","import { EventEmitter } from 'events';\n\nimport { calculateAverage } from '../util/MathUtil';\n\nimport { VAD_TALK_WHILE_MUTED, DETECTOR_STATE_CHANGE } from './DetectionEvents';\n\n\n/**\n * The threshold which the average VAD values for a span of time needs to exceed to trigger an event.\n * @type {number}\n */\nconst VAD_AVG_THRESHOLD = 0.6;\n\n/**\n * The VAD score needed to trigger the processing algorithm, i.e. if a sample has the VAD score >= VAD_VOICE_LEVEL\n * we start processing all scores for a time span defined by const PROCESS_TIME_FRAME_SPAN_MS.\n * @type {number}\n */\nconst VAD_VOICE_LEVEL = 0.9;\n\n/**\n * Sample rate of TrackVADEmitter, it defines how many audio samples are processed at a time.\n * @type {number}\n */\n\n/**\n * Time span over which we calculate an average score used to determine if we trigger the event.\n * @type {number}\n */\nconst PROCESS_TIME_FRAME_SPAN_MS = 700;\n\n/**\n * Detect if provided VAD score which is generated on a muted device is voice and fires an event.\n */\nexport default class VADTalkMutedDetection extends EventEmitter {\n    /**\n     * Creates <tt>VADTalkMutedDetection</tt>\n     * @constructor\n     */\n    constructor() {\n        super();\n\n        /**\n         * Flag which denotes the current state of the detection service i.e.if there is already a processing operation\n         * ongoing.\n         */\n        this._processing = false;\n\n        /**\n         * Buffer that keeps the VAD scores for a period of time.\n         */\n        this._scoreArray = [];\n\n        /**\n         * Current mute state of the audio track being monitored.\n         */\n        this._active = false;\n\n        this._calculateVADScore = this._calculateVADScore.bind(this);\n    }\n\n    /**\n     * Compute cumulative VAD score function called once the PROCESS_TIME_FRAME_SPAN_MS timeout has elapsed.\n     * @returns {void}\n     * @fires VAD_TALK_WHILE_MUTED\n     */\n    _calculateVADScore() {\n        const score = calculateAverage(this._scoreArray);\n\n        if (score > VAD_AVG_THRESHOLD) {\n            this.emit(VAD_TALK_WHILE_MUTED);\n\n            // Event was fired. Stop event emitter and remove listeners so no residue events kick off after this point\n            // and a single VAD_TALK_WHILE_MUTED is generated per mic muted state.\n            this._setActiveState(false);\n        }\n\n        // We reset the context in case a new process phase needs to be triggered.\n        this.reset();\n    }\n\n    /**\n     * Set the active state of the detection service and notify any listeners.\n     *\n     * @param {boolean} active\n     * @fires DETECTOR_STATE_CHANGE\n     */\n    _setActiveState(active) {\n        this._active = active;\n        this.emit(DETECTOR_STATE_CHANGE, this._active);\n    }\n\n    /**\n     * Change the state according to the muted status of the tracked device.\n     *\n     * @param {boolean} isMuted - Is the device muted or not.\n     */\n    changeMuteState(isMuted) {\n        // This service only needs to run when the microphone is muted.\n        this._setActiveState(isMuted);\n        this.reset();\n    }\n\n    /**\n     * Check whether or not the service is active or not.\n     *\n     * @returns {boolean}\n     */\n    isActive() {\n        return this._active;\n    }\n\n    /**\n     * Listens for {@link TrackVADEmitter} events and processes them.\n     *\n     * @param {Object} vadScore -VAD score emitted by {@link TrackVADEmitter}\n     * @param {Date}   vadScore.timestamp - Exact time at which processed PCM sample was generated.\n     * @param {number} vadScore.score - VAD score on a scale from 0 to 1 (i.e. 0.7)\n     * @param {string} vadScore.deviceId - Device id of the associated track.\n     * @listens VAD_SCORE_PUBLISHED\n     */\n    processVADScore(vadScore) {\n        if (!this._active) {\n            return;\n        }\n\n        // There is a processing phase on going, add score to buffer array.\n        if (this._processing) {\n            this._scoreArray.push(vadScore.score);\n\n            return;\n        }\n\n        // Because we remove all listeners on the vadEmitter once the main event is triggered,\n        // there is no need to check for rogue events.\n        if (vadScore.score > VAD_VOICE_LEVEL) {\n            this._processing = true;\n            this._scoreArray.push(vadScore.score);\n\n            // Start gathering VAD scores for the configured period of time.\n            this._processTimeout = setTimeout(this._calculateVADScore, PROCESS_TIME_FRAME_SPAN_MS);\n        }\n    }\n\n    /**\n     * Reset the processing context, clear buffer, cancel the timeout trigger.\n     *\n     * @returns {void}\n     */\n    reset() {\n        this._processing = false;\n        this._scoreArray = [];\n        clearTimeout(this._processTimeout);\n    }\n}\n","export enum E2ePingEvents {\n    /**\n     * Indicates that the end-to-end round-trip-time for a participant has changed.\n     */\n    E2E_RTT_CHANGED = 'e2eping.e2e_rtt_changed'\n};\n\n// exported for backward compatibility\nexport const E2E_RTT_CHANGED = E2ePingEvents.E2E_RTT_CHANGED;\n","import { getLogger } from '@jitsi/logger';\n\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\nimport * as E2ePingEvents\n    from '../../service/e2eping/E2ePingEvents';\nimport { createE2eRttEvent } from '../../service/statistics/AnalyticsEvents';\nimport Statistics from '../statistics/statistics';\n\nconst logger = getLogger(__filename);\n\n/**\n * The 'type' of a message which designates an e2e ping request.\n * @type {string}\n */\nconst E2E_PING_REQUEST = 'e2e-ping-request';\n\n/**\n * The 'type' of a message which designates an e2e ping response.\n * @type {string}\n */\nconst E2E_PING_RESPONSE = 'e2e-ping-response';\n\n/**\n * Saves e2e ping related state for a single JitsiParticipant.\n */\nclass ParticipantWrapper {\n    /**\n     * Creates a ParticipantWrapper\n     * @param {JitsiParticipant} participant - The remote participant that this\n     * object wraps.\n     * @param {E2ePing} e2eping\n     */\n    constructor(participant, e2eping) {\n        // The JitsiParticipant\n        this.participant = participant;\n\n        // The E2ePing\n        this.e2eping = e2eping;\n\n        // Caches the ID\n        this.id = participant.getId();\n\n        // Recently sent requests\n        this.requests = {};\n\n        // The ID of the last sent request. We just increment it for each new\n        // request. Start at 1 so we can consider only thruthy values valid.\n        this.lastRequestId = 1;\n\n        this.clearIntervals = this.clearIntervals.bind(this);\n        this.sendRequest = this.sendRequest.bind(this);\n        this.handleResponse = this.handleResponse.bind(this);\n        this.maybeSendAnalytics = this.maybeSendAnalytics.bind(this);\n        this.sendAnalytics = this.sendAnalytics.bind(this);\n\n        // If the data channel was already open (this is likely a participant\n        // joining an existing conference) send a request immediately.\n        if (e2eping.isDataChannelOpen) {\n            this.sendRequest();\n        }\n\n        this.pingInterval = window.setInterval(\n            this.sendRequest, e2eping.pingIntervalMs);\n        this.analyticsInterval = window.setTimeout(\n            this.maybeSendAnalytics, this.e2eping.analyticsIntervalMs);\n    }\n\n    /**\n     * Clears the interval which sends pings.\n     * @type {*}\n     */\n    clearIntervals() {\n        if (this.pingInterval) {\n            window.clearInterval(this.pingInterval);\n        }\n        if (this.analyticsInterval) {\n            window.clearInterval(this.analyticsInterval);\n        }\n    }\n\n    /**\n     * Sends the next ping request.\n     * @type {*}\n     */\n    sendRequest() {\n        const requestId = this.lastRequestId++;\n        const requestMessage = {\n            type: E2E_PING_REQUEST,\n            id: requestId\n        };\n\n        this.e2eping.sendMessage(requestMessage, this.id);\n        this.requests[requestId] = {\n            id: requestId,\n            timeSent: window.performance.now()\n        };\n    }\n\n    /**\n     * Handles a response from this participant.\n     * @type {*}\n     */\n    handleResponse(response) {\n        const request = this.requests[response.id];\n\n        if (request) {\n            request.rtt = window.performance.now() - request.timeSent;\n            this.e2eping.eventEmitter.emit(\n                E2ePingEvents.E2E_RTT_CHANGED,\n                this.participant,\n                request.rtt);\n        }\n\n        this.maybeSendAnalytics();\n    }\n\n    /**\n     * Goes over the requests, clearing ones which we don't need anymore, and\n     * if it finds at least one request with a valid RTT in the last\n     * 'analyticsIntervalMs' then sends an analytics event.\n     * @type {*}\n     */\n    maybeSendAnalytics() {\n        const now = window.performance.now();\n\n        // The RTT we'll report is the minimum RTT measured in the last\n        // analyticsInterval\n        let rtt = Infinity;\n        let request, requestId;\n\n        // It's time to send analytics. Clean up all requests and find the\n        for (requestId in this.requests) {\n            if (this.requests.hasOwnProperty(requestId)) {\n                request = this.requests[requestId];\n\n                if (request.timeSent < now - this.e2eping.analyticsIntervalMs) {\n                    // An old request. We don't care about it anymore.\n                    delete this.requests[requestId];\n                } else if (request.rtt) {\n                    rtt = Math.min(rtt, request.rtt);\n                }\n            }\n        }\n\n        if (rtt < Infinity) {\n            this.sendAnalytics(rtt);\n        }\n    }\n\n    /**\n     * Sends an analytics event for this participant with the given RTT.\n     * @type {*}\n     */\n    sendAnalytics(rtt) {\n        Statistics.sendAnalytics(createE2eRttEvent(\n            this.id,\n            this.participant.getProperty('region'),\n            rtt));\n    }\n}\n\n/**\n * Implements end-to-end ping (from one conference participant to another) via\n * the jitsi-videobridge channel (either WebRTC data channel or web socket).\n *\n * TODO: use a broadcast message instead of individual pings to each remote\n * participant.\n *\n * This class:\n * 1. Sends periodic ping requests to all other participants in the\n * conference.\n * 2. Responds to ping requests from other participants.\n * 3. Fires events with the end-to-end RTT to each participant whenever a\n * response is received.\n * 4. Fires analytics events with the end-to-end RTT periodically.\n */\nexport default class E2ePing {\n    /**\n     * @param {JitsiConference} conference - The conference.\n     * @param {Function} sendMessage - The function to use to send a message.\n     * @param {Object} options\n     */\n    constructor(conference, options, sendMessage) {\n        this.conference = conference;\n        this.eventEmitter = conference.eventEmitter;\n        this.sendMessage = sendMessage;\n\n        // The interval at which pings will be sent (<= 0 disables sending).\n        this.pingIntervalMs = 10000;\n\n        // The interval at which analytics events will be sent.\n        this.analyticsIntervalMs = 60000;\n\n        // Maps a participant ID to its ParticipantWrapper\n        this.participants = {};\n\n        // Whether the WebRTC channel has been opened or not.\n        this.isDataChannelOpen = false;\n\n        if (options && options.e2eping) {\n            if (typeof options.e2eping.pingInterval === 'number') {\n                this.pingIntervalMs = options.e2eping.pingInterval;\n            }\n            if (typeof options.e2eping.analyticsInterval === 'number') {\n                this.analyticsIntervalMs = options.e2eping.analyticsInterval;\n            }\n\n            // We want to report at most once a ping interval.\n            if (this.analyticsIntervalMs > 0 && this.analyticsIntervalMs\n                < this.pingIntervalMs) {\n                this.analyticsIntervalMs = this.pingIntervalMs;\n            }\n        }\n        logger.info(\n            `Initializing e2e ping; pingInterval=${\n                this.pingIntervalMs}, analyticsInterval=${\n                this.analyticsIntervalMs}.`);\n\n        this.participantJoined = this.participantJoined.bind(this);\n        conference.on(\n            JitsiConferenceEvents.USER_JOINED,\n            this.participantJoined);\n\n        this.participantLeft = this.participantLeft.bind(this);\n        conference.on(\n            JitsiConferenceEvents.USER_LEFT,\n            this.participantLeft);\n\n        this.messageReceived = this.messageReceived.bind(this);\n        conference.on(\n            JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,\n            this.messageReceived);\n\n        this.dataChannelOpened = this.dataChannelOpened.bind(this);\n        conference.on(\n            JitsiConferenceEvents.DATA_CHANNEL_OPENED,\n            this.dataChannelOpened);\n    }\n\n    /**\n     * Notifies this instance that the communications channel has been opened\n     * and it can now send messages via sendMessage.\n     */\n    dataChannelOpened() {\n        this.isDataChannelOpen = true;\n\n        // We don't want to wait the whole interval before sending the first\n        // request, but we can't send it immediately after the participant joins\n        // either, because our data channel might not have initialized.\n        // So once the data channel initializes, send requests to everyone.\n        // Wait an additional 200ms to give a chance to the remote side (if it\n        // also just connected as is the case for the first 2 participants in a\n        // conference) to open its data channel.\n        for (const id in this.participants) {\n            if (this.participants.hasOwnProperty(id)) {\n                const participantWrapper = this.participants[id];\n\n                window.setTimeout(participantWrapper.sendRequest, 200);\n            }\n        }\n    }\n\n    /**\n     * Handles a message that was received.\n     *\n     * @param participant - The message sender.\n     * @param payload - The payload of the message.\n     */\n    messageReceived(participant, payload) {\n        // Listen to E2E PING requests and responses from other participants\n        // in the conference.\n        if (payload.type === E2E_PING_REQUEST) {\n            this.handleRequest(participant.getId(), payload);\n        } else if (payload.type === E2E_PING_RESPONSE) {\n            this.handleResponse(participant.getId(), payload);\n        }\n    }\n\n    /**\n     * Handles a participant joining the conference. Starts to send ping\n     * requests to the participant.\n     *\n     * @param {String} id - The ID of the participant.\n     * @param {JitsiParticipant} participant - The participant that joined.\n     */\n    participantJoined(id, participant) {\n        if (this.pingIntervalMs <= 0) {\n            return;\n        }\n\n        if (this.participants[id]) {\n            logger.info(\n                `Participant wrapper already exists for ${id}. Clearing.`);\n            this.participants[id].clearIntervals();\n            delete this.participants[id];\n        }\n\n        this.participants[id] = new ParticipantWrapper(participant, this);\n    }\n\n    /**\n     * Handles a participant leaving the conference. Stops sending requests.\n     *\n     * @param {String} id - The ID of the participant.\n     */\n    participantLeft(id) {\n        if (this.pingIntervalMs <= 0) {\n            return;\n        }\n\n        if (this.participants[id]) {\n            this.participants[id].clearIntervals();\n            delete this.participants[id];\n        }\n    }\n\n    /**\n     * Handles a ping request coming from another participant.\n     *\n     * @param {string} participantId - The ID of the participant who sent the\n     * request.\n     * @param {Object} request - The request.\n     */\n    handleRequest(participantId, request) {\n        // If it's a valid request, just send a response.\n        if (request && request.id) {\n            const response = {\n                type: E2E_PING_RESPONSE,\n                id: request.id\n            };\n\n            this.sendMessage(response, participantId);\n        } else {\n            logger.info(\n                `Received an invalid e2e ping request from ${participantId}.`);\n        }\n    }\n\n    /**\n     * Handles a ping response coming from another participant\n     * @param {string} participantId - The ID of the participant who sent the\n     * response.\n     * @param {Object} response - The response.\n     */\n    handleResponse(participantId, response) {\n        const participantWrapper = this.participants[participantId];\n\n        if (participantWrapper) {\n            participantWrapper.handleResponse(response);\n        }\n    }\n\n    /**\n     * Stops this E2ePing (i.e. stop sending requests).\n     */\n    stop() {\n        logger.info('Stopping e2eping');\n\n        this.conference.off(\n            JitsiConferenceEvents.USER_JOINED,\n            this.participantJoined);\n        this.conference.off(\n            JitsiConferenceEvents.USER_LEFT,\n            this.participantLeft);\n        this.conference.off(\n            JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,\n            this.messageReceived);\n        this.conference.off(\n            JitsiConferenceEvents.DATA_CHANNEL_OPENED,\n            this.dataChannelOpened);\n\n        for (const id in this.participants) {\n            if (this.participants.hasOwnProperty(id)) {\n                this.participants[id].clearIntervals();\n            }\n        }\n\n        this.participants = {};\n    }\n}\n\n","import { getLogger } from '@jitsi/logger';\n\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\n\nconst logger = getLogger(__filename);\n\n/**\n * Emits {@link JitsiConferenceEvents.JVB121_STATUS} events based on the current\n * P2P status and the conference participants count. See the event description\n * for more info.\n */\nexport default class Jvb121EventGenerator {\n    /**\n     * Creates new <tt>Jvb121EventGenerator</tt> for the given conference.\n     * @param {JitsiConference} conference\n     */\n    constructor(conference) {\n        this._conference = conference;\n\n        /**\n         * Indicates whether it's a one to one JVB conference (<tt>true</tt>)\n         * or a multiparty (<tt>false</tt>). Will be also <tt>false</tt> if\n         * the conference is currently in the P2P mode.\n         * @type {boolean}\n         * @private\n         */\n        this._jvb121 = true;\n\n        this._conference.addEventListener(\n            JitsiConferenceEvents.USER_JOINED, () => this.evaluateStatus());\n        this._conference.addEventListener(\n            JitsiConferenceEvents.USER_LEFT, () => this.evaluateStatus());\n        this._conference.addEventListener(\n            JitsiConferenceEvents.P2P_STATUS, () => this.evaluateStatus());\n    }\n\n    /**\n     * Checks whether the JVB121 value should be updated and a new event\n     * emitted.\n     */\n    evaluateStatus() {\n        const oldStatus = this._jvb121;\n        const newStatus\n            = !this._conference.isP2PActive()\n                && this._conference.getParticipantCount() <= 2;\n\n        if (oldStatus !== newStatus) {\n            this._jvb121 = newStatus;\n            logger.debug(`JVB121 status ${oldStatus} => ${newStatus}`);\n            this._conference.eventEmitter.emit(\n                JitsiConferenceEvents.JVB121_STATUS, oldStatus, newStatus);\n        }\n    }\n}\n","import { getLogger } from '@jitsi/logger';\nimport isEqual from 'lodash.isequal';\n\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\nimport FeatureFlags from '../flags/FeatureFlags';\n\nconst logger = getLogger(__filename);\nconst MAX_HEIGHT_ONSTAGE = 2160;\nconst MAX_HEIGHT_THUMBNAIL = 180;\nconst LASTN_UNLIMITED = -1;\n\n/**\n * This class translates the legacy signaling format between the client and the bridge (that affects bandwidth\n * allocation) to the new format described here https://github.com/jitsi/jitsi-videobridge/blob/master/doc/allocation.md\n */\nclass ReceiverVideoConstraints {\n    /**\n     * Creates a new instance.\n     */\n    constructor() {\n        // Default constraints used for endpoints that are not explicitly included in constraints.\n        // These constraints are used for endpoints that are thumbnails in the stage view.\n        this._defaultConstraints = { 'maxHeight': MAX_HEIGHT_THUMBNAIL };\n\n        // The number of videos requested from the bridge.\n        this._lastN = LASTN_UNLIMITED;\n\n        // The number representing the maximum video height the local client should receive from the bridge.\n        this._maxFrameHeight = MAX_HEIGHT_ONSTAGE;\n\n        // The endpoint IDs of the participants that are currently selected.\n        this._selectedEndpoints = [];\n\n        this._receiverVideoConstraints = {\n            constraints: {},\n            defaultConstraints: this.defaultConstraints,\n            lastN: this._lastN,\n            onStageEndpoints: [],\n            selectedEndpoints: this._selectedEndpoints\n        };\n    }\n\n    /**\n     * Returns the receiver video constraints that need to be sent on the bridge channel.\n     */\n    get constraints() {\n        this._receiverVideoConstraints.lastN = this._lastN;\n\n        if (!this._selectedEndpoints.length) {\n            return this._receiverVideoConstraints;\n        }\n\n        // The client is assumed to be in TileView if it has selected more than one endpoint, otherwise it is\n        // assumed to be in StageView.\n        this._receiverVideoConstraints.constraints = {};\n        if (this._selectedEndpoints.length > 1) {\n            /**\n             * Tile view.\n             * Only the default constraints are specified here along with lastN (if it is set).\n             * {\n             *  'colibriClass': 'ReceiverVideoConstraints',\n             *  'defaultConstraints': { 'maxHeight': 360 }\n             * }\n             */\n            this._receiverVideoConstraints.defaultConstraints = { 'maxHeight': this._maxFrameHeight };\n            this._receiverVideoConstraints.onStageEndpoints = [];\n            this._receiverVideoConstraints.selectedEndpoints = [];\n        } else {\n            /**\n             * Stage view.\n             * The participant on stage is specified in onStageEndpoints and a higher maxHeight is specified\n             * for that endpoint while a default maxHeight of 180 is applied to all the other endpoints.\n             * {\n             *  'colibriClass': 'ReceiverVideoConstraints',\n             *  'onStageEndpoints': ['A'],\n             *  'defaultConstraints': { 'maxHeight':  180 },\n             *  'constraints': {\n             *      'A': { 'maxHeight': 720 }\n             *   }\n             * }\n             */\n            this._receiverVideoConstraints.constraints[this._selectedEndpoints[0]] = {\n                'maxHeight': this._maxFrameHeight\n            };\n            this._receiverVideoConstraints.defaultConstraints = this._defaultConstraints;\n            this._receiverVideoConstraints.onStageEndpoints = this._selectedEndpoints;\n            this._receiverVideoConstraints.selectedEndpoints = [];\n        }\n\n        return this._receiverVideoConstraints;\n    }\n\n    /**\n     * Updates the lastN field of the ReceiverVideoConstraints sent to the bridge.\n     *\n     * @param {number} value\n     * @returns {boolean} Returns true if the the value has been updated, false otherwise.\n     */\n    updateLastN(value) {\n        const changed = this._lastN !== value;\n\n        if (changed) {\n            this._lastN = value;\n            logger.debug(`Updating ReceiverVideoConstraints lastN(${value})`);\n        }\n\n        return changed;\n    }\n\n    /**\n     * Updates the resolution (height requested) in the contraints field of the ReceiverVideoConstraints\n     * sent to the bridge.\n     *\n     * @param {number} maxFrameHeight\n     * @requires {boolean} Returns true if the the value has been updated, false otherwise.\n     */\n    updateReceiveResolution(maxFrameHeight) {\n        const changed = this._maxFrameHeight !== maxFrameHeight;\n\n        if (changed) {\n            this._maxFrameHeight = maxFrameHeight;\n            logger.debug(`Updating receive maxFrameHeight: ${maxFrameHeight}`);\n        }\n\n        return changed;\n    }\n\n    /**\n     * Updates the receiver constraints sent to the bridge.\n     *\n     * @param {Object} videoConstraints\n     * @returns {boolean} Returns true if the the value has been updated, false otherwise.\n     */\n    updateReceiverVideoConstraints(videoConstraints) {\n        const changed = !isEqual(this._receiverVideoConstraints, videoConstraints);\n\n        if (changed) {\n            this._receiverVideoConstraints = videoConstraints;\n            logger.debug(`Updating ReceiverVideoConstraints ${JSON.stringify(videoConstraints)}`);\n        }\n\n        return changed;\n    }\n\n    /**\n     * Updates the list of selected endpoints.\n     *\n     * @param {Array<string>} ids\n     * @returns {void}\n     */\n    updateSelectedEndpoints(ids) {\n        logger.debug(`Updating selected endpoints: ${JSON.stringify(ids)}`);\n        this._selectedEndpoints = ids;\n    }\n}\n\n/**\n * This class manages the receive video contraints for a given {@link JitsiConference}. These constraints are\n * determined by the application based on how the remote video streams need to be displayed. This class is responsible\n * for communicating these constraints to the bridge over the bridge channel.\n */\nexport default class ReceiveVideoController {\n    /**\n     * Creates a new instance for a given conference.\n     *\n     * @param {JitsiConference} conference the conference instance for which the new instance will be managing\n     * the receive video quality constraints.\n     * @param {RTC} rtc the rtc instance which is responsible for initializing the bridge channel.\n     */\n    constructor(conference, rtc) {\n        this._conference = conference;\n        this._rtc = rtc;\n\n        const { config } = conference.options;\n\n        // The number of videos requested from the bridge, -1 represents unlimited or all available videos.\n        this._lastN = config?.startLastN ?? (config?.channelLastN || LASTN_UNLIMITED);\n\n        // The number representing the maximum video height the local client should receive from the bridge.\n        this._maxFrameHeight = MAX_HEIGHT_ONSTAGE;\n\n        // Enable new receiver constraints by default unless it is explicitly disabled through config.js.\n        const useNewReceiverConstraints = config?.useNewBandwidthAllocationStrategy ?? true;\n\n        if (useNewReceiverConstraints) {\n            this._receiverVideoConstraints = new ReceiverVideoConstraints();\n            const lastNUpdated = this._receiverVideoConstraints.updateLastN(this._lastN);\n\n            lastNUpdated && this._rtc.setNewReceiverVideoConstraints(this._receiverVideoConstraints.constraints);\n        } else {\n            this._rtc.setLastN(this._lastN);\n        }\n\n        // The endpoint IDs of the participants that are currently selected.\n        this._selectedEndpoints = [];\n\n        this._conference.on(\n            JitsiConferenceEvents._MEDIA_SESSION_STARTED,\n            session => this._onMediaSessionStarted(session));\n    }\n\n    /**\n     * Handles the {@link JitsiConferenceEvents.MEDIA_SESSION_STARTED}, that is when the conference creates new media\n     * session. The preferred receive frameHeight is applied on the media session.\n     *\n     * @param {JingleSessionPC} mediaSession - the started media session.\n     * @returns {void}\n     * @private\n     */\n    _onMediaSessionStarted(mediaSession) {\n        if (mediaSession.isP2P || !this._receiverVideoConstraints) {\n            mediaSession.setReceiverVideoConstraint(this._maxFrameHeight);\n        } else {\n            this._receiverVideoConstraints.updateReceiveResolution(this._maxFrameHeight);\n            this._rtc.setNewReceiverVideoConstraints(this._receiverVideoConstraints.constraints);\n        }\n    }\n\n    /**\n     * Returns the lastN value for the conference.\n     *\n     * @returns {number}\n     */\n    getLastN() {\n        return this._lastN;\n    }\n\n    /**\n     * Elects the participants with the given ids to be the selected participants in order to always receive video\n     * for this participant (even when last n is enabled).\n     *\n     * @param {Array<string>} ids - The user ids.\n     * @returns {void}\n     */\n    selectEndpoints(ids) {\n        this._selectedEndpoints = ids;\n\n        if (this._receiverVideoConstraints) {\n            // Filter out the local endpointId from the list of selected endpoints.\n            const remoteEndpointIds = ids.filter(id => id !== this._conference.myUserId());\n            const oldConstraints = JSON.parse(JSON.stringify(this._receiverVideoConstraints.constraints));\n\n            remoteEndpointIds.length && this._receiverVideoConstraints.updateSelectedEndpoints(remoteEndpointIds);\n            const newConstraints = this._receiverVideoConstraints.constraints;\n\n            // Send bridge message only when the constraints change.\n            if (!isEqual(newConstraints, oldConstraints)) {\n                this._rtc.setNewReceiverVideoConstraints(newConstraints);\n            }\n\n            return;\n        }\n        this._rtc.selectEndpoints(ids);\n    }\n\n    /**\n     * Selects a new value for \"lastN\". The requested amount of videos are going to be delivered after the value is\n     * in effect. Set to -1 for unlimited or all available videos.\n     *\n     * @param {number} value the new value for lastN.\n     * @returns {void}\n     */\n    setLastN(value) {\n        if (this._lastN !== value) {\n            this._lastN = value;\n\n            if (this._receiverVideoConstraints) {\n                const lastNUpdated = this._receiverVideoConstraints.updateLastN(value);\n\n                // Send out the message on the bridge channel if lastN was updated.\n                lastNUpdated && this._rtc.setNewReceiverVideoConstraints(this._receiverVideoConstraints.constraints);\n\n                return;\n            }\n            this._rtc.setLastN(value);\n        }\n    }\n\n    /**\n     * Sets the maximum video resolution the local participant should receive from remote participants.\n     *\n     * @param {number|undefined} maxFrameHeight - the new value.\n     * @returns {void}\n     */\n    setPreferredReceiveMaxFrameHeight(maxFrameHeight) {\n        this._maxFrameHeight = maxFrameHeight;\n\n        for (const session of this._conference.getMediaSessions()) {\n            if (session.isP2P || !this._receiverVideoConstraints) {\n                maxFrameHeight && session.setReceiverVideoConstraint(maxFrameHeight);\n            } else {\n                const resolutionUpdated = this._receiverVideoConstraints.updateReceiveResolution(maxFrameHeight);\n\n                resolutionUpdated\n                    && this._rtc.setNewReceiverVideoConstraints(this._receiverVideoConstraints.constraints);\n            }\n        }\n    }\n\n    /**\n     * Sets the receiver constraints for the conference.\n     *\n     * @param {Object} constraints The video constraints.\n     */\n    setReceiverConstraints(constraints) {\n        if (!this._receiverVideoConstraints) {\n            this._receiverVideoConstraints = new ReceiverVideoConstraints();\n        }\n\n        const isEndpointsFormat = Object.keys(constraints).includes('onStageEndpoints', 'selectedEndpoints');\n        const isSourcesFormat = Object.keys(constraints).includes('onStageSources', 'selectedSources');\n\n        if (!FeatureFlags.isSourceNameSignalingEnabled() && isSourcesFormat) {\n            throw new Error(\n                '\"onStageSources\" and \"selectedSources\" are not supported when sourceNameSignaling is disabled.'\n            );\n        }\n\n        if (FeatureFlags.isSourceNameSignalingEnabled() && isEndpointsFormat) {\n            throw new Error(\n                '\"onStageEndpoints\" and \"selectedEndpoints\" are not supported when sourceNameSignaling is enabled.'\n            );\n        }\n        const constraintsChanged = this._receiverVideoConstraints.updateReceiverVideoConstraints(constraints);\n\n        if (constraintsChanged) {\n            this._lastN = constraints.lastN ?? this._lastN;\n            this._selectedEndpoints = constraints.selectedEndpoints ?? this._selectedEndpoints;\n            this._rtc.setNewReceiverVideoConstraints(constraints);\n\n            const p2pSession = this._conference.getMediaSessions().find(session => session.isP2P);\n\n            if (p2pSession) {\n                let maxFrameHeight = Object.values(constraints.constraints)[0]?.maxHeight;\n\n                if (!maxFrameHeight) {\n                    maxFrameHeight = constraints.defaultConstraints?.maxHeight;\n                }\n                maxFrameHeight && p2pSession.setReceiverVideoConstraint(maxFrameHeight);\n            }\n        }\n    }\n}\n","import { getLogger } from '@jitsi/logger';\n\nimport * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\nimport RTCEvents from '../../service/RTC/RTCEvents';\nimport FeatureFlags from '../flags/FeatureFlags';\nimport MediaSessionEvents from '../xmpp/MediaSessionEvents';\n\nconst logger = getLogger(__filename);\nconst MAX_LOCAL_RESOLUTION = 2160;\n\n/**\n * The class manages send video constraints across media sessions({@link JingleSessionPC}) which belong to\n * {@link JitsiConference}. It finds the lowest common value, between the local user's send preference and\n * the remote party's receive preference. Also this module will consider only the active session's receive value,\n * because local tracks are shared and while JVB may have no preference, the remote p2p may have and they may be totally\n * different.\n */\nexport default class SendVideoController {\n    /**\n     * Creates new instance for a given conference.\n     *\n     * @param {JitsiConference} conference - the conference instance for which the new instance will be managing\n     * the send video quality constraints.\n     * @param {RTC} rtc - the rtc instance that is responsible for sending the messages on the bridge channel.\n     */\n    constructor(conference, rtc) {\n        this._conference = conference;\n        this._preferredSendMaxFrameHeight = MAX_LOCAL_RESOLUTION;\n        this._rtc = rtc;\n\n        /**\n         * Source name based sender constraints.\n         * @type {Map<string, number>};\n         */\n\n        this._sourceSenderConstraints = new Map();\n        this._conference.on(\n            JitsiConferenceEvents._MEDIA_SESSION_STARTED,\n            session => this._onMediaSessionStarted(session));\n        this._conference.on(\n            JitsiConferenceEvents._MEDIA_SESSION_ACTIVE_CHANGED,\n            () => this._configureConstraintsForLocalSources());\n        this._rtc.on(\n            RTCEvents.SENDER_VIDEO_CONSTRAINTS_CHANGED,\n            videoConstraints => this._onSenderConstraintsReceived(videoConstraints));\n    }\n\n    /**\n     * Configures the video encodings on the local sources when a media connection is established or becomes active.\n     *\n     * @returns {Promise<void[]>}\n     * @private\n     */\n    _configureConstraintsForLocalSources() {\n        if (FeatureFlags.isSourceNameSignalingEnabled()) {\n            for (const track of this._rtc.getLocalVideoTracks()) {\n                const sourceName = track.getSourceName();\n\n                sourceName && this._propagateSendMaxFrameHeight(sourceName);\n            }\n        } else {\n            this._propagateSendMaxFrameHeight();\n        }\n    }\n\n    /**\n     * Handles the {@link JitsiConferenceEvents.MEDIA_SESSION_STARTED}, that is when the conference creates new media\n     * session. It doesn't mean it's already active though. For example the JVB connection may be created after\n     * the conference has entered the p2p mode already.\n     *\n     * @param {JingleSessionPC} mediaSession - the started media session.\n     * @private\n     */\n    _onMediaSessionStarted(mediaSession) {\n        mediaSession.addListener(\n            MediaSessionEvents.REMOTE_VIDEO_CONSTRAINTS_CHANGED,\n            session => {\n                if (session === this._conference.getActiveMediaSession()) {\n                    this._configureConstraintsForLocalSources();\n                }\n            });\n    }\n\n    /**\n     * Propagates the video constraints if they have changed.\n     *\n     * @param {Object} videoConstraints - The sender video constraints received from the bridge.\n     * @returns {Promise<void[]>}\n     * @private\n     */\n    _onSenderConstraintsReceived(videoConstraints) {\n        if (FeatureFlags.isSourceNameSignalingEnabled()) {\n            const { maxHeight, sourceName } = videoConstraints;\n            const localVideoTracks = this._conference.getLocalVideoTracks() ?? [];\n\n            for (const track of localVideoTracks) {\n                // Propagate the sender constraint only if it has changed.\n                if (track.getSourceName() === sourceName\n                    && (!this._sourceSenderConstraints.has(sourceName)\n                    || this._sourceSenderConstraints.get(sourceName) !== maxHeight)) {\n                    this._sourceSenderConstraints.set(sourceName, maxHeight);\n                    logger.debug(`Sender constraints for source:${sourceName} changed to maxHeight:${maxHeight}`);\n                    this._propagateSendMaxFrameHeight(sourceName);\n                }\n            }\n        } else if (this._senderVideoConstraints?.idealHeight !== videoConstraints.idealHeight) {\n            this._senderVideoConstraints = videoConstraints;\n            this._propagateSendMaxFrameHeight();\n        }\n    }\n\n    /**\n     * Figures out the send video constraint as specified by {@link _selectSendMaxFrameHeight} and sets it on all media\n     * sessions for the reasons mentioned in this class description.\n     *\n     * @param {string} sourceName - The source for which sender constraints have changed.\n     * @returns {Promise<void[]>}\n     * @private\n     */\n    _propagateSendMaxFrameHeight(sourceName = null) {\n        if (FeatureFlags.isSourceNameSignalingEnabled() && !sourceName) {\n            throw new Error('sourceName missing for calculating the sendMaxHeight for video tracks');\n        }\n        const sendMaxFrameHeight = this._selectSendMaxFrameHeight(sourceName);\n        const promises = [];\n\n        if (sendMaxFrameHeight >= 0) {\n            for (const session of this._conference.getMediaSessions()) {\n                promises.push(session.setSenderVideoConstraint(sendMaxFrameHeight, sourceName));\n            }\n        }\n\n        return Promise.all(promises);\n    }\n\n    /**\n     * Selects the lowest common value for the local video send constraint by looking at local user's preference and\n     * the active media session's receive preference set by the remote party.\n     *\n     * @param {string} sourceName - The source for which sender constraints have changed.\n     * @returns {number|undefined}\n     * @private\n     */\n    _selectSendMaxFrameHeight(sourceName = null) {\n        if (FeatureFlags.isSourceNameSignalingEnabled() && !sourceName) {\n            throw new Error('sourceName missing for calculating the sendMaxHeight for video tracks');\n        }\n        const activeMediaSession = this._conference.getActiveMediaSession();\n        const remoteRecvMaxFrameHeight = activeMediaSession\n            ? activeMediaSession.isP2P\n                ? activeMediaSession.getRemoteRecvMaxFrameHeight()\n                : sourceName ? this._sourceSenderConstraints.get(sourceName) : this._senderVideoConstraints?.idealHeight\n            : undefined;\n\n        if (this._preferredSendMaxFrameHeight >= 0 && remoteRecvMaxFrameHeight >= 0) {\n            return Math.min(this._preferredSendMaxFrameHeight, remoteRecvMaxFrameHeight);\n        } else if (remoteRecvMaxFrameHeight >= 0) {\n            return remoteRecvMaxFrameHeight;\n        }\n\n        return this._preferredSendMaxFrameHeight;\n    }\n\n    /**\n     * Sets local preference for max send video frame height.\n     *\n     * @param {number} maxFrameHeight - the new value to set.\n     * @returns {Promise<void[]>} - resolved when the operation is complete.\n     */\n    setPreferredSendMaxFrameHeight(maxFrameHeight) {\n        this._preferredSendMaxFrameHeight = maxFrameHeight;\n\n        if (FeatureFlags.isSourceNameSignalingEnabled()) {\n            const promises = [];\n\n            for (const sourceName of this._sourceSenderConstraints.keys()) {\n                promises.push(this._propagateSendMaxFrameHeight(sourceName));\n            }\n\n            return Promise.allSettled(promises);\n        }\n\n        return this._propagateSendMaxFrameHeight();\n    }\n}\n","/**\n * A collection of utility functions for taking in XML and parsing it to return\n * certain values.\n */\nexport default {\n    /**\n     * Parses the presence update of the focus and returns an object with the\n     * statuses related to recording.\n     *\n     * @param {Node} presence - An XMPP presence update.\n     * @returns {Object} The current presence values related to recording.\n     */\n    getFocusRecordingUpdate(presence) {\n        const jibriStatus = presence\n            && presence.getElementsByTagName('jibri-recording-status')[0];\n\n        if (!jibriStatus) {\n            return;\n        }\n\n        return {\n            error: jibriStatus.getAttribute('failure_reason'),\n            initiator: jibriStatus.getAttribute('initiator'),\n            recordingMode: jibriStatus.getAttribute('recording_mode'),\n            sessionID: jibriStatus.getAttribute('session_id'),\n            status: jibriStatus.getAttribute('status')\n        };\n    },\n\n    /**\n     * Parses the presence update from a hidden domain participant and returns\n     * an object with the statuses related to recording.\n     *\n     * @param {Node} presence - An XMPP presence update.\n     * @returns {Object} The current presence values related to recording.\n     */\n    getHiddenDomainUpdate(presence) {\n        const liveStreamViewURLContainer\n            = presence.getElementsByTagName('live-stream-view-url')[0];\n        const liveStreamViewURL = liveStreamViewURLContainer\n            && liveStreamViewURLContainer.textContent;\n        const modeContainer\n            = presence.getElementsByTagName('mode')[0];\n        const mode = modeContainer\n            && modeContainer.textContent\n            && modeContainer.textContent.toLowerCase();\n        const sessionIDContainer\n            = presence.getElementsByTagName('session_id')[0];\n        const sessionID\n            = sessionIDContainer && sessionIDContainer.textContent;\n\n        return {\n            liveStreamViewURL,\n            mode,\n            sessionID\n        };\n    },\n\n    /**\n     * Returns the recording session ID from a successful IQ.\n     *\n     * @param {Node} response - The response from the IQ.\n     * @returns {string} The session ID of the recording session.\n     */\n    getSessionIdFromIq(response) {\n        const jibri = response && response.getElementsByTagName('jibri')[0];\n\n        return jibri && jibri.getAttribute('session_id');\n    },\n\n    /**\n     * Returns the recording session ID from a presence, if it exists.\n     *\n     * @param {Node} presence - An XMPP presence update.\n     * @returns {string|undefined} The session ID of the recording session.\n     */\n    getSessionId(presence) {\n        const sessionIdContainer\n            = presence.getElementsByTagName('session_id')[0];\n        const sessionId = sessionIdContainer && sessionIdContainer.textContent;\n\n        return sessionId;\n    },\n\n    /**\n     * Returns whether or not a presence is from the focus.\n     *\n     * @param {Node} presence - An XMPP presence update.\n     * @returns {boolean} True if the presence is from the focus.\n     */\n    isFromFocus(presence) {\n        return presence.getAttribute('from').includes('focus');\n    }\n};\n","import { $iq } from 'strophe.js';\n\nimport recordingXMLUtils from './recordingXMLUtils';\n\n/**\n * Represents a recording session.\n */\nexport default class JibriSession {\n    /**\n     * Initializes a new JibriSession instance.\n     *\n     * @constructor\n     */\n    constructor(options = {}) {\n        this._connection = options.connection;\n        this._mode = options.mode;\n\n        this._setSessionID(options.sessionID);\n        this.setStatus(options.status);\n    }\n\n    /**\n     * Returns the error related to the session instance, if any.\n     *\n     * @returns {string|undefined}\n     */\n    getError() {\n        return this._error;\n    }\n\n    /**\n     * Returns the session ID of the session instance.\n     *\n     * @returns {string|undefined}\n     */\n    getID() {\n        return this._sessionID;\n    }\n\n    /**\n     * Returns the initiator of the session instance.\n     *\n     * @returns {JitsiParticipant|string} The participant that started the session.\n     */\n    getInitiator() {\n        return this._initiator;\n    }\n\n    /**\n     * Returns the streaming URL of the session.\n     *\n     * @returns {string|undefined}\n     */\n    getLiveStreamViewURL() {\n        return this._liveStreamViewURL;\n    }\n\n    /**\n     * Returns the current status of the session.\n     *\n     * @returns {string|undefined}\n     */\n    getStatus() {\n        return this._status;\n    }\n\n    /**\n     * Returns the jid of the participant that stopped the session.\n     *\n     * @returns {JitsiParticipant|string} The participant that stopped the session.\n     */\n    getTerminator() {\n        return this._terminator;\n    }\n\n    /**\n     * Returns the current recording mode of the session, such as \"file\".\n     *\n     * @returns {string}\n     */\n    getMode() {\n        return this._mode;\n    }\n\n    /**\n     * Sets the last known error message related to the session.\n     *\n     * @param {string} error - The error string explaining why the session\n     * entered an error state.\n     * @returns {void}\n     */\n    setError(error) {\n        this._error = error;\n    }\n\n    /**\n     * Sets the last live stream URL for the session instance. Usually this is\n     * a YouTube URL and usually this is only set for \"stream\" sessions.\n     *\n     * @param {string} url - The live stream URL associated with the session.\n     * @returns {void}\n     */\n    setLiveStreamViewURL(url) {\n        this._liveStreamViewURL = url;\n    }\n\n    /**\n     * Sets the last known status for this recording session.\n     *\n     * @param {string} status - The new status to set.\n     * @returns {void}\n     */\n    setStatus(status) {\n        this._status = status;\n    }\n\n    /**\n     * Sets the participant that started the session.\n     * @param {JitsiParticipant | string} participant - The participant or resource id\n     * if local participant.\n     */\n    setInitiator(participant) {\n        this._initiator = participant;\n    }\n\n    /**\n     * Sets the participant that stopped the session.\n     * @param {JitsiParticipant | string} participant - The participant or the resource id\n     * if local participant.\n     */\n    setTerminator(participant) {\n        this._terminator = participant;\n    }\n\n    /**\n     * Sends a message to start the actual recording.\n     *\n     * @param {Object} options - Additional arguments for starting the\n     * recording.\n     * @param {string} [options.appData] - Data specific to the app/service that\n     * the result file will be uploaded.\n     * @param {string} [options.broadcastId] - The broadcast ID of an\n     * associated YouTube stream, used for knowing the URL from which the stream\n     * can be viewed.\n     * @param {string} options.focusMucJid - The JID of the focus participant\n     * that controls recording.\n     * @param {streamId} options.streamId - Necessary for live streaming, this\n     * is the stream key needed to start a live streaming session with the\n     * streaming service provider.\n     * @returns Promise\n     */\n    start({ appData, broadcastId, focusMucJid, streamId }) {\n        return new Promise((resolve, reject) => {\n            this._connection.sendIQ(\n                this._createIQ({\n                    action: 'start',\n                    appData,\n                    focusMucJid,\n                    broadcastId,\n                    streamId\n                }),\n                result => {\n                    // All users will eventually receive the 'pending' status\n                    // from the backend, but for the user initiating the session\n                    // it's better to give some instant feedback that recording\n                    // is starting so fire 'pending' here manually.\n                    this.setStatus('pending');\n                    this._setSessionID(\n                        recordingXMLUtils.getSessionIdFromIq(result));\n\n                    resolve();\n                },\n                error => {\n                    this._setErrorFromIq(error);\n\n                    reject(error);\n                });\n        });\n    }\n\n    /**\n     * Sends a message to actually stop the recording session.\n     *\n     * @param {Object} options - Additional arguments for stopping the\n     * recording.\n     * @param {Object} options.focusMucJid - The JID of the focus participant\n     * that controls recording.\n     * @returns Promise\n     */\n    stop({ focusMucJid }) {\n        return new Promise((resolve, reject) => {\n            this._connection.sendIQ(\n                this._createIQ({\n                    action: 'stop',\n                    focusMucJid\n                }),\n                resolve,\n                reject);\n        });\n    }\n\n    /**\n     * Generates the message to change the status of the recording session.\n     *\n     * @param {string} status - The new status to which the recording session\n     * should transition.\n     * @param {string} [options.appData] - Data specific to the app/service that\n     * the result file will be uploaded.\n     * @param {string} [options.broadcastId] - The broadcast ID of an\n     * associated YouTube stream, used for knowing the URL from which the stream\n     * can be viewed.\n     * @param {string} options.focusMucJid - The JID of the focus participant\n     * that controls recording.\n     * @param {streamId} options.streamId - Necessary for live streaming, this\n     * is the stream key needed to start a live streaming session with the\n     * streaming service provider.\n     * @returns Object - The XMPP IQ message.\n     */\n    _createIQ({ action, appData, broadcastId, focusMucJid, streamId }) {\n        return $iq({\n            to: focusMucJid,\n            type: 'set'\n        })\n        .c('jibri', {\n            'xmlns': 'http://jitsi.org/protocol/jibri',\n            'action': action,\n            'app_data': appData,\n            'recording_mode': this._mode,\n            'streamid': streamId,\n            'you_tube_broadcast_id': broadcastId\n        })\n        .up();\n    }\n\n    /**\n     * Handles the error from an iq and stores the error.\n     *\n     * @param {Node} errorIq - The error response from an Iq.\n     * @private\n     * @returns {void}\n     */\n    _setErrorFromIq(errorIq) {\n        const error = errorIq.getElementsByTagName('error')[0];\n\n        this.setError(error.children[0].tagName);\n    }\n\n    /**\n     * Sets the known session ID for this recording session.\n     *\n     * @param {string} sessionID\n     * @private\n     * @returns {void}\n     */\n    _setSessionID(sessionID) {\n        this._sessionID = sessionID;\n    }\n}\n","import { getLogger } from '@jitsi/logger';\n\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\n\nimport JibriSession from './JibriSession';\nimport recordingXMLUtils from './recordingXMLUtils';\n\nconst logger = getLogger(__filename);\n\n/**\n * A class responsible for starting and stopping recording sessions and emitting\n * state updates for them.\n */\nclass RecordingManager {\n    /**\n     * Initialize {@code RecordingManager} with other objects that are necessary\n     * for starting a recording.\n     *\n     * @param {ChatRoom} chatRoom - The chat room to handle.\n     * @returns {void}\n     */\n    constructor(chatRoom) {\n        /**\n         * All known recording sessions from the current conference.\n         */\n        this._sessions = {};\n\n        this._chatRoom = chatRoom;\n\n        this.onPresence = this.onPresence.bind(this);\n\n        this._chatRoom.eventEmitter.addListener(\n            XMPPEvents.PRESENCE_RECEIVED, this.onPresence);\n    }\n\n    /**\n     * Finds an existing recording session by session ID.\n     *\n     * @param {string} sessionID - The session ID associated with the recording.\n     * @returns {JibriSession|undefined}\n     */\n    getSession(sessionID) {\n        return this._sessions[sessionID];\n    }\n\n    /**\n     * Callback to invoke to parse through a presence update to find recording\n     * related updates (from Jibri participant doing the recording and the\n     * focus which controls recording).\n     *\n     * @param {Object} event - The presence data from the pubsub event.\n     * @param {Node} event.presence - An XMPP presence update.\n     * @param {boolean} event.fromHiddenDomain - Whether or not the update comes\n     * from a participant that is trusted but not visible, as would be the case\n     * with the Jibri recorder participant.\n     * @returns {void}\n     */\n    onPresence({ fromHiddenDomain, presence }) {\n        if (recordingXMLUtils.isFromFocus(presence)) {\n            this._handleFocusPresence(presence);\n        } else if (fromHiddenDomain) {\n            this._handleJibriPresence(presence);\n        }\n    }\n\n    /**\n     * Start a recording session.\n     *\n     * @param {Object} options - Configuration for the recording.\n     * @param {string} [options.appData] - Data specific to the app/service that\n     * the result file will be uploaded.\n     * @param {string} [optional] options.broadcastId - The channel on which a\n     * live stream will occur.\n     * @param {string} options.mode - The mode in which recording should be\n     * started. Recognized values are \"file\" and \"stream\".\n     * @param {string} [optional] options.streamId - The stream key to be used\n     * for live stream broadcasting. Required for live streaming.\n     * @returns {Promise} A promise for starting a recording, which will pass\n     * back the session on success. The promise resolves after receiving an\n     * acknowledgment of the start request success or fail.\n     */\n    startRecording(options) {\n        const session = new JibriSession({\n            ...options,\n            connection: this._chatRoom.connection\n        });\n\n        return session.start({\n            appData: options.appData,\n            broadcastId: options.broadcastId,\n            focusMucJid: this._chatRoom.focusMucJid,\n            streamId: options.streamId\n        })\n            .then(() => {\n                // Only store the session and emit if the session has not been\n                // added already. This is a workaround for the session getting\n                // created due to a presence update to announce a \"pending\"\n                // recording being received before JibriSession#start finishes.\n                if (!this.getSession(session.getID())) {\n                    this._addSession(session);\n                    this._emitSessionUpdate(session);\n                }\n\n                return session;\n            })\n            .catch(error => {\n                this._emitSessionUpdate(session);\n\n                return Promise.reject(error);\n            });\n    }\n\n    /**\n     * Stop a recording session.\n     *\n     * @param {string} sessionID - The ID associated with the recording session\n     * to be stopped.\n     * @returns {Promise} The promise resolves after receiving an\n     * acknowledgment of the stop request success or fail.\n     */\n    stopRecording(sessionID) {\n        const session = this.getSession(sessionID);\n\n        if (session) {\n            return session.stop({ focusMucJid: this._chatRoom.focusMucJid });\n        }\n\n        return Promise.reject(new Error('Could not find session'));\n    }\n\n    /**\n     * Stores a reference to the passed in JibriSession.\n     *\n     * @param {string} session - The JibriSession instance to store.\n     * @returns {void}\n     */\n    _addSession(session) {\n        this._sessions[session.getID()] = session;\n    }\n\n    /**\n     * Create a new instance of a recording session and stores a reference to\n     * it.\n     *\n     * @param {string} sessionID - The session ID of the recording in progress.\n     * @param {string} status - The current status of the recording session.\n     * @param {string} mode - The recording mode of the session.\n     * @returns {JibriSession}\n     */\n    _createSession(sessionID, status, mode) {\n        const session = new JibriSession({\n            connection: this._chatRoom.connection,\n            focusMucJid: this._chatRoom.focusMucJid,\n            mode,\n            sessionID,\n            status\n        });\n\n        this._addSession(session);\n\n        return session;\n    }\n\n    /**\n     * Notifies listeners of an update to a recording session.\n     *\n     * @param {JibriSession} session - The session that has been updated.\n     * @param {string|undefined} initiator - The jid of the initiator of the update.\n     */\n    _emitSessionUpdate(session, initiator) {\n        this._chatRoom.eventEmitter.emit(\n            XMPPEvents.RECORDER_STATE_CHANGED, session, initiator);\n    }\n\n    /**\n     * Parses presence to update an existing JibriSession or to create a new\n     * JibriSession.\n     *\n     * @param {Node} presence - An XMPP presence update.\n     * @returns {void}\n     */\n    _handleFocusPresence(presence) {\n        const jibriStatus = recordingXMLUtils.getFocusRecordingUpdate(presence);\n\n        if (!jibriStatus) {\n            return;\n        }\n\n        const { error, initiator, recordingMode, sessionID, status } = jibriStatus;\n\n        // We'll look for an existing session or create one (in case we're a\n        // participant joining a call with an existing recording going on).\n        let session = this.getSession(sessionID);\n\n        // Handle the case where a status update is received in presence but\n        // the local participant has joined while the JibriSession has already\n        // ended.\n        if (!session && status === 'off') {\n            logger.warn(\n                'Ignoring recording presence update',\n                'Received a new session with status off.');\n\n            return;\n        }\n\n        // Jicofo sends updates via presence, and any extension in presence\n        // is sent until it is explicitly removed.  It's difficult for\n        // Jicofo to know when a presence has been sent once, so it won't\n        // remove jibri status extension.  This means we may receive the same\n        // status update more than once, so check for that here\n        if (session\n            && session.getStatus() === status\n            && session.getError() === error) {\n            logger.warn('Ignoring duplicate presence update: ',\n                JSON.stringify(jibriStatus));\n\n            return;\n        }\n\n        if (!session) {\n            session = this._createSession(sessionID, status, recordingMode);\n        }\n\n        session.setStatus(status);\n\n        if (error) {\n            session.setError(error);\n        }\n\n        this._emitSessionUpdate(session, initiator);\n    }\n\n    /**\n     * Handles updates from the Jibri which can broadcast a YouTube URL that\n     * needs to be updated in a JibriSession.\n     *\n     * @param {Node} presence - An XMPP presence update.\n     * @returns {void}\n     */\n    _handleJibriPresence(presence) {\n        const { liveStreamViewURL, mode, sessionID }\n            = recordingXMLUtils.getHiddenDomainUpdate(presence);\n\n        if (!sessionID) {\n            logger.warn(\n                'Ignoring potential jibri presence due to no session id.');\n\n            return;\n        }\n\n        let session = this.getSession(sessionID);\n\n        if (!session) {\n            session = this._createSession(sessionID, '', mode);\n        }\n\n        session.setLiveStreamViewURL(liveStreamViewURL);\n\n        this._emitSessionUpdate(session);\n    }\n}\n\nexport default RecordingManager;\n","import { getLogger } from '@jitsi/logger';\n\nimport * as ConferenceEvents from '../../JitsiConferenceEvents';\nimport { MediaType } from '../../service/RTC/MediaType';\nimport * as ConnectionQualityEvents from '../../service/connectivity/ConnectionQualityEvents';\nimport { createAudioOutputProblemEvent } from '../../service/statistics/AnalyticsEvents';\n\nimport Statistics from './statistics';\n\nconst logger = getLogger(__filename);\n\n/**\n * Number of local samples that will be used for comparison before and after the remote sample is received.\n */\nconst NUMBER_OF_LOCAL_SAMPLES = 2;\n\n/**\n * Collects the average audio levels per participant from the local stats and the stats received by every remote\n * participant and compares them to detect potential audio problem for a participant.\n */\nexport default class AudioOutputProblemDetector {\n\n    /**\n     * Creates new <tt>AudioOutputProblemDetector</tt> instance.\n     *\n     * @param {JitsiConference} conference - The conference instance to be monitored.\n     */\n    constructor(conference) {\n        this._conference = conference;\n        this._localAudioLevelCache = {};\n        this._reportedParticipants = [];\n        this._audioProblemCandidates = {};\n        this._numberOfRemoteAudioLevelsReceived = {};\n        this._onLocalAudioLevelsReport = this._onLocalAudioLevelsReport.bind(this);\n        this._onRemoteAudioLevelReceived = this._onRemoteAudioLevelReceived.bind(this);\n        this._clearUserData = this._clearUserData.bind(this);\n        this._conference.on(ConnectionQualityEvents.REMOTE_STATS_UPDATED, this._onRemoteAudioLevelReceived);\n        this._conference.statistics.addConnectionStatsListener(this._onLocalAudioLevelsReport);\n        this._conference.on(ConferenceEvents.USER_LEFT, this._clearUserData);\n    }\n\n    /**\n     * A listener for audio level data received by a remote participant.\n     *\n     * @param {string} userID - The user id of the participant that sent the data.\n     * @param {number} audioLevel - The average audio level value.\n     * @returns {void}\n     */\n    _onRemoteAudioLevelReceived(userID, { avgAudioLevels }) {\n        const numberOfReports = (this._numberOfRemoteAudioLevelsReceived[userID] + 1) || 0;\n\n        this._numberOfRemoteAudioLevelsReceived[userID] = numberOfReports;\n\n        if (this._reportedParticipants.indexOf(userID) !== -1 || (userID in this._audioProblemCandidates)\n                || avgAudioLevels <= 0 || numberOfReports < 3) {\n            return;\n        }\n\n        const participant = this._conference.getParticipantById(userID);\n\n        if (participant) {\n            const tracks = participant.getTracksByMediaType(MediaType.AUDIO);\n\n            if (tracks.length > 0 && participant.isAudioMuted()) {\n                // We don't need to report an error if everything seems fine with the participant and its tracks but\n                // the participant is audio muted. Since those are average audio levels we potentially can receive non\n                // zero values for muted track.\n                return;\n            }\n        }\n\n        const localAudioLevels = this._localAudioLevelCache[userID];\n\n        if (!Array.isArray(localAudioLevels) || localAudioLevels.every(audioLevel => audioLevel === 0)) {\n            this._audioProblemCandidates[userID] = {\n                remoteAudioLevels: avgAudioLevels,\n                localAudioLevels: []\n            };\n        }\n    }\n\n    /**\n     * A listener for audio level data retrieved by the local stats.\n     *\n     * @param {TraceablePeerConnection} tpc - The <tt>TraceablePeerConnection</tt> instance used to gather the data.\n     * @param {Object} avgAudioLevels - The average audio levels per participant.\n     * @returns {void}\n     */\n    _onLocalAudioLevelsReport(tpc, { avgAudioLevels }) {\n        if (tpc !== this._conference.getActivePeerConnection()) {\n            return;\n        }\n\n        Object.keys(avgAudioLevels).forEach(userID => {\n            if (this._reportedParticipants.indexOf(userID) !== -1) {\n                return;\n            }\n\n            const localAudioLevels = this._localAudioLevelCache[userID];\n\n            if (!Array.isArray(localAudioLevels)) {\n                this._localAudioLevelCache[userID] = [ ];\n            } else if (localAudioLevels.length >= NUMBER_OF_LOCAL_SAMPLES) {\n                localAudioLevels.shift();\n            }\n\n            this._localAudioLevelCache[userID].push(avgAudioLevels[userID]);\n        });\n\n\n        Object.keys(this._audioProblemCandidates).forEach(userID => {\n            const { localAudioLevels, remoteAudioLevels } = this._audioProblemCandidates[userID];\n\n            localAudioLevels.push(avgAudioLevels[userID]);\n\n            if (localAudioLevels.length === NUMBER_OF_LOCAL_SAMPLES) {\n                if (localAudioLevels.every(audioLevel => typeof audioLevel === 'undefined' || audioLevel === 0)) {\n                    const localAudioLevelsString = JSON.stringify(localAudioLevels);\n\n                    Statistics.sendAnalytics(\n                        createAudioOutputProblemEvent(userID, localAudioLevelsString, remoteAudioLevels));\n                    logger.warn(`A potential problem is detected with the audio output for participant ${\n                        userID}, local audio levels: ${localAudioLevelsString}, remote audio levels: ${\n                        remoteAudioLevels}`);\n                    this._reportedParticipants.push(userID);\n                    this._clearUserData(userID);\n                }\n\n                delete this._audioProblemCandidates[userID];\n            }\n        });\n    }\n\n    /**\n     * Clears the data stored for a participant.\n     *\n     * @param {string} userID - The id of the participant.\n     * @returns {void}\n     */\n    _clearUserData(userID) {\n        delete this._localAudioLevelCache[userID];\n    }\n\n    /**\n     * Disposes the allocated resources.\n     *\n     * @returns {void}\n     */\n    dispose() {\n        this._conference.off(ConnectionQualityEvents.REMOTE_STATS_UPDATED, this._onRemoteAudioLevelReceived);\n        this._conference.off(ConferenceEvents.USER_LEFT, this._clearUserData);\n        this._conference.statistics.removeConnectionStatsListener(this._onLocalAudioLevelsReport);\n        this._localAudioLevelCache = undefined;\n        this._audioProblemCandidates = undefined;\n        this._reportedParticipants = undefined;\n        this._numberOfRemoteAudioLevelsReceived = undefined;\n        this._conference = undefined;\n    }\n}\n","import { getLogger } from '@jitsi/logger';\nimport isEqual from 'lodash.isequal';\n\nimport * as ConferenceEvents from '../../JitsiConferenceEvents';\nimport { MediaType } from '../../service/RTC/MediaType';\nimport { VideoType } from '../../service/RTC/VideoType';\nimport * as ConnectionQualityEvents\n    from '../../service/connectivity/ConnectionQualityEvents';\nimport {\n    createRtpStatsEvent,\n    createTransportStatsEvent\n} from '../../service/statistics/AnalyticsEvents';\nimport browser from '../browser';\n\nimport Statistics from './statistics';\n\n\nconst logger = getLogger(__filename);\n\n/**\n * This will calculate an average for one, named stat and submit it to\n * the analytics module when requested. It automatically counts the samples.\n */\nclass AverageStatReport {\n    /**\n     * Creates new <tt>AverageStatReport</tt> for given name.\n     * @param {string} name that's the name of the event that will be reported\n     * to the analytics module.\n     */\n    constructor(name) {\n        this.name = name;\n        this.count = 0;\n        this.sum = 0;\n        this.samples = [];\n    }\n\n    /**\n     * Adds the next value that will be included in the average when\n     * {@link calculate} is called.\n     * @param {number} nextValue\n     */\n    addNext(nextValue) {\n        if (typeof nextValue !== 'number') {\n            logger.error(\n                `${this.name} - invalid value for idx: ${this.count}`,\n                nextValue);\n        } else if (!isNaN(nextValue)) {\n            this.sum += nextValue;\n            this.samples.push(nextValue);\n            this.count += 1;\n        }\n    }\n\n    /**\n     * Calculates an average for the samples collected using {@link addNext}.\n     * @return {number|NaN} an average of all collected samples or <tt>NaN</tt>\n     * if no samples were collected.\n     */\n    calculate() {\n        return this.sum / this.count;\n    }\n\n    /**\n     * Appends the report to the analytics \"data\" object. The object will be\n     * set under <tt>prefix</tt> + {@link this.name} key.\n     * @param {Object} report the analytics \"data\" object\n     */\n    appendReport(report) {\n        report[`${this.name}_avg`] = this.calculate();\n        report[`${this.name}_samples`] = JSON.stringify(this.samples);\n    }\n\n    /**\n     * Clears all memory of any samples collected, so that new average can be\n     * calculated using this instance.\n     */\n    reset() {\n        this.samples = [];\n        this.sum = 0;\n        this.count = 0;\n    }\n}\n\n/**\n * Class gathers the stats that are calculated and reported for a\n * {@link TraceablePeerConnection} even if it's not currently active. For\n * example we want to monitor RTT for the JVB connection while in P2P mode.\n */\nclass ConnectionAvgStats {\n    /**\n     * Creates new <tt>ConnectionAvgStats</tt>\n     * @param {AvgRTPStatsReporter} avgRtpStatsReporter\n     * @param {boolean} isP2P\n     * @param {number} n the number of samples, before arithmetic mean is to be\n     * calculated and values submitted to the analytics module.\n     */\n    constructor(avgRtpStatsReporter, isP2P, n) {\n        /**\n         * Is this instance for JVB or P2P connection ?\n         * @type {boolean}\n         */\n        this.isP2P = isP2P;\n\n        /**\n         * How many samples are to be included in arithmetic mean calculation.\n         * @type {number}\n         * @private\n         */\n        this._n = n;\n\n        /**\n         * The current sample index. Starts from 0 and goes up to {@link _n})\n         * when analytics report will be submitted.\n         * @type {number}\n         * @private\n         */\n        this._sampleIdx = 0;\n\n        /**\n         * Average round trip time reported by the ICE candidate pair.\n         * @type {AverageStatReport}\n         */\n        this._avgRTT = new AverageStatReport('rtt');\n\n        /**\n         * Map stores average RTT to the JVB reported by remote participants.\n         * Mapped per participant id {@link JitsiParticipant.getId}.\n         *\n         * This is used only when {@link ConnectionAvgStats.isP2P} equals to\n         * <tt>false</tt>.\n         *\n         * @type {Map<string,AverageStatReport>}\n         * @private\n         */\n        this._avgRemoteRTTMap = new Map();\n\n        /**\n         * The conference for which stats will be collected and reported.\n         * @type {JitsiConference}\n         * @private\n         */\n        this._avgRtpStatsReporter = avgRtpStatsReporter;\n\n        /**\n         * The latest average E2E RTT for the JVB connection only.\n         *\n         * This is used only when {@link ConnectionAvgStats.isP2P} equals to\n         * <tt>false</tt>.\n         *\n         * @type {number}\n         */\n        this._avgEnd2EndRTT = undefined;\n\n        this._onConnectionStats = (tpc, stats) => {\n            if (this.isP2P === tpc.isP2P) {\n                this._calculateAvgStats(stats);\n            }\n        };\n\n        const conference = avgRtpStatsReporter._conference;\n\n        conference.statistics.addConnectionStatsListener(\n            this._onConnectionStats);\n\n        if (!this.isP2P) {\n            this._onUserLeft = id => this._avgRemoteRTTMap.delete(id);\n            conference.on(ConferenceEvents.USER_LEFT, this._onUserLeft);\n\n            this._onRemoteStatsUpdated\n                = (id, data) => this._processRemoteStats(id, data);\n            conference.on(\n                ConnectionQualityEvents.REMOTE_STATS_UPDATED,\n                this._onRemoteStatsUpdated);\n        }\n    }\n\n    /**\n     * Processes next batch of stats.\n     * @param {go figure} data\n     * @private\n     */\n    _calculateAvgStats(data) {\n        if (!data) {\n            logger.error('No stats');\n\n            return;\n        }\n\n        if (browser.supportsRTTStatistics()) {\n            if (data.transport && data.transport.length) {\n                this._avgRTT.addNext(data.transport[0].rtt);\n            }\n        }\n\n        this._sampleIdx += 1;\n\n        if (this._sampleIdx >= this._n) {\n            if (browser.supportsRTTStatistics()) {\n                const conference = this._avgRtpStatsReporter._conference;\n\n                const batchReport = {\n                    p2p: this.isP2P,\n                    'conference_size': conference.getParticipantCount()\n                };\n\n                if (data.transport && data.transport.length) {\n                    Object.assign(batchReport, {\n                        'local_candidate_type':\n                            data.transport[0].localCandidateType,\n                        'remote_candidate_type':\n                            data.transport[0].remoteCandidateType,\n                        'transport_type': data.transport[0].type\n                    });\n                }\n\n                this._avgRTT.appendReport(batchReport);\n\n                if (this.isP2P) {\n                    // Report RTT diff only for P2P.\n                    const jvbEnd2EndRTT = this\n                        ._avgRtpStatsReporter.jvbStatsMonitor._avgEnd2EndRTT;\n\n                    if (!isNaN(jvbEnd2EndRTT)) {\n                        // eslint-disable-next-line dot-notation\n                        batchReport['rtt_diff']\n                            = this._avgRTT.calculate() - jvbEnd2EndRTT;\n                    }\n                } else {\n                    // Report end to end RTT only for JVB.\n                    const avgRemoteRTT = this._calculateAvgRemoteRTT();\n                    const avgLocalRTT = this._avgRTT.calculate();\n\n                    this._avgEnd2EndRTT = avgLocalRTT + avgRemoteRTT;\n\n                    if (!isNaN(avgLocalRTT) && !isNaN(avgRemoteRTT)) {\n                        // eslint-disable-next-line dot-notation\n                        batchReport['end2end_rtt_avg'] = this._avgEnd2EndRTT;\n                    }\n                }\n\n                Statistics.sendAnalytics(createRtpStatsEvent(batchReport));\n            }\n\n            this._resetAvgStats();\n        }\n    }\n\n    /**\n     * Calculates arithmetic mean of all RTTs towards the JVB reported by\n     * participants.\n     * @return {number|NaN} NaN if not available (not enough data)\n     * @private\n     */\n    _calculateAvgRemoteRTT() {\n        let count = 0, sum = 0;\n\n        // FIXME should we ignore RTT for participant\n        // who \"is having connectivity issues\" ?\n        for (const remoteAvg of this._avgRemoteRTTMap.values()) {\n            const avg = remoteAvg.calculate();\n\n            if (!isNaN(avg)) {\n                sum += avg;\n                count += 1;\n                remoteAvg.reset();\n            }\n        }\n\n        return sum / count;\n    }\n\n    /**\n     * Processes {@link ConnectionQualityEvents.REMOTE_STATS_UPDATED} to analyse\n     * RTT towards the JVB reported by each participant.\n     * @param {string} id {@link JitsiParticipant.getId}\n     * @param {go figure in ConnectionQuality.js} data\n     * @private\n     */\n    _processRemoteStats(id, data) {\n        const validData = typeof data.jvbRTT === 'number';\n        let rttAvg = this._avgRemoteRTTMap.get(id);\n\n        if (!rttAvg && validData) {\n            rttAvg = new AverageStatReport(`${id}_stat_rtt`);\n            this._avgRemoteRTTMap.set(id, rttAvg);\n        }\n\n        if (validData) {\n            rttAvg.addNext(data.jvbRTT);\n        } else if (rttAvg) {\n            this._avgRemoteRTTMap.delete(id);\n        }\n    }\n\n    /**\n     * Reset cache of all averages and {@link _sampleIdx}.\n     * @private\n     */\n    _resetAvgStats() {\n        this._avgRTT.reset();\n        if (this._avgRemoteRTTMap) {\n            this._avgRemoteRTTMap.clear();\n        }\n        this._sampleIdx = 0;\n    }\n\n    /**\n     *\n     */\n    dispose() {\n\n        const conference = this._avgRtpStatsReporter._conference;\n\n        conference.statistics.removeConnectionStatsListener(\n            this._onConnectionStats);\n        if (!this.isP2P) {\n            conference.off(\n                ConnectionQualityEvents.REMOTE_STATS_UPDATED,\n                this._onRemoteStatsUpdated);\n            conference.off(\n                ConferenceEvents.USER_LEFT,\n                this._onUserLeft);\n        }\n    }\n}\n\n/**\n * Reports average RTP statistics values (arithmetic mean) to the analytics\n * module for things like bit rate, bandwidth, packet loss etc. It keeps track\n * of the P2P vs JVB conference modes and submits the values under different\n * namespaces (the events for P2P mode have 'p2p.' prefix). Every switch between\n * P2P mode resets the data collected so far and averages are calculated from\n * scratch.\n */\nexport default class AvgRTPStatsReporter {\n    /**\n     * Creates new instance of <tt>AvgRTPStatsReporter</tt>\n     * @param {JitsiConference} conference\n     * @param {number} n the number of samples, before arithmetic mean is to be\n     * calculated and values submitted to the analytics module.\n     */\n    constructor(conference, n) {\n        /**\n         * How many {@link ConnectionQualityEvents.LOCAL_STATS_UPDATED} samples\n         * are to be included in arithmetic mean calculation.\n         * @type {number}\n         * @private\n         */\n        this._n = n;\n\n        if (n > 0) {\n            logger.info(`Avg RTP stats will be calculated every ${n} samples`);\n        } else {\n            logger.info('Avg RTP stats reports are disabled.');\n\n            // Do not initialize\n            return;\n        }\n\n        /**\n         * The current sample index. Starts from 0 and goes up to {@link _n})\n         * when analytics report will be submitted.\n         * @type {number}\n         * @private\n         */\n        this._sampleIdx = 0;\n\n        /**\n         * The conference for which stats will be collected and reported.\n         * @type {JitsiConference}\n         * @private\n         */\n        this._conference = conference;\n\n        /**\n         * Average audio upload bitrate\n         * XXX What are the units?\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgAudioBitrateUp\n            = new AverageStatReport('bitrate_audio_upload');\n\n        /**\n         * Average audio download bitrate\n         * XXX What are the units?\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgAudioBitrateDown\n            = new AverageStatReport('bitrate_audio_download');\n\n        /**\n         * Average video upload bitrate\n         * XXX What are the units?\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgVideoBitrateUp\n            = new AverageStatReport('bitrate_video_upload');\n\n        /**\n         * Average video download bitrate\n         * XXX What are the units?\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgVideoBitrateDown\n            = new AverageStatReport('bitrate_video_download');\n\n        /**\n         * Average upload bandwidth\n         * XXX What are the units?\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgBandwidthUp\n            = new AverageStatReport('bandwidth_upload');\n\n        /**\n         * Average download bandwidth\n         * XXX What are the units?\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgBandwidthDown\n            = new AverageStatReport('bandwidth_download');\n\n        /**\n         * Average total packet loss\n         * XXX What are the units?\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgPacketLossTotal\n            = new AverageStatReport('packet_loss_total');\n\n        /**\n         * Average upload packet loss\n         * XXX What are the units?\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgPacketLossUp\n            = new AverageStatReport('packet_loss_upload');\n\n        /**\n         * Average download packet loss\n         * XXX What are the units?\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgPacketLossDown\n            = new AverageStatReport('packet_loss_download');\n\n        /**\n         * Average FPS for remote videos\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgRemoteFPS = new AverageStatReport('framerate_remote');\n\n        /**\n         * Average FPS for remote screen streaming videos (reported only if not\n         * a <tt>NaN</tt>).\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgRemoteScreenFPS\n            = new AverageStatReport('framerate_screen_remote');\n\n        /**\n         * Average FPS for local video (camera)\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgLocalFPS = new AverageStatReport('framerate_local');\n\n        /**\n         * Average FPS for local screen streaming video (reported only if not\n         * a <tt>NaN</tt>).\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgLocalScreenFPS\n            = new AverageStatReport('framerate_screen_local');\n\n        /**\n         * Average pixels for remote screen streaming videos (reported only if\n         * not a <tt>NaN</tt>).\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgRemoteCameraPixels\n            = new AverageStatReport('pixels_remote');\n\n        /**\n         * Average pixels for remote screen streaming videos (reported only if\n         * not a <tt>NaN</tt>).\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgRemoteScreenPixels\n            = new AverageStatReport('pixels_screen_remote');\n\n        /**\n         * Average pixels for local video (camera)\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgLocalCameraPixels\n            = new AverageStatReport('pixels_local');\n\n        /**\n         * Average pixels for local screen streaming video (reported only if not\n         * a <tt>NaN</tt>).\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgLocalScreenPixels\n            = new AverageStatReport('pixels_screen_local');\n\n        /**\n         * Average connection quality as defined by\n         * the {@link ConnectionQuality} module.\n         * @type {AverageStatReport}\n         * @private\n         */\n        this._avgCQ = new AverageStatReport('connection_quality');\n\n        this._cachedTransportStats = undefined;\n\n        this._onLocalStatsUpdated = data => {\n            this._calculateAvgStats(data);\n            this._maybeSendTransportAnalyticsEvent(data);\n        };\n        conference.on(\n            ConnectionQualityEvents.LOCAL_STATS_UPDATED,\n            this._onLocalStatsUpdated);\n\n        this._onP2PStatusChanged = () => {\n            logger.debug('Resetting average stats calculation');\n            this._resetAvgStats();\n            this.jvbStatsMonitor._resetAvgStats();\n            this.p2pStatsMonitor._resetAvgStats();\n        };\n        conference.on(\n            ConferenceEvents.P2P_STATUS,\n            this._onP2PStatusChanged);\n\n        this._onJvb121StatusChanged = (oldStatus, newStatus) => {\n            // We want to reset only on the transition from false => true,\n            // because otherwise those stats are resetted on JVB <=> P2P\n            // transition.\n            if (newStatus === true) {\n                logger.info('Resetting JVB avg RTP stats');\n                this._resetAvgJvbStats();\n            }\n        };\n        conference.on(\n            ConferenceEvents.JVB121_STATUS,\n            this._onJvb121StatusChanged);\n\n        this.jvbStatsMonitor\n            = new ConnectionAvgStats(this, false /* JVB */, n);\n\n        this.p2pStatsMonitor\n            = new ConnectionAvgStats(this, true /* P2P */, n);\n    }\n\n    /**\n     * Processes next batch of stats reported on\n     * {@link ConnectionQualityEvents.LOCAL_STATS_UPDATED}.\n     * @param {go figure} data\n     * @private\n     */\n    _calculateAvgStats(data) {\n\n        if (!data) {\n            logger.error('No stats');\n\n            return;\n        }\n\n        const isP2P = this._conference.isP2PActive();\n        const confSize = this._conference.getParticipantCount();\n\n        if (!isP2P && confSize < 2) {\n\n            // There's no point in collecting stats for a JVB conference of 1.\n            // That happens for short period of time after everyone leaves\n            // the room, until Jicofo terminates the session.\n            return;\n        }\n\n        /* Uncomment to figure out stats structure\n        for (const key in data) {\n            if (data.hasOwnProperty(key)) {\n                logger.info(`local stat ${key}: `, data[key]);\n            }\n        } */\n\n        const bitrate = data.bitrate;\n        const bandwidth = data.bandwidth;\n        const packetLoss = data.packetLoss;\n        const frameRate = data.framerate;\n        const resolution = data.resolution;\n\n        if (!bitrate) {\n            logger.error('No \"bitrate\"');\n\n            return;\n        } else if (!bandwidth) {\n            logger.error('No \"bandwidth\"');\n\n            return;\n        } else if (!packetLoss) {\n            logger.error('No \"packetloss\"');\n\n            return;\n        } else if (!frameRate) {\n            logger.error('No \"framerate\"');\n\n            return;\n        } else if (!resolution) {\n            logger.error('No resolution');\n\n            return;\n        }\n\n        this._avgAudioBitrateUp.addNext(bitrate.audio.upload);\n        this._avgAudioBitrateDown.addNext(bitrate.audio.download);\n\n        this._avgVideoBitrateUp.addNext(bitrate.video.upload);\n        this._avgVideoBitrateDown.addNext(bitrate.video.download);\n\n        if (browser.supportsBandwidthStatistics()) {\n            this._avgBandwidthUp.addNext(bandwidth.upload);\n            this._avgBandwidthDown.addNext(bandwidth.download);\n        }\n\n        this._avgPacketLossUp.addNext(packetLoss.upload);\n        this._avgPacketLossDown.addNext(packetLoss.download);\n        this._avgPacketLossTotal.addNext(packetLoss.total);\n\n        this._avgCQ.addNext(data.connectionQuality);\n\n        if (frameRate) {\n            this._avgRemoteFPS.addNext(\n                this._calculateAvgVideoFps(\n                    frameRate, false /* remote */, VideoType.CAMERA));\n            this._avgRemoteScreenFPS.addNext(\n                this._calculateAvgVideoFps(\n                    frameRate, false /* remote */, VideoType.DESKTOP));\n\n            this._avgLocalFPS.addNext(\n                this._calculateAvgVideoFps(\n                    frameRate, true /* local */, VideoType.CAMERA));\n            this._avgLocalScreenFPS.addNext(\n                this._calculateAvgVideoFps(\n                    frameRate, true /* local */, VideoType.DESKTOP));\n        }\n\n        if (resolution) {\n            this._avgRemoteCameraPixels.addNext(\n                this._calculateAvgVideoPixels(\n                    resolution, false /* remote */, VideoType.CAMERA));\n\n            this._avgRemoteScreenPixels.addNext(\n                this._calculateAvgVideoPixels(\n                    resolution, false /* remote */, VideoType.DESKTOP));\n\n            this._avgLocalCameraPixels.addNext(\n                this._calculateAvgVideoPixels(\n                    resolution, true /* local */, VideoType.CAMERA));\n\n            this._avgLocalScreenPixels.addNext(\n                this._calculateAvgVideoPixels(\n                    resolution, true /* local */, VideoType.DESKTOP));\n        }\n\n        this._sampleIdx += 1;\n\n        if (this._sampleIdx >= this._n) {\n\n            const batchReport = {\n                p2p: isP2P,\n                'conference_size': confSize\n            };\n\n            if (data.transport && data.transport.length) {\n                Object.assign(batchReport, {\n                    'local_candidate_type':\n                        data.transport[0].localCandidateType,\n                    'remote_candidate_type':\n                        data.transport[0].remoteCandidateType,\n                    'transport_type': data.transport[0].type\n                });\n            }\n\n            this._avgAudioBitrateUp.appendReport(batchReport);\n            this._avgAudioBitrateDown.appendReport(batchReport);\n\n            this._avgVideoBitrateUp.appendReport(batchReport);\n            this._avgVideoBitrateDown.appendReport(batchReport);\n\n            if (browser.supportsBandwidthStatistics()) {\n                this._avgBandwidthUp.appendReport(batchReport);\n                this._avgBandwidthDown.appendReport(batchReport);\n            }\n            this._avgPacketLossUp.appendReport(batchReport);\n            this._avgPacketLossDown.appendReport(batchReport);\n            this._avgPacketLossTotal.appendReport(batchReport);\n\n            this._avgRemoteFPS.appendReport(batchReport);\n            if (!isNaN(this._avgRemoteScreenFPS.calculate())) {\n                this._avgRemoteScreenFPS.appendReport(batchReport);\n            }\n            this._avgLocalFPS.appendReport(batchReport);\n            if (!isNaN(this._avgLocalScreenFPS.calculate())) {\n                this._avgLocalScreenFPS.appendReport(batchReport);\n            }\n\n            this._avgRemoteCameraPixels.appendReport(batchReport);\n            if (!isNaN(this._avgRemoteScreenPixels.calculate())) {\n                this._avgRemoteScreenPixels.appendReport(batchReport);\n            }\n            this._avgLocalCameraPixels.appendReport(batchReport);\n            if (!isNaN(this._avgLocalScreenPixels.calculate())) {\n                this._avgLocalScreenPixels.appendReport(batchReport);\n            }\n\n            this._avgCQ.appendReport(batchReport);\n\n            Statistics.sendAnalytics(createRtpStatsEvent(batchReport));\n\n            this._resetAvgStats();\n        }\n    }\n\n    /**\n     * Calculates average number of pixels for the report\n     *\n     * @param {map} peerResolutions a map of peer resolutions\n     * @param {boolean} isLocal if the average is to be calculated for the local\n     * video or <tt>false</tt> if for remote videos.\n     * @param {VideoType} videoType\n     * @return {number|NaN} average number of pixels or <tt>NaN</tt> if there\n     * are no samples.\n     * @private\n     */\n    _calculateAvgVideoPixels(peerResolutions, isLocal, videoType) {\n        let peerPixelsSum = 0;\n        let peerCount = 0;\n        const myID = this._conference.myUserId();\n\n        for (const peerID of Object.keys(peerResolutions)) {\n            if (isLocal ? peerID === myID : peerID !== myID) {\n                const participant\n                    = isLocal\n                        ? null\n                        : this._conference.getParticipantById(peerID);\n                const videosResolution = peerResolutions[peerID];\n\n                // Do not continue without participant for non local peerID\n                if ((isLocal || participant) && videosResolution) {\n                    const peerAvgPixels = this._calculatePeerAvgVideoPixels(\n                        videosResolution, participant, videoType);\n\n                    if (!isNaN(peerAvgPixels)) {\n                        peerPixelsSum += peerAvgPixels;\n                        peerCount += 1;\n                    }\n                }\n            }\n        }\n\n        return peerPixelsSum / peerCount;\n    }\n\n    /**\n     * Calculate average pixels for either remote or local participant\n     * @param {object} videos maps resolution per video SSRC\n     * @param {JitsiParticipant|null} participant remote participant or\n     * <tt>null</tt> for local video pixels calculation.\n     * @param {VideoType} videoType the type of the video for which an average\n     * will be calculated.\n     * @return {number|NaN} average video pixels of all participant's videos or\n     * <tt>NaN</tt> if currently not available\n     * @private\n     */\n    _calculatePeerAvgVideoPixels(videos, participant, videoType) {\n        let ssrcs = Object.keys(videos).map(ssrc => Number(ssrc));\n        let videoTracks = null;\n\n        // NOTE that this method is supposed to be called for the stats\n        // received from the current peerconnection.\n        const tpc = this._conference.getActivePeerConnection();\n\n        if (participant) {\n            videoTracks = participant.getTracksByMediaType(MediaType.VIDEO);\n            if (videoTracks) {\n                ssrcs\n                    = ssrcs.filter(\n                        ssrc => videoTracks.find(\n                            track =>\n                                !track.isMuted()\n                                    && track.getSSRC() === ssrc\n                                    && track.videoType === videoType));\n            }\n        } else {\n            videoTracks = this._conference.getLocalTracks(MediaType.VIDEO);\n            ssrcs\n                = ssrcs.filter(\n                    ssrc => videoTracks.find(\n                        track =>\n                            !track.isMuted()\n                                && tpc.getLocalSSRC(track) === ssrc\n                                && track.videoType === videoType));\n        }\n\n        let peerPixelsSum = 0;\n        let peerSsrcCount = 0;\n\n        for (const ssrc of ssrcs) {\n            const peerSsrcPixels\n                = Number(videos[ssrc].height) * Number(videos[ssrc].width);\n\n            // FPS is reported as 0 for users with no video\n            if (!isNaN(peerSsrcPixels) && peerSsrcPixels > 0) {\n                peerPixelsSum += peerSsrcPixels;\n                peerSsrcCount += 1;\n            }\n        }\n\n        return peerPixelsSum / peerSsrcCount;\n    }\n\n\n    /**\n     * Calculates average FPS for the report\n     * @param {go figure} frameRate\n     * @param {boolean} isLocal if the average is to be calculated for the local\n     * video or <tt>false</tt> if for remote videos.\n     * @param {VideoType} videoType\n     * @return {number|NaN} average FPS or <tt>NaN</tt> if there are no samples.\n     * @private\n     */\n    _calculateAvgVideoFps(frameRate, isLocal, videoType) {\n        let peerFpsSum = 0;\n        let peerCount = 0;\n        const myID = this._conference.myUserId();\n\n        for (const peerID of Object.keys(frameRate)) {\n            if (isLocal ? peerID === myID : peerID !== myID) {\n                const participant\n                    = isLocal\n                        ? null : this._conference.getParticipantById(peerID);\n                const videosFps = frameRate[peerID];\n\n                // Do not continue without participant for non local peerID\n                if ((isLocal || participant) && videosFps) {\n                    const peerAvgFPS\n                        = this._calculatePeerAvgVideoFps(\n                            videosFps, participant, videoType);\n\n                    if (!isNaN(peerAvgFPS)) {\n                        peerFpsSum += peerAvgFPS;\n                        peerCount += 1;\n                    }\n                }\n            }\n        }\n\n        return peerFpsSum / peerCount;\n    }\n\n    /**\n     * Calculate average FPS for either remote or local participant\n     * @param {object} videos maps FPS per video SSRC\n     * @param {JitsiParticipant|null} participant remote participant or\n     * <tt>null</tt> for local FPS calculation.\n     * @param {VideoType} videoType the type of the video for which an average\n     * will be calculated.\n     * @return {number|NaN} average FPS of all participant's videos or\n     * <tt>NaN</tt> if currently not available\n     * @private\n     */\n    _calculatePeerAvgVideoFps(videos, participant, videoType) {\n        let ssrcs = Object.keys(videos).map(ssrc => Number(ssrc));\n        let videoTracks = null;\n\n        // NOTE that this method is supposed to be called for the stats\n        // received from the current peerconnection.\n        const tpc = this._conference.getActivePeerConnection();\n\n        if (participant) {\n            videoTracks = participant.getTracksByMediaType(MediaType.VIDEO);\n            if (videoTracks) {\n                ssrcs\n                    = ssrcs.filter(\n                        ssrc => videoTracks.find(\n                            track => !track.isMuted()\n                                && track.getSSRC() === ssrc\n                                && track.videoType === videoType));\n            }\n        } else {\n            videoTracks = this._conference.getLocalTracks(MediaType.VIDEO);\n            ssrcs\n                = ssrcs.filter(\n                    ssrc => videoTracks.find(\n                        track => !track.isMuted()\n                            && tpc.getLocalSSRC(track) === ssrc\n                            && track.videoType === videoType));\n        }\n\n        let peerFpsSum = 0;\n        let peerSsrcCount = 0;\n\n        for (const ssrc of ssrcs) {\n            const peerSsrcFps = Number(videos[ssrc]);\n\n            // FPS is reported as 0 for users with no video\n            if (!isNaN(peerSsrcFps) && peerSsrcFps > 0) {\n                peerFpsSum += peerSsrcFps;\n                peerSsrcCount += 1;\n            }\n        }\n\n        return peerFpsSum / peerSsrcCount;\n    }\n\n    /**\n     * Sends the 'transport.stats' analytics event whenever we detect that\n     * there is a change in the local or remote candidate type on the transport\n     * that is currently selected.\n     * @param {*} data\n     * @private\n     */\n    _maybeSendTransportAnalyticsEvent(data) {\n        if (!data || !data.transport || !data.transport.length) {\n            return;\n        }\n        const transportStats = {\n            p2p: data.transport[0].p2p,\n            'local_candidate_type': data.transport[0].localCandidateType,\n            'remote_candidate_type': data.transport[0].remoteCandidateType,\n            'transport_type': data.transport[0].type\n        };\n\n        if (!this._cachedTransportStats || !isEqual(transportStats, this._cachedTransportStats)) {\n            this._cachedTransportStats = transportStats;\n            Statistics.sendAnalytics(createTransportStatsEvent(transportStats));\n        }\n    }\n\n    /**\n     * Resets the stats related to JVB connection. Must not be called when in\n     * P2P mode, because then the {@link AverageStatReport} instances are\n     * tracking P2P stats. Note that this should never happen unless something\n     * is wrong with the P2P and JVB121 events.\n     * @private\n     */\n    _resetAvgJvbStats() {\n        this._resetAvgStats();\n        this.jvbStatsMonitor._resetAvgStats();\n    }\n\n    /**\n     * Reset cache of all averages and {@link _sampleIdx}.\n     * @private\n     */\n    _resetAvgStats() {\n        this._avgAudioBitrateUp.reset();\n        this._avgAudioBitrateDown.reset();\n\n        this._avgVideoBitrateUp.reset();\n        this._avgVideoBitrateDown.reset();\n\n        this._avgBandwidthUp.reset();\n        this._avgBandwidthDown.reset();\n\n        this._avgPacketLossUp.reset();\n        this._avgPacketLossDown.reset();\n        this._avgPacketLossTotal.reset();\n\n        this._avgRemoteFPS.reset();\n        this._avgRemoteScreenFPS.reset();\n        this._avgLocalFPS.reset();\n        this._avgLocalScreenFPS.reset();\n\n        this._avgRemoteCameraPixels.reset();\n        this._avgRemoteScreenPixels.reset();\n        this._avgLocalCameraPixels.reset();\n        this._avgLocalScreenPixels.reset();\n\n        this._avgCQ.reset();\n\n        this._sampleIdx = 0;\n    }\n\n    /**\n     * Unregisters all event listeners and stops working.\n     */\n    dispose() {\n        this._conference.off(\n            ConferenceEvents.P2P_STATUS,\n            this._onP2PStatusChanged);\n        this._conference.off(\n            ConnectionQualityEvents.LOCAL_STATS_UPDATED,\n            this._onLocalStatsUpdated);\n        this._conference.off(\n            ConferenceEvents.JVB121_STATUS,\n            this._onJvb121StatusChanged);\n        this.jvbStatsMonitor.dispose();\n        this.p2pStatsMonitor.dispose();\n    }\n}\n","/**\n * A model for keeping track of each user's total\n * time as a dominant speaker. The model also\n * keeps track of the user's last known name\n * in case the user has left the meeting,\n * which is also tracked.\n */\nclass SpeakerStats {\n    private _userId: string;\n    private _isLocalStats: boolean;\n    private _dominantSpeakerStart: number;\n    private _hasLeft: boolean;\n    private _facialExpressions: { [key in FacialExpressions]: number };\n    totalDominantSpeakerTime: number;\n    displayName: string;\n    /**\n     * Initializes a new SpeakerStats instance.\n     *\n     * @constructor\n     * @param {string} userId - The id of the user being tracked.\n     * @param {string} displayName - The name of the user being tracked.\n     * @param {boolean} isLocalStats - True if the stats model tracks\n     * the local user.\n     * @returns {void}\n     */\n    constructor(userId, displayName, isLocalStats) {\n        this._userId = userId;\n        this.setDisplayName(displayName);\n        this._isLocalStats = isLocalStats || false;\n        this.setDominantSpeaker(false);\n        this.totalDominantSpeakerTime = 0;\n        this._dominantSpeakerStart = 0;\n        this._hasLeft = false;\n        this._facialExpressions = {\n            happy: 0,\n            neutral: 0,\n            surprised: 0,\n            angry: 0,\n            fearful: 0,\n            disgusted: 0,\n            sad: 0\n        };\n    }\n\n    /**\n     * Get the user id being tracked.\n     *\n     * @returns {string} The user id.\n     */\n    getUserId() {\n        return this._userId;\n    }\n\n    /**\n     * Get the name of the user being tracked.\n     *\n     * @returns {string} The user name.\n     */\n    getDisplayName() {\n        return this.displayName;\n    }\n\n    /**\n     * Updates the last known name of the user being tracked.\n     *\n     * @param {string} - The user name.\n     * @returns {void}\n     */\n    setDisplayName(newName) {\n        this.displayName = newName;\n    }\n\n    /**\n     * Returns true if the stats are tracking the local user.\n     *\n     * @returns {boolean}\n     */\n    isLocalStats() {\n        return this._isLocalStats;\n    }\n\n    /**\n     * Returns true if the tracked user is currently a dominant speaker.\n     *\n     * @returns {boolean}\n     */\n    isDominantSpeaker() {\n        return this._dominantSpeakerStart > 0;\n    }\n\n    /**\n     * Returns true if the tracked user is currently a dominant speaker.\n     *\n     * @param {boolean} - If true, the user will being accumulating time\n     * as dominant speaker. If false, the user will not accumulate time\n     * and will record any time accumulated since starting as dominant speaker.\n     * @returns {void}\n     */\n    setDominantSpeaker(isNowDominantSpeaker) {\n        if (!this.isDominantSpeaker() && isNowDominantSpeaker) {\n            this._dominantSpeakerStart = Date.now();\n        } else if (this.isDominantSpeaker() && !isNowDominantSpeaker) {\n            const now = Date.now();\n            const timeElapsed = now - this._dominantSpeakerStart;\n\n            this.totalDominantSpeakerTime += timeElapsed;\n            this._dominantSpeakerStart = 0;\n        }\n    }\n\n    /**\n     * Get how long the tracked user has been dominant speaker.\n     *\n     * @returns {number} - The speaker time in milliseconds.\n     */\n    getTotalDominantSpeakerTime() {\n        let total = this.totalDominantSpeakerTime;\n\n        if (this.isDominantSpeaker()) {\n            total += Date.now() - this._dominantSpeakerStart;\n        }\n\n        return total;\n    }\n\n    /**\n     * Get whether or not the user is still in the meeting.\n     *\n     * @returns {boolean} True if the user is no longer in the meeting.\n     */\n    hasLeft() {\n        return this._hasLeft;\n    }\n\n    /**\n     * Set the user as having left the meeting.\n     *\n     * @returns {void}\n     */\n    markAsHasLeft() {\n        this._hasLeft = true;\n        this.setDominantSpeaker(false);\n    }\n\n    /**\n     * Gets the facial expressions of the user.\n     *\n     * @returns {Object}\n     */\n    getFacialExpressions() {\n        return this._facialExpressions;\n    }\n\n    /**\n     * Sets the facial expressions of the user.\n     *\n     * @param {Object} facialExpressions - object with facial expressions.\n     * @returns {void}\n     */\n    setFacialExpressions(facialExpressions) {\n        this._facialExpressions = facialExpressions;\n    }\n\n    /**\n     * Adds a new facial expression to speaker stats.\n     *\n     * @param  {string} facialExpression\n     * @param {number} duration\n     */\n    addFacialExpression(facialExpression, duration) {\n        this._facialExpressions[facialExpression] += duration;\n    }\n}\n\nexport default SpeakerStats;\n\n/**\n * FacialExpressions Enum\n */\nexport enum FacialExpressions {\n    happy = 'happy',\n    neutral = 'neutral',\n    surprised = 'surprised',\n    angry = 'angry',\n    fearful = 'fearful',\n    disgusted = 'disgusted',\n    sad = 'sad',\n};","import * as JitsiConferenceEvents from '../../JitsiConferenceEvents';\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\n\nimport SpeakerStats from './SpeakerStats';\n\n/**\n * A collection for tracking speaker stats. Attaches listeners\n * to the conference to automatically update on tracked events.\n */\nexport default class SpeakerStatsCollector {\n    /**\n     * Initializes a new SpeakerStatsCollector instance.\n     *\n     * @constructor\n     * @param {JitsiConference} conference - The conference to track.\n     * @returns {void}\n     */\n    constructor(conference) {\n        this.stats = {\n            users: {\n\n                // userId: SpeakerStats\n            },\n            dominantSpeakerId: null\n        };\n\n        const userId = conference.myUserId();\n\n        this.stats.users[userId] = new SpeakerStats(userId, null, true);\n        this.conference = conference;\n\n        conference.addEventListener(\n            JitsiConferenceEvents.DOMINANT_SPEAKER_CHANGED,\n            this._onDominantSpeaker.bind(this));\n        conference.addEventListener(\n            JitsiConferenceEvents.USER_JOINED,\n            this._onUserJoin.bind(this));\n        conference.addEventListener(\n            JitsiConferenceEvents.USER_LEFT,\n            this._onUserLeave.bind(this));\n        conference.addEventListener(\n            JitsiConferenceEvents.DISPLAY_NAME_CHANGED,\n            this._onDisplayNameChange.bind(this));\n        conference.addEventListener(\n            JitsiConferenceEvents.FACIAL_EXPRESSION_ADDED,\n            this._onFacialExpressionAdd.bind(this));\n        if (conference.xmpp) {\n            conference.xmpp.addListener(\n                XMPPEvents.SPEAKER_STATS_RECEIVED,\n                this._updateStats.bind(this));\n        }\n    }\n\n    /**\n     * Reacts to dominant speaker change events by changing its speaker stats\n     * models to reflect the current dominant speaker.\n     *\n     * @param {string} dominantSpeakerId - The user id of the new\n     * dominant speaker.\n     * @returns {void}\n     * @private\n     */\n    _onDominantSpeaker(dominantSpeakerId) {\n        const oldDominantSpeaker\n            = this.stats.users[this.stats.dominantSpeakerId];\n        const newDominantSpeaker = this.stats.users[dominantSpeakerId];\n\n        oldDominantSpeaker && oldDominantSpeaker.setDominantSpeaker(false);\n        newDominantSpeaker && newDominantSpeaker.setDominantSpeaker(true);\n        this.stats.dominantSpeakerId = dominantSpeakerId;\n    }\n\n    /**\n     * Reacts to user join events by creating a new SpeakerStats model.\n     *\n     * @param {string} userId - The user id of the new user.\n     * @param {JitsiParticipant} - The JitsiParticipant model for the new user.\n     * @returns {void}\n     * @private\n     */\n    _onUserJoin(userId, participant) {\n        if (participant.isHidden()) {\n            return;\n        }\n\n        if (!this.stats.users[userId]) {\n            this.stats.users[userId] = new SpeakerStats(userId, participant.getDisplayName());\n        }\n    }\n\n    /**\n     * Reacts to user leave events by updating the associated user's\n     * SpeakerStats model.\n     *\n     * @param {string} userId - The user id of the user that left.\n     * @returns {void}\n     * @private\n     */\n    _onUserLeave(userId) {\n        const savedUser = this.stats.users[userId];\n\n        if (savedUser) {\n            savedUser.markAsHasLeft();\n        }\n    }\n\n    /**\n     * Reacts to user name change events by updating the last known name\n     * tracked in the associated SpeakerStats model.\n     *\n     * @param {string} userId - The user id of the user that left.\n     * @returns {void}\n     * @private\n     */\n    _onDisplayNameChange(userId, newName) {\n        const savedUser = this.stats.users[userId];\n\n        if (savedUser) {\n            savedUser.setDisplayName(newName);\n        }\n    }\n\n    /**\n     * Adds a new facial expression with its duration of a remote user.\n     *\n     * @param {string} userId - The user id of the user that left.\n     * @param {Object} data - The facial expression with its duration.\n     * @returns {void}\n     * @private\n     */\n    _onFacialExpressionAdd(userId, data) {\n        const savedUser = this.stats.users[userId];\n\n        if (savedUser) {\n            savedUser.addFacialExpression(data.facialExpression, data.duration);\n        }\n    }\n\n    /**\n     * Return a copy of the tracked SpeakerStats models.\n     *\n     * @returns {Object} The keys are the user ids and the values are the\n     * associated user's SpeakerStats model.\n     */\n    getStats() {\n        return this.stats.users;\n    }\n\n    /**\n     * Updates of the current stats is requested, passing the new values.\n     *\n     * @param {Object} newStats - The new values used to update current one.\n     * @private\n     */\n    _updateStats(newStats) {\n        for (const userId in newStats) { // eslint-disable-line guard-for-in\n            let speakerStatsToUpdate;\n            const newParticipant = this.conference.getParticipantById(userId);\n\n            // we want to ignore hidden participants\n            if (!newParticipant || !newParticipant.isHidden()) {\n                if (this.stats.users[userId]) {\n                    speakerStatsToUpdate = this.stats.users[userId];\n\n                    if (!speakerStatsToUpdate.getDisplayName()) {\n                        speakerStatsToUpdate\n                            .setDisplayName(newStats[userId].displayName);\n                    }\n                } else {\n                    speakerStatsToUpdate = new SpeakerStats(\n                        userId, newStats[userId].displayName);\n                    this.stats.users[userId] = speakerStatsToUpdate;\n                    speakerStatsToUpdate.markAsHasLeft();\n                }\n            }\n\n            speakerStatsToUpdate.totalDominantSpeakerTime\n                = newStats[userId].totalDominantSpeakerTime;\n\n            speakerStatsToUpdate.setFacialExpressions(newStats[userId].facialExpressions);\n        }\n    }\n}\n","/* eslint-disable max-params */\n\n/**\n * This object stores variables needed around the recording of an audio stream\n * and passing this recording along with additional information along to\n * different processes\n */\nexport default class RecordingResult {\n    /**\n     * @param blob the recording audio stream as a single blob\n     * @param name the name of the person of the audio stream\n     * @param startTime the time in UTC when recording of the audiostream started\n     * @param wordArray the recorder audio stream transcribed as an array of Word objects\n     */\n    constructor(blob, name, startTime, wordArray) {\n        this.blob = blob;\n        this.name = name;\n        this.startTime = startTime;\n        this.wordArray = wordArray;\n    }\n}\n","/**\n * A TrackRecorder object holds all the information needed for recording a\n * single JitsiTrack (either remote or local)\n * @param track The JitsiTrack the object is going to hold\n */\nexport default class TrackRecorder {\n    /**\n     * @param track The JitsiTrack the object is going to hold\n     */\n    constructor(track) {\n        // The JitsiTrack holding the stream\n        this.track = track;\n\n        // The MediaRecorder recording the stream\n        this.recorder = null;\n\n        // The array of data chunks recorded from the stream\n        // acts as a buffer until the data is stored on disk\n        this.data = null;\n\n        // the name of the person of the JitsiTrack. This can be undefined and/or\n        // not unique\n        this.name = null;\n\n        // the time of the start of the recording\n        this.startTime = null;\n    }\n}\n","import RecordingResult from './recordingResult';\nimport TrackRecorder from './trackRecorder';\n\n/**\n * Possible audio formats MIME types\n */\nconst AUDIO_WEBM = 'audio/webm'; // Supported in chrome\nconst AUDIO_OGG = 'audio/ogg'; // Supported in firefox\n\n/**\n * Starts the recording of a JitsiTrack in a TrackRecorder object.\n * This will also define the timestamp and try to update the name\n * @param trackRecorder the TrackRecorder to start\n */\nfunction startRecorder(trackRecorder) {\n    if (trackRecorder.recorder === undefined) {\n        throw new Error('Passed an object to startRecorder which is not a '\n            + 'TrackRecorder object');\n    }\n    trackRecorder.recorder.start();\n    trackRecorder.startTime = new Date();\n}\n\n/**\n * Stops the recording of a JitsiTrack in a TrackRecorder object.\n * This will also try to update the name\n * @param trackRecorder the TrackRecorder to stop\n */\nfunction stopRecorder(trackRecorder) {\n    if (trackRecorder.recorder === undefined) {\n        throw new Error('Passed an object to stopRecorder which is not a '\n            + 'TrackRecorder object');\n    }\n    trackRecorder.recorder.stop();\n}\n\n/**\n * Determines which kind of audio recording the browser supports\n * chrome supports \"audio/webm\" and firefox supports \"audio/ogg\"\n */\nfunction determineCorrectFileType() {\n    if (MediaRecorder.isTypeSupported(AUDIO_WEBM)) {\n        return AUDIO_WEBM;\n    } else if (MediaRecorder.isTypeSupported(AUDIO_OGG)) {\n        return AUDIO_OGG;\n    }\n    throw new Error(\n        'unable to create a MediaRecorder with the right mimetype!');\n}\n\n/**\n * main exported object of the file, holding all\n * relevant functions and variables for the outside world\n * @param jitsiConference the jitsiConference which this object\n * is going to record\n */\nfunction AudioRecorder(jitsiConference) {\n    // array of TrackRecorders, where each trackRecorder\n    // holds the JitsiTrack, MediaRecorder and recorder data\n    this.recorders = [];\n\n    // get which file type is supported by the current browser\n    this.fileType = determineCorrectFileType();\n\n    // boolean flag for active recording\n    this.isRecording = false;\n\n    // the jitsiconference the object is recording\n    this.jitsiConference = jitsiConference;\n}\n\n/**\n * Add the exported module so that it can be accessed by other files\n */\nAudioRecorder.determineCorrectFileType = determineCorrectFileType;\n\n/**\n * Adds a new TrackRecorder object to the array.\n *\n * @param track the track potentially holding an audio stream\n */\nAudioRecorder.prototype.addTrack = function(track) {\n    if (track.isAudioTrack()) {\n        // create the track recorder\n        const trackRecorder = this.instantiateTrackRecorder(track);\n\n        // push it to the local array of all recorders\n\n        this.recorders.push(trackRecorder);\n\n        // update the name of the trackRecorders\n        this.updateNames();\n\n        // If we're already recording, immediately start recording this new\n        // track.\n        if (this.isRecording) {\n            startRecorder(trackRecorder);\n        }\n    }\n};\n\n/**\n * Creates a TrackRecorder object. Also creates the MediaRecorder and\n * data array for the trackRecorder.\n * @param track the JitsiTrack holding the audio MediaStream(s)\n */\nAudioRecorder.prototype.instantiateTrackRecorder = function(track) {\n    const trackRecorder = new TrackRecorder(track);\n\n    // Create a new stream which only holds the audio track\n    const originalStream = trackRecorder.track.getOriginalStream();\n    const stream = new MediaStream();\n\n    originalStream.getAudioTracks().forEach(t => stream.addTrack(t));\n\n    // Create the MediaRecorder\n    trackRecorder.recorder = new MediaRecorder(stream,\n        { mimeType: this.fileType });\n\n    // array for holding the recorder data. Resets it when\n    // audio already has been recorder once\n    trackRecorder.data = [];\n\n    // function handling a dataEvent, e.g the stream gets new data\n    trackRecorder.recorder.ondataavailable = function(dataEvent) {\n        if (dataEvent.data.size > 0) {\n            trackRecorder.data.push(dataEvent.data);\n        }\n    };\n\n    return trackRecorder;\n};\n\n/**\n * Notifies the module that a specific track has stopped, e.g participant left\n * the conference.\n * if the recording has not started yet, the TrackRecorder will be removed from\n * the array. If the recording has started, the recorder will stop recording\n * but not removed from the array so that the recorded stream can still be\n * accessed\n *\n * @param {JitsiTrack} track the JitsiTrack to remove from the recording session\n */\nAudioRecorder.prototype.removeTrack = function(track) {\n    if (track.isVideoTrack()) {\n        return;\n    }\n\n    const array = this.recorders;\n    let i;\n\n    for (i = 0; i < array.length; i++) {\n        if (array[i].track.getParticipantId() === track.getParticipantId()) {\n            const recorderToRemove = array[i];\n\n            if (this.isRecording) {\n                stopRecorder(recorderToRemove);\n            } else {\n                // remove the TrackRecorder from the array\n                array.splice(i, 1);\n            }\n        }\n    }\n\n    // make sure the names are up to date\n    this.updateNames();\n};\n\n/**\n * Tries to update the name value of all TrackRecorder in the array.\n * If it hasn't changed,it will keep the exiting name. If it changes to a\n * undefined value, the old value will also be kept.\n */\nAudioRecorder.prototype.updateNames = function() {\n    const conference = this.jitsiConference;\n\n    this.recorders.forEach(trackRecorder => {\n        if (trackRecorder.track.isLocal()) {\n            trackRecorder.name = 'the transcriber';\n        } else {\n            const id = trackRecorder.track.getParticipantId();\n            const participant = conference.getParticipantById(id);\n            const newName = participant.getDisplayName();\n\n            if (newName !== 'undefined') {\n                trackRecorder.name = newName;\n            }\n        }\n    });\n};\n\n/**\n * Starts the audio recording of every local and remote track\n */\nAudioRecorder.prototype.start = function() {\n    if (this.isRecording) {\n        throw new Error('audiorecorder is already recording');\n    }\n\n    // set boolean isRecording flag to true so if new participants join the\n    // conference, that track can instantly start recording as well\n    this.isRecording = true;\n\n    // start all the mediaRecorders\n    this.recorders.forEach(trackRecorder => startRecorder(trackRecorder));\n\n    // log that recording has started\n    console.log(\n        `Started the recording of the audio. There are currently ${\n            this.recorders.length} recorders active.`);\n};\n\n/**\n * Stops the audio recording of every local and remote track\n */\nAudioRecorder.prototype.stop = function() {\n    // set the boolean flag to false\n    this.isRecording = false;\n\n    // stop all recorders\n    this.recorders.forEach(trackRecorder => stopRecorder(trackRecorder));\n    console.log('stopped recording');\n};\n\n/**\n * link hacking to download all recorded audio streams\n */\nAudioRecorder.prototype.download = function() {\n    this.recorders.forEach(trackRecorder => {\n        const blob = new Blob(trackRecorder.data, { type: this.fileType });\n        const url = URL.createObjectURL(blob);\n        const a = document.createElement('a');\n\n        document.body.appendChild(a);\n        a.style = 'display: none';\n        a.href = url;\n        a.download = `test.${this.fileType.split('/')[1]}`;\n        a.click();\n        window.URL.revokeObjectURL(url);\n    });\n};\n\n/**\n * returns the audio files of all recorders as an array of objects,\n * which include the name of the owner of the track and the starting time stamp\n * @returns {Array} an array of RecordingResult objects\n */\nAudioRecorder.prototype.getRecordingResults = function() {\n    if (this.isRecording) {\n        throw new Error(\n            'cannot get blobs because the AudioRecorder is still recording!');\n    }\n\n    // make sure the names are up to date before sending them off\n    this.updateNames();\n\n    const array = [];\n\n    this.recorders.forEach(\n        recorder =>\n            array.push(\n                new RecordingResult(\n                    new Blob(recorder.data, { type: this.fileType }),\n                    recorder.name,\n                    recorder.startTime)));\n\n    return array;\n};\n\n/**\n * Gets the mime type of the recorder audio\n * @returns {String} the mime type of the recorder audio\n */\nAudioRecorder.prototype.getFileType = function() {\n    return this.fileType;\n};\n\n/**\n * export the main object AudioRecorder\n */\nexport default AudioRecorder;\n","/**\n * An object representing a transcribed word, with some additional information\n * @param word the word\n * @param begin the time the word was started being uttered\n * @param end the time the word stopped being uttered\n */\nexport default class Word {\n    /**\n     * @param word the word\n     * @param begin the time the word was started being uttered\n     * @param end the time the word stopped being uttered\n     */\n    constructor(word, begin, end) {\n        this.word = word;\n        this.begin = begin;\n        this.end = end;\n    }\n\n    /**\n     * Get the string representation of the word\n     * @returns {*} the word as a string\n     */\n    getWord() {\n        return this.word;\n    }\n\n    /**\n     * Get the time the word started being uttered\n     * @returns {*} the start time as an integer\n     */\n    getBeginTime() {\n        return this.begin;\n    }\n\n    /**\n     * Get the time the word stopped being uttered\n     * @returns {*} the end time as an integer\n     */\n    getEndTime() {\n        return this.end;\n    }\n}\n","/* global config */\n\nimport Word from '../word';\n\nimport audioRecorder from './../audioRecorder';\nimport AbstractTranscriptionService from './AbstractTranscriptionService';\n\n/**\n * Implements a TranscriptionService for a Sphinx4 http server\n */\nexport default class SphinxService extends AbstractTranscriptionService {\n    /**\n     * Implements a TranscriptionService for a Sphinx4 http server\n     */\n    constructor() {\n        super();\n\n        // set the correct url\n        this.url = getURL();\n    }\n\n    /**\n     * Overrides the sendRequest method from AbstractTranscriptionService\n     * it will send the audio stream the a Sphinx4 server to get the transcription\n     *\n     * @param audioFileBlob the recorder audio stream an a single Blob\n     * @param callback the callback function retrieving the server response\n     */\n    sendRequest(audioFileBlob, callback) {\n        console.log(`sending an audio file  to ${this.url}`);\n        console.log(`the audio file being sent: ${audioFileBlob}`);\n        const request = new XMLHttpRequest();\n\n        request.onreadystatechange = function() {\n            if (request.readyState === XMLHttpRequest.DONE\n                && request.status === 200) {\n                callback(request.responseText);\n            } else if (request.readyState === XMLHttpRequest.DONE) {\n                throw new Error(\n                    `unable to accept response from sphinx server. status: ${request.status}`);\n            }\n\n            // if not ready no point to throw an error\n        };\n        request.open('POST', this.url);\n        request.setRequestHeader('Content-Type',\n            audioRecorder.determineCorrectFileType());\n        request.send(audioFileBlob);\n        console.log(`send ${audioFileBlob}`);\n    }\n\n    /**\n     * Overrides the formatResponse method from AbstractTranscriptionService\n     * It will parse the answer from the server in the expected format\n     *\n     * @param response the JSON body retrieved from the Sphinx4 server\n     */\n    formatResponse(response) {\n        const result = JSON.parse(response).objects;\n\n        // make sure to delete the session id object, which is always\n        // the first value in the JSON array\n        result.shift();\n        const array = [];\n\n        result.forEach(\n            word => word.filler\n                || array.push(new Word(word.word, word.start, word.end)));\n\n        return array;\n    }\n\n    /**\n     * checks wether the reply is empty, or doesn't contain a correct JSON object\n     * @param response the server response\n     * @return {boolean} whether the response is valid\n     */\n    verify(response) {\n        console.log(`response from server:${response.toString()}`);\n\n        // test if server responded with a string object\n        if (typeof response !== 'string') {\n            return false;\n        }\n\n        // test if the string can be parsed into valid JSON\n        let json;\n\n        try {\n            json = JSON.parse(response);\n        } catch (error) {\n            console.log(error);\n\n            return false;\n        }\n\n        // check if the JSON has a \"objects\" value\n        if (json.objects === undefined) {\n            return false;\n        }\n\n        // get the \"objects\" value and check for a session ID\n        const array = json.objects;\n\n        if (!(array[0] && array[0]['session-id'])) {\n            return false;\n        }\n\n        // everything seems to be in order\n        return true;\n    }\n}\n\n/**\n * Gets the URL to the Sphinx4 server from the config file. If it's not there,\n * it will throw an error\n *\n * @returns {string} the URL to the sphinx4 server\n */\nfunction getURL() {\n    const message = 'config does not contain an url to a Sphinx4 https server';\n\n    if (config.sphinxURL === undefined) {\n        console.log(message);\n    } else {\n        const toReturn = config.sphinxURL;\n\n        if (toReturn.includes !== undefined && toReturn.includes('https://')) {\n            return toReturn;\n        }\n        console.log(message);\n\n    }\n}\n","/**\n * Abstract class representing an interface to implement a speech-to-text\n * service on.\n */\nexport default class TranscriptionService {\n    /**\n     * Abstract class representing an interface to implement a speech-to-text\n     * service on.\n     */\n    constructor() {\n        throw new Error('TranscriptionService is abstract and cannot be created');\n    }\n\n    /**\n     * This method can be used to send the recorder audio stream and\n     * retrieve the answer from the transcription service from the callback\n     *\n     * @param {RecordingResult} recordingResult a recordingResult object which\n     * includes the recorded audio stream as a blob\n     * @param {Function} callback  which will retrieve the a RecordingResult with\n     *        the answer as a WordArray\n     */\n    send(recordingResult, callback) {\n        this.sendRequest(recordingResult.blob, response => {\n            if (this.verify(response)) {\n                recordingResult.wordArray = this.formatResponse(response);\n            } else {\n                console.log('the retrieved response from the server is not valid!');\n                recordingResult.wordArray = [];\n            }\n            callback(recordingResult);\n        });\n    }\n\n    /**\n     * Abstract method which will rend the recorder audio stream to the implemented\n     * transcription service and will retrieve an answer, which will be\n     * called on the given callback method\n     *\n     * @param {Blob} audioBlob the recorded audio stream as a single Blob\n     * @param {function} callback function which will retrieve the answer\n     *                            from the service\n     */\n    sendRequest(audioBlob, callback) { // eslint-disable-line no-unused-vars\n        throw new Error('TranscriptionService.sendRequest is abstract');\n    }\n\n    /**\n     * Abstract method which will parse the output from the implemented\n     * transcription service to the expected format\n     *\n     * The transcriber class expect an array of word objects, where each word\n     * object is one transcribed word by the service.\n     *\n     * The expected output of this method is an array of word objects, in\n     * the correct order. That is, the first object in the array is the first word\n     * being said, and the last word in the array is the last word being said\n     *\n     * @param response the answer from the speech-to-text server which needs to be\n     *                 formatted\n     * @return {Array<Word>} an array of Word objects\n     */\n    formatResponse(response) { // eslint-disable-line no-unused-vars\n        throw new Error('TranscriptionService.format is abstract');\n    }\n\n    /**\n     * Abstract method which will verify that the response from the server is valid\n     *\n     * @param response the response from the server\n     * @return {boolean} true if response is valid, false otherwise\n     */\n    verify(response) { // eslint-disable-line no-unused-vars\n        throw new Error('TranscriptionService.verify is abstract');\n    }\n}\n","import AudioRecorder from './audioRecorder';\nimport SphinxService from './transcriptionServices/SphinxTranscriptionService';\n\nconst BEFORE_STATE = 'before';\nconst RECORDING_STATE = 'recording';\nconst TRANSCRIBING_STATE = 'transcribing';\nconst FINISHED_STATE = 'finished';\n\n// the amount of characters each line in the transcription will have\nconst MAXIMUM_SENTENCE_LENGTH = 80;\n\n/**\n * This is the main object for handing the Transcription. It interacts with\n * the audioRecorder to record every person in a conference and sends the\n * recorder audio to a transcriptionService. The returned speech-to-text result\n * will be merged to create a transcript\n * @param {AudioRecorder} audioRecorder An audioRecorder recording a conference\n */\nfunction Transcriber() {\n    // the object which can record all audio in the conference\n    this.audioRecorder = new AudioRecorder();\n\n    // this object can send the recorder audio to a speech-to-text service\n    this.transcriptionService = new SphinxService();\n\n    // holds a counter to keep track if merging can start\n    this.counter = null;\n\n    // holds the date when transcription started which makes it possible\n    // to calculate the offset between recordings\n    this.startTime = null;\n\n    // will hold the transcription once it is completed\n    this.transcription = null;\n\n    // this will be a method which will be called once the transcription is done\n    // with the transcription as parameter\n    this.callback = null;\n\n    // stores all the retrieved speech-to-text results to merge together\n    // this value will store an Array<Word> object\n    this.results = [];\n\n    // Stores the current state of the transcription process\n    this.state = BEFORE_STATE;\n\n    // Used in the updateTranscription method to add a new line when the\n    // sentence becomes to long\n    this.lineLength = 0;\n}\n\n/**\n * Method to start the transcription process. It will tell the audioRecorder\n * to start storing all audio streams and record the start time for merging\n * purposes\n */\nTranscriber.prototype.start = function start() {\n    if (this.state !== BEFORE_STATE) {\n        throw new Error(\n            `The transcription can only start when it's in the \"${\n                BEFORE_STATE}\" state. It's currently in the \"${\n                this.state}\" state`);\n    }\n    this.state = RECORDING_STATE;\n    this.audioRecorder.start();\n    this.startTime = new Date();\n};\n\n/**\n * Method to stop the transcription process. It will tell the audioRecorder to\n * stop, and get all the recorded audio to send it to the transcription service\n\n * @param callback a callback which will receive the transcription\n */\nTranscriber.prototype.stop = function stop(callback) {\n    if (this.state !== RECORDING_STATE) {\n        throw new Error(\n            `The transcription can only stop when it's in the \"${\n                RECORDING_STATE}\" state. It's currently in the \"${\n                this.state}\" state`);\n    }\n\n    // stop the recording\n    console.log('stopping recording and sending audio files');\n    this.audioRecorder.stop();\n\n    // and send all recorded audio to the transcription service\n    const callBack = blobCallBack.bind(null, this);\n\n    this.audioRecorder.getRecordingResults().forEach(recordingResult => {\n        this.transcriptionService.send(recordingResult, callBack);\n        this.counter++;\n    });\n\n    // set the state to \"transcribing\" so that maybeMerge() functions correctly\n    this.state = TRANSCRIBING_STATE;\n\n    // and store the callback for later\n    this.callback = callback;\n};\n\n/**\n * This method gets the answer from the transcription service, calculates the\n * offset and adds is to every Word object. It will also start the merging\n * when every send request has been received\n *\n * note: Make sure to bind this as a Transcription object\n * @param {Transcriber} transcriber the transcriber instance\n * @param {RecordingResult} answer a RecordingResult object with a defined\n * WordArray\n */\nfunction blobCallBack(transcriber, answer) {\n    console.log(\n        'retrieved an answer from the transcription service. The answer has an'\n            + ` array of length: ${answer.wordArray.length}`);\n\n    // first add the offset between the start of the transcription and\n    // the start of the recording to all start and end times\n    if (answer.wordArray.length > 0) {\n        let offset = answer.startTime.getUTCMilliseconds()\n            - transcriber.startTime.getUTCMilliseconds();\n\n        // transcriber time will always be earlier\n\n        if (offset < 0) {\n            offset = 0; // presume 0 if it somehow not earlier\n        }\n\n        let array = '[';\n\n        answer.wordArray.forEach(wordObject => {\n            wordObject.begin += offset;\n            wordObject.end += offset;\n            array += `${wordObject.word},`;\n        });\n        array += ']';\n        console.log(array);\n\n        // give a name value to the Array object so that the merging can access\n        // the name value without having to use the whole recordingResult object\n        // in the algorithm\n        answer.wordArray.name = answer.name;\n    }\n\n    // then store the array and decrease the counter\n    transcriber.results.push(answer.wordArray);\n    transcriber.counter--;\n    console.log(`current counter: ${transcriber.counter}`);\n\n    // and check if all results have been received.\n    transcriber.maybeMerge();\n}\n\n/**\n * this method will check if the counter is zero. If it is, it will call\n * the merging method\n */\nTranscriber.prototype.maybeMerge = function() {\n    if (this.state === TRANSCRIBING_STATE && this.counter === 0) {\n        // make sure to include the events in the result arrays before\n        // merging starts\n        this.merge();\n    }\n};\n\n/**\n * This method will merge all speech-to-text arrays together in one\n * readable transcription string\n */\nTranscriber.prototype.merge = function() {\n    console.log(\n        `starting merge process!\\n The length of the array: ${\n            this.results.length}`);\n    this.transcription = '';\n\n    // the merging algorithm will look over all Word objects who are at pos 0 in\n    // every array. It will then select the one closest in time to the\n    // previously placed word, while removing the selected word from its array\n    // note: words can be skipped the skipped word's begin and end time somehow\n    // end up between the closest word start and end time\n    const arrays = this.results;\n\n    // arrays of Word objects\n    const potentialWords = []; // array of the first Word objects\n    // check if any arrays are already empty and remove them\n\n    hasPopulatedArrays(arrays);\n\n    // populate all the potential Words for a first time\n    arrays.forEach(array => pushWordToSortedArray(potentialWords, array));\n\n    // keep adding words to transcription until all arrays are exhausted\n    while (hasPopulatedArrays(arrays)) {\n        // first select the lowest array;\n        let lowestWordArray = arrays[0];\n\n        arrays.forEach(wordArray => {\n            if (wordArray[0].begin < lowestWordArray[0].begin) {\n                lowestWordArray = wordArray;\n            }\n        });\n\n        // put the word in the transcription\n        let wordToAdd = lowestWordArray.shift();\n\n        this.updateTranscription(wordToAdd, lowestWordArray.name);\n\n        // keep going until a word in another array has a smaller time\n        // or the array is empty\n        while (lowestWordArray.length > 0) {\n            let foundSmaller = false;\n            const wordToCompare = lowestWordArray[0].begin;\n\n            arrays.forEach(wordArray => {\n                if (wordArray[0].begin < wordToCompare) {\n                    foundSmaller = true;\n                }\n            });\n\n            // add next word if no smaller time has been found\n            if (foundSmaller) {\n                break;\n            }\n\n            wordToAdd = lowestWordArray.shift();\n            this.updateTranscription(wordToAdd, null);\n        }\n\n    }\n\n    // set the state to finished and do the necessary left-over tasks\n    this.state = FINISHED_STATE;\n    if (this.callback) {\n        this.callback(this.transcription);\n    }\n};\n\n/**\n * Appends a word object to the transcription. It will make a new line with a\n * name if a name is specified\n * @param {Word} word the Word object holding the word to append\n * @param {String|null} name the name of a new speaker. Null if not applicable\n */\nTranscriber.prototype.updateTranscription = function(word, name) {\n    if (name !== undefined && name !== null) {\n        this.transcription += `\\n${name}:`;\n        this.lineLength = name.length + 1; // +1 for the semi-colon\n    }\n    if (this.lineLength + word.word.length > MAXIMUM_SENTENCE_LENGTH) {\n        this.transcription += '\\n    ';\n        this.lineLength = 4; // because of the 4 spaces after the new line\n    }\n    this.transcription += ` ${word.word}`;\n    this.lineLength += word.word.length + 1; // +1 for the space\n};\n\n/**\n * Check if the given 2 dimensional array has any non-zero Word-arrays in them.\n * All zero-element arrays inside will be removed\n * If any non-zero-element arrays are found, the method will return true.\n * otherwise it will return false\n * @param {Array<Array>} twoDimensionalArray the array to check\n * @returns {boolean} true if any non-zero arrays inside, otherwise false\n */\nfunction hasPopulatedArrays(twoDimensionalArray) {\n    for (let i = 0; i < twoDimensionalArray.length; i++) {\n        if (twoDimensionalArray[i].length === 0) {\n            twoDimensionalArray.splice(i, 1);\n        }\n    }\n\n    return twoDimensionalArray.length > 0;\n}\n\n/**\n * Push a word to the right location in a sorted array. The array is sorted\n * from lowest to highest start time. Every word is stored in an object which\n * includes the name of the person saying the word.\n *\n * @param {Array<Word>} array the sorted array to push to\n * @param {Word} word the word to push into the array\n */\nfunction pushWordToSortedArray(array, word) {\n    if (array.length === 0) {\n        array.push(word);\n    } else {\n        if (array[array.length - 1].begin <= word.begin) {\n            array.push(word);\n\n            return;\n        }\n\n        for (let i = 0; i < array.length; i++) {\n            if (word.begin < array[i].begin) {\n                array.splice(i, 0, word);\n\n                return;\n            }\n        }\n        array.push(word); // fail safe\n    }\n}\n\n/**\n * Gives the transcriber a JitsiTrack holding an audioStream to transcribe.\n * The JitsiTrack is given to the audioRecorder. If it doesn't hold an\n * audiostream, it will not be added by the audioRecorder\n * @param {JitsiTrack} track the track to give to the audioRecorder\n */\nTranscriber.prototype.addTrack = function(track) {\n    this.audioRecorder.addTrack(track);\n};\n\n/**\n * Remove the given track from the auioRecorder\n * @param track\n */\nTranscriber.prototype.removeTrack = function(track) {\n    this.audioRecorder.removeTrack(track);\n};\n\n/**\n * Will return the created transcription if it's avialable or throw an error\n * when it's not done yet\n * @returns {String} the transcription as a String\n */\nTranscriber.prototype.getTranscription = function() {\n    if (this.state !== FINISHED_STATE) {\n        throw new Error(\n            `The transcription can only be retrieved when it's in the \"${\n                FINISHED_STATE}\" state. It's currently in the \"${\n                this.state}\" state`);\n    }\n\n    return this.transcription;\n};\n\n/**\n * Returns the current state of the transcription process\n */\nTranscriber.prototype.getState = function() {\n    return this.state;\n};\n\n/**\n * Resets the state to the \"before\" state, such that it's again possible to\n * call the start method\n */\nTranscriber.prototype.reset = function() {\n    this.state = BEFORE_STATE;\n    this.counter = null;\n    this.transcription = null;\n    this.startTime = null;\n    this.callback = null;\n    this.results = [];\n    this.lineLength = 0;\n};\n\nexport default Transcriber;\n","import Statistics from '../statistics/statistics';\n\nconst logger = require('@jitsi/logger').getLogger(__filename);\n\n/**\n * Creates new instance of <tt>ComponentsVersions</tt> which will be discovering\n * the versions of conferencing system components in given\n * <tt>JitsiConference</tt>.\n * @param conference <tt>JitsiConference</tt> instance which will be used to\n *        listen for focus presence updates.\n * @constructor\n */\nexport default function ComponentsVersions(conference) {\n\n    this.versions = {};\n\n    this.conference = conference;\n    this.conference.addCommandListener(\n        'versions', this.processVersions.bind(this));\n}\n\nComponentsVersions.prototype.processVersions\n    = function(versions, mucResource, mucJid) {\n        if (!this.conference.isFocus(mucJid)) {\n            logger.warn(\n                `Received versions not from the focus user: ${versions}`,\n                mucJid);\n\n            return;\n        }\n\n        const log = [];\n\n        versions.children.forEach(component => {\n\n            const name = component.attributes.name;\n            const version = component.value;\n\n            if (this.versions[name] !== version) {\n                this.versions[name] = version;\n                logger.info(`Got ${name} version: ${version}`);\n\n                log.push({\n                    id: 'component_version',\n                    component: name,\n                    version\n                });\n            }\n        });\n\n        // logs versions to stats\n        if (log.length > 0) {\n            Statistics.sendLog(JSON.stringify(log));\n        }\n    };\n\n/**\n * Obtains the version of conferencing system component.\n * @param componentName the name of the component for which we want to obtain\n *        the version.\n * @returns {String} which describes the version of the component identified by\n *          given <tt>componentName</tt> or <tt>undefined</tt> if not found.\n */\nComponentsVersions.prototype.getComponentVersion = function(componentName) {\n    return this.versions[componentName];\n};\n","export enum VideoSIPGWStatusConstants {\n    /**\n     * Status that video SIP GW service is available.\n     */\n    STATUS_AVAILABLE = 'available',\n\n    /**\n     * Status that video SIP GW service is not available.\n     */\n    STATUS_UNDEFINED = 'undefined',\n\n    /**\n     * Status that video SIP GW service is available but there are no free nodes\n     * at the moment to serve new requests.\n     */\n    STATUS_BUSY = 'busy'\n};\n\nexport enum VideoSIPGWStateConstants {\n    /**\n     * Video SIP GW session state, currently running.\n     */\n    STATE_ON = 'on',\n\n    /**\n     * Video SIP GW session state, currently stopped and not running.\n     */\n    STATE_OFF = 'off',\n\n    /**\n     * Video SIP GW session state, currently is starting.\n     */\n    STATE_PENDING = 'pending',\n\n    /**\n     * Video SIP GW session state, has observed some issues and is retrying at the\n     * moment.\n     */\n    STATE_RETRYING = 'retrying',\n\n    /**\n     * Video SIP GW session state, tried to start but it failed.\n     */\n    STATE_FAILED = 'failed'\n};\n\nexport enum VideoSIPGWErrorConstants {\n    /**\n     * Error on trying to create video SIP GW session in conference where\n     * there is no room connection (hasn't joined or has left the room).\n     */\n    ERROR_NO_CONNECTION = 'error_no_connection',\n\n    /**\n     * Error on trying to create video SIP GW session with address for which\n     * there is an already created session.\n     */\n    ERROR_SESSION_EXISTS = 'error_session_already_exists'\n};\n\n// exported for backward compatibility\nexport const STATUS_AVAILABLE = VideoSIPGWStatusConstants.STATUS_AVAILABLE;\nexport const STATUS_UNDEFINED = VideoSIPGWStatusConstants.STATUS_UNDEFINED;\nexport const STATUS_BUSY = VideoSIPGWStatusConstants.STATUS_BUSY;\n\nexport const STATE_ON = VideoSIPGWStateConstants.STATE_ON;\nexport const STATE_OFF = VideoSIPGWStateConstants.STATE_OFF;\nexport const STATE_PENDING = VideoSIPGWStateConstants.STATE_PENDING;\nexport const STATE_RETRYING = VideoSIPGWStateConstants.STATE_RETRYING;\nexport const STATE_FAILED = VideoSIPGWStateConstants.STATE_FAILED;\n\nexport const ERROR_NO_CONNECTION = VideoSIPGWErrorConstants.ERROR_NO_CONNECTION;\nexport const ERROR_SESSION_EXISTS = VideoSIPGWErrorConstants.ERROR_SESSION_EXISTS;\n","import { getLogger } from '@jitsi/logger';\nimport { $iq } from 'strophe.js';\n\nimport Listenable from '../util/Listenable';\n\nimport * as VideoSIPGWConstants from './VideoSIPGWConstants';\n\nconst logger = getLogger(__filename);\n\n/**\n * The event name for current sip video session state changed.\n * @type {string} event name for sip video session state changed.\n */\nconst STATE_CHANGED = 'STATE_CHANGED';\n\n/**\n * Jitsi video SIP GW session. Holding its state and able to start/stop it.\n * When session is in OFF or FAILED stated it cannot be used anymore.\n */\nexport default class JitsiVideoSIPGWSession extends Listenable {\n\n    /**\n     * Creates new session with the desired sip address and display name.\n     *\n     * @param {string} sipAddress - The sip address to use when\n     * starting the session.\n     * @param {string} displayName - The display name to use for\n     * that participant.\n     * @param {ChatRoom} chatRoom - The chat room this session is bound to.\n     */\n    constructor(sipAddress, displayName, chatRoom) {\n        super();\n\n        this.sipAddress = sipAddress;\n        this.displayName = displayName;\n        this.chatRoom = chatRoom;\n\n        /*\n         * The initial state is undefined. Initial state cannot be STATE_OFF,\n         * the session enters this state when it was in STATE_ON and was stopped\n         * and such session cannot be used anymore.\n         *\n         * @type {VideoSIPGWConstants|undefined}\n         */\n        this.state = undefined;\n    }\n\n    /**\n     * Stops the current session.\n     */\n    stop() {\n        if (this.state === VideoSIPGWConstants.STATE_OFF\n            || this.state === VideoSIPGWConstants.STATE_FAILED) {\n            logger.warn('Video SIP GW session already stopped or failed!');\n\n            return;\n        }\n\n        this._sendJibriIQ('stop');\n    }\n\n    /**\n     * Starts a new session. Sends an iq to the focus.\n     */\n    start() {\n        // if state is off, this session was active for some reason\n        // and we should create new one, rather than reusing it\n        if (this.state === VideoSIPGWConstants.STATE_ON\n            || this.state === VideoSIPGWConstants.STATE_OFF\n            || this.state === VideoSIPGWConstants.STATE_PENDING\n            || this.state === VideoSIPGWConstants.STATE_RETRYING) {\n            logger.warn('Video SIP GW session already started!');\n\n            return;\n        }\n\n        this._sendJibriIQ('start');\n    }\n\n    /**\n     * Changes the state of this session.\n     *\n     * @param {string} newState - The new {VideoSIPGWConstants} state to set.\n     * @param {string} [optional] failureReason - The reason why a failure state\n     * was entered.\n     * @returns {void}\n     */\n    setState(newState, failureReason) {\n        if (newState === this.state) {\n            return;\n        }\n\n        const oldState = this.state;\n\n        this.state = newState;\n        this.eventEmitter.emit(STATE_CHANGED,\n            {\n                address: this.sipAddress,\n                failureReason,\n                oldState,\n                newState: this.state,\n                displayName: this.displayName\n            }\n        );\n    }\n\n    /**\n     * Subscribes the passed listener to the event for state change of this\n     * session.\n     *\n     * @param {Function} listener - The function that will receive the event.\n     */\n    addStateListener(listener) {\n        this.addListener(STATE_CHANGED, listener);\n    }\n\n    /**\n     * Unsubscribes the passed handler.\n     *\n     * @param {Function} listener - The function to be removed.\n     */\n    removeStateListener(listener) {\n        this.removeListener(STATE_CHANGED, listener);\n    }\n\n    /**\n     * Sends a jibri command using an iq.\n     *\n     * @private\n     * @param {string} action - The action to send ('start' or 'stop').\n     */\n    _sendJibriIQ(action) {\n        const attributes = {\n            'xmlns': 'http://jitsi.org/protocol/jibri',\n            'action': action,\n            sipaddress: this.sipAddress\n        };\n\n        attributes.displayname = this.displayName;\n\n        const iq = $iq({\n            to: this.chatRoom.focusMucJid,\n            type: 'set' })\n            .c('jibri', attributes)\n            .up();\n\n        logger.debug(`${action} video SIP GW session`, iq.nodeTree);\n        this.chatRoom.connection.sendIQ(\n            iq,\n            () => {}, // eslint-disable-line no-empty-function\n            error => {\n                logger.error(\n                    `Failed to ${action} video SIP GW session, error: `, error);\n                this.setState(VideoSIPGWConstants.STATE_FAILED);\n            });\n    }\n}\n","import { getLogger } from '@jitsi/logger';\nconst logger = getLogger(__filename);\n\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\n\nimport JitsiVideoSIPGWSession from './JitsiVideoSIPGWSession';\nimport * as Constants from './VideoSIPGWConstants';\n\n/**\n * Main video SIP GW handler. Stores references of all created sessions.\n */\nexport default class VideoSIPGW {\n\n    /**\n     * Creates new handler.\n     *\n     * @param {ChatRoom} chatRoom - Tha chat room to handle.\n     */\n    constructor(chatRoom) {\n        this.chatRoom = chatRoom;\n        this.eventEmitter = chatRoom.eventEmitter;\n        logger.debug('creating VideoSIPGW');\n        this.sessions = {};\n\n        this.sessionStateChangeListener = this.sessionStateChanged.bind(this);\n\n        // VideoSIPGW, JitsiConference and ChatRoom are not reusable and no\n        // more than one VideoSIPGW can be created per JitsiConference,\n        // so we don't bother to cleanup\n        chatRoom.addPresenceListener('jibri-sip-call-state',\n            this.handleJibriSIPState.bind(this));\n    }\n\n    /**\n     * Handles presence nodes with name: jibri-sip-call-state.\n     *\n     * @param {Object} node the presence node Object to handle.\n     * Object representing part of the presence received over xmpp.\n     */\n    handleJibriSIPState(node) {\n        const attributes = node.attributes;\n\n        if (!attributes) {\n            return;\n        }\n\n        logger.debug('Handle video sip gw state : ', attributes);\n\n        const newState = attributes.state;\n\n        if (newState === this.state) {\n            return;\n        }\n\n        switch (newState) {\n        case Constants.STATE_ON:\n        case Constants.STATE_OFF:\n        case Constants.STATE_PENDING:\n        case Constants.STATE_RETRYING:\n        case Constants.STATE_FAILED: {\n            const address = attributes.sipaddress;\n\n            if (!address) {\n                return;\n            }\n\n            // find the corresponding session and set its state\n            const session = this.sessions[address];\n\n            if (session) {\n                session.setState(newState, attributes.failure_reason);\n            } else {\n                logger.warn('Video SIP GW session not found:', address);\n            }\n        }\n        }\n    }\n\n    /**\n     * Creates new session and stores its reference if it does not exist or\n     * returns an error otherwise.\n     *\n     * @param {string} sipAddress - The sip address to use.\n     * @param {string} displayName - The display name to use.\n     * @returns {JitsiVideoSIPGWSession|Error}\n     */\n    createVideoSIPGWSession(sipAddress, displayName) {\n        if (this.sessions[sipAddress]) {\n            logger.warn('There was already a Video SIP GW session for address',\n                sipAddress);\n\n            return new Error(Constants.ERROR_SESSION_EXISTS);\n        }\n\n        const session = new JitsiVideoSIPGWSession(\n            sipAddress, displayName, this.chatRoom);\n\n        session.addStateListener(this.sessionStateChangeListener);\n\n        this.sessions[sipAddress] = session;\n\n        return session;\n    }\n\n    /**\n     * Listener for session state changed. When a session goes to off or failed\n     * we delete its reference.\n     *\n     * @param {options} event - { address, oldState, newState, displayName }\n     */\n    sessionStateChanged(event) {\n        const address = event.address;\n\n        if (event.newState === Constants.STATE_OFF\n            || event.newState === Constants.STATE_FAILED) {\n            const session = this.sessions[address];\n\n            if (!session) {\n                logger.error('Missing Video SIP GW session with address:',\n                    address);\n\n                return;\n            }\n\n            session.removeStateListener(this.sessionStateChangeListener);\n            delete this.sessions[address];\n        }\n\n        this.eventEmitter.emit(\n            XMPPEvents.VIDEO_SIP_GW_SESSION_STATE_CHANGED,\n            event);\n    }\n}\n","import { getLogger } from '@jitsi/logger';\nimport { Strophe } from 'strophe.js';\n\nimport { MediaType } from '../../service/RTC/MediaType';\nimport * as SignalingEvents from '../../service/RTC/SignalingEvents';\nimport SignalingLayer, { getMediaTypeFromSourceName } from '../../service/RTC/SignalingLayer';\nimport { VideoType } from '../../service/RTC/VideoType';\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\nimport FeatureFlags from '../flags/FeatureFlags';\n\nimport { filterNodeFromPresenceJSON } from './ChatRoom';\n\nconst logger = getLogger(__filename);\n\nexport const SOURCE_INFO_PRESENCE_ELEMENT = 'SourceInfo';\n\n/**\n * Default XMPP implementation of the {@link SignalingLayer} interface. Obtains\n * the data from the MUC presence.\n */\nexport default class SignalingLayerImpl extends SignalingLayer {\n    /**\n     * Creates new instance.\n     */\n    constructor() {\n        super();\n\n        /**\n         * A map that stores SSRCs of remote streams. And is used only locally\n         * We store the mapping when jingle is received, and later is used\n         * onaddstream webrtc event where we have only the ssrc\n         * FIXME: This map got filled and never cleaned and can grow during long\n         * conference\n         * @type {Map<number, string>} maps SSRC number to jid\n         */\n        this.ssrcOwners = new Map();\n\n        /**\n         *\n         * @type {ChatRoom|null}\n         */\n        this.chatRoom = null;\n\n        /**\n         * @type {Map<SourceName, SourceInfo>}\n         * @private\n         */\n        this._localSourceState = { };\n\n        /**\n         * @type {Map<EndpointId, Map<SourceName, SourceInfo>>}\n         * @private\n         */\n        this._remoteSourceState = { };\n\n        /**\n         * A map that stores the source name of a track identified by it's ssrc.\n         * We store the mapping when jingle is received, and later is used\n         * onaddstream webrtc event where we have only the ssrc\n         * FIXME: This map got filled and never cleaned and can grow during long\n         * conference\n         * @type {Map<number, string>} maps SSRC number to source name\n         */\n        this._sourceNames = new Map();\n    }\n\n    /**\n     * Adds <SourceInfo> element to the local presence.\n     *\n     * @returns {void}\n     * @private\n     */\n    _addLocalSourceInfoToPresence() {\n        if (this.chatRoom) {\n            return this.chatRoom.addOrReplaceInPresence(\n                SOURCE_INFO_PRESENCE_ELEMENT,\n                { value: JSON.stringify(this._localSourceState) });\n        }\n\n        return false;\n    }\n\n    /**\n     * Check is given endpoint has advertised <SourceInfo/> in it's presence which means that the source name signaling\n     * is used by this endpoint.\n     *\n     * @param {EndpointId} endpointId\n     * @returns {boolean}\n     */\n    _doesEndpointSendNewSourceInfo(endpointId) {\n        const presence = this.chatRoom?.getLastPresence(endpointId);\n\n        return Boolean(presence && presence.find(node => node.tagName === SOURCE_INFO_PRESENCE_ELEMENT));\n    }\n\n    /**\n     * Sets the <tt>ChatRoom</tt> instance used and binds presence listeners.\n     * @param {ChatRoom} room\n     */\n    setChatRoom(room) {\n        const oldChatRoom = this.chatRoom;\n\n        this.chatRoom = room;\n        if (oldChatRoom) {\n            oldChatRoom.removePresenceListener(\n                'audiomuted', this._audioMuteHandler);\n            oldChatRoom.removePresenceListener(\n                'videomuted', this._videoMuteHandler);\n            oldChatRoom.removePresenceListener(\n                'videoType', this._videoTypeHandler);\n            if (FeatureFlags.isSourceNameSignalingEnabled()) {\n                this._sourceInfoHandler\n                    && oldChatRoom.removePresenceListener(\n                        SOURCE_INFO_PRESENCE_ELEMENT, this._sourceInfoHandler);\n                this._memberLeftHandler\n                    && oldChatRoom.removeEventListener(\n                        XMPPEvents.MUC_MEMBER_LEFT, this._memberLeftHandler);\n            }\n        }\n        if (room) {\n            if (FeatureFlags.isSourceNameSignalingEnabled()) {\n                this._bindChatRoomEventHandlers(room);\n                this._addLocalSourceInfoToPresence();\n            } else {\n                // TODO the logic below has been duplicated in _bindChatRoomEventHandlers, clean this up once\n                //  the new impl has been tested well enough\n                // SignalingEvents\n                this._audioMuteHandler = (node, from) => {\n                    this.eventEmitter.emit(\n                        SignalingEvents.PEER_MUTED_CHANGED,\n                        from, MediaType.AUDIO, node.value === 'true');\n                };\n                room.addPresenceListener('audiomuted', this._audioMuteHandler);\n\n                this._videoMuteHandler = (node, from) => {\n                    this.eventEmitter.emit(\n                        SignalingEvents.PEER_MUTED_CHANGED,\n                        from, MediaType.VIDEO, node.value === 'true');\n                };\n                room.addPresenceListener('videomuted', this._videoMuteHandler);\n\n                this._videoTypeHandler = (node, from) => {\n                    this.eventEmitter.emit(\n                        SignalingEvents.PEER_VIDEO_TYPE_CHANGED,\n                        from, node.value);\n                };\n                room.addPresenceListener('videoType', this._videoTypeHandler);\n            }\n        }\n    }\n\n    /**\n     * Binds event listeners to the chat room instance.\n     * @param {ChatRoom} room\n     * @private\n     * @returns {void}\n     */\n    _bindChatRoomEventHandlers(room) {\n        const emitAudioMutedEvent = (endpointId, muted) => {\n            this.eventEmitter.emit(\n                SignalingEvents.PEER_MUTED_CHANGED,\n                endpointId,\n                MediaType.AUDIO,\n                muted);\n        };\n        const emitVideoMutedEvent = (endpointId, muted) => {\n            this.eventEmitter.emit(\n                SignalingEvents.PEER_MUTED_CHANGED,\n                endpointId,\n                MediaType.VIDEO,\n                muted);\n        };\n\n        // SignalingEvents\n        this._audioMuteHandler = (node, from) => {\n            if (!this._doesEndpointSendNewSourceInfo(from)) {\n                emitAudioMutedEvent(from, node.value === 'true');\n            }\n        };\n        room.addPresenceListener('audiomuted', this._audioMuteHandler);\n\n        this._videoMuteHandler = (node, from) => {\n            if (!this._doesEndpointSendNewSourceInfo(from)) {\n                emitVideoMutedEvent(from, node.value === 'true');\n            }\n        };\n        room.addPresenceListener('videomuted', this._videoMuteHandler);\n\n        const emitVideoTypeEvent = (endpointId, videoType) => {\n            this.eventEmitter.emit(\n                SignalingEvents.PEER_VIDEO_TYPE_CHANGED,\n                endpointId, videoType);\n        };\n\n        this._videoTypeHandler = (node, from) => {\n            if (!this._doesEndpointSendNewSourceInfo(from)) {\n                emitVideoTypeEvent(from, node.value);\n            }\n        };\n\n        if (!FeatureFlags.isMultiStreamSupportEnabled()) {\n            room.addPresenceListener('videoType', this._videoTypeHandler);\n        }\n\n        this._sourceInfoHandler = (node, mucNick) => {\n            const endpointId = mucNick;\n            const { value } = node;\n            const sourceInfoJSON = JSON.parse(value);\n            const emitEventsFromHere = this._doesEndpointSendNewSourceInfo(endpointId);\n            const endpointSourceState\n                = this._remoteSourceState[endpointId] || (this._remoteSourceState[endpointId] = {});\n\n            for (const sourceName of Object.keys(sourceInfoJSON)) {\n                const mediaType = getMediaTypeFromSourceName(sourceName);\n                const newMutedState = Boolean(sourceInfoJSON[sourceName].muted);\n                const oldSourceState = endpointSourceState[sourceName]\n                    || (endpointSourceState[sourceName] = { sourceName });\n\n                if (oldSourceState.muted !== newMutedState) {\n                    oldSourceState.muted = newMutedState;\n                    if (emitEventsFromHere && mediaType === MediaType.AUDIO) {\n                        emitAudioMutedEvent(endpointId, newMutedState);\n                    } else {\n                        emitVideoMutedEvent(endpointId, newMutedState);\n                    }\n                }\n\n                // Assume a default videoType of 'camera' for video sources.\n                const newVideoType = mediaType === MediaType.VIDEO\n                    ? sourceInfoJSON[sourceName].videoType ?? VideoType.CAMERA\n                    : undefined;\n\n                if (oldSourceState.videoType !== newVideoType) {\n                    oldSourceState.videoType = newVideoType;\n\n                    // videoType is not allowed to change on a given JitsiLocalTrack when multi stream support is\n                    // enabled.\n                    emitEventsFromHere\n                        && !FeatureFlags.isMultiStreamSupportEnabled()\n                        && emitVideoTypeEvent(endpointId, newVideoType);\n                }\n            }\n\n            // Cleanup removed source names\n            const newSourceNames = Object.keys(sourceInfoJSON);\n\n            for (const sourceName of Object.keys(endpointSourceState)) {\n                if (newSourceNames.indexOf(sourceName) === -1) {\n                    delete endpointSourceState[sourceName];\n                }\n            }\n        };\n        room.addPresenceListener('SourceInfo', this._sourceInfoHandler);\n\n        // Cleanup when participant leaves\n        this._memberLeftHandler = jid => {\n            const endpointId = Strophe.getResourceFromJid(jid);\n\n            delete this._remoteSourceState[endpointId];\n\n            if (FeatureFlags.isSourceNameSignalingEnabled()) {\n                for (const [ key, value ] of this.ssrcOwners.entries()) {\n                    if (value === endpointId) {\n                        delete this._sourceNames[key];\n                    }\n                }\n            }\n        };\n\n        room.addEventListener(XMPPEvents.MUC_MEMBER_LEFT, this._memberLeftHandler);\n    }\n\n    /**\n     * Finds the first source of given media type for the given endpoint.\n     * @param endpointId\n     * @param mediaType\n     * @returns {SourceInfo|null}\n     * @private\n     */\n    _findEndpointSourceInfoForMediaType(endpointId, mediaType) {\n        const remoteSourceState = this._remoteSourceState[endpointId];\n\n        if (!remoteSourceState) {\n            return null;\n        }\n\n        for (const sourceInfo of Object.values(remoteSourceState)) {\n            const _mediaType = getMediaTypeFromSourceName(sourceInfo.sourceName);\n\n            if (_mediaType === mediaType) {\n                return sourceInfo;\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * @inheritDoc\n     */\n    getPeerMediaInfo(owner, mediaType) {\n        const legacyGetPeerMediaInfo = () => {\n            if (this.chatRoom) {\n                return this.chatRoom.getMediaPresenceInfo(owner, mediaType);\n            }\n            logger.error('Requested peer media info, before room was set');\n        };\n\n        if (FeatureFlags.isSourceNameSignalingEnabled()) {\n            const lastPresence = this.chatRoom.getLastPresence(owner);\n\n            if (!lastPresence) {\n                throw new Error(`getPeerMediaInfo - no presence stored for: ${owner}`);\n            }\n\n            if (!this._doesEndpointSendNewSourceInfo(owner)) {\n                return legacyGetPeerMediaInfo();\n            }\n\n            /**\n             * @type {PeerMediaInfo}\n             */\n            const mediaInfo = {};\n            const endpointMediaSource = this._findEndpointSourceInfoForMediaType(owner, mediaType);\n\n            // The defaults are provided only, because getPeerMediaInfo is a legacy method. This will be eventually\n            // changed into a getSourceInfo method which returns undefined if there's no source. Also there will be\n            // no mediaType argument there.\n            if (mediaType === MediaType.AUDIO) {\n                mediaInfo.muted = endpointMediaSource ? endpointMediaSource.muted : true;\n            } else if (mediaType === MediaType.VIDEO) {\n                mediaInfo.muted = endpointMediaSource ? endpointMediaSource.muted : true;\n                mediaInfo.videoType = endpointMediaSource ? endpointMediaSource.videoType : undefined;\n\n                const codecTypeNode = filterNodeFromPresenceJSON(lastPresence, 'jitsi_participant_codecType');\n\n                if (codecTypeNode.length > 0) {\n                    mediaInfo.codecType = codecTypeNode[0].value;\n                }\n            } else {\n                throw new Error(`Unsupported media type: ${mediaType}`);\n            }\n\n            return mediaInfo;\n        }\n\n        return legacyGetPeerMediaInfo();\n    }\n\n    /**\n     * @inheritDoc\n     */\n    getPeerSourceInfo(owner, sourceName) {\n        return this._remoteSourceState[owner] ? this._remoteSourceState[owner][sourceName] : undefined;\n    }\n\n    /**\n     * @inheritDoc\n     */\n    getSSRCOwner(ssrc) {\n        return this.ssrcOwners.get(ssrc);\n    }\n\n    /**\n     * Set an SSRC owner.\n     * @param {number} ssrc an SSRC to be owned\n     * @param {string} endpointId owner's ID (MUC nickname)\n     * @throws TypeError if <tt>ssrc</tt> is not a number\n     */\n    setSSRCOwner(ssrc, endpointId) {\n        if (typeof ssrc !== 'number') {\n            throw new TypeError(`SSRC(${ssrc}) must be a number`);\n        }\n\n        // Now signaling layer instance is shared between different JingleSessionPC instances, so although very unlikely\n        // an SSRC conflict could potentially occur. Log a message to make debugging easier.\n        const existingOwner = this.ssrcOwners.get(ssrc);\n\n        if (existingOwner && existingOwner !== endpointId) {\n            logger.error(`SSRC owner re-assigned from ${existingOwner} to ${endpointId}`);\n        }\n        this.ssrcOwners.set(ssrc, endpointId);\n    }\n\n    /**\n     * Adjusts muted status of given track.\n     *\n     * @param {SourceName} sourceName - the name of the track's source.\n     * @param {boolean} muted - the new muted status.\n     * @returns {boolean}\n     */\n    setTrackMuteStatus(sourceName, muted) {\n        if (!this._localSourceState[sourceName]) {\n            this._localSourceState[sourceName] = {};\n        }\n\n        this._localSourceState[sourceName].muted = muted;\n\n        if (this.chatRoom) {\n            // FIXME This only adjusts the presence, but doesn't actually send it. Here we temporarily rely on\n            // the legacy signaling part to send the presence. Remember to add \"send presence\" here when the legacy\n            // signaling is removed.\n            return this._addLocalSourceInfoToPresence();\n        }\n\n        return false;\n    }\n\n    /**\n     * Sets track's video type.\n     * @param {SourceName} sourceName - the track's source name.\n     * @param {VideoType} videoType - the new video type.\n     * @returns {boolean}\n     */\n    setTrackVideoType(sourceName, videoType) {\n        if (!this._localSourceState[sourceName]) {\n            this._localSourceState[sourceName] = {};\n        }\n\n        if (this._localSourceState[sourceName].videoType !== videoType) {\n            // Include only if not a camera (default)\n            this._localSourceState[sourceName].videoType = videoType === VideoType.CAMERA ? undefined : videoType;\n\n            // NOTE this doesn't send the actual presence, because is called from the same place where the legacy video\n            // type is emitted which does the actual sending. A send presence statement needs to be added when\n            // the legacy part is removed.\n            return this._addLocalSourceInfoToPresence();\n        }\n\n        return false;\n    }\n\n    /**\n     * @inheritDoc\n     */\n    getTrackSourceName(ssrc) {\n        return this._sourceNames.get(ssrc);\n    }\n\n    /**\n     * Saves the source name for a track identified by it's ssrc.\n     * @param {number} ssrc the ssrc of the target track.\n     * @param {SourceName} sourceName the track's source name to save.\n     * @throws TypeError if <tt>ssrc</tt> is not a number\n     */\n    setTrackSourceName(ssrc, sourceName) {\n        if (typeof ssrc !== 'number') {\n            throw new TypeError(`SSRC(${ssrc}) must be a number`);\n        }\n\n        // Now signaling layer instance is shared between different JingleSessionPC instances, so although very unlikely\n        // an SSRC conflict could potentially occur. Log a message to make debugging easier.\n        const existingName = this._sourceNames.get(ssrc);\n\n        if (existingName && existingName !== sourceName) {\n            logger.error(`SSRC(${ssrc}) sourceName re-assigned from ${existingName} to ${sourceName}`);\n        }\n\n        this._sourceNames.set(ssrc, sourceName);\n    }\n\n}\n","import { getLogger } from '@jitsi/logger';\nimport EventEmitter from 'events';\nimport $ from 'jquery';\nimport isEqual from 'lodash.isequal';\nimport { Strophe } from 'strophe.js';\n\nimport * as JitsiConferenceErrors from './JitsiConferenceErrors';\nimport JitsiConferenceEventManager from './JitsiConferenceEventManager';\nimport * as JitsiConferenceEvents from './JitsiConferenceEvents';\nimport JitsiParticipant from './JitsiParticipant';\nimport JitsiTrackError from './JitsiTrackError';\nimport * as JitsiTrackErrors from './JitsiTrackErrors';\nimport * as JitsiTrackEvents from './JitsiTrackEvents';\nimport authenticateAndUpgradeRole from './authenticateAndUpgradeRole';\nimport { CodecSelection } from './modules/RTC/CodecSelection';\nimport RTC from './modules/RTC/RTC';\nimport { SS_DEFAULT_FRAME_RATE } from './modules/RTC/ScreenObtainer';\nimport browser from './modules/browser';\nimport ConnectionQuality from './modules/connectivity/ConnectionQuality';\nimport IceFailedHandling\n    from './modules/connectivity/IceFailedHandling';\nimport ParticipantConnectionStatusHandler\n    from './modules/connectivity/ParticipantConnectionStatus';\nimport * as DetectionEvents from './modules/detection/DetectionEvents';\nimport NoAudioSignalDetection from './modules/detection/NoAudioSignalDetection';\nimport P2PDominantSpeakerDetection from './modules/detection/P2PDominantSpeakerDetection';\nimport VADAudioAnalyser from './modules/detection/VADAudioAnalyser';\nimport VADNoiseDetection from './modules/detection/VADNoiseDetection';\nimport VADTalkMutedDetection from './modules/detection/VADTalkMutedDetection';\nimport { E2EEncryption } from './modules/e2ee/E2EEncryption';\nimport E2ePing from './modules/e2eping/e2eping';\nimport Jvb121EventGenerator from './modules/event/Jvb121EventGenerator';\nimport FeatureFlags from './modules/flags/FeatureFlags';\nimport ReceiveVideoController from './modules/qualitycontrol/ReceiveVideoController';\nimport SendVideoController from './modules/qualitycontrol/SendVideoController';\nimport RecordingManager from './modules/recording/RecordingManager';\nimport Settings from './modules/settings/Settings';\nimport AudioOutputProblemDetector from './modules/statistics/AudioOutputProblemDetector';\nimport AvgRTPStatsReporter from './modules/statistics/AvgRTPStatsReporter';\nimport SpeakerStatsCollector from './modules/statistics/SpeakerStatsCollector';\nimport Statistics from './modules/statistics/statistics';\nimport Transcriber from './modules/transcription/transcriber';\nimport GlobalOnErrorHandler from './modules/util/GlobalOnErrorHandler';\nimport RandomUtil from './modules/util/RandomUtil';\nimport ComponentsVersions from './modules/version/ComponentsVersions';\nimport VideoSIPGW from './modules/videosipgw/VideoSIPGW';\nimport * as VideoSIPGWConstants from './modules/videosipgw/VideoSIPGWConstants';\nimport SignalingLayerImpl from './modules/xmpp/SignalingLayerImpl';\nimport {\n    FEATURE_E2EE,\n    FEATURE_JIGASI,\n    JITSI_MEET_MUC_TYPE\n} from './modules/xmpp/xmpp';\nimport BridgeVideoType from './service/RTC/BridgeVideoType';\nimport CodecMimeType from './service/RTC/CodecMimeType';\nimport { MediaType } from './service/RTC/MediaType';\nimport RTCEvents from './service/RTC/RTCEvents';\nimport { getSourceNameForJitsiTrack } from './service/RTC/SignalingLayer';\nimport { VideoType } from './service/RTC/VideoType';\nimport {\n    ACTION_JINGLE_RESTART,\n    ACTION_JINGLE_SI_RECEIVED,\n    ACTION_JINGLE_SI_TIMEOUT,\n    ACTION_JINGLE_TERMINATE,\n    ACTION_P2P_DECLINED,\n    ACTION_P2P_ESTABLISHED,\n    ACTION_P2P_FAILED,\n    ACTION_P2P_SWITCH_TO_JVB,\n    ICE_ESTABLISHMENT_DURATION_DIFF,\n    createConferenceEvent,\n    createJingleEvent,\n    createP2PEvent\n} from './service/statistics/AnalyticsEvents';\nimport { XMPPEvents } from './service/xmpp/XMPPEvents';\n\nconst logger = getLogger(__filename);\n\n/**\n * How long since Jicofo is supposed to send a session-initiate, before\n * {@link ACTION_JINGLE_SI_TIMEOUT} analytics event is sent (in ms).\n * @type {number}\n */\nconst JINGLE_SI_TIMEOUT = 5000;\n\n/**\n * Creates a JitsiConference object with the given name and properties.\n * Note: this constructor is not a part of the public API (objects should be\n * created using JitsiConnection.createConference).\n * @param options.config properties / settings related to the conference that\n * will be created.\n * @param options.name the name of the conference\n * @param options.connection the JitsiConnection object for this\n * JitsiConference.\n * @param {number} [options.config.avgRtpStatsN=15] how many samples are to be\n * collected by {@link AvgRTPStatsReporter}, before arithmetic mean is\n * calculated and submitted to the analytics module.\n * @param {boolean} [options.config.enableIceRestart=false] - enables the ICE\n * restart logic.\n * @param {boolean} [options.config.p2p.enabled] when set to <tt>true</tt>\n * the peer to peer mode will be enabled. It means that when there are only 2\n * participants in the conference an attempt to make direct connection will be\n * made. If the connection succeeds the conference will stop sending data\n * through the JVB connection and will use the direct one instead.\n * @param {number} [options.config.p2p.backToP2PDelay=5] a delay given in\n * seconds, before the conference switches back to P2P, after the 3rd\n * participant has left the room.\n * @param {number} [options.config.channelLastN=-1] The requested amount of\n * videos are going to be delivered after the value is in effect. Set to -1 for\n * unlimited or all available videos.\n * @param {number} [options.config.forceJVB121Ratio]\n * \"Math.random() < forceJVB121Ratio\" will determine whether a 2 people\n * conference should be moved to the JVB instead of P2P. The decision is made on\n * the responder side, after ICE succeeds on the P2P connection.\n * @constructor\n *\n * FIXME Make all methods which are called from lib-internal classes\n *       to non-public (use _). To name a few:\n *       {@link JitsiConference.onLocalRoleChanged}\n *       {@link JitsiConference.onUserRoleChanged}\n *       {@link JitsiConference.onMemberLeft}\n *       and so on...\n */\nexport default function JitsiConference(options) {\n    if (!options.name || options.name.toLowerCase() !== options.name.toString()) {\n        const errmsg\n            = 'Invalid conference name (no conference name passed or it '\n                + 'contains invalid characters like capital letters)!';\n\n        logger.error(errmsg);\n        throw new Error(errmsg);\n    }\n    this.connection = options.connection;\n    this.xmpp = this.connection?.xmpp;\n\n    if (this.xmpp.isRoomCreated(options.name, options.customDomain)) {\n        const errmsg = 'A conference with the same name has already been created!';\n\n        delete this.connection;\n        delete this.xmpp;\n        logger.error(errmsg);\n        throw new Error(errmsg);\n    }\n    this.eventEmitter = new EventEmitter();\n    this.options = options;\n    this.eventManager = new JitsiConferenceEventManager(this);\n    this.participants = {};\n\n    /**\n     * The signaling layer instance.\n     * @type {SignalingLayerImpl}\n     * @private\n     */\n    this._signalingLayer = new SignalingLayerImpl();\n\n    this._init(options);\n    this.componentsVersions = new ComponentsVersions(this);\n\n    /**\n     * Jingle session instance for the JVB connection.\n     * @type {JingleSessionPC}\n     */\n    this.jvbJingleSession = null;\n    this.lastDominantSpeaker = null;\n    this.dtmfManager = null;\n    this.somebodySupportsDTMF = false;\n    this.authEnabled = false;\n    this.startAudioMuted = false;\n    this.startVideoMuted = false;\n    this.startMutedPolicy = {\n        audio: false,\n        video: false\n    };\n    this.isMutedByFocus = false;\n\n    // when muted by focus we receive the jid of the initiator of the mute\n    this.mutedByFocusActor = null;\n\n    this.isVideoMutedByFocus = false;\n\n    // when video muted by focus we receive the jid of the initiator of the mute\n    this.mutedVideoByFocusActor = null;\n\n    // Flag indicates if the 'onCallEnded' method was ever called on this\n    // instance. Used to log extra analytics event for debugging purpose.\n    // We need to know if the potential issue happened before or after\n    // the restart.\n    this.wasStopped = false;\n\n    // Conference properties, maintained by jicofo.\n    this.properties = {};\n\n    /**\n     * The object which monitors local and remote connection statistics (e.g.\n     * sending bitrate) and calculates a number which represents the connection\n     * quality.\n     */\n    this.connectionQuality\n        = new ConnectionQuality(this, this.eventEmitter, options);\n\n    /**\n     * Reports average RTP statistics to the analytics module.\n     * @type {AvgRTPStatsReporter}\n     */\n    this.avgRtpStatsReporter\n        = new AvgRTPStatsReporter(this, options.config.avgRtpStatsN || 15);\n\n    /**\n     * Detects issues with the audio of remote participants.\n     * @type {AudioOutputProblemDetector}\n     */\n    if (!options.config.disableAudioLevels) {\n        this._audioOutputProblemDetector = new AudioOutputProblemDetector(this);\n    }\n\n    /**\n     * Indicates whether the connection is interrupted or not.\n     */\n    this.isJvbConnectionInterrupted = false;\n\n    /**\n     * The object which tracks active speaker times\n     */\n    this.speakerStatsCollector = new SpeakerStatsCollector(this);\n\n    /* P2P related fields below: */\n\n    /**\n     * Stores reference to deferred start P2P task. It's created when 3rd\n     * participant leaves the room in order to avoid ping pong effect (it\n     * could be just a page reload).\n     * @type {number|null}\n     */\n    this.deferredStartP2PTask = null;\n\n    const delay\n        = parseInt(options.config.p2p && options.config.p2p.backToP2PDelay, 10);\n\n    /**\n     * A delay given in seconds, before the conference switches back to P2P\n     * after the 3rd participant has left.\n     * @type {number}\n     */\n    this.backToP2PDelay = isNaN(delay) ? 5 : delay;\n    logger.info(`backToP2PDelay: ${this.backToP2PDelay}`);\n\n    /**\n     * If set to <tt>true</tt> it means the P2P ICE is no longer connected.\n     * When <tt>false</tt> it means that P2P ICE (media) connection is up\n     * and running.\n     * @type {boolean}\n     */\n    this.isP2PConnectionInterrupted = false;\n\n    /**\n     * Flag set to <tt>true</tt> when P2P session has been established\n     * (ICE has been connected) and this conference is currently in the peer to\n     * peer mode (P2P connection is the active one).\n     * @type {boolean}\n     */\n    this.p2p = false;\n\n    /**\n     * A JingleSession for the direct peer to peer connection.\n     * @type {JingleSessionPC}\n     */\n    this.p2pJingleSession = null;\n\n    this.videoSIPGWHandler = new VideoSIPGW(this.room);\n    this.recordingManager = new RecordingManager(this.room);\n\n    /**\n     * If the conference.joined event has been sent this will store the timestamp when it happened.\n     *\n     * @type {undefined|number}\n     * @private\n     */\n    this._conferenceJoinAnalyticsEventSent = undefined;\n\n    /**\n     * End-to-End Encryption. Make it available if supported.\n     */\n    if (this.isE2EESupported()) {\n        logger.info('End-to-End Encryption is supported');\n\n        this._e2eEncryption = new E2EEncryption(this);\n    }\n\n    /**\n     * Flag set to <tt>true</tt> when Jicofo sends a presence message indicating that the max audio sender limit has\n     * been reached for the call. Once this is set, unmuting audio will be disabled from the client until it gets reset\n     * again by Jicofo.\n     */\n    this._audioSenderLimitReached = undefined;\n\n    /**\n     * Flag set to <tt>true</tt> when Jicofo sends a presence message indicating that the max video sender limit has\n     * been reached for the call. Once this is set, unmuting video will be disabled from the client until it gets reset\n     * again by Jicofo.\n     */\n    this._videoSenderLimitReached = undefined;\n}\n\n// FIXME convert JitsiConference to ES6 - ASAP !\nJitsiConference.prototype.constructor = JitsiConference;\n\n/**\n * Create a resource for the a jid. We use the room nickname (the resource part\n * of the occupant JID, see XEP-0045) as the endpoint ID in colibri. We require\n * endpoint IDs to be 8 hex digits because in some cases they get serialized\n * into a 32bit field.\n *\n * @param {string} jid - The id set onto the XMPP connection.\n * @param {boolean} isAuthenticatedUser - Whether or not the user has connected\n * to the XMPP service with a password.\n * @returns {string}\n * @static\n */\nJitsiConference.resourceCreator = function(jid, isAuthenticatedUser) {\n    let mucNickname;\n\n    if (isAuthenticatedUser) {\n        // For authenticated users generate a random ID.\n        mucNickname = RandomUtil.randomHexString(8).toLowerCase();\n    } else {\n        // We try to use the first part of the node (which for anonymous users\n        // on prosody is a UUID) to match the previous behavior (and maybe make\n        // debugging easier).\n        mucNickname = Strophe.getNodeFromJid(jid)?.substr(0, 8)\n            .toLowerCase();\n\n        // But if this doesn't have the required format we just generate a new\n        // random nickname.\n        const re = /[0-9a-f]{8}/g;\n\n        if (!mucNickname || !re.test(mucNickname)) {\n            mucNickname = RandomUtil.randomHexString(8).toLowerCase();\n        }\n    }\n\n    return mucNickname;\n};\n\n/**\n * Initializes the conference object properties\n * @param options {object}\n * @param options.connection {JitsiConnection} overrides this.connection\n */\nJitsiConference.prototype._init = function(options = {}) {\n    this.eventManager.setupXMPPListeners();\n\n    const { config } = this.options;\n\n    // Get the codec preference settings from config.js.\n    // 'preferH264' and 'disableH264' settings have been deprecated for a while,\n    // 'preferredCodec' and 'disabledCodec' will have precedence over them.\n    const codecSettings = {\n        disabledCodec: config.videoQuality\n            ? config.videoQuality.disabledCodec\n            : config.p2p && config.p2p.disableH264 && CodecMimeType.H264,\n        enforcePreferredCodec: config.videoQuality && config.videoQuality.enforcePreferredCodec,\n        jvbCodec: (config.videoQuality && config.videoQuality.preferredCodec)\n            || (config.preferH264 && CodecMimeType.H264),\n        p2pCodec: config.p2p\n            ? config.p2p.preferredCodec || (config.p2p.preferH264 && CodecMimeType.H264)\n            : CodecMimeType.VP8\n    };\n\n    this.codecSelection = new CodecSelection(this, codecSettings);\n    this._statsCurrentId = config.statisticsId ? config.statisticsId : Settings.callStatsUserName;\n    this.room = this.xmpp.createRoom(\n        this.options.name, {\n            ...config,\n            statsId: this._statsCurrentId\n        },\n        JitsiConference.resourceCreator\n    );\n\n    this._signalingLayer.setChatRoom(this.room);\n\n    // Connection interrupted/restored listeners\n    this._onIceConnectionInterrupted\n        = this._onIceConnectionInterrupted.bind(this);\n    this.room.addListener(\n        XMPPEvents.CONNECTION_INTERRUPTED, this._onIceConnectionInterrupted);\n\n    this._onIceConnectionRestored = this._onIceConnectionRestored.bind(this);\n    this.room.addListener(\n        XMPPEvents.CONNECTION_RESTORED, this._onIceConnectionRestored);\n\n    this._onIceConnectionEstablished\n        = this._onIceConnectionEstablished.bind(this);\n    this.room.addListener(\n        XMPPEvents.CONNECTION_ESTABLISHED, this._onIceConnectionEstablished);\n\n    this._updateProperties = this._updateProperties.bind(this);\n    this.room.addListener(XMPPEvents.CONFERENCE_PROPERTIES_CHANGED,\n        this._updateProperties);\n\n    this._sendConferenceJoinAnalyticsEvent = this._sendConferenceJoinAnalyticsEvent.bind(this);\n    this.room.addListener(XMPPEvents.MEETING_ID_SET, this._sendConferenceJoinAnalyticsEvent);\n\n    this._removeLocalSourceOnReject = this._removeLocalSourceOnReject.bind(this);\n    this._updateRoomPresence = this._updateRoomPresence.bind(this);\n    this.room.addListener(XMPPEvents.SESSION_ACCEPT, this._updateRoomPresence);\n    this.room.addListener(XMPPEvents.SOURCE_ADD, this._updateRoomPresence);\n    this.room.addListener(XMPPEvents.SOURCE_ADD_ERROR, this._removeLocalSourceOnReject);\n    this.room.addListener(XMPPEvents.SOURCE_REMOVE, this._updateRoomPresence);\n\n    this.e2eping = new E2ePing(\n        this,\n        config,\n        (message, to) => {\n            try {\n                this.sendMessage(\n                    message, to, true /* sendThroughVideobridge */);\n            } catch (error) {\n                logger.warn('Failed to send E2E ping request or response.', error && error.msg);\n            }\n        });\n\n    if (!this.rtc) {\n        this.rtc = new RTC(this, options);\n        this.eventManager.setupRTCListeners();\n        if (FeatureFlags.isSourceNameSignalingEnabled()) {\n            this._registerRtcListeners(this.rtc);\n        }\n    }\n\n    this.receiveVideoController = new ReceiveVideoController(this, this.rtc);\n    this.sendVideoController = new SendVideoController(this, this.rtc);\n\n    this.participantConnectionStatus\n        = new ParticipantConnectionStatusHandler(\n            this.rtc,\n            this,\n            {\n                // These options are not public API, leaving it here only as an entry point through config for tuning\n                // up purposes. Default values should be adjusted as soon as optimal values are discovered.\n                p2pRtcMuteTimeout: config._p2pConnStatusRtcMuteTimeout,\n                rtcMuteTimeout: config._peerConnStatusRtcMuteTimeout,\n                outOfLastNTimeout: config._peerConnStatusOutOfLastNTimeout\n            });\n    this.participantConnectionStatus.init();\n\n    // Add the ability to enable callStats only on a percentage of users based on config.js settings.\n    let enableCallStats = true;\n\n    if (config.testing && config.testing.callStatsThreshold) {\n        enableCallStats = (Math.random() * 100) <= config.testing.callStatsThreshold;\n    }\n\n    if (!this.statistics) {\n        this.statistics = new Statistics(this.xmpp, {\n            aliasName: this._statsCurrentId,\n            userName: config.statisticsDisplayName ? config.statisticsDisplayName : this.myUserId(),\n            confID: config.confID || `${this.connection.options.hosts.domain}/${this.options.name}`,\n            siteID: config.siteID,\n            customScriptUrl: config.callStatsCustomScriptUrl,\n            callStatsID: config.callStatsID,\n            callStatsSecret: config.callStatsSecret,\n            callStatsApplicationLogsDisabled: config.callStatsApplicationLogsDisabled,\n            enableCallStats,\n            roomName: this.options.name,\n            applicationName: config.applicationName,\n            getWiFiStatsMethod: config.getWiFiStatsMethod,\n            configParams: config.callStatsConfigParams\n        });\n        Statistics.analytics.addPermanentProperties({\n            'callstats_name': this._statsCurrentId\n        });\n\n        // Start performance observer for monitoring long tasks\n        if (config.longTasksStatsInterval) {\n            this.statistics.attachLongTasksStats(this);\n        }\n    }\n\n    this.eventManager.setupChatRoomListeners();\n\n    // Always add listeners because on reload we are executing leave and the\n    // listeners are removed from statistics module.\n    this.eventManager.setupStatisticsListeners();\n\n    // Disable VAD processing on Safari since it causes audio input to\n    // fail on some of the mobile devices.\n    if (config.enableTalkWhileMuted && browser.supportsVADDetection()) {\n        // If VAD processor factory method is provided uses VAD based detection, otherwise fallback to audio level\n        // based detection.\n        if (config.createVADProcessor) {\n            logger.info('Using VAD detection for generating talk while muted events');\n\n            if (!this._audioAnalyser) {\n                this._audioAnalyser = new VADAudioAnalyser(this, config.createVADProcessor);\n            }\n\n            const vadTalkMutedDetection = new VADTalkMutedDetection();\n\n            vadTalkMutedDetection.on(DetectionEvents.VAD_TALK_WHILE_MUTED, () =>\n                this.eventEmitter.emit(JitsiConferenceEvents.TALK_WHILE_MUTED));\n\n            this._audioAnalyser.addVADDetectionService(vadTalkMutedDetection);\n        } else {\n            logger.warn('No VAD Processor was provided. Talk while muted detection service was not initialized!');\n        }\n    }\n\n    // Disable noisy mic detection on safari since it causes the audio input to\n    // fail on Safari on iPadOS.\n    if (config.enableNoisyMicDetection && browser.supportsVADDetection()) {\n        if (config.createVADProcessor) {\n            if (!this._audioAnalyser) {\n                this._audioAnalyser = new VADAudioAnalyser(this, config.createVADProcessor);\n            }\n\n            const vadNoiseDetection = new VADNoiseDetection();\n\n            vadNoiseDetection.on(DetectionEvents.VAD_NOISY_DEVICE, () =>\n                this.eventEmitter.emit(JitsiConferenceEvents.NOISY_MIC));\n\n            this._audioAnalyser.addVADDetectionService(vadNoiseDetection);\n        } else {\n            logger.warn('No VAD Processor was provided. Noisy microphone detection service was not initialized!');\n        }\n    }\n\n    // Generates events based on no audio input detector.\n    if (config.enableNoAudioDetection) {\n        this._noAudioSignalDetection = new NoAudioSignalDetection(this);\n        this._noAudioSignalDetection.on(DetectionEvents.NO_AUDIO_INPUT, () => {\n            this.eventEmitter.emit(JitsiConferenceEvents.NO_AUDIO_INPUT);\n        });\n        this._noAudioSignalDetection.on(DetectionEvents.AUDIO_INPUT_STATE_CHANGE, hasAudioSignal => {\n            this.eventEmitter.emit(JitsiConferenceEvents.AUDIO_INPUT_STATE_CHANGE, hasAudioSignal);\n        });\n    }\n\n\n    if ('channelLastN' in config) {\n        this.setLastN(config.channelLastN);\n    }\n\n    /**\n     * Emits {@link JitsiConferenceEvents.JVB121_STATUS}.\n     * @type {Jvb121EventGenerator}\n     */\n    this.jvb121Status = new Jvb121EventGenerator(this);\n\n    // creates dominant speaker detection that works only in p2p mode\n    this.p2pDominantSpeakerDetection = new P2PDominantSpeakerDetection(this);\n\n    if (config && config.deploymentInfo && config.deploymentInfo.userRegion) {\n        this.setLocalParticipantProperty(\n            'region', config.deploymentInfo.userRegion);\n    }\n\n    // Publish the codec type to presence.\n    this.setLocalParticipantProperty('codecType', this.codecSelection.getPreferredCodec());\n\n    // Set transcription language presence extension.\n    // In case the language config is undefined or has the default value that the transcriber uses\n    // (in our case Jigasi uses 'en-US'), don't set the participant property in order to avoid\n    // needlessly polluting the presence stanza.\n    if (config && config.transcriptionLanguage && config.transcriptionLanguage !== 'en-US') {\n        this.setLocalParticipantProperty('transcription_language', config.transcriptionLanguage);\n    }\n};\n\n/**\n * Joins the conference.\n * @param password {string} the password\n * @param replaceParticipant {boolean} whether the current join replaces\n * an existing participant with same jwt from the meeting.\n */\nJitsiConference.prototype.join = function(password, replaceParticipant = false) {\n    if (this.room) {\n        this.room.join(password, replaceParticipant).then(() => this._maybeSetSITimeout());\n    }\n};\n\n/**\n * Authenticates and upgrades the role of the local participant/user.\n *\n * @returns {Object} A <tt>thenable</tt> which (1) settles when the process of\n * authenticating and upgrading the role of the local participant/user finishes\n * and (2) has a <tt>cancel</tt> method that allows the caller to interrupt the\n * process.\n */\nJitsiConference.prototype.authenticateAndUpgradeRole = function(options) {\n    return authenticateAndUpgradeRole.call(this, {\n        ...options,\n        onCreateResource: JitsiConference.resourceCreator\n    });\n};\n\n/**\n * Check if joined to the conference.\n */\nJitsiConference.prototype.isJoined = function() {\n    return this.room && this.room.joined;\n};\n\n/**\n * Tells whether or not the P2P mode is enabled in the configuration.\n * @return {boolean}\n */\nJitsiConference.prototype.isP2PEnabled = function() {\n    return Boolean(this.options.config.p2p && this.options.config.p2p.enabled)\n\n        // FIXME: remove once we have a default config template. -saghul\n        || typeof this.options.config.p2p === 'undefined';\n};\n\n/**\n * When in P2P test mode, the conference will not automatically switch to P2P\n * when there 2 participants.\n * @return {boolean}\n */\nJitsiConference.prototype.isP2PTestModeEnabled = function() {\n    return Boolean(this.options.config.testing\n        && this.options.config.testing.p2pTestMode);\n};\n\n/**\n * Leaves the conference.\n * @returns {Promise}\n */\nJitsiConference.prototype.leave = async function() {\n    if (this.participantConnectionStatus) {\n        this.participantConnectionStatus.dispose();\n        this.participantConnectionStatus = null;\n    }\n    if (this.avgRtpStatsReporter) {\n        this.avgRtpStatsReporter.dispose();\n        this.avgRtpStatsReporter = null;\n    }\n\n    if (this._audioOutputProblemDetector) {\n        this._audioOutputProblemDetector.dispose();\n        this._audioOutputProblemDetector = null;\n    }\n\n    if (this.e2eping) {\n        this.e2eping.stop();\n        this.e2eping = null;\n    }\n\n    this.getLocalTracks().forEach(track => this.onLocalTrackRemoved(track));\n\n    this.rtc.closeBridgeChannel();\n\n    this._sendConferenceLeftAnalyticsEvent();\n\n    if (this.statistics) {\n        this.statistics.dispose();\n    }\n\n    this._delayedIceFailed && this._delayedIceFailed.cancel();\n\n    this._maybeClearDeferredStartP2P();\n    this._maybeClearSITimeout();\n\n    // Close both JVb and P2P JingleSessions\n    if (this.jvbJingleSession) {\n        this.jvbJingleSession.close();\n        this.jvbJingleSession = null;\n    }\n    if (this.p2pJingleSession) {\n        this.p2pJingleSession.close();\n        this.p2pJingleSession = null;\n    }\n\n    // Leave the conference. If this.room == null we are calling second time leave().\n    if (!this.room) {\n        throw new Error('The conference has already been left');\n    }\n\n    const room = this.room;\n\n    // Unregister connection state listeners\n    room.removeListener(\n        XMPPEvents.CONNECTION_INTERRUPTED,\n        this._onIceConnectionInterrupted);\n    room.removeListener(\n        XMPPEvents.CONNECTION_RESTORED,\n        this._onIceConnectionRestored);\n    room.removeListener(\n        XMPPEvents.CONNECTION_ESTABLISHED,\n        this._onIceConnectionEstablished);\n\n    room.removeListener(\n        XMPPEvents.CONFERENCE_PROPERTIES_CHANGED,\n        this._updateProperties);\n\n    room.removeListener(XMPPEvents.MEETING_ID_SET, this._sendConferenceJoinAnalyticsEvent);\n    room.removeListener(XMPPEvents.SESSION_ACCEPT, this._updateRoomPresence);\n    room.removeListener(XMPPEvents.SOURCE_ADD, this._updateRoomPresence);\n    room.removeListener(XMPPEvents.SOURCE_ADD_ERROR, this._removeLocalSourceOnReject);\n    room.removeListener(XMPPEvents.SOURCE_REMOVE, this._updateRoomPresence);\n\n    this.eventManager.removeXMPPListeners();\n\n    this._signalingLayer.setChatRoom(null);\n\n    this.room = null;\n\n    let leaveError;\n\n    try {\n        await room.leave();\n    } catch (err) {\n        leaveError = err;\n\n        // Remove all participants because currently the conference\n        // won't be usable anyway. This is done on success automatically\n        // by the ChatRoom instance.\n        this.getParticipants().forEach(\n            participant => this.onMemberLeft(participant.getJid()));\n    }\n\n    if (this.rtc) {\n        this.rtc.destroy();\n    }\n\n    if (leaveError) {\n        throw leaveError;\n    }\n};\n\n/**\n * Returns the currently active media session if any.\n *\n * @returns {JingleSessionPC|undefined}\n */\nJitsiConference.prototype.getActiveMediaSession = function() {\n    return this.isP2PActive() ? this.p2pJingleSession : this.jvbJingleSession;\n};\n\n/**\n * Returns an array containing all media sessions existing in this conference.\n *\n * @returns {Array<JingleSessionPC>}\n */\nJitsiConference.prototype.getMediaSessions = function() {\n    const sessions = [];\n\n    this.jvbJingleSession && sessions.push(this.jvbJingleSession);\n    this.p2pJingleSession && sessions.push(this.p2pJingleSession);\n\n    return sessions;\n};\n\n/**\n * Registers event listeners on the RTC instance.\n * @param {RTC} rtc - the RTC module instance used by this conference.\n * @private\n * @returns {void}\n */\nJitsiConference.prototype._registerRtcListeners = function(rtc) {\n    rtc.addListener(RTCEvents.DATA_CHANNEL_OPEN, () => {\n        for (const localTrack of this.rtc.localTracks) {\n            localTrack.isVideoTrack() && this._sendBridgeVideoTypeMessage(localTrack);\n        }\n    });\n};\n\n/**\n * Sends the 'VideoTypeMessage' to the bridge on the bridge channel so that the bridge can make bitrate allocation\n * decisions based on the video type of the local source.\n *\n * @param {JitsiLocalTrack} localtrack - The track associated with the local source signaled to the bridge.\n * @returns {void}\n * @private\n */\nJitsiConference.prototype._sendBridgeVideoTypeMessage = function(localtrack) {\n    let videoType = !localtrack || localtrack.isMuted() ? BridgeVideoType.NONE : localtrack.getVideoType();\n\n    if (videoType === BridgeVideoType.DESKTOP && this._desktopSharingFrameRate > SS_DEFAULT_FRAME_RATE) {\n        videoType = BridgeVideoType.DESKTOP_HIGH_FPS;\n    }\n\n    if (FeatureFlags.isSourceNameSignalingEnabled() && localtrack) {\n        this.rtc.sendSourceVideoType(localtrack.getSourceName(), videoType);\n    } else if (!FeatureFlags.isSourceNameSignalingEnabled()) {\n        this.rtc.setVideoType(videoType);\n    }\n};\n\n/**\n * Returns name of this conference.\n */\nJitsiConference.prototype.getName = function() {\n    return this.options.name.toString();\n};\n\n/**\n * Returns the {@link JitsiConnection} used by this this conference.\n */\nJitsiConference.prototype.getConnection = function() {\n    return this.connection;\n};\n\n/**\n * Check if authentication is enabled for this conference.\n */\nJitsiConference.prototype.isAuthEnabled = function() {\n    return this.authEnabled;\n};\n\n/**\n * Check if user is logged in.\n */\nJitsiConference.prototype.isLoggedIn = function() {\n    return Boolean(this.authIdentity);\n};\n\n/**\n * Get authorized login.\n */\nJitsiConference.prototype.getAuthLogin = function() {\n    return this.authIdentity;\n};\n\n/**\n * Check if external authentication is enabled for this conference.\n */\nJitsiConference.prototype.isExternalAuthEnabled = function() {\n    return this.room && this.room.moderator.isExternalAuthEnabled();\n};\n\n/**\n * Get url for external authentication.\n * @param {boolean} [urlForPopup] if true then return url for login popup,\n *                                else url of login page.\n * @returns {Promise}\n */\nJitsiConference.prototype.getExternalAuthUrl = function(urlForPopup) {\n    return new Promise((resolve, reject) => {\n        if (!this.isExternalAuthEnabled()) {\n            reject();\n\n            return;\n        }\n        if (urlForPopup) {\n            this.room.moderator.getPopupLoginUrl(resolve, reject);\n        } else {\n            this.room.moderator.getLoginUrl(resolve, reject);\n        }\n    });\n};\n\n/**\n * Returns the local tracks of the given media type, or all local tracks if no\n * specific type is given.\n * @param {MediaType} [mediaType] Optional media type (audio or video).\n */\nJitsiConference.prototype.getLocalTracks = function(mediaType) {\n    let tracks = [];\n\n    if (this.rtc) {\n        tracks = this.rtc.getLocalTracks(mediaType);\n    }\n\n    return tracks;\n};\n\n/**\n * Obtains local audio track.\n * @return {JitsiLocalTrack|null}\n */\nJitsiConference.prototype.getLocalAudioTrack = function() {\n    return this.rtc ? this.rtc.getLocalAudioTrack() : null;\n};\n\n/**\n * Obtains local video track.\n * @return {JitsiLocalTrack|null}\n */\nJitsiConference.prototype.getLocalVideoTrack = function() {\n    return this.rtc ? this.rtc.getLocalVideoTrack() : null;\n};\n\n/**\n * Returns all the local video tracks.\n * @returns {Array<JitsiLocalTrack>}\n */\nJitsiConference.prototype.getLocalVideoTracks = function() {\n    return this.rtc ? this.rtc.getLocalVideoTracks() : null;\n};\n\n/**\n * Obtains the performance statistics.\n * @returns {Object|null}\n */\nJitsiConference.prototype.getPerformanceStats = function() {\n    return {\n        longTasksStats: this.statistics.getLongTasksStats()\n    };\n};\n\n/**\n * Attaches a handler for events(For example - \"participant joined\".) in the\n * conference. All possible event are defined in JitsiConferenceEvents.\n * @param eventId the event ID.\n * @param handler handler for the event.\n *\n * Note: consider adding eventing functionality by extending an EventEmitter\n * impl, instead of rolling ourselves\n */\nJitsiConference.prototype.on = function(eventId, handler) {\n    if (this.eventEmitter) {\n        this.eventEmitter.on(eventId, handler);\n    }\n};\n\n/**\n * Removes event listener\n * @param eventId the event ID.\n * @param [handler] optional, the specific handler to unbind\n *\n * Note: consider adding eventing functionality by extending an EventEmitter\n * impl, instead of rolling ourselves\n */\nJitsiConference.prototype.off = function(eventId, handler) {\n    if (this.eventEmitter) {\n        this.eventEmitter.removeListener(eventId, handler);\n    }\n};\n\n// Common aliases for event emitter\nJitsiConference.prototype.addEventListener = JitsiConference.prototype.on;\nJitsiConference.prototype.removeEventListener = JitsiConference.prototype.off;\n\n/**\n * Receives notifications from other participants about commands / custom events\n * (sent by sendCommand or sendCommandOnce methods).\n * @param command {String} the name of the command\n * @param handler {Function} handler for the command\n */\nJitsiConference.prototype.addCommandListener = function(command, handler) {\n    if (this.room) {\n        this.room.addPresenceListener(command, handler);\n    }\n};\n\n/**\n  * Removes command  listener\n  * @param command {String} the name of the command\n  * @param handler {Function} handler to remove for the command\n  */\nJitsiConference.prototype.removeCommandListener = function(command, handler) {\n    if (this.room) {\n        this.room.removePresenceListener(command, handler);\n    }\n};\n\n/**\n * Sends text message to the other participants in the conference\n * @param message the text message.\n * @param elementName the element name to encapsulate the message.\n * @deprecated Use 'sendMessage' instead. TODO: this should be private.\n */\nJitsiConference.prototype.sendTextMessage = function(message, elementName = 'body') {\n    if (this.room) {\n        this.room.sendMessage(message, elementName);\n    }\n};\n\n/**\n * Send private text message to another participant of the conference\n * @param id the id of the participant to send a private message.\n * @param message the text message.\n * @param elementName the element name to encapsulate the message.\n * @deprecated Use 'sendMessage' instead. TODO: this should be private.\n */\nJitsiConference.prototype.sendPrivateTextMessage = function(id, message, elementName = 'body') {\n    if (this.room) {\n        this.room.sendPrivateMessage(id, message, elementName);\n    }\n};\n\n/**\n * Send presence command.\n * @param name {String} the name of the command.\n * @param values {Object} with keys and values that will be sent.\n **/\nJitsiConference.prototype.sendCommand = function(name, values) {\n    if (this.room) {\n        this.room.addOrReplaceInPresence(name, values) && this.room.sendPresence();\n    } else {\n        logger.warn('Not sending a command, room not initialized.');\n    }\n\n};\n\n/**\n * Send presence command one time.\n * @param name {String} the name of the command.\n * @param values {Object} with keys and values that will be sent.\n **/\nJitsiConference.prototype.sendCommandOnce = function(name, values) {\n    this.sendCommand(name, values);\n    this.removeCommand(name);\n};\n\n/**\n * Removes presence command.\n * @param name {String} the name of the command.\n **/\nJitsiConference.prototype.removeCommand = function(name) {\n    if (this.room) {\n        this.room.removeFromPresence(name);\n    }\n};\n\n/**\n * Sets the display name for this conference.\n * @param name the display name to set\n */\nJitsiConference.prototype.setDisplayName = function(name) {\n    if (this.room) {\n        const nickKey = 'nick';\n\n        // if there is no display name already set, avoid setting an empty one\n        if (!name && !this.room.getFromPresence(nickKey)) {\n            return;\n        }\n\n        this.room.addOrReplaceInPresence(nickKey, {\n            attributes: { xmlns: 'http://jabber.org/protocol/nick' },\n            value: name\n        }) && this.room.sendPresence();\n    }\n};\n\n/**\n * Set new subject for this conference. (available only for moderator)\n * @param {string} subject new subject\n */\nJitsiConference.prototype.setSubject = function(subject) {\n    if (this.room && this.isModerator()) {\n        this.room.setSubject(subject);\n    } else {\n        logger.warn(`Failed to set subject, ${this.room ? '' : 'not in a room, '}${\n            this.isModerator() ? '' : 'participant is not a moderator'}`);\n    }\n};\n\n/**\n * Get a transcriber object for all current participants in this conference\n * @return {Transcriber} the transcriber object\n */\nJitsiConference.prototype.getTranscriber = function() {\n    if (this.transcriber === undefined) {\n        this.transcriber = new Transcriber();\n\n        // add all existing local audio tracks to the transcriber\n        const localAudioTracks = this.getLocalTracks(MediaType.AUDIO);\n\n        for (const localAudio of localAudioTracks) {\n            this.transcriber.addTrack(localAudio);\n        }\n\n        // and all remote audio tracks\n        const remoteAudioTracks = this.rtc.getRemoteTracks(MediaType.AUDIO);\n\n        for (const remoteTrack of remoteAudioTracks) {\n            this.transcriber.addTrack(remoteTrack);\n        }\n    }\n\n    return this.transcriber;\n};\n\n/**\n * Returns the transcription status.\n *\n * @returns {String} \"on\" or \"off\".\n */\nJitsiConference.prototype.getTranscriptionStatus = function() {\n    return this.room.transcriptionStatus;\n};\n\n/**\n * Adds JitsiLocalTrack object to the conference.\n * @param {JitsiLocalTrack} track the JitsiLocalTrack object.\n * @returns {Promise<JitsiLocalTrack>}\n * @throws {Error} if the specified track is a video track and there is already\n * another video track in the conference.\n */\nJitsiConference.prototype.addTrack = function(track) {\n    const mediaType = track.getType();\n    const localTracks = this.rtc.getLocalTracks(mediaType);\n\n    // Ensure there's exactly 1 local track of each media type in the conference.\n    if (localTracks.length > 0) {\n        // Don't be excessively harsh and severe if the API client happens to attempt to add the same local track twice.\n        if (track === localTracks[0]) {\n            return Promise.resolve(track);\n        }\n\n        if (FeatureFlags.isMultiStreamSupportEnabled() && mediaType === MediaType.VIDEO) {\n            const addTrackPromises = [];\n\n            this.p2pJingleSession && addTrackPromises.push(this.p2pJingleSession.addTrack(track));\n            this.jvbJingleSession && addTrackPromises.push(this.jvbJingleSession.addTrack(track));\n\n            return Promise.all(addTrackPromises)\n                .then(() => {\n                    this._setupNewTrack(track);\n\n                    // TODO Update presence and sent videoType message.\n                    if (this.isMutedByFocus || this.isVideoMutedByFocus) {\n                        this._fireMuteChangeEvent(track);\n                    }\n                });\n        }\n\n        return Promise.reject(new Error(`Cannot add second ${mediaType} track to the conference`));\n    }\n\n    return this.replaceTrack(null, track);\n};\n\n/**\n * Fires TRACK_AUDIO_LEVEL_CHANGED change conference event (for local tracks).\n * @param {number} audioLevel the audio level\n * @param {TraceablePeerConnection} [tpc]\n */\nJitsiConference.prototype._fireAudioLevelChangeEvent = function(audioLevel, tpc) {\n    const activeTpc = this.getActivePeerConnection();\n\n    // There will be no TraceablePeerConnection if audio levels do not come from\n    // a peerconnection. LocalStatsCollector.js measures audio levels using Web\n    // Audio Analyser API and emits local audio levels events through\n    // JitsiTrack.setAudioLevel, but does not provide TPC instance which is\n    // optional.\n    if (!tpc || activeTpc === tpc) {\n        this.eventEmitter.emit(\n            JitsiConferenceEvents.TRACK_AUDIO_LEVEL_CHANGED,\n            this.myUserId(), audioLevel);\n    }\n};\n\n/**\n * Fires TRACK_MUTE_CHANGED change conference event.\n * @param track the JitsiTrack object related to the event.\n */\nJitsiConference.prototype._fireMuteChangeEvent = function(track) {\n    // check if track was muted by focus and now is unmuted by user\n    if (this.isMutedByFocus && track.isAudioTrack() && !track.isMuted()) {\n        this.isMutedByFocus = false;\n\n        // unmute local user on server\n        this.room.muteParticipant(this.room.myroomjid, false, MediaType.AUDIO);\n    } else if (this.isVideoMutedByFocus && track.isVideoTrack() && !track.isMuted()) {\n        this.isVideoMutedByFocus = false;\n\n        // unmute local user on server\n        this.room.muteParticipant(this.room.myroomjid, false, MediaType.VIDEO);\n    }\n\n    let actorParticipant;\n\n    if (this.mutedByFocusActor && track.isAudioTrack()) {\n        const actorId = Strophe.getResourceFromJid(this.mutedByFocusActor);\n\n        actorParticipant = this.participants[actorId];\n    } else if (this.mutedVideoByFocusActor && track.isVideoTrack()) {\n        const actorId = Strophe.getResourceFromJid(this.mutedVideoByFocusActor);\n\n        actorParticipant = this.participants[actorId];\n    }\n\n    // Send the video type message to the bridge if the track is not removed/added to the pc as part of\n    // the mute/unmute operation. This currently happens only on Firefox.\n    if (track.isVideoTrack() && !browser.doesVideoMuteByStreamRemove()) {\n        this._sendBridgeVideoTypeMessage(track);\n    }\n\n    this.eventEmitter.emit(JitsiConferenceEvents.TRACK_MUTE_CHANGED, track, actorParticipant);\n};\n\n/**\n * Returns the list of local tracks that need to be added to the peerconnection on join.\n * This takes the startAudioMuted/startVideoMuted flags into consideration since we do not\n * want to add the tracks if the user joins the call audio/video muted. The tracks will be\n * added when the user unmutes for the first time.\n * @returns {Array<JitsiLocalTrack>} - list of local tracks that are unmuted.\n */\nJitsiConference.prototype._getInitialLocalTracks = function() {\n    // Always add the audio track on certain platforms:\n    //  * Safari / WebKit: because of a known issue where audio playout doesn't happen\n    //    if the user joins audio and video muted.\n    //  * React Native: after iOS 15, if a user joins muted they won't be able to unmute.\n    return this.getLocalTracks()\n        .filter(track => {\n            const trackType = track.getType();\n\n            if (trackType === MediaType.AUDIO\n                    && (!this.isStartAudioMuted() || browser.isWebKitBased() || browser.isReactNative())) {\n                return true;\n            } else if (trackType === MediaType.VIDEO && !this.isStartVideoMuted()) {\n                return true;\n            }\n\n            return false;\n        });\n};\n\n/**\n * Clear JitsiLocalTrack properties and listeners.\n * @param track the JitsiLocalTrack object.\n */\nJitsiConference.prototype.onLocalTrackRemoved = function(track) {\n    track.setConference(null);\n    this.rtc.removeLocalTrack(track);\n    track.removeEventListener(JitsiTrackEvents.TRACK_MUTE_CHANGED, track.muteHandler);\n    if (track.isAudioTrack()) {\n        track.removeEventListener(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED, track.audioLevelHandler);\n    }\n\n    // send event for stopping screen sharing\n    // FIXME: we assume we have only one screen sharing track\n    // if we change this we need to fix this check\n    if (track.isVideoTrack() && track.videoType === VideoType.DESKTOP) {\n        this.statistics.sendScreenSharingEvent(false);\n    }\n\n    this.eventEmitter.emit(JitsiConferenceEvents.TRACK_REMOVED, track);\n};\n\n/**\n * Removes JitsiLocalTrack from the conference and performs\n * a new offer/answer cycle.\n * @param {JitsiLocalTrack} track\n * @returns {Promise}\n */\nJitsiConference.prototype.removeTrack = function(track) {\n    return this.replaceTrack(track, null);\n};\n\n/**\n * Replaces oldTrack with newTrack and performs a single offer/answer\n *  cycle after both operations are done.  Either oldTrack or newTrack\n *  can be null; replacing a valid 'oldTrack' with a null 'newTrack'\n *  effectively just removes 'oldTrack'\n * @param {JitsiLocalTrack} oldTrack the current stream in use to be replaced\n * @param {JitsiLocalTrack} newTrack the new stream to use\n * @returns {Promise} resolves when the replacement is finished\n */\nJitsiConference.prototype.replaceTrack = function(oldTrack, newTrack) {\n    const oldVideoType = oldTrack?.getVideoType();\n    const newVideoType = newTrack?.getVideoType();\n\n    if (FeatureFlags.isMultiStreamSupportEnabled() && oldTrack && newTrack && oldVideoType !== newVideoType) {\n        throw new Error(`Replacing a track of videoType=${oldVideoType} with a track of videoType=${newVideoType} is`\n            + ' not supported in this mode.');\n    }\n    const oldTrackBelongsToConference = this === oldTrack?.conference;\n\n    if (oldTrackBelongsToConference && oldTrack.disposed) {\n        return Promise.reject(new JitsiTrackError(JitsiTrackErrors.TRACK_IS_DISPOSED));\n    }\n    if (newTrack?.disposed) {\n        return Promise.reject(new JitsiTrackError(JitsiTrackErrors.TRACK_IS_DISPOSED));\n    }\n\n    if (oldTrack && !oldTrackBelongsToConference) {\n        logger.warn(`JitsiConference.replaceTrack oldTrack (${oldTrack} does not belong to this conference`);\n    }\n\n    // Now replace the stream at the lower levels\n    return this._doReplaceTrack(oldTrackBelongsToConference ? oldTrack : null, newTrack)\n        .then(() => {\n            oldTrackBelongsToConference && this.onLocalTrackRemoved(oldTrack);\n            newTrack && this._setupNewTrack(newTrack);\n\n            // Send 'VideoTypeMessage' on the bridge channel when a video track is added/removed.\n            if ((oldTrackBelongsToConference && oldTrack?.isVideoTrack()) || newTrack?.isVideoTrack()) {\n                this._sendBridgeVideoTypeMessage(newTrack);\n            }\n\n            // updates presence when we replace the video tracks desktop with screen and screen with desktop\n            if (oldTrackBelongsToConference && oldTrack?.isVideoTrack()\n\n                // we do not want to send presence update during setEffect switching, which does remove and then add\n                && !(oldTrack?._setEffectInProgress || newTrack?._setEffectInProgress)) {\n                this._updateRoomPresence(this.getActiveMediaSession());\n            }\n\n            if (newTrack !== null && (this.isMutedByFocus || this.isVideoMutedByFocus)) {\n                this._fireMuteChangeEvent(newTrack);\n            }\n\n            return Promise.resolve();\n        })\n        .catch(error => {\n            logger.error(`replaceTrack failed: ${error?.stack}`);\n\n            return Promise.reject(error);\n        });\n};\n\n/**\n * Replaces the tracks at the lower level by going through the Jingle session\n * and WebRTC peer connection. The method will resolve immediately if there is\n * currently no JingleSession started.\n * @param {JitsiLocalTrack|null} oldTrack the track to be removed during\n * the process or <tt>null</t> if the method should act as \"add track\"\n * @param {JitsiLocalTrack|null} newTrack the new track to be added or\n * <tt>null</tt> if the method should act as \"remove track\"\n * @return {Promise} resolved when the process is done or rejected with a string\n * which describes the error.\n * @private\n */\nJitsiConference.prototype._doReplaceTrack = function(oldTrack, newTrack) {\n    const replaceTrackPromises = [];\n\n    if (this.jvbJingleSession) {\n        replaceTrackPromises.push(this.jvbJingleSession.replaceTrack(oldTrack, newTrack));\n    } else {\n        logger.info('_doReplaceTrack - no JVB JingleSession');\n    }\n\n    if (this.p2pJingleSession) {\n        replaceTrackPromises.push(this.p2pJingleSession.replaceTrack(oldTrack, newTrack));\n    } else {\n        logger.info('_doReplaceTrack - no P2P JingleSession');\n    }\n\n    return Promise.all(replaceTrackPromises);\n};\n\n/**\n * Handler for when a source-add for a local source is rejected by Jicofo.\n *\n * @param {JingleSessionPC} jingleSession - The media session.\n * @param {Error} error - The error message.\n * @param {MediaType} mediaType - The media type of the track associated with the source that was rejected.\n * @returns {void}\n */\nJitsiConference.prototype._removeLocalSourceOnReject = function(jingleSession, error, mediaType) {\n    if (!jingleSession) {\n        return;\n    }\n    logger.warn(`Source-add rejected on ${jingleSession}, reason=\"${error?.reason}\", message=\"${error?.msg}\"`);\n    const track = this.getLocalTracks(mediaType)[0];\n\n    this.eventEmitter.emit(JitsiConferenceEvents.TRACK_UNMUTE_REJECTED, track);\n};\n\n/**\n * Operations related to creating a new track\n * @param {JitsiLocalTrack} newTrack the new track being created\n */\nJitsiConference.prototype._setupNewTrack = function(newTrack) {\n    const mediaType = newTrack.getType();\n\n    if (newTrack.isAudioTrack() || (newTrack.isVideoTrack() && newTrack.videoType !== VideoType.DESKTOP)) {\n        // Report active device to statistics\n        const devices = RTC.getCurrentlyAvailableMediaDevices();\n        const device = devices\n            .find(d => d.kind === `${newTrack.getTrack().kind}input` && d.label === newTrack.getTrack().label);\n\n        if (device) {\n            Statistics.sendActiveDeviceListEvent(RTC.getEventDataForActiveDevice(device));\n        }\n    }\n\n    // Create a source name for this track if it doesn't exist.\n    if (FeatureFlags.isSourceNameSignalingEnabled() && !newTrack.getSourceName()) {\n        const sourceName = getSourceNameForJitsiTrack(\n            this.myUserId(),\n            mediaType,\n            this.getLocalTracks(mediaType)?.length);\n\n        newTrack.setSourceName(sourceName);\n    }\n\n    this.rtc.addLocalTrack(newTrack);\n    newTrack.setConference(this);\n\n    // Add event handlers.\n    newTrack.muteHandler = this._fireMuteChangeEvent.bind(this, newTrack);\n    newTrack.addEventListener(JitsiTrackEvents.TRACK_MUTE_CHANGED, newTrack.muteHandler);\n\n    if (newTrack.isAudioTrack()) {\n        newTrack.audioLevelHandler = this._fireAudioLevelChangeEvent.bind(this);\n        newTrack.addEventListener(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED, newTrack.audioLevelHandler);\n    }\n\n    this.eventEmitter.emit(JitsiConferenceEvents.TRACK_ADDED, newTrack);\n};\n\n/**\n * Sets the video type.\n * @param track\n * @return <tt>true</tt> if video type was changed in presence.\n * @private\n */\nJitsiConference.prototype._setNewVideoType = function(track) {\n    let videoTypeChanged = false;\n\n    if (FeatureFlags.isSourceNameSignalingEnabled() && track) {\n        videoTypeChanged = this._signalingLayer.setTrackVideoType(track.getSourceName(), track.videoType);\n    }\n\n    if (!FeatureFlags.isMultiStreamSupportEnabled()) {\n        const videoTypeTagName = 'videoType';\n\n        // If track is missing we revert to default type Camera, the case where we screenshare and\n        // we return to be video muted.\n        const trackVideoType = track ? track.videoType : VideoType.CAMERA;\n\n        // If video type is camera and there is no videoType in presence, we skip adding it, as this is the default one\n        if (trackVideoType !== VideoType.CAMERA || this.room.getFromPresence(videoTypeTagName)) {\n            // We will not use this.sendCommand here to avoid sending the presence immediately, as later we may also\n            // set the mute status.\n            const legacyTypeChanged = this.room.addOrReplaceInPresence(videoTypeTagName, { value: trackVideoType });\n\n            videoTypeChanged = videoTypeChanged || legacyTypeChanged;\n        }\n    }\n\n    return videoTypeChanged;\n};\n\n/**\n * Sets mute status.\n * @param mediaType\n * @param localTrack\n * @param isMuted\n * @param <tt>true</tt> when presence was changed, <tt>false</tt> otherwise.\n * @private\n */\nJitsiConference.prototype._setTrackMuteStatus = function(mediaType, localTrack, isMuted) {\n    let presenceChanged = false;\n\n    if (FeatureFlags.isSourceNameSignalingEnabled() && localTrack) {\n        presenceChanged = this._signalingLayer.setTrackMuteStatus(localTrack.getSourceName(), isMuted);\n    }\n\n    // Add the 'audioMuted' and 'videoMuted' tags when source name signaling is enabled for backward compatibility.\n    // It won't be used anymore when multiple stream support is enabled.\n    if (!FeatureFlags.isMultiStreamSupportEnabled()) {\n        let audioMuteChanged, videoMuteChanged;\n\n        if (!this.room) {\n            return false;\n        }\n\n        if (mediaType === MediaType.AUDIO) {\n            audioMuteChanged = this.room.addAudioInfoToPresence(isMuted);\n        } else {\n            videoMuteChanged = this.room.addVideoInfoToPresence(isMuted);\n        }\n\n        presenceChanged = presenceChanged || audioMuteChanged || videoMuteChanged;\n    }\n\n    return presenceChanged;\n};\n\n/**\n * Method called by the {@link JitsiLocalTrack} (a video one) in order to add\n * back the underlying WebRTC MediaStream to the PeerConnection (which has\n * removed on video mute).\n * @param {JitsiLocalTrack} track the local track that will be added as part of\n * the unmute operation.\n * @return {Promise} resolved when the process is done or rejected with a string\n * which describes the error.\n */\nJitsiConference.prototype._addLocalTrackAsUnmute = function(track) {\n    const addAsUnmutePromises = [];\n\n    if (this.jvbJingleSession) {\n        addAsUnmutePromises.push(this.jvbJingleSession.addTrackAsUnmute(track));\n    } else {\n        logger.debug('Add local MediaStream as unmute - no JVB Jingle session started yet');\n    }\n\n    if (this.p2pJingleSession) {\n        addAsUnmutePromises.push(this.p2pJingleSession.addTrackAsUnmute(track));\n    } else {\n        logger.debug('Add local MediaStream as unmute - no P2P Jingle session started yet');\n    }\n\n    return Promise.allSettled(addAsUnmutePromises);\n};\n\n/**\n * Method called by the {@link JitsiLocalTrack} (a video one) in order to remove\n * the underlying WebRTC MediaStream from the PeerConnection. The purpose of\n * that is to stop sending any data and turn off the HW camera device.\n * @param {JitsiLocalTrack} track the local track that will be removed.\n * @return {Promise}\n */\nJitsiConference.prototype._removeLocalTrackAsMute = function(track) {\n    const removeAsMutePromises = [];\n\n    if (this.jvbJingleSession) {\n        removeAsMutePromises.push(this.jvbJingleSession.removeTrackAsMute(track));\n    } else {\n        logger.debug('Remove local MediaStream - no JVB JingleSession started yet');\n    }\n    if (this.p2pJingleSession) {\n        removeAsMutePromises.push(this.p2pJingleSession.removeTrackAsMute(track));\n    } else {\n        logger.debug('Remove local MediaStream - no P2P JingleSession started yet');\n    }\n\n    return Promise.allSettled(removeAsMutePromises);\n};\n\n/**\n * Get role of the local user.\n * @returns {string} user role: 'moderator' or 'none'\n */\nJitsiConference.prototype.getRole = function() {\n    return this.room.role;\n};\n\n/**\n * Returns whether or not the current conference has been joined as a hidden\n * user.\n *\n * @returns {boolean|null} True if hidden, false otherwise. Will return null if\n * no connection is active.\n */\nJitsiConference.prototype.isHidden = function() {\n    if (!this.connection) {\n        return null;\n    }\n\n    return Strophe.getDomainFromJid(this.connection.getJid())\n        === this.options.config.hiddenDomain;\n};\n\n/**\n * Check if local user is moderator.\n * @returns {boolean|null} true if local user is moderator, false otherwise. If\n * we're no longer in the conference room then <tt>null</tt> is returned.\n */\nJitsiConference.prototype.isModerator = function() {\n    return this.room ? this.room.isModerator() : null;\n};\n\n/**\n * Set password for the room.\n * @param {string} password new password for the room.\n * @returns {Promise}\n */\nJitsiConference.prototype.lock = function(password) {\n    if (!this.isModerator()) {\n        return Promise.reject(new Error('You are not moderator.'));\n    }\n\n    return new Promise((resolve, reject) => {\n        this.room.lockRoom(\n            password || '',\n            () => resolve(),\n            err => reject(err),\n            () => reject(JitsiConferenceErrors.PASSWORD_NOT_SUPPORTED));\n    });\n};\n\n/**\n * Remove password from the room.\n * @returns {Promise}\n */\nJitsiConference.prototype.unlock = function() {\n    return this.lock();\n};\n\n/**\n * Elects the participant with the given id to be the selected participant in\n * order to receive higher video quality (if simulcast is enabled).\n * Or cache it if channel is not created and send it once channel is available.\n * @param participantId the identifier of the participant\n * @throws NetworkError or InvalidStateError or Error if the operation fails.\n * @returns {void}\n */\nJitsiConference.prototype.selectParticipant = function(participantId) {\n    this.selectParticipants([ participantId ]);\n};\n\n/*\n * Elects participants with given ids to be the selected participants in order\n * to receive higher video quality (if simulcast is enabled). The argument\n * should be an array of participant id strings or an empty array; an error will\n * be thrown if a non-array is passed in. The error is thrown as a layer of\n * protection against passing an invalid argument, as the error will happen in\n * the bridge and may not be visible in the client.\n *\n * @param {Array<strings>} participantIds - An array of identifiers for\n * participants.\n * @returns {void}\n */\nJitsiConference.prototype.selectParticipants = function(participantIds) {\n    if (!Array.isArray(participantIds)) {\n        throw new Error('Invalid argument; participantIds must be an array.');\n    }\n\n    this.receiveVideoController.selectEndpoints(participantIds);\n};\n\n/**\n * Obtains the current value for \"lastN\". See {@link setLastN} for more info.\n * @returns {number}\n */\nJitsiConference.prototype.getLastN = function() {\n    return this.receiveVideoController.getLastN();\n};\n\n/**\n * Obtains the forwarded sources list in this conference.\n * @return {Array<string>|null}\n */\nJitsiConference.prototype.getForwardedSources = function() {\n    return this.rtc.getForwardedSources();\n};\n\n/**\n * Selects a new value for \"lastN\". The requested amount of videos are going\n * to be delivered after the value is in effect. Set to -1 for unlimited or\n * all available videos.\n * @param lastN the new number of videos the user would like to receive.\n * @throws Error or RangeError if the given value is not a number or is smaller\n * than -1.\n */\nJitsiConference.prototype.setLastN = function(lastN) {\n    if (!Number.isInteger(lastN) && !Number.parseInt(lastN, 10)) {\n        throw new Error(`Invalid value for lastN: ${lastN}`);\n    }\n    const n = Number(lastN);\n\n    if (n < -1) {\n        throw new RangeError('lastN cannot be smaller than -1');\n    }\n    this.receiveVideoController.setLastN(n);\n\n    // If the P2P session is not fully established yet, we wait until it gets\n    // established.\n    if (this.p2pJingleSession) {\n        const isVideoActive = n !== 0;\n\n        this.p2pJingleSession\n            .setMediaTransferActive(true, isVideoActive)\n            .catch(error => {\n                logger.error(\n                    `Failed to adjust video transfer status (${isVideoActive})`,\n                    error);\n            });\n    }\n};\n\n/**\n * Checks if the participant given by participantId is currently included in\n * the last N.\n * @param {string} participantId the identifier of the participant we would\n * like to check.\n * @return {boolean} true if the participant with id is in the last N set or\n * if there's no last N set, false otherwise.\n * @deprecated this method should never be used to figure out the UI, but\n * {@link ParticipantConnectionStatus} should be used instead.\n */\nJitsiConference.prototype.isInLastN = function(participantId) {\n    return this.rtc.isInLastN(participantId);\n};\n\n/**\n * @return Array<JitsiParticipant> an array of all participants in this\n * conference.\n */\nJitsiConference.prototype.getParticipants = function() {\n    return Object.values(this.participants);\n};\n\n/**\n * Returns the number of participants in the conference, including the local\n * participant.\n * @param countHidden {boolean} Whether or not to include hidden participants\n * in the count. Default: false.\n **/\nJitsiConference.prototype.getParticipantCount = function(countHidden = false) {\n    let participants = this.getParticipants();\n\n    if (!countHidden) {\n        participants = participants.filter(p => !p.isHidden());\n    }\n\n    // Add one for the local participant.\n    return participants.length + 1;\n};\n\n/**\n * @returns {JitsiParticipant} the participant in this conference with the\n * specified id (or undefined if there isn't one).\n * @param id the id of the participant.\n */\nJitsiConference.prototype.getParticipantById = function(id) {\n    return this.participants[id];\n};\n\n/**\n * Grant owner rights to the participant.\n * @param {string} id id of the participant to grant owner rights to.\n */\nJitsiConference.prototype.grantOwner = function(id) {\n    const participant = this.getParticipantById(id);\n\n    if (!participant) {\n        return;\n    }\n    this.room.setAffiliation(participant.getJid(), 'owner');\n};\n\n/**\n * Revoke owner rights to the participant or local Participant as\n * the user might want to refuse to be a moderator.\n * @param {string} id id of the participant to revoke owner rights to.\n */\nJitsiConference.prototype.revokeOwner = function(id) {\n    const participant = this.getParticipantById(id);\n    const isMyself = this.myUserId() === id;\n    const role = this.isMembersOnly() ? 'member' : 'none';\n\n    if (isMyself) {\n        this.room.setAffiliation(this.room.myroomjid, role);\n    } else if (participant) {\n        this.room.setAffiliation(participant.getJid(), role);\n    }\n};\n\n\n/**\n * Kick participant from this conference.\n * @param {string} id id of the participant to kick\n * @param {string} reason reason of the participant to kick\n */\nJitsiConference.prototype.kickParticipant = function(id, reason) {\n    const participant = this.getParticipantById(id);\n\n    if (!participant) {\n        return;\n    }\n    this.room.kick(participant.getJid(), reason);\n};\n\n/**\n * Maybe clears the timeout which emits {@link ACTION_JINGLE_SI_TIMEOUT}\n * analytics event.\n * @private\n */\nJitsiConference.prototype._maybeClearSITimeout = function() {\n    if (this._sessionInitiateTimeout\n            && (this.jvbJingleSession || this.getParticipantCount() < 2)) {\n        window.clearTimeout(this._sessionInitiateTimeout);\n        this._sessionInitiateTimeout = null;\n    }\n};\n\n/**\n * Sets a timeout which will emit {@link ACTION_JINGLE_SI_TIMEOUT} analytics\n * event.\n * @private\n */\nJitsiConference.prototype._maybeSetSITimeout = function() {\n    // Jicofo is supposed to invite if there are at least 2 participants\n    if (!this.jvbJingleSession\n            && this.getParticipantCount() >= 2\n            && !this._sessionInitiateTimeout) {\n        this._sessionInitiateTimeout = window.setTimeout(() => {\n            this._sessionInitiateTimeout = null;\n            Statistics.sendAnalytics(createJingleEvent(\n                ACTION_JINGLE_SI_TIMEOUT,\n                {\n                    p2p: false,\n                    value: JINGLE_SI_TIMEOUT\n                }));\n        }, JINGLE_SI_TIMEOUT);\n    }\n};\n\n/**\n * Mutes a participant.\n * @param {string} id The id of the participant to mute.\n */\nJitsiConference.prototype.muteParticipant = function(id, mediaType) {\n    const muteMediaType = mediaType ? mediaType : MediaType.AUDIO;\n\n    if (muteMediaType !== MediaType.AUDIO && muteMediaType !== MediaType.VIDEO) {\n        logger.error(`Unsupported media type: ${muteMediaType}`);\n\n        return;\n    }\n\n    const participant = this.getParticipantById(id);\n\n    if (!participant) {\n        return;\n    }\n    this.room.muteParticipant(participant.getJid(), true, muteMediaType);\n};\n\n/* eslint-disable max-params */\n\n/**\n * Notifies this JitsiConference that a new member has joined its chat room.\n *\n * FIXME This should NOT be exposed!\n *\n * @param jid the jid of the participant in the MUC\n * @param nick the display name of the participant\n * @param role the role of the participant in the MUC\n * @param isHidden indicates if this is a hidden participant (system\n * participant for example a recorder).\n * @param statsID the participant statsID (optional)\n * @param status the initial status if any\n * @param identity the member identity, if any\n * @param botType the member botType, if any\n * @param fullJid the member full jid, if any\n * @param features the member botType, if any\n * @param isReplaceParticipant whether this join replaces a participant with\n * the same jwt.\n */\nJitsiConference.prototype.onMemberJoined = function(\n        jid, nick, role, isHidden, statsID, status, identity, botType, fullJid, features, isReplaceParticipant) {\n    const id = Strophe.getResourceFromJid(jid);\n\n    if (id === 'focus' || this.myUserId() === id) {\n        return;\n    }\n\n    const participant\n        = new JitsiParticipant(jid, this, nick, isHidden, statsID, status, identity);\n\n    participant.setRole(role);\n    participant.setBotType(botType);\n    participant.setFeatures(features);\n    participant.setIsReplacing(isReplaceParticipant);\n\n    this.participants[id] = participant;\n    this.eventEmitter.emit(\n        JitsiConferenceEvents.USER_JOINED,\n        id,\n        participant);\n\n    this._updateFeatures(participant);\n\n    // maybeStart only if we had finished joining as then we will have information for the number of participants\n    if (this.isJoined()) {\n        this._maybeStartOrStopP2P();\n    }\n\n    this._maybeSetSITimeout();\n};\n\n/* eslint-enable max-params */\n\n/**\n * Get notified when we joined the room.\n *\n * FIXME This should NOT be exposed!\n *\n * @private\n */\nJitsiConference.prototype._onMucJoined = function() {\n    this._maybeStartOrStopP2P();\n};\n\n/**\n * Updates features for a participant.\n * @param {JitsiParticipant} participant - The participant to query for features.\n * @returns {void}\n * @private\n */\nJitsiConference.prototype._updateFeatures = function(participant) {\n    participant.getFeatures()\n        .then(features => {\n            participant._supportsDTMF = features.has('urn:xmpp:jingle:dtmf:0');\n            this.updateDTMFSupport();\n\n            if (features.has(FEATURE_JIGASI)) {\n                participant.setProperty('features_jigasi', true);\n            }\n\n            if (features.has(FEATURE_E2EE)) {\n                participant.setProperty('features_e2ee', true);\n            }\n        })\n        .catch(() => false);\n};\n\n/**\n * Get notified when member bot type had changed.\n * @param jid the member jid\n * @param botType the new botType value\n * @private\n */\nJitsiConference.prototype._onMemberBotTypeChanged = function(jid, botType) {\n\n    // find the participant and mark it as non bot, as the real one will join\n    // in a moment\n    const peers = this.getParticipants();\n    const botParticipant = peers.find(p => p.getJid() === jid);\n\n    if (botParticipant) {\n        botParticipant.setBotType(botType);\n        const id = Strophe.getResourceFromJid(jid);\n\n        this.eventEmitter.emit(\n            JitsiConferenceEvents.BOT_TYPE_CHANGED,\n            id,\n            botType);\n    }\n\n    // if botType changed to undefined, botType was removed, in case of\n    // poltergeist mode this is the moment when the poltergeist had exited and\n    // the real participant had already replaced it.\n    // In this case we can check and try p2p\n    if (!botParticipant.getBotType()) {\n        this._maybeStartOrStopP2P();\n    }\n};\n\nJitsiConference.prototype.onMemberLeft = function(jid) {\n    const id = Strophe.getResourceFromJid(jid);\n\n    if (id === 'focus' || this.myUserId() === id) {\n        return;\n    }\n\n    const participant = this.participants[id];\n    const mediaSessions = this.getMediaSessions();\n    let tracksToBeRemoved = [];\n\n    for (const session of mediaSessions) {\n        const remoteTracks = session.peerconnection.getRemoteTracks(id);\n\n        remoteTracks && (tracksToBeRemoved = [ ...tracksToBeRemoved, ...remoteTracks ]);\n\n        // Remove the ssrcs from the remote description and renegotiate.\n        session.removeRemoteStreamsOnLeave(id);\n    }\n\n    // Fire the event before renegotiation is done so that the thumbnails can be removed immediately.\n    tracksToBeRemoved.forEach(track => {\n        this.eventEmitter.emit(JitsiConferenceEvents.TRACK_REMOVED, track);\n    });\n\n    if (participant) {\n        delete this.participants[id];\n        this.eventEmitter.emit(JitsiConferenceEvents.USER_LEFT, id, participant);\n    }\n\n    if (this.room !== null) { // Skip if we have left the room already.\n        this._maybeStartOrStopP2P(true /* triggered by user left event */);\n        this._maybeClearSITimeout();\n    }\n};\n\n/* eslint-disable max-params */\n\n/**\n * Designates an event indicating that we were kicked from the XMPP MUC.\n * @param {boolean} isSelfPresence - whether it is for local participant\n * or another participant.\n * @param {string} actorId - the id of the participant who was initiator\n * of the kick.\n * @param {string?} kickedParticipantId - when it is not a kick for local participant,\n * this is the id of the participant which was kicked.\n * @param {string} reason - reason of the participant to kick\n * @param {boolean?} isReplaceParticipant - whether this is a server initiated kick in order\n * to replace it with a participant with same jwt.\n */\nJitsiConference.prototype.onMemberKicked = function(\n        isSelfPresence,\n        actorId,\n        kickedParticipantId,\n        reason,\n        isReplaceParticipant) {\n    // This check which be true when we kick someone else. With the introduction of lobby\n    // the ChatRoom KICKED event is now also emitted for ourselves (the kicker) so we want to\n    // avoid emitting an event where `undefined` kicked someone.\n    if (actorId === this.myUserId()) {\n        return;\n    }\n\n    const actorParticipant = this.participants[actorId];\n\n    if (isSelfPresence) {\n        this.eventEmitter.emit(\n            JitsiConferenceEvents.KICKED, actorParticipant, reason, isReplaceParticipant);\n\n        this.leave();\n\n        return;\n    }\n\n    const kickedParticipant = this.participants[kickedParticipantId];\n\n    kickedParticipant.setIsReplaced(isReplaceParticipant);\n\n    this.eventEmitter.emit(\n        JitsiConferenceEvents.PARTICIPANT_KICKED, actorParticipant, kickedParticipant, reason);\n};\n\n/**\n * Method called on local MUC role change.\n * @param {string} role the name of new user's role as defined by XMPP MUC.\n */\nJitsiConference.prototype.onLocalRoleChanged = function(role) {\n    // Emit role changed for local  JID\n    this.eventEmitter.emit(\n        JitsiConferenceEvents.USER_ROLE_CHANGED, this.myUserId(), role);\n};\n\nJitsiConference.prototype.onUserRoleChanged = function(jid, role) {\n    const id = Strophe.getResourceFromJid(jid);\n    const participant = this.getParticipantById(id);\n\n    if (!participant) {\n        return;\n    }\n    participant.setRole(role);\n    this.eventEmitter.emit(JitsiConferenceEvents.USER_ROLE_CHANGED, id, role);\n};\n\nJitsiConference.prototype.onDisplayNameChanged = function(jid, displayName) {\n    const id = Strophe.getResourceFromJid(jid);\n    const participant = this.getParticipantById(id);\n\n    if (!participant) {\n        return;\n    }\n\n    if (participant._displayName === displayName) {\n        return;\n    }\n\n    participant._displayName = displayName;\n    this.eventEmitter.emit(\n        JitsiConferenceEvents.DISPLAY_NAME_CHANGED,\n        id,\n        displayName);\n};\n\n/**\n * Notifies this JitsiConference that a JitsiRemoteTrack was added to the conference.\n *\n * @param {JitsiRemoteTrack} track the JitsiRemoteTrack which was added to this JitsiConference.\n */\nJitsiConference.prototype.onRemoteTrackAdded = function(track) {\n    if (track.isP2P && !this.isP2PActive()) {\n        logger.info('Trying to add remote P2P track, when not in P2P - IGNORED');\n\n        return;\n    } else if (!track.isP2P && this.isP2PActive()) {\n        logger.info('Trying to add remote JVB track, when in P2P - IGNORED');\n\n        return;\n    }\n\n    const id = track.getParticipantId();\n    const participant = this.getParticipantById(id);\n\n    if (!participant) {\n        logger.error(`No participant found for id: ${id}`);\n\n        return;\n    }\n\n    // Add track to JitsiParticipant.\n    participant._tracks.push(track);\n\n    if (this.transcriber) {\n        this.transcriber.addTrack(track);\n    }\n\n    const emitter = this.eventEmitter;\n\n    track.addEventListener(\n        JitsiTrackEvents.TRACK_MUTE_CHANGED,\n        () => emitter.emit(JitsiConferenceEvents.TRACK_MUTE_CHANGED, track));\n    track.isAudioTrack() && track.addEventListener(\n        JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED,\n        (audioLevel, tpc) => {\n            const activeTPC = this.getActivePeerConnection();\n\n            if (activeTPC === tpc) {\n                emitter.emit(JitsiConferenceEvents.TRACK_AUDIO_LEVEL_CHANGED, id, audioLevel);\n            }\n        }\n    );\n\n    emitter.emit(JitsiConferenceEvents.TRACK_ADDED, track);\n};\n\n/**\n * Callback called by the Jingle plugin when 'session-answer' is received.\n * @param {JingleSessionPC} session the Jingle session for which an answer was\n * received.\n * @param {jQuery} answer a jQuery selector pointing to 'jingle' IQ element\n */\n// eslint-disable-next-line no-unused-vars\nJitsiConference.prototype.onCallAccepted = function(session, answer) {\n    if (this.p2pJingleSession === session) {\n        logger.info('P2P setAnswer');\n\n        this.p2pJingleSession.setAnswer(answer);\n        this.eventEmitter.emit(JitsiConferenceEvents._MEDIA_SESSION_STARTED, this.p2pJingleSession);\n    }\n};\n\n/**\n * Callback called by the Jingle plugin when 'transport-info' is received.\n * @param {JingleSessionPC} session the Jingle session for which the IQ was\n * received\n * @param {jQuery} transportInfo a jQuery selector pointing to 'jingle' IQ\n * element\n */\n// eslint-disable-next-line no-unused-vars\nJitsiConference.prototype.onTransportInfo = function(session, transportInfo) {\n    if (this.p2pJingleSession === session) {\n        logger.info('P2P addIceCandidates');\n        this.p2pJingleSession.addIceCandidates(transportInfo);\n    }\n};\n\n/**\n * Notifies this JitsiConference that a JitsiRemoteTrack was removed from\n * the conference.\n *\n * @param {JitsiRemoteTrack} removedTrack\n */\nJitsiConference.prototype.onRemoteTrackRemoved = function(removedTrack) {\n    this.getParticipants().forEach(participant => {\n        const tracks = participant.getTracks();\n\n        for (let i = 0; i < tracks.length; i++) {\n            if (tracks[i] === removedTrack) {\n                // Since the tracks have been compared and are\n                // considered equal the result of splice can be ignored.\n                participant._tracks.splice(i, 1);\n\n                this.eventEmitter.emit(JitsiConferenceEvents.TRACK_REMOVED, removedTrack);\n\n                if (this.transcriber) {\n                    this.transcriber.removeTrack(removedTrack);\n                }\n\n                break;\n            }\n        }\n    }, this);\n};\n\n/**\n * Handles an incoming call event for the P2P jingle session.\n */\nJitsiConference.prototype._onIncomingCallP2P = function(jingleSession, jingleOffer) {\n\n    let rejectReason;\n\n    if ((!this.isP2PEnabled() && !this.isP2PTestModeEnabled()) || browser.isFirefox() || browser.isWebKitBased()) {\n        rejectReason = {\n            reason: 'decline',\n            reasonDescription: 'P2P disabled',\n            errorMsg: 'P2P mode disabled in the configuration or browser unsupported'\n        };\n    } else if (this.p2pJingleSession) {\n        // Reject incoming P2P call (already in progress)\n        rejectReason = {\n            reason: 'busy',\n            reasonDescription: 'P2P already in progress',\n            errorMsg: 'Duplicated P2P \"session-initiate\"'\n        };\n    } else if (!this._shouldBeInP2PMode()) {\n        rejectReason = {\n            reason: 'decline',\n            reasonDescription: 'P2P requirements not met',\n            errorMsg: 'Received P2P \"session-initiate\" when should not be in P2P mode'\n        };\n        Statistics.sendAnalytics(createJingleEvent(ACTION_P2P_DECLINED));\n    }\n\n    if (rejectReason) {\n        this._rejectIncomingCall(jingleSession, rejectReason);\n    } else {\n        this._acceptP2PIncomingCall(jingleSession, jingleOffer);\n    }\n};\n\n/**\n * Handles an incoming call event.\n */\nJitsiConference.prototype.onIncomingCall = function(jingleSession, jingleOffer, now) {\n    // Handle incoming P2P call\n    if (jingleSession.isP2P) {\n        this._onIncomingCallP2P(jingleSession, jingleOffer);\n    } else {\n        if (!this.isFocus(jingleSession.remoteJid)) {\n            const description = 'Rejecting session-initiate from non-focus.';\n\n            this._rejectIncomingCall(\n                jingleSession, {\n                    reason: 'security-error',\n                    reasonDescription: description,\n                    errorMsg: description\n                });\n\n            return;\n        }\n        this._acceptJvbIncomingCall(jingleSession, jingleOffer, now);\n    }\n};\n\n/**\n * Accepts an incoming call event for the JVB jingle session.\n */\nJitsiConference.prototype._acceptJvbIncomingCall = function(jingleSession, jingleOffer, now) {\n\n    // Accept incoming call\n    this.jvbJingleSession = jingleSession;\n    this.room.connectionTimes['session.initiate'] = now;\n    this._sendConferenceJoinAnalyticsEvent();\n\n    if (this.wasStopped) {\n        Statistics.sendAnalyticsAndLog(createJingleEvent(ACTION_JINGLE_RESTART, { p2p: false }));\n    }\n\n    const serverRegion\n        = $(jingleOffer)\n            .find('>bridge-session[xmlns=\"http://jitsi.org/protocol/focus\"]')\n            .attr('region');\n\n    this.eventEmitter.emit(JitsiConferenceEvents.SERVER_REGION_CHANGED, serverRegion);\n\n    this._maybeClearSITimeout();\n    Statistics.sendAnalytics(createJingleEvent(\n        ACTION_JINGLE_SI_RECEIVED,\n        {\n            p2p: false,\n            value: now\n        }));\n\n    try {\n        jingleSession.initialize(\n            this.room,\n            this.rtc,\n            this._signalingLayer,\n            {\n                ...this.options.config,\n                enableInsertableStreams: this.isE2EEEnabled()\n            });\n    } catch (error) {\n        GlobalOnErrorHandler.callErrorHandler(error);\n        logger.error(error);\n\n        return;\n    }\n\n    // Open a channel with the videobridge.\n    this._setBridgeChannel(jingleOffer, jingleSession.peerconnection);\n\n    const localTracks = this._getInitialLocalTracks();\n\n    try {\n        jingleSession.acceptOffer(\n            jingleOffer,\n            () => {\n                // If for any reason invite for the JVB session arrived after\n                // the P2P has been established already the media transfer needs\n                // to be turned off here.\n                if (this.isP2PActive() && this.jvbJingleSession) {\n                    this._suspendMediaTransferForJvbConnection();\n                }\n\n                this.eventEmitter.emit(JitsiConferenceEvents._MEDIA_SESSION_STARTED, jingleSession);\n                if (!this.isP2PActive()) {\n                    this.eventEmitter.emit(JitsiConferenceEvents._MEDIA_SESSION_ACTIVE_CHANGED, jingleSession);\n                }\n            },\n            error => {\n                GlobalOnErrorHandler.callErrorHandler(error);\n                logger.error('Failed to accept incoming Jingle session', error);\n            },\n            localTracks\n        );\n\n        // Enable or disable simulcast for plan-b screensharing based on the capture fps if it is set through the UI.\n        this._desktopSharingFrameRate\n            && jingleSession.peerconnection.setDesktopSharingFrameRate(this._desktopSharingFrameRate);\n\n        // Start callstats as soon as peerconnection is initialized,\n        // do not wait for XMPPEvents.PEERCONNECTION_READY, as it may never\n        // happen in case if user doesn't have or denied permission to\n        // both camera and microphone.\n        logger.info('Starting CallStats for JVB connection...');\n        this.statistics.startCallStats(\n            this.jvbJingleSession.peerconnection,\n            'jitsi' /* Remote user ID for JVB is 'jitsi' */);\n        this.statistics.startRemoteStats(this.jvbJingleSession.peerconnection);\n    } catch (e) {\n        GlobalOnErrorHandler.callErrorHandler(e);\n        logger.error(e);\n    }\n};\n\n/**\n * Sets the BridgeChannel.\n *\n * @param {jQuery} offerIq a jQuery selector pointing to the jingle element of\n * the offer IQ which may carry the WebSocket URL for the 'websocket'\n * BridgeChannel mode.\n * @param {TraceablePeerConnection} pc the peer connection which will be used\n * to listen for new WebRTC Data Channels (in the 'datachannel' mode).\n */\nJitsiConference.prototype._setBridgeChannel = function(offerIq, pc) {\n    let wsUrl = null;\n    const webSocket\n        = $(offerIq)\n            .find('>content>transport>web-socket')\n            .first();\n\n    if (webSocket.length === 1) {\n        wsUrl = webSocket[0].getAttribute('url');\n    }\n\n    if (wsUrl) {\n        // If the offer contains a websocket use it.\n        this.rtc.initializeBridgeChannel(null, wsUrl);\n    } else {\n        // Otherwise, fall back to an attempt to use SCTP.\n        this.rtc.initializeBridgeChannel(pc, null);\n    }\n};\n\n/**\n * Rejects incoming Jingle call.\n * @param {JingleSessionPC} jingleSession the session instance to be rejected.\n * @param {object} [options]\n * @param {string} options.reason the name of the reason element as defined\n * by Jingle\n * @param {string} options.reasonDescription the reason description which will\n * be included in Jingle 'session-terminate' message.\n * @param {string} options.errorMsg an error message to be logged on global\n * error handler\n * @private\n */\nJitsiConference.prototype._rejectIncomingCall = function(jingleSession, options) {\n    if (options && options.errorMsg) {\n        GlobalOnErrorHandler.callErrorHandler(new Error(options.errorMsg));\n    }\n\n    // Terminate the jingle session with a reason\n    jingleSession.terminate(\n        null /* success callback => we don't care */,\n        error => {\n            logger.warn(\n                'An error occurred while trying to terminate'\n                    + ' invalid Jingle session', error);\n        }, {\n            reason: options && options.reason,\n            reasonDescription: options && options.reasonDescription,\n            sendSessionTerminate: true\n        });\n};\n\n/**\n * Handles the call ended event.\n * XXX is this due to the remote side terminating the Jingle session?\n *\n * @param {JingleSessionPC} jingleSession the jingle session which has been\n * terminated.\n * @param {String} reasonCondition the Jingle reason condition.\n * @param {String|null} reasonText human readable reason text which may provide\n * more details about why the call has been terminated.\n */\nJitsiConference.prototype.onCallEnded = function(jingleSession, reasonCondition, reasonText) {\n    logger.info(\n        `Call ended: ${reasonCondition} - ${reasonText} P2P ?${\n            jingleSession.isP2P}`);\n    if (jingleSession === this.jvbJingleSession) {\n        this.wasStopped = true;\n\n        Statistics.sendAnalytics(\n            createJingleEvent(ACTION_JINGLE_TERMINATE, { p2p: false }));\n\n        // Stop the stats\n        if (this.statistics) {\n            this.statistics.stopRemoteStats(\n                this.jvbJingleSession.peerconnection);\n            logger.info('Stopping JVB CallStats');\n            this.statistics.stopCallStats(\n                this.jvbJingleSession.peerconnection);\n        }\n\n        // Current JVB JingleSession is no longer valid, so set it to null\n        this.jvbJingleSession = null;\n\n        // Let the RTC service do any cleanups\n        this.rtc.onCallEnded();\n    } else if (jingleSession === this.p2pJingleSession) {\n        const stopOptions = {};\n\n        // It's the responder who decides to enforce JVB mode, so that both\n        // initiator and responder are aware if it was intentional.\n        if (reasonCondition === 'decline' && reasonText === 'force JVB121') {\n            logger.info('In forced JVB 121 mode...');\n            Statistics.analytics.addPermanentProperties({ forceJvb121: true });\n        } else if (reasonCondition === 'connectivity-error'\n            && reasonText === 'ICE FAILED') {\n            // It can happen that the other peer detects ICE failed and\n            // terminates the session, before we get the event on our side.\n            // But we are able to parse the reason and mark it here.\n            Statistics.analytics.addPermanentProperties({ p2pFailed: true });\n        } else if (reasonCondition === 'success' && reasonText === 'restart') {\n            // When we are restarting media sessions we don't want to switch the tracks\n            // to the JVB just yet.\n            stopOptions.requestRestart = true;\n        }\n        this._stopP2PSession(stopOptions);\n    } else {\n        logger.error(\n            'Received onCallEnded for invalid session',\n            jingleSession.sid,\n            jingleSession.remoteJid,\n            reasonCondition,\n            reasonText);\n    }\n};\n\n/**\n * Handles the suspend detected event. Leaves the room and fires suspended.\n * @param {JingleSessionPC} jingleSession\n */\nJitsiConference.prototype.onSuspendDetected = function(jingleSession) {\n    if (!jingleSession.isP2P) {\n        this.leave();\n        this.eventEmitter.emit(JitsiConferenceEvents.SUSPEND_DETECTED);\n    }\n};\n\nJitsiConference.prototype.updateDTMFSupport = function() {\n    let somebodySupportsDTMF = false;\n    const participants = this.getParticipants();\n\n    // check if at least 1 participant supports DTMF\n    for (let i = 0; i < participants.length; i += 1) {\n        if (participants[i].supportsDTMF()) {\n            somebodySupportsDTMF = true;\n            break;\n        }\n    }\n    if (somebodySupportsDTMF !== this.somebodySupportsDTMF) {\n        this.somebodySupportsDTMF = somebodySupportsDTMF;\n        this.eventEmitter.emit(\n            JitsiConferenceEvents.DTMF_SUPPORT_CHANGED,\n            somebodySupportsDTMF);\n    }\n};\n\n/**\n * Allows to check if there is at least one user in the conference\n * that supports DTMF.\n * @returns {boolean} true if somebody supports DTMF, false otherwise\n */\nJitsiConference.prototype.isDTMFSupported = function() {\n    return this.somebodySupportsDTMF;\n};\n\n/**\n * Returns the local user's ID\n * @return {string} local user's ID\n */\nJitsiConference.prototype.myUserId = function() {\n    return (\n        this.room && this.room.myroomjid\n            ? Strophe.getResourceFromJid(this.room.myroomjid)\n            : null);\n};\n\nJitsiConference.prototype.sendTones = function(tones, duration, pause) {\n    const peerConnection = this.getActivePeerConnection();\n\n    if (peerConnection) {\n        peerConnection.sendTones(tones, duration, pause);\n    } else {\n        logger.warn('cannot sendTones: no peer connection');\n    }\n};\n\n/**\n * Starts recording the current conference.\n *\n * @param {Object} options - Configuration for the recording. See\n * {@link Chatroom#startRecording} for more info.\n * @returns {Promise} See {@link Chatroom#startRecording} for more info.\n */\nJitsiConference.prototype.startRecording = function(options) {\n    if (this.room) {\n        return this.recordingManager.startRecording(options);\n    }\n\n    return Promise.reject(new Error('The conference is not created yet!'));\n};\n\n/**\n * Stop a recording session.\n *\n * @param {string} sessionID - The ID of the recording session that\n * should be stopped.\n * @returns {Promise} See {@link Chatroom#stopRecording} for more info.\n */\nJitsiConference.prototype.stopRecording = function(sessionID) {\n    if (this.room) {\n        return this.recordingManager.stopRecording(sessionID);\n    }\n\n    return Promise.reject(new Error('The conference is not created yet!'));\n};\n\n/**\n * Returns true if the SIP calls are supported and false otherwise\n */\nJitsiConference.prototype.isSIPCallingSupported = function() {\n    if (this.room) {\n        return this.room.isSIPCallingSupported();\n    }\n\n    return false;\n};\n\n/**\n * Dials a number.\n * @param number the number\n */\nJitsiConference.prototype.dial = function(number) {\n    if (this.room) {\n        return this.room.dial(number);\n    }\n\n    return new Promise((resolve, reject) => {\n        reject(new Error('The conference is not created yet!'));\n    });\n};\n\n/**\n * Hangup an existing call\n */\nJitsiConference.prototype.hangup = function() {\n    if (this.room) {\n        return this.room.hangup();\n    }\n\n    return new Promise((resolve, reject) => {\n        reject(new Error('The conference is not created yet!'));\n    });\n};\n\n/**\n * Starts the transcription service.\n */\nJitsiConference.prototype.startTranscriber = function() {\n    return this.dial('jitsi_meet_transcribe');\n};\n\n\n/**\n * Stops the transcription service.\n */\nJitsiConference.prototype.stopTranscriber = JitsiConference.prototype.hangup;\n\n/**\n * Returns the phone number for joining the conference.\n */\nJitsiConference.prototype.getPhoneNumber = function() {\n    if (this.room) {\n        return this.room.getPhoneNumber();\n    }\n\n    return null;\n};\n\n/**\n * Returns the pin for joining the conference with phone.\n */\nJitsiConference.prototype.getPhonePin = function() {\n    if (this.room) {\n        return this.room.getPhonePin();\n    }\n\n    return null;\n};\n\n/**\n * Returns the meeting unique ID if any.\n *\n * @returns {string|undefined}\n */\nJitsiConference.prototype.getMeetingUniqueId = function() {\n    if (this.room) {\n        return this.room.getMeetingId();\n    }\n};\n\n/**\n * Will return P2P or JVB <tt>TraceablePeerConnection</tt> depending on\n * which connection is currently active.\n *\n * @return {TraceablePeerConnection|null} null if there isn't any active\n * <tt>TraceablePeerConnection</tt> currently available.\n * @public (FIXME how to make package local ?)\n */\nJitsiConference.prototype.getActivePeerConnection = function() {\n    const session = this.isP2PActive() ? this.p2pJingleSession : this.jvbJingleSession;\n\n    return session ? session.peerconnection : null;\n};\n\n/**\n * Returns the connection state for the current room. Its ice connection state\n * for its session.\n * NOTE that \"completed\" ICE state which can appear on the P2P connection will\n * be converted to \"connected\".\n * @return {string|null} ICE state name or <tt>null</tt> if there is no active\n * peer connection at this time.\n */\nJitsiConference.prototype.getConnectionState = function() {\n    const peerConnection = this.getActivePeerConnection();\n\n    return peerConnection ? peerConnection.getConnectionState() : null;\n};\n\n/**\n * Make all new participants mute their audio/video on join.\n * @param policy {Object} object with 2 boolean properties for video and audio:\n * @param {boolean} audio if audio should be muted.\n * @param {boolean} video if video should be muted.\n */\nJitsiConference.prototype.setStartMutedPolicy = function(policy) {\n    if (!this.isModerator()) {\n        logger.warn(`Failed to set start muted policy, ${this.room ? '' : 'not in a room, '}${\n            this.isModerator() ? '' : 'participant is not a moderator'}`);\n\n        return;\n    }\n    this.startMutedPolicy = policy;\n    this.room.addOrReplaceInPresence('startmuted', {\n        attributes: {\n            audio: policy.audio,\n            video: policy.video,\n            xmlns: 'http://jitsi.org/jitmeet/start-muted'\n        }\n    }) && this.room.sendPresence();\n};\n\n/**\n * Returns current start muted policy\n * @returns {Object} with 2 properties - audio and video.\n */\nJitsiConference.prototype.getStartMutedPolicy = function() {\n    return this.startMutedPolicy;\n};\n\n/**\n * Check if audio is muted on join.\n */\nJitsiConference.prototype.isStartAudioMuted = function() {\n    return this.startAudioMuted;\n};\n\n/**\n * Check if video is muted on join.\n */\nJitsiConference.prototype.isStartVideoMuted = function() {\n    return this.startVideoMuted;\n};\n\n/**\n * Returns measured connectionTimes.\n */\nJitsiConference.prototype.getConnectionTimes = function() {\n    return this.room.connectionTimes;\n};\n\n/**\n * Sets a property for the local participant.\n */\nJitsiConference.prototype.setLocalParticipantProperty = function(name, value) {\n    this.sendCommand(`jitsi_participant_${name}`, { value });\n};\n\n/**\n *  Removes a property for the local participant and sends the updated presence.\n */\nJitsiConference.prototype.removeLocalParticipantProperty = function(name) {\n    this.removeCommand(`jitsi_participant_${name}`);\n    this.room.sendPresence();\n};\n\n/**\n * Gets a local participant property.\n *\n * @return value of the local participant property if the tagName exists in the\n * list of properties, otherwise returns undefined.\n */\nJitsiConference.prototype.getLocalParticipantProperty = function(name) {\n    const property = this.room.presMap.nodes.find(prop =>\n        prop.tagName === `jitsi_participant_${name}`\n    );\n\n    return property ? property.value : undefined;\n};\n\n/**\n * Sends the given feedback through CallStats if enabled.\n *\n * @param overallFeedback an integer between 1 and 5 indicating the\n * user feedback\n * @param detailedFeedback detailed feedback from the user. Not yet used\n * @returns {Promise} Resolves if feedback is submitted successfully.\n */\nJitsiConference.prototype.sendFeedback = function(overallFeedback, detailedFeedback) {\n    return this.statistics.sendFeedback(overallFeedback, detailedFeedback);\n};\n\n/**\n * Returns true if the callstats integration is enabled, otherwise returns\n * false.\n *\n * @returns true if the callstats integration is enabled, otherwise returns\n * false.\n */\nJitsiConference.prototype.isCallstatsEnabled = function() {\n    return this.statistics.isCallstatsEnabled();\n};\n\n/**\n * Finds the SSRC of a given track\n *\n * @param track\n * @returns {number|undefined} the SSRC of the specificed track, otherwise undefined.\n */\nJitsiConference.prototype.getSsrcByTrack = function(track) {\n    return track.isLocal() ? this.getActivePeerConnection()?.getLocalSSRC(track) : track.getSSRC();\n};\n\n/**\n * Handles track attached to container (Calls associateStreamWithVideoTag method\n * from statistics module)\n * @param {JitsiLocalTrack|JitsiRemoteTrack} track the track\n * @param container the container\n */\nJitsiConference.prototype._onTrackAttach = function(track, container) {\n    const isLocal = track.isLocal();\n    let ssrc = null;\n    const isP2P = track.isP2P;\n    const remoteUserId = isP2P ? track.getParticipantId() : 'jitsi';\n    const peerConnection\n        = isP2P\n            ? this.p2pJingleSession && this.p2pJingleSession.peerconnection\n            : this.jvbJingleSession && this.jvbJingleSession.peerconnection;\n\n    if (isLocal) {\n        // Local tracks have SSRC stored on per peer connection basis.\n        if (peerConnection) {\n            ssrc = peerConnection.getLocalSSRC(track);\n        }\n    } else {\n        ssrc = track.getSSRC();\n    }\n    if (!container.id || !ssrc || !peerConnection) {\n        return;\n    }\n\n    this.statistics.associateStreamWithVideoTag(\n        peerConnection,\n        ssrc,\n        isLocal,\n        remoteUserId,\n        track.getUsageLabel(),\n        container.id);\n};\n\n/**\n * Logs an \"application log\" message.\n * @param message {string} The message to log. Note that while this can be a\n * generic string, the convention used by lib-jitsi-meet and jitsi-meet is to\n * log valid JSON strings, with an \"id\" field used for distinguishing between\n * message types. E.g.: {id: \"recorder_status\", status: \"off\"}\n */\nJitsiConference.prototype.sendApplicationLog = function(message) {\n    Statistics.sendLog(message);\n};\n\n/**\n * Checks if the user identified by given <tt>mucJid</tt> is the conference focus.\n * @param mucJid the full MUC address of the user to be checked.\n * @returns {boolean|null} <tt>true</tt> if MUC user is the conference focus,\n * <tt>false</tt> when is not. <tt>null</tt> if we're not in the MUC anymore and\n * are unable to figure out the status or if given <tt>mucJid</tt> is invalid.\n */\nJitsiConference.prototype.isFocus = function(mucJid) {\n    return this.room ? this.room.isFocus(mucJid) : null;\n};\n\n/**\n * Fires CONFERENCE_FAILED event with INCOMPATIBLE_SERVER_VERSIONS parameter\n */\nJitsiConference.prototype._fireIncompatibleVersionsEvent = function() {\n    this.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_FAILED,\n        JitsiConferenceErrors.INCOMPATIBLE_SERVER_VERSIONS);\n};\n\n/**\n * Sends a message via the data channel.\n * @param to {string} the id of the endpoint that should receive the message.\n * If \"\" the message will be sent to all participants.\n * @param payload {object} the payload of the message.\n * @throws NetworkError or InvalidStateError or Error if the operation fails.\n * @deprecated Use 'sendMessage' instead. TODO: this should be private.\n */\nJitsiConference.prototype.sendEndpointMessage = function(to, payload) {\n    this.rtc.sendChannelMessage(to, payload);\n};\n\n/**\n * Sends local stats via the bridge channel which then forwards to other endpoints selectively.\n * @param {Object} payload The payload of the message.\n * @throws NetworkError/InvalidStateError/Error if the operation fails or if there is no data channel created.\n */\nJitsiConference.prototype.sendEndpointStatsMessage = function(payload) {\n    this.rtc.sendEndpointStatsMessage(payload);\n};\n\n/**\n * Sends a broadcast message via the data channel.\n * @param payload {object} the payload of the message.\n * @throws NetworkError or InvalidStateError or Error if the operation fails.\n * @deprecated Use 'sendMessage' instead. TODO: this should be private.\n */\nJitsiConference.prototype.broadcastEndpointMessage = function(payload) {\n    this.sendEndpointMessage('', payload);\n};\n\n/**\n * Sends a message to a given endpoint (if 'to' is a non-empty string), or\n * broadcasts it to all endpoints in the conference.\n * @param {string} to The ID of the endpoint/participant which is to receive\n * the message, or '' to broadcast the message to all endpoints in the\n * conference.\n * @param {string|object} message the message to send. If this is of type\n * 'string' it will be sent as a chat message. If it is of type 'object', it\n * will be encapsulated in a format recognized by jitsi-meet and converted to\n * JSON before being sent.\n * @param {boolean} sendThroughVideobridge Whether to send the message through\n * jitsi-videobridge (via the COLIBRI data channel or web socket), or through\n * the XMPP MUC. Currently only objects can be sent through jitsi-videobridge.\n */\nJitsiConference.prototype.sendMessage = function(message, to = '', sendThroughVideobridge = false) {\n    const messageType = typeof message;\n\n    // Through videobridge we support only objects. Through XMPP we support\n    // objects (encapsulated in a specific JSON format) and strings (i.e.\n    // regular chat messages).\n    if (messageType !== 'object'\n            && (sendThroughVideobridge || messageType !== 'string')) {\n        logger.error(`Can not send a message of type ${messageType}`);\n\n        return;\n    }\n\n    if (sendThroughVideobridge) {\n        this.sendEndpointMessage(to, message);\n    } else {\n        let messageToSend = message;\n\n        // Name of packet extension of message stanza to send the required\n        // message in.\n        let elementName = 'body';\n\n        if (messageType === 'object') {\n            elementName = 'json-message';\n\n            // Mark as valid JSON message if not already\n            if (!messageToSend.hasOwnProperty(JITSI_MEET_MUC_TYPE)) {\n                messageToSend[JITSI_MEET_MUC_TYPE] = '';\n            }\n\n            try {\n                messageToSend = JSON.stringify(messageToSend);\n            } catch (e) {\n                logger.error('Can not send a message, stringify failed: ', e);\n\n                return;\n            }\n        }\n\n        if (to) {\n            this.sendPrivateTextMessage(to, messageToSend, elementName);\n        } else {\n            // Broadcast\n            this.sendTextMessage(messageToSend, elementName);\n        }\n    }\n\n};\n\nJitsiConference.prototype.isConnectionInterrupted = function() {\n    return this.isP2PActive()\n        ? this.isP2PConnectionInterrupted : this.isJvbConnectionInterrupted;\n};\n\n/**\n * Handles {@link XMPPEvents.CONNECTION_RESTARTED} event. This happens when the bridge goes down\n * and Jicofo moves conferences away to a different bridge.\n * @param {JingleSessionPC} session\n * @private\n */\nJitsiConference.prototype._onConferenceRestarted = function(session) {\n    if (!session.isP2P && this.options.config.enableForcedReload) {\n        this.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_FAILED, JitsiConferenceErrors.CONFERENCE_RESTARTED);\n    }\n};\n\n/**\n * Handles {@link XMPPEvents.CONNECTION_INTERRUPTED}\n * @param {JingleSessionPC} session\n * @private\n */\nJitsiConference.prototype._onIceConnectionInterrupted = function(session) {\n    if (session.isP2P) {\n        this.isP2PConnectionInterrupted = true;\n    } else {\n        this.isJvbConnectionInterrupted = true;\n    }\n    if (session.isP2P === this.isP2PActive()) {\n        this.eventEmitter.emit(JitsiConferenceEvents.CONNECTION_INTERRUPTED);\n    }\n};\n\n/**\n * Handles {@link XMPPEvents.CONNECTION_ICE_FAILED}\n * @param {JingleSessionPC} session\n * @private\n */\nJitsiConference.prototype._onIceConnectionFailed = function(session) {\n    // We do nothing for the JVB connection, because it's up to the Jicofo to\n    // eventually come up with the new offer (at least for the time being).\n    if (session.isP2P) {\n        // Add p2pFailed property to analytics to distinguish, between \"good\"\n        // and \"bad\" connection\n        Statistics.analytics.addPermanentProperties({ p2pFailed: true });\n\n        if (this.p2pJingleSession) {\n            Statistics.sendAnalyticsAndLog(\n                createP2PEvent(\n                    ACTION_P2P_FAILED,\n                    {\n                        initiator: this.p2pJingleSession.isInitiator\n                    }));\n\n        }\n        this._stopP2PSession({\n            reason: 'connectivity-error',\n            reasonDescription: 'ICE FAILED'\n        });\n    } else if (session && this.jvbJingleSession === session) {\n        this._delayedIceFailed = new IceFailedHandling(this);\n        this._delayedIceFailed.start(session);\n    }\n};\n\n/**\n * Handles {@link XMPPEvents.CONNECTION_RESTORED}\n * @param {JingleSessionPC} session\n * @private\n */\nJitsiConference.prototype._onIceConnectionRestored = function(session) {\n    if (session.isP2P) {\n        this.isP2PConnectionInterrupted = false;\n    } else {\n        this.isJvbConnectionInterrupted = false;\n        this._delayedIceFailed && this._delayedIceFailed.cancel();\n    }\n\n    if (session.isP2P === this.isP2PActive()) {\n        this.eventEmitter.emit(JitsiConferenceEvents.CONNECTION_RESTORED);\n    }\n};\n\n/**\n * Accept incoming P2P Jingle call.\n * @param {JingleSessionPC} jingleSession the session instance\n * @param {jQuery} jingleOffer a jQuery selector pointing to 'jingle' IQ element\n * @private\n */\nJitsiConference.prototype._acceptP2PIncomingCall = function(jingleSession, jingleOffer) {\n    this.isP2PConnectionInterrupted = false;\n\n    // Accept the offer\n    this.p2pJingleSession = jingleSession;\n    this._sendConferenceJoinAnalyticsEvent();\n\n    this.p2pJingleSession.initialize(\n        this.room,\n        this.rtc,\n        this._signalingLayer,\n        {\n            ...this.options.config,\n            enableInsertableStreams: this.isE2EEEnabled()\n        });\n\n    logger.info('Starting CallStats for P2P connection...');\n\n    let remoteID = Strophe.getResourceFromJid(this.p2pJingleSession.remoteJid);\n\n    const participant = this.participants[remoteID];\n\n    if (participant) {\n        remoteID = participant.getStatsID() || remoteID;\n    }\n\n    this.statistics.startCallStats(\n        this.p2pJingleSession.peerconnection,\n        remoteID);\n\n    const localTracks = this.getLocalTracks();\n\n    this.p2pJingleSession.acceptOffer(\n        jingleOffer,\n        () => {\n            logger.debug('Got RESULT for P2P \"session-accept\"');\n\n            this.eventEmitter.emit(\n                JitsiConferenceEvents._MEDIA_SESSION_STARTED,\n                jingleSession);\n        },\n        error => {\n            logger.error(\n                'Failed to accept incoming P2P Jingle session', error);\n        },\n        localTracks);\n};\n\n/**\n * Adds remote tracks to the conference associated with the JVB session.\n * @private\n */\nJitsiConference.prototype._addRemoteJVBTracks = function() {\n    this._addRemoteTracks('JVB', this.jvbJingleSession.peerconnection.getRemoteTracks());\n};\n\n/**\n * Adds remote tracks to the conference associated with the P2P session.\n * @private\n */\nJitsiConference.prototype._addRemoteP2PTracks = function() {\n    this._addRemoteTracks('P2P', this.p2pJingleSession.peerconnection.getRemoteTracks());\n};\n\n/**\n * Generates fake \"remote track added\" events for given Jingle session.\n * @param {string} logName the session's nickname which will appear in log\n * messages.\n * @param {Array<JitsiRemoteTrack>} remoteTracks the tracks that will be added\n * @private\n */\nJitsiConference.prototype._addRemoteTracks = function(logName, remoteTracks) {\n    for (const track of remoteTracks) {\n        logger.info(`Adding remote ${logName} track: ${track}`);\n        this.onRemoteTrackAdded(track);\n    }\n};\n\n/**\n * Called when {@link XMPPEvents.CONNECTION_ESTABLISHED} event is\n * triggered for a {@link JingleSessionPC}. Switches the conference to use\n * the P2P connection if the event comes from the P2P session.\n * @param {JingleSessionPC} jingleSession the session instance.\n * @private\n */\nJitsiConference.prototype._onIceConnectionEstablished = function(jingleSession) {\n    if (this.p2pJingleSession !== null) {\n        // store the establishment time of the p2p session as a field of the\n        // JitsiConference because the p2pJingleSession might get disposed (thus\n        // the value is lost).\n        this.p2pEstablishmentDuration\n            = this.p2pJingleSession.establishmentDuration;\n    }\n\n    if (this.jvbJingleSession !== null) {\n        this.jvbEstablishmentDuration\n            = this.jvbJingleSession.establishmentDuration;\n    }\n\n    let done = false;\n    const forceJVB121Ratio = this.options.config.forceJVB121Ratio;\n\n    // We don't care about the JVB case, there's nothing to be done\n    if (!jingleSession.isP2P) {\n        done = true;\n    } else if (this.p2pJingleSession !== jingleSession) {\n        logger.error('CONNECTION_ESTABLISHED - wrong P2P session instance ?!');\n\n        done = true;\n    } else if (!jingleSession.isInitiator\n        && typeof forceJVB121Ratio === 'number'\n        && Math.random() < forceJVB121Ratio) {\n        logger.info(`Forcing JVB 121 mode (ratio=${forceJVB121Ratio})...`);\n        Statistics.analytics.addPermanentProperties({ forceJvb121: true });\n        this._stopP2PSession({\n            reason: 'decline',\n            reasonDescription: 'force JVB121'\n        });\n\n        done = true;\n    }\n\n    if (!isNaN(this.p2pEstablishmentDuration)\n        && !isNaN(this.jvbEstablishmentDuration)) {\n        const establishmentDurationDiff\n            = this.p2pEstablishmentDuration - this.jvbEstablishmentDuration;\n\n        Statistics.sendAnalytics(\n            ICE_ESTABLISHMENT_DURATION_DIFF,\n            { value: establishmentDurationDiff });\n    }\n\n    if (jingleSession.isP2P === this.isP2PActive()) {\n        this.eventEmitter.emit(JitsiConferenceEvents.CONNECTION_ESTABLISHED);\n    }\n\n    if (done) {\n\n        return;\n    }\n\n    // Update P2P status and emit events\n    this._setP2PStatus(true);\n\n    // Remove remote tracks\n    if (this.jvbJingleSession) {\n        this._removeRemoteJVBTracks();\n    } else {\n        logger.info('Not removing remote JVB tracks - no session yet');\n    }\n\n    this._addRemoteP2PTracks();\n\n    // Stop media transfer over the JVB connection\n    if (this.jvbJingleSession) {\n        this._suspendMediaTransferForJvbConnection();\n    }\n\n    logger.info('Starting remote stats with p2p connection');\n    this.statistics.startRemoteStats(this.p2pJingleSession.peerconnection);\n\n    Statistics.sendAnalyticsAndLog(\n        createP2PEvent(\n            ACTION_P2P_ESTABLISHED,\n            {\n                initiator: this.p2pJingleSession.isInitiator\n            }));\n\n};\n\n/**\n * Called when the chat room reads a new list of properties from jicofo's\n * presence. The properties may have changed, but they don't have to.\n *\n * @param {Object} properties - The properties keyed by the property name\n * ('key').\n * @private\n */\nJitsiConference.prototype._updateProperties = function(properties = {}) {\n    const changed = !isEqual(properties, this.properties);\n\n    this.properties = properties;\n    if (changed) {\n        this.eventEmitter.emit(JitsiConferenceEvents.PROPERTIES_CHANGED, this.properties);\n\n        const audioLimitReached = this.properties['audio-limit-reached'] === 'true';\n        const videoLimitReached = this.properties['video-limit-reached'] === 'true';\n\n        if (this._audioSenderLimitReached !== audioLimitReached) {\n            this._audioSenderLimitReached = audioLimitReached;\n            this.eventEmitter.emit(JitsiConferenceEvents.AUDIO_UNMUTE_PERMISSIONS_CHANGED, audioLimitReached);\n            logger.info(`Audio unmute permissions set by Jicofo to ${audioLimitReached}`);\n        }\n\n        if (this._videoSenderLimitReached !== videoLimitReached) {\n            this._videoSenderLimitReached = videoLimitReached;\n            this.eventEmitter.emit(JitsiConferenceEvents.VIDEO_UNMUTE_PERMISSIONS_CHANGED, videoLimitReached);\n            logger.info(`Video unmute permissions set by Jicofo to ${videoLimitReached}`);\n        }\n\n        // Some of the properties need to be added to analytics events.\n        const analyticsKeys = [\n\n            // The number of jitsi-videobridge instances currently used for the\n            // conference.\n            'bridge-count',\n\n            // The conference creation time (set by jicofo).\n            'created-ms'\n        ];\n\n        analyticsKeys.forEach(key => {\n            if (properties[key] !== undefined) {\n                Statistics.analytics.addPermanentProperties({\n                    [key.replace('-', '_')]: properties[key]\n                });\n            }\n        });\n    }\n};\n\n/**\n * Gets a conference property with a given key.\n *\n * @param {string} key - The key.\n * @returns {*} The value\n */\nJitsiConference.prototype.getProperty = function(key) {\n    return this.properties[key];\n};\n\n/**\n * Clears the deferred start P2P task if it has been scheduled.\n * @private\n */\nJitsiConference.prototype._maybeClearDeferredStartP2P = function() {\n    if (this.deferredStartP2PTask) {\n        logger.info('Cleared deferred start P2P task');\n        clearTimeout(this.deferredStartP2PTask);\n        this.deferredStartP2PTask = null;\n    }\n};\n\n/**\n * Removes from the conference remote tracks associated with the JVB\n * connection.\n * @private\n */\nJitsiConference.prototype._removeRemoteJVBTracks = function() {\n    this._removeRemoteTracks(\n        'JVB', this.jvbJingleSession.peerconnection.getRemoteTracks());\n};\n\n/**\n * Removes from the conference remote tracks associated with the P2P\n * connection.\n * @private\n */\nJitsiConference.prototype._removeRemoteP2PTracks = function() {\n    this._removeRemoteTracks(\n        'P2P', this.p2pJingleSession.peerconnection.getRemoteTracks());\n};\n\n/**\n * Generates fake \"remote track removed\" events for given Jingle session.\n * @param {string} sessionNickname the session's nickname which will appear in\n * log messages.\n * @param {Array<JitsiRemoteTrack>} remoteTracks the tracks that will be removed\n * @private\n */\nJitsiConference.prototype._removeRemoteTracks = function(sessionNickname, remoteTracks) {\n    for (const track of remoteTracks) {\n        logger.info(`Removing remote ${sessionNickname} track: ${track}`);\n        this.onRemoteTrackRemoved(track);\n    }\n};\n\n/**\n * Resumes media transfer over the JVB connection.\n * @private\n */\nJitsiConference.prototype._resumeMediaTransferForJvbConnection = function() {\n    logger.info('Resuming media transfer over the JVB connection...');\n    this.jvbJingleSession.setMediaTransferActive(true, true).then(\n        () => {\n            logger.info('Resumed media transfer over the JVB connection!');\n        },\n        error => {\n            logger.error(\n                'Failed to resume media transfer over the JVB connection:',\n                error);\n        });\n};\n\n/**\n * Sets new P2P status and updates some events/states hijacked from\n * the <tt>JitsiConference</tt>.\n * @param {boolean} newStatus the new P2P status value, <tt>true</tt> means that\n * P2P is now in use, <tt>false</tt> means that the JVB connection is now in use\n * @private\n */\nJitsiConference.prototype._setP2PStatus = function(newStatus) {\n    if (this.p2p === newStatus) {\n        logger.debug(`Called _setP2PStatus with the same status: ${newStatus}`);\n\n        return;\n    }\n    this.p2p = newStatus;\n    if (newStatus) {\n        logger.info('Peer to peer connection established!');\n\n        // When we end up in a valid P2P session need to reset the properties\n        // in case they have persisted, after session with another peer.\n        Statistics.analytics.addPermanentProperties({\n            p2pFailed: false,\n            forceJvb121: false\n        });\n\n        // Sync up video transfer active in case p2pJingleSession not existed\n        // when the lastN value was being adjusted.\n        const isVideoActive = this.getLastN() !== 0;\n\n        this.p2pJingleSession\n            .setMediaTransferActive(true, isVideoActive)\n            .catch(error => {\n                logger.error(\n                    'Failed to sync up P2P video transfer status'\n                        + `(${isVideoActive})`, error);\n            });\n    } else {\n        logger.info('Peer to peer connection closed!');\n    }\n\n    // Put the JVB connection on hold/resume\n    if (this.jvbJingleSession) {\n        this.statistics.sendConnectionResumeOrHoldEvent(\n            this.jvbJingleSession.peerconnection, !newStatus);\n    }\n\n    // Clear dtmfManager, so that it can be recreated with new connection\n    this.dtmfManager = null;\n\n    // Update P2P status\n    this.eventEmitter.emit(\n        JitsiConferenceEvents.P2P_STATUS,\n        this,\n        this.p2p);\n    this.eventEmitter.emit(JitsiConferenceEvents._MEDIA_SESSION_ACTIVE_CHANGED, this.getActiveMediaSession());\n\n    // Refresh connection interrupted/restored\n    this.eventEmitter.emit(\n        this.isConnectionInterrupted()\n            ? JitsiConferenceEvents.CONNECTION_INTERRUPTED\n            : JitsiConferenceEvents.CONNECTION_RESTORED);\n};\n\n/**\n * Starts new P2P session.\n * @param {string} remoteJid the JID of the remote participant\n * @private\n */\nJitsiConference.prototype._startP2PSession = function(remoteJid) {\n    this._maybeClearDeferredStartP2P();\n    if (this.p2pJingleSession) {\n        logger.error('P2P session already started!');\n\n        return;\n    }\n\n    this.isP2PConnectionInterrupted = false;\n    this.p2pJingleSession\n        = this.xmpp.connection.jingle.newP2PJingleSession(\n            this.room.myroomjid,\n            remoteJid);\n    logger.info(\n        'Created new P2P JingleSession', this.room.myroomjid, remoteJid);\n    this._sendConferenceJoinAnalyticsEvent();\n\n    this.p2pJingleSession.initialize(\n        this.room,\n        this.rtc,\n        this._signalingLayer,\n        {\n            ...this.options.config,\n            enableInsertableStreams: this.isE2EEEnabled()\n        });\n\n    logger.info('Starting CallStats for P2P connection...');\n\n    let remoteID = Strophe.getResourceFromJid(this.p2pJingleSession.remoteJid);\n\n    const participant = this.participants[remoteID];\n\n    if (participant) {\n        remoteID = participant.getStatsID() || remoteID;\n    }\n\n    this.statistics.startCallStats(\n        this.p2pJingleSession.peerconnection,\n        remoteID);\n\n    const localTracks = this.getLocalTracks();\n\n    this.p2pJingleSession.invite(localTracks);\n};\n\n/**\n * Suspends media transfer over the JVB connection.\n * @private\n */\nJitsiConference.prototype._suspendMediaTransferForJvbConnection = function() {\n    logger.info('Suspending media transfer over the JVB connection...');\n    this.jvbJingleSession.setMediaTransferActive(false, false).then(\n        () => {\n            logger.info('Suspended media transfer over the JVB connection !');\n        },\n        error => {\n            logger.error(\n                'Failed to suspend media transfer over the JVB connection:',\n                error);\n        });\n};\n\n/**\n * Method when called will decide whether it's the time to start or stop\n * the P2P session.\n * @param {boolean} userLeftEvent if <tt>true</tt> it means that the call\n * originates from the user left event.\n * @private\n */\nJitsiConference.prototype._maybeStartOrStopP2P = function(userLeftEvent) {\n    if (!this.isP2PEnabled()\n            || this.isP2PTestModeEnabled()\n            || browser.isFirefox()\n            || browser.isWebKitBased()\n            || this.isE2EEEnabled()) {\n        logger.info('Auto P2P disabled');\n\n        return;\n    }\n    const peers = this.getParticipants();\n    const peerCount = peers.length;\n\n    // FIXME 1 peer and it must *support* P2P switching\n    const shouldBeInP2P = this._shouldBeInP2PMode();\n\n    // Clear deferred \"start P2P\" task\n    if (!shouldBeInP2P && this.deferredStartP2PTask) {\n        this._maybeClearDeferredStartP2P();\n    }\n\n    // Start peer to peer session\n    if (!this.p2pJingleSession && shouldBeInP2P) {\n        const peer = peerCount && peers[0];\n\n\n        const myId = this.myUserId();\n        const peersId = peer.getId();\n\n        if (myId > peersId) {\n            logger.debug(\n                'I\\'m the bigger peersId - '\n                + 'the other peer should start P2P', myId, peersId);\n\n            return;\n        } else if (myId === peersId) {\n            logger.error('The same IDs ? ', myId, peersId);\n\n            return;\n        }\n\n        const jid = peer.getJid();\n\n        if (userLeftEvent) {\n            if (this.deferredStartP2PTask) {\n                logger.error('Deferred start P2P task\\'s been set already!');\n\n                return;\n            }\n            logger.info(\n                `Will start P2P with: ${jid} after ${\n                    this.backToP2PDelay} seconds...`);\n            this.deferredStartP2PTask = setTimeout(\n                this._startP2PSession.bind(this, jid),\n                this.backToP2PDelay * 1000);\n        } else {\n            logger.info(`Will start P2P with: ${jid}`);\n            this._startP2PSession(jid);\n        }\n    } else if (this.p2pJingleSession && !shouldBeInP2P) {\n        logger.info(`Will stop P2P with: ${this.p2pJingleSession.remoteJid}`);\n\n        // Log that there will be a switch back to the JVB connection\n        if (this.p2pJingleSession.isInitiator && peerCount > 1) {\n            Statistics.sendAnalyticsAndLog(\n                createP2PEvent(ACTION_P2P_SWITCH_TO_JVB));\n        }\n        this._stopP2PSession();\n    }\n};\n\n/**\n * Tells whether or not this conference should be currently in the P2P mode.\n *\n * @private\n * @returns {boolean}\n */\nJitsiConference.prototype._shouldBeInP2PMode = function() {\n    const peers = this.getParticipants();\n    const peerCount = peers.length;\n    const hasBotPeer = peers.find(p => p.getBotType() === 'poltergeist' || p.hasFeature(FEATURE_JIGASI)) !== undefined;\n    const shouldBeInP2P = peerCount === 1 && !hasBotPeer;\n\n    logger.debug(`P2P? peerCount: ${peerCount}, hasBotPeer: ${hasBotPeer} => ${shouldBeInP2P}`);\n\n    return shouldBeInP2P;\n};\n\n/**\n * Stops the current P2P session.\n * @param {Object} options - Options for stopping P2P.\n * @param {string} options.reason - One of the Jingle \"reason\" element\n * names as defined by https://xmpp.org/extensions/xep-0166.html#def-reason\n * @param {string} options.reasonDescription - Text\n * description that will be included in the session terminate message\n * @param {boolean} requestRestart - Whether this is due to a session restart, in which case\n * media will not be resumed on the JVB.\n * @private\n */\nJitsiConference.prototype._stopP2PSession = function(options = {}) {\n    const {\n        reason = 'success',\n        reasonDescription = 'Turning off P2P session',\n        requestRestart = false\n    } = options;\n\n    if (!this.p2pJingleSession) {\n        logger.error('No P2P session to be stopped!');\n\n        return;\n    }\n\n    const wasP2PEstablished = this.isP2PActive();\n\n    // Swap remote tracks, but only if the P2P has been fully established\n    if (wasP2PEstablished) {\n        if (this.jvbJingleSession && !requestRestart) {\n            this._resumeMediaTransferForJvbConnection();\n        }\n\n        // Remove remote P2P tracks\n        this._removeRemoteP2PTracks();\n    }\n\n    // Stop P2P stats\n    logger.info('Stopping remote stats for P2P connection');\n    this.statistics.stopRemoteStats(this.p2pJingleSession.peerconnection);\n    logger.info('Stopping CallStats for P2P connection');\n    this.statistics.stopCallStats(this.p2pJingleSession.peerconnection);\n\n    this.p2pJingleSession.terminate(\n        () => {\n            logger.info('P2P session terminate RESULT');\n        },\n        error => {\n            // Because both initiator and responder are simultaneously\n            // terminating their JingleSessions in case of the 'to JVB switch'\n            // when 3rd participant joins, both will dispose their sessions and\n            // reply with 'item-not-found' (see strophe.jingle.js). We don't\n            // want to log this as an error since it's expected behaviour.\n            //\n            // We want them both to terminate, because in case of initiator's\n            // crash the responder would stay in P2P mode until ICE fails which\n            // could take up to 20 seconds.\n            //\n            // NOTE: whilst this is an error callback,  'success' as a reason is\n            // considered as graceful session terminate\n            // where both initiator and responder terminate their sessions\n            // simultaneously.\n            if (reason !== 'success') {\n                logger.error('An error occurred while trying to terminate P2P Jingle session', error);\n            }\n        }, {\n            reason,\n            reasonDescription,\n            sendSessionTerminate: this.room\n                && this.getParticipantById(\n                    Strophe.getResourceFromJid(this.p2pJingleSession.remoteJid))\n        });\n\n    this.p2pJingleSession = null;\n\n    // Update P2P status and other affected events/states\n    this._setP2PStatus(false);\n\n    if (wasP2PEstablished) {\n        // Add back remote JVB tracks\n        if (this.jvbJingleSession && !requestRestart) {\n            this._addRemoteJVBTracks();\n        } else {\n            logger.info('Not adding remote JVB tracks - no session yet');\n        }\n    }\n};\n\n/**\n * Updates room presence if needed and send the packet in case of a modification.\n * @param {JingleSessionPC} jingleSession the session firing the event, contains the peer connection which\n * tracks we will check.\n * @param {Object|null} ctx a context object we can distinguish multiple calls of the same pass of updating tracks.\n */\nJitsiConference.prototype._updateRoomPresence = function(jingleSession, ctx) {\n    if (!jingleSession) {\n        return;\n    }\n\n    // skips sending presence twice for the same pass of updating ssrcs\n    if (ctx) {\n        if (ctx.skip) {\n            return;\n        }\n        ctx.skip = true;\n    }\n\n    let presenceChanged = false;\n    let muteStatusChanged, videoTypeChanged;\n    const localTracks = this.getLocalTracks();\n\n    // Set presence for all the available local tracks.\n    for (const track of localTracks) {\n        muteStatusChanged = this._setTrackMuteStatus(track.getType(), track, track.isMuted());\n        if (track.getType() === MediaType.VIDEO) {\n            videoTypeChanged = this._setNewVideoType(track);\n        }\n        presenceChanged = presenceChanged || muteStatusChanged || videoTypeChanged;\n    }\n\n    // Set the presence in the legacy format if there are no local tracks and multi stream support is not enabled.\n    if (!localTracks.length && !FeatureFlags.isMultiStreamSupportEnabled()) {\n        const audioMuteStatusChanged = this._setTrackMuteStatus(MediaType.AUDIO, undefined, true);\n        const videoMuteStatusChanged = this._setTrackMuteStatus(MediaType.VIDEO, undefined, true);\n\n        videoTypeChanged = this._setNewVideoType();\n        presenceChanged = audioMuteStatusChanged || videoMuteStatusChanged || videoTypeChanged;\n    }\n\n    presenceChanged && this.room.sendPresence();\n};\n\n/**\n * Checks whether or not the conference is currently in the peer to peer mode.\n * Being in peer to peer mode means that the direct connection has been\n * established and the P2P connection is being used for media transmission.\n * @return {boolean} <tt>true</tt> if in P2P mode or <tt>false</tt> otherwise.\n */\nJitsiConference.prototype.isP2PActive = function() {\n    return this.p2p;\n};\n\n/**\n * Returns the current ICE state of the P2P connection.\n * NOTE: method is used by the jitsi-meet-torture tests.\n * @return {string|null} an ICE state or <tt>null</tt> if there's currently\n * no P2P connection.\n */\nJitsiConference.prototype.getP2PConnectionState = function() {\n    if (this.isP2PActive()) {\n        return this.p2pJingleSession.peerconnection.getConnectionState();\n    }\n\n    return null;\n};\n\n/**\n * Configures the peerconnection so that a given framre rate can be achieved for desktop share.\n *\n * @param {number} maxFps The capture framerate to be used for desktop tracks.\n * @returns {boolean} true if the operation is successful, false otherwise.\n */\nJitsiConference.prototype.setDesktopSharingFrameRate = function(maxFps) {\n    if (typeof maxFps !== 'number' || isNaN(maxFps)) {\n        logger.error(`Invalid value ${maxFps} specified for desktop capture frame rate`);\n\n        return false;\n    }\n\n    this._desktopSharingFrameRate = maxFps;\n\n    // Enable or disable simulcast for plan-b screensharing based on the capture fps.\n    this.jvbJingleSession && this.jvbJingleSession.peerconnection.setDesktopSharingFrameRate(maxFps);\n\n    // Set the capture rate for desktop sharing.\n    this.rtc.setDesktopSharingFrameRate(maxFps);\n\n    return true;\n};\n\n/**\n * Manually starts new P2P session (should be used only in the tests).\n */\nJitsiConference.prototype.startP2PSession = function() {\n    const peers = this.getParticipants();\n\n    // Start peer to peer session\n    if (peers.length === 1) {\n        const peerJid = peers[0].getJid();\n\n        this._startP2PSession(peerJid);\n    } else {\n        throw new Error(\n            'There must be exactly 1 participant to start the P2P session !');\n    }\n};\n\n/**\n * Manually stops the current P2P session (should be used only in the tests).\n */\nJitsiConference.prototype.stopP2PSession = function(options) {\n    this._stopP2PSession(options);\n};\n\n/**\n * Get a summary of how long current participants have been the dominant speaker\n * @returns {object}\n */\nJitsiConference.prototype.getSpeakerStats = function() {\n    return this.speakerStatsCollector.getStats();\n};\n\n/**\n * Sends a facial expression with its duration to the xmpp server.\n * @param {Object} payload\n */\nJitsiConference.prototype.sendFacialExpression = function(payload) {\n    this.xmpp.sendFacialExpressionEvent(this.room.roomjid, payload);\n};\n\n/**\n * Sets the constraints for the video that is requested from the bridge.\n *\n * @param {Object} videoConstraints The constraints which are specified in the\n * following format. The message updates the fields that are present and leaves the\n * rest unchanged on the bridge. Therefore, any field that is not applicable anymore\n * should be cleared by passing an empty object or list (whatever is applicable).\n * {\n *      'lastN': 20,\n *      'selectedEndpoints': ['A', 'B', 'C'],\n *      'onStageEndpoints': ['A'],\n *      'defaultConstraints': { 'maxHeight': 180 },\n *      'constraints': {\n *          'A': { 'maxHeight': 720 }\n *      }\n * }\n */\nJitsiConference.prototype.setReceiverConstraints = function(videoConstraints) {\n    this.receiveVideoController.setReceiverConstraints(videoConstraints);\n};\n\n/**\n * Sets the maximum video size the local participant should receive from remote\n * participants.\n *\n * @param {number} maxFrameHeight - the maximum frame height, in pixels,\n * this receiver is willing to receive.\n * @returns {void}\n */\nJitsiConference.prototype.setReceiverVideoConstraint = function(maxFrameHeight) {\n    this.receiveVideoController.setPreferredReceiveMaxFrameHeight(maxFrameHeight);\n};\n\n/**\n * Sets the maximum video size the local participant should send to remote\n * participants.\n * @param {number} maxFrameHeight - The user preferred max frame height.\n * @returns {Promise} promise that will be resolved when the operation is\n * successful and rejected otherwise.\n */\nJitsiConference.prototype.setSenderVideoConstraint = function(maxFrameHeight) {\n    return this.sendVideoController.setPreferredSendMaxFrameHeight(maxFrameHeight);\n};\n\n/**\n * Creates a video SIP GW session and returns it if service is enabled. Before\n * creating a session one need to check whether video SIP GW service is\n * available in the system {@link JitsiConference.isVideoSIPGWAvailable}. Even\n * if there are available nodes to serve this request, after creating the\n * session those nodes can be taken and the request about using the\n * created session can fail.\n *\n * @param {string} sipAddress - The sip address to be used.\n * @param {string} displayName - The display name to be used for this session.\n * @returns {JitsiVideoSIPGWSession|Error} Returns null if conference is not\n * initialised and there is no room.\n */\nJitsiConference.prototype.createVideoSIPGWSession = function(sipAddress, displayName) {\n    if (!this.room) {\n        return new Error(VideoSIPGWConstants.ERROR_NO_CONNECTION);\n    }\n\n    return this.videoSIPGWHandler\n        .createVideoSIPGWSession(sipAddress, displayName);\n};\n\n/**\n * Sends a conference.join analytics event.\n *\n * @returns {void}\n */\nJitsiConference.prototype._sendConferenceJoinAnalyticsEvent = function() {\n    const meetingId = this.getMeetingUniqueId();\n\n    if (this._conferenceJoinAnalyticsEventSent || !meetingId || this.getActivePeerConnection() === null) {\n        return;\n    }\n\n    Statistics.sendAnalytics(createConferenceEvent('joined', {\n        meetingId,\n        participantId: `${meetingId}.${this._statsCurrentId}`\n    }));\n    this._conferenceJoinAnalyticsEventSent = Date.now();\n};\n\n/**\n * Sends conference.left analytics event.\n * @private\n */\nJitsiConference.prototype._sendConferenceLeftAnalyticsEvent = function() {\n    const meetingId = this.getMeetingUniqueId();\n\n    if (!meetingId || !this._conferenceJoinAnalyticsEventSent) {\n\n        return;\n    }\n\n    Statistics.sendAnalytics(createConferenceEvent('left', {\n        meetingId,\n        participantId: `${meetingId}.${this._statsCurrentId}`,\n        stats: {\n            duration: Math.floor((Date.now() - this._conferenceJoinAnalyticsEventSent) / 1000),\n            perf: this.getPerformanceStats()\n        }\n    }));\n};\n\n/**\n * Restarts all active media sessions.\n *\n * @returns {void}\n */\nJitsiConference.prototype._restartMediaSessions = function() {\n    if (this.p2pJingleSession) {\n        this._stopP2PSession({\n            reasonDescription: 'restart',\n            requestRestart: true\n        });\n    }\n\n    if (this.jvbJingleSession) {\n        this.jvbJingleSession.terminate(\n            null /* success callback => we don't care */,\n            error => {\n                logger.warn('An error occurred while trying to terminate the JVB session', error);\n            }, {\n                reason: 'success',\n                reasonDescription: 'restart required',\n                requestRestart: true,\n                sendSessionTerminate: true\n            });\n    }\n\n    this._maybeStartOrStopP2P(false);\n};\n\n/**\n * Returns whether End-To-End encryption is enabled.\n *\n * @returns {boolean}\n */\nJitsiConference.prototype.isE2EEEnabled = function() {\n    return Boolean(this._e2eEncryption && this._e2eEncryption.isEnabled());\n};\n\n/**\n * Returns whether End-To-End encryption is supported. Note that not all participants\n * in the conference may support it.\n *\n * @returns {boolean}\n */\nJitsiConference.prototype.isE2EESupported = function() {\n    return E2EEncryption.isSupported(this.options.config);\n};\n\n/**\n * Enables / disables End-to-End encryption.\n *\n * @param {boolean} enabled whether to enable E2EE or not.\n * @returns {void}\n */\nJitsiConference.prototype.toggleE2EE = function(enabled) {\n    if (!this.isE2EESupported()) {\n        logger.warn('Cannot enable / disable E2EE: platform is not supported.');\n\n        return;\n    }\n\n    this._e2eEncryption.setEnabled(enabled);\n};\n\n/**\n * Sets the key and index for End-to-End encryption.\n *\n * @param {CryptoKey} [keyInfo.encryptionKey] - encryption key.\n * @param {Number} [keyInfo.index] - the index of the encryption key.\n * @returns {void}\n */\nJitsiConference.prototype.setMediaEncryptionKey = function(keyInfo) {\n    this._e2eEncryption.setEncryptionKey(keyInfo);\n};\n\n/**\n * Returns <tt>true</tt> if lobby support is enabled in the backend.\n *\n * @returns {boolean} whether lobby is supported in the backend.\n */\nJitsiConference.prototype.isLobbySupported = function() {\n    return Boolean(this.room && this.room.getLobby().isSupported());\n};\n\n/**\n * Returns <tt>true</tt> if the room has members only enabled.\n *\n * @returns {boolean} whether conference room is members only.\n */\nJitsiConference.prototype.isMembersOnly = function() {\n    return Boolean(this.room && this.room.membersOnlyEnabled);\n};\n\n/**\n * Enables lobby by moderators\n *\n * @returns {Promise} resolves when lobby room is joined or rejects with the error.\n */\nJitsiConference.prototype.enableLobby = function() {\n    if (this.room && this.isModerator()) {\n        return this.room.getLobby().enable();\n    }\n\n    return Promise.reject(\n        new Error('The conference not started or user is not moderator'));\n};\n\n/**\n * Disabled lobby by moderators\n *\n * @returns {void}\n */\nJitsiConference.prototype.disableLobby = function() {\n    if (this.room && this.isModerator()) {\n        this.room.getLobby().disable();\n    } else {\n        logger.warn(`Failed to disable lobby, ${this.room ? '' : 'not in a room, '}${\n            this.isModerator() ? '' : 'participant is not a moderator'}`);\n    }\n};\n\n/**\n * Joins the lobby room with display name and optional email or with a shared password to skip waiting.\n *\n * @param {string} displayName Display name should be set to show it to moderators.\n * @param {string} email Optional email is used to present avatar to the moderator.\n * @returns {Promise<never>}\n */\nJitsiConference.prototype.joinLobby = function(displayName, email) {\n    if (this.room) {\n        return this.room.getLobby().join(displayName, email);\n    }\n\n    return Promise.reject(new Error('The conference not started'));\n};\n\n/**\n * Gets the local id for a participant in a lobby room.\n * Returns undefined when current participant is not in the lobby room.\n * This is used for lobby room private chat messages.\n *\n * @returns {string}\n */\nJitsiConference.prototype.myLobbyUserId = function() {\n    if (this.room) {\n        return this.room.getLobby().getLocalId();\n    }\n};\n\n/**\n * Sends a message to a lobby room.\n * When id is specified it sends a private message.\n * Otherwise it sends the message to all moderators.\n * @param {message} Object The message to send\n * @param {string} id The participant id.\n *\n * @returns {void}\n */\nJitsiConference.prototype.sendLobbyMessage = function(message, id) {\n    if (this.room) {\n        if (id) {\n            return this.room.getLobby().sendPrivateMessage(id, message);\n        }\n\n        return this.room.getLobby().sendMessage(message);\n    }\n};\n\n/**\n * Adds a message listener to the lobby room\n * @param {Function} listener The listener function,\n * called when a new message is received in the lobby room.\n *\n * @returns {Function} Handler returned to be able to remove it later.\n */\nJitsiConference.prototype.addLobbyMessageListener = function(listener) {\n    if (this.room) {\n        return this.room.getLobby().addMessageListener(listener);\n    }\n};\n\n/**\n * Removes a message handler from the lobby room\n * @param {Function} handler The handler function  to remove.\n *\n * @returns {void}\n */\nJitsiConference.prototype.removeLobbyMessageHandler = function(handler) {\n    if (this.room) {\n        return this.room.getLobby().removeMessageHandler(handler);\n    }\n};\n\n/**\n * Denies an occupant in the lobby room access to the conference.\n * @param {string} id The participant id.\n */\nJitsiConference.prototype.lobbyDenyAccess = function(id) {\n    if (this.room) {\n        this.room.getLobby().denyAccess(id);\n    }\n};\n\n/**\n * Approves the request to join the conference to a participant waiting in the lobby.\n *\n * @param {string} id The participant id.\n */\nJitsiConference.prototype.lobbyApproveAccess = function(id) {\n    if (this.room) {\n        this.room.getLobby().approveAccess(id);\n    }\n};\n\n/**\n * Returns <tt>true</tt> if AV Moderation support is enabled in the backend.\n *\n * @returns {boolean} whether AV Moderation is supported in the backend.\n */\nJitsiConference.prototype.isAVModerationSupported = function() {\n    return Boolean(this.room && this.room.getAVModeration().isSupported());\n};\n\n/**\n * Enables AV Moderation.\n * @param {MediaType} mediaType \"audio\" or \"video\"\n */\nJitsiConference.prototype.enableAVModeration = function(mediaType) {\n    if (this.room && this.isModerator()\n        && (mediaType === MediaType.AUDIO || mediaType === MediaType.VIDEO)) {\n        this.room.getAVModeration().enable(true, mediaType);\n    } else {\n        logger.warn(`Failed to enable AV moderation, ${this.room ? '' : 'not in a room, '}${\n            this.isModerator() ? '' : 'participant is not a moderator, '}${\n            this.room && this.isModerator() ? 'wrong media type passed' : ''}`);\n    }\n};\n\n/**\n * Disables AV Moderation.\n * @param {MediaType} mediaType \"audio\" or \"video\"\n */\nJitsiConference.prototype.disableAVModeration = function(mediaType) {\n    if (this.room && this.isModerator()\n        && (mediaType === MediaType.AUDIO || mediaType === MediaType.VIDEO)) {\n        this.room.getAVModeration().enable(false, mediaType);\n    } else {\n        logger.warn(`Failed to disable AV moderation, ${this.room ? '' : 'not in a room, '}${\n            this.isModerator() ? '' : 'participant is not a moderator, '}${\n            this.room && this.isModerator() ? 'wrong media type passed' : ''}`);\n    }\n};\n\n/**\n * Approve participant access to certain media, allows unmuting audio or video.\n *\n * @param {MediaType} mediaType \"audio\" or \"video\"\n * @param id the id of the participant.\n */\nJitsiConference.prototype.avModerationApprove = function(mediaType, id) {\n    if (this.room && this.isModerator()\n        && (mediaType === MediaType.AUDIO || mediaType === MediaType.VIDEO)) {\n\n        const participant = this.getParticipantById(id);\n\n        if (!participant) {\n            return;\n        }\n\n        this.room.getAVModeration().approve(mediaType, participant.getJid());\n    } else {\n        logger.warn(`AV moderation approve skipped , ${this.room ? '' : 'not in a room, '}${\n            this.isModerator() ? '' : 'participant is not a moderator, '}${\n            this.room && this.isModerator() ? 'wrong media type passed' : ''}`);\n    }\n};\n\n/**\n * Reject participant access to certain media, blocks unmuting audio or video.\n *\n * @param {MediaType} mediaType \"audio\" or \"video\"\n * @param id the id of the participant.\n */\nJitsiConference.prototype.avModerationReject = function(mediaType, id) {\n    if (this.room && this.isModerator()\n        && (mediaType === MediaType.AUDIO || mediaType === MediaType.VIDEO)) {\n\n        const participant = this.getParticipantById(id);\n\n        if (!participant) {\n            return;\n        }\n\n        this.room.getAVModeration().reject(mediaType, participant.getJid());\n    } else {\n        logger.warn(`AV moderation reject skipped , ${this.room ? '' : 'not in a room, '}${\n            this.isModerator() ? '' : 'participant is not a moderator, '}${\n            this.room && this.isModerator() ? 'wrong media type passed' : ''}`);\n    }\n};\n\n/**\n * Returns the breakout rooms manager object.\n *\n * @returns {Object} the breakout rooms manager.\n */\nJitsiConference.prototype.getBreakoutRooms = function() {\n    return this.room?.getBreakoutRooms();\n};\n","import JitsiConference from './JitsiConference';\nimport * as JitsiConnectionEvents from './JitsiConnectionEvents';\nimport Statistics from './modules/statistics/statistics';\nimport XMPP from './modules/xmpp/xmpp';\nimport {\n    CONNECTION_DISCONNECTED as ANALYTICS_CONNECTION_DISCONNECTED,\n    createConnectionFailedEvent\n} from './service/statistics/AnalyticsEvents';\n\n/**\n * Creates a new connection object for the Jitsi Meet server side video\n * conferencing service. Provides access to the JitsiConference interface.\n * @param appID identification for the provider of Jitsi Meet video conferencing\n * services.\n * @param token the JWT token used to authenticate with the server(optional)\n * @param options Object with properties / settings related to connection with\n * the server.\n * @constructor\n */\nexport default function JitsiConnection(appID, token, options) {\n    this.appID = appID;\n    this.token = token;\n    this.options = options;\n    this.xmpp = new XMPP(options, token);\n\n    /* eslint-disable max-params */\n    this.addEventListener(JitsiConnectionEvents.CONNECTION_FAILED,\n        (errType, msg, credentials, details) => {\n            Statistics.sendAnalyticsAndLog(\n                createConnectionFailedEvent(errType, msg, details));\n        });\n    /* eslint-enable max-params */\n\n    this.addEventListener(JitsiConnectionEvents.CONNECTION_DISCONNECTED,\n        msg => {\n            // we can see disconnects from normal tab closing of the browser\n            // and then there are no msgs, but we want to log only disconnects\n            // when there is real error\n            // XXX Do we need the difference in handling between the log and\n            // analytics event here?\n            if (msg) {\n                Statistics.sendAnalytics(\n                    ANALYTICS_CONNECTION_DISCONNECTED,\n                    { message: msg });\n            }\n            Statistics.sendLog(\n                JSON.stringify(\n                    {\n                        id: ANALYTICS_CONNECTION_DISCONNECTED,\n                        msg\n                    }));\n        });\n}\n\n/**\n * Connect the client with the server.\n * @param options {object} connecting options\n * (for example authentications parameters).\n */\nJitsiConnection.prototype.connect = function(options = {}) {\n    this.xmpp.connect(options.id, options.password);\n};\n\n/**\n * Attach to existing connection. Can be used for optimizations. For example:\n * if the connection is created on the server we can attach to it and start\n * using it.\n *\n * @param options {object} connecting options - rid, sid and jid.\n */\nJitsiConnection.prototype.attach = function(options) {\n    this.xmpp.attach(options);\n};\n\n/**\n * Disconnect the client from the server.\n * @returns {Promise} - Resolves when the disconnect process is finished or rejects with an error.\n */\nJitsiConnection.prototype.disconnect = function(...args) {\n    // XXX Forward any arguments passed to JitsiConnection.disconnect to\n    // XMPP.disconnect. For example, the caller of JitsiConnection.disconnect\n    // may optionally pass the event which triggered the disconnect in order to\n    // provide the implementation with finer-grained context.\n    return this.xmpp.disconnect(...args);\n};\n\n/**\n * Returns the jid of the participant associated with the XMPP connection.\n *\n * @returns {string} The jid of the participant.\n */\nJitsiConnection.prototype.getJid = function() {\n    return this.xmpp.getJid();\n};\n\n/**\n * This method allows renewal of the tokens if they are expiring.\n * @param token the new token.\n */\nJitsiConnection.prototype.setToken = function(token) {\n    this.token = token;\n};\n\n/**\n * Creates and joins new conference.\n * @param name the name of the conference; if null - a generated name will be\n * provided from the api\n * @param options Object with properties / settings related to the conference\n * that will be created.\n * @returns {JitsiConference} returns the new conference object.\n */\nJitsiConnection.prototype.initJitsiConference = function(name, options) {\n    return new JitsiConference({\n        name,\n        config: options,\n        connection: this\n    });\n};\n\n/**\n * Subscribes the passed listener to the event.\n * @param event {JitsiConnectionEvents} the connection event.\n * @param listener {Function} the function that will receive the event\n */\nJitsiConnection.prototype.addEventListener = function(event, listener) {\n    this.xmpp.addListener(event, listener);\n};\n\n/**\n * Unsubscribes the passed handler.\n * @param event {JitsiConnectionEvents} the connection event.\n * @param listener {Function} the function that will receive the event\n */\nJitsiConnection.prototype.removeEventListener = function(event, listener) {\n    this.xmpp.removeListener(event, listener);\n};\n\n/**\n * Returns measured connectionTimes.\n */\nJitsiConnection.prototype.getConnectionTimes = function() {\n    return this.xmpp.connectionTimes;\n};\n\n/**\n * Adds new feature to the list of supported features for the local\n * participant.\n * @param {String} feature the name of the feature.\n * @param {boolean} submit if true - the new list of features will be\n * immediately submitted to the others.\n */\nJitsiConnection.prototype.addFeature = function(feature, submit = false) {\n    this.xmpp.caps.addFeature(feature, submit, true);\n};\n\n/**\n * Removes a feature from the list of supported features for the local\n * participant\n * @param {String} feature the name of the feature.\n * @param {boolean} submit if true - the new list of features will be\n * immediately submitted to the others.\n */\nJitsiConnection.prototype.removeFeature = function(feature, submit = false) {\n    this.xmpp.caps.removeFeature(feature, submit, true);\n};\n\n/**\n * Get object with internal logs.\n */\nJitsiConnection.prototype.getLogs = function() {\n    const data = this.xmpp.getJingleLog();\n\n    const metadata = {};\n\n    metadata.time = new Date();\n    metadata.url = window.location.href;\n    metadata.ua = navigator.userAgent;\n\n    const log = this.xmpp.getXmppLog();\n\n    if (log) {\n        metadata.xmpp = log;\n    }\n\n    data.metadata = metadata;\n\n    return data;\n};\n","/**\n * The events for the media devices.\n */\n\nexport enum JitsiMediaDevicesEvents {\n    /**\n     * Indicates that the list of available media devices has been changed. The\n     * event provides the following parameters to its listeners:\n     *\n     * @param {MediaDeviceInfo[]} devices - array of MediaDeviceInfo or\n     *  MediaDeviceInfo-like objects that are currently connected.\n     *  @see https://developer.mozilla.org/en-US/docs/Web/API/MediaDeviceInfo\n     */\n    DEVICE_LIST_CHANGED = 'mediaDevices.devicechange',\n\n    /**\n     * Event emitted when the user granted/blocked a permission for the camera / mic.\n     * Used to keep track of the granted permissions on browsers which don't\n     * support the Permissions API.\n     */\n    PERMISSIONS_CHANGED = 'rtc.permissions_changed',\n\n    /**\n     * Indicates that the environment is currently showing permission prompt to\n     * access camera and/or microphone. The event provides the following\n     * parameters to its listeners:\n     *\n     * @param {'chrome'|'opera'|'firefox'|'safari'|'nwjs'\n     *  |'react-native'|'android'} environmentType - type of browser or\n     *  other execution environment.\n     */\n    PERMISSION_PROMPT_IS_SHOWN = 'mediaDevices.permissionPromptIsShown',\n\n    SLOW_GET_USER_MEDIA = 'mediaDevices.slowGetUserMedia'\n};\n\n// exported for backward compatibility\nexport const DEVICE_LIST_CHANGED = JitsiMediaDevicesEvents.DEVICE_LIST_CHANGED;\nexport const PERMISSIONS_CHANGED = JitsiMediaDevicesEvents.PERMISSIONS_CHANGED;\nexport const PERMISSION_PROMPT_IS_SHOWN = JitsiMediaDevicesEvents.PERMISSION_PROMPT_IS_SHOWN;\nexport const SLOW_GET_USER_MEDIA = JitsiMediaDevicesEvents.SLOW_GET_USER_MEDIA;\n","import EventEmitter from 'events';\n\nimport * as JitsiMediaDevicesEvents from './JitsiMediaDevicesEvents';\nimport RTC from './modules/RTC/RTC';\nimport browser from './modules/browser';\nimport Statistics from './modules/statistics/statistics';\nimport { MediaType } from './service/RTC/MediaType';\nimport RTCEvents from './service/RTC/RTCEvents';\n\nconst AUDIO_PERMISSION_NAME = 'microphone';\nconst PERMISSION_GRANTED_STATUS = 'granted';\nconst VIDEO_PERMISSION_NAME = 'camera';\n\n/**\n * Media devices utilities for Jitsi.\n */\nclass JitsiMediaDevices {\n    /**\n     * Initializes a {@code JitsiMediaDevices} object. There will be a single\n     * instance of this class.\n     */\n    constructor() {\n        this._eventEmitter = new EventEmitter();\n        this._permissions = {};\n\n        RTC.addListener(\n            RTCEvents.DEVICE_LIST_CHANGED,\n            devices =>\n                this._eventEmitter.emit(\n                    JitsiMediaDevicesEvents.DEVICE_LIST_CHANGED,\n                    devices));\n        RTC.addListener(\n            RTCEvents.DEVICE_LIST_AVAILABLE,\n            devices =>\n                this._logOutputDevice(\n                    this.getAudioOutputDevice(),\n                    devices));\n\n        // We would still want to update the permissions cache in case the permissions API is not supported.\n        RTC.addListener(\n            RTCEvents.PERMISSIONS_CHANGED,\n            permissions => this._handlePermissionsChange(permissions));\n\n        // Test if the W3C Permissions API is implemented and the 'camera' and 'microphone' permissions are\n        // implemented. If supported add onchange listeners.\n        this._permissionsApiSupported = new Promise(resolve => {\n            if (!navigator.permissions) {\n                resolve(false);\n\n                return;\n            }\n\n            const self = this;\n\n            const promises = [];\n\n            promises.push(navigator.permissions.query({ name: VIDEO_PERMISSION_NAME })\n                .then(status => {\n                    this._handlePermissionsChange({\n                        [MediaType.VIDEO]: this._parsePermissionState(status)\n                    });\n                    status.onchange = function() {\n                        try {\n                            self._handlePermissionsChange({\n                                [MediaType.VIDEO]: self._parsePermissionState(this)\n                            });\n                        } catch (error) {\n                            // Nothing to do.\n                        }\n                    };\n\n                    return true;\n                })\n                .catch(() => false));\n\n            promises.push(navigator.permissions.query({ name: AUDIO_PERMISSION_NAME })\n                .then(status => {\n                    this._handlePermissionsChange({\n                        [MediaType.AUDIO]: this._parsePermissionState(status)\n                    });\n                    status.onchange = function() {\n                        try {\n                            self._handlePermissionsChange({\n                                [MediaType.AUDIO]: self._parsePermissionState(this)\n                            });\n                        } catch (error) {\n                            // Nothing to do.\n                        }\n                    };\n\n                    return true;\n                })\n                .catch(() => false));\n\n            Promise.all(promises).then(results => resolve(results.every(supported => supported)));\n\n        });\n    }\n\n\n    /**\n     * Parses a PermissionState object and returns true for granted and false otherwise.\n     *\n     * @param {PermissionState} permissionStatus - The PermissionState object retrieved from the Permissions API.\n     * @returns {boolean} - True for granted and false for denied.\n     * @throws {TypeError}\n     */\n    _parsePermissionState(permissionStatus = {}) {\n        // The status attribute is deprecated, and state\n        // should be used instead, but check both for now\n        // for backwards compatibility.\n        const status = permissionStatus.state || permissionStatus.status;\n\n        if (typeof status !== 'string') {\n            throw new TypeError();\n        }\n\n        return status === PERMISSION_GRANTED_STATUS;\n    }\n\n    /**\n     * Updates the local granted/denied permissions cache. A permissions might be\n     * granted, denied, or undefined. This is represented by having its media\n     * type key set to {@code true} or {@code false} respectively.\n     *\n     * @param {Object} permissions - Object with the permissions.\n     */\n    _handlePermissionsChange(permissions) {\n        const hasPermissionsChanged\n            = [ MediaType.AUDIO, MediaType.VIDEO ]\n                .some(type => type in permissions && permissions[type] !== this._permissions[type]);\n\n        if (hasPermissionsChanged) {\n            this._permissions = {\n                ...this._permissions,\n                ...permissions\n            };\n            this._eventEmitter.emit(JitsiMediaDevicesEvents.PERMISSIONS_CHANGED, this._permissions);\n\n            if (this._permissions[MediaType.AUDIO] || this._permissions[MediaType.VIDEO]) {\n                // Triggering device list update when the permissiions are granted in order to update\n                // the labels the devices.\n                // eslint-disable-next-line no-empty-function\n                this.enumerateDevices(() => {});\n            }\n        }\n    }\n\n    /**\n     * Gathers data and sends it to statistics.\n     * @param deviceID the device id to log\n     * @param devices list of devices\n     */\n    _logOutputDevice(deviceID, devices) {\n        const device\n            = devices.find(\n                d => d.kind === 'audiooutput' && d.deviceId === deviceID);\n\n        if (device) {\n            Statistics.sendActiveDeviceListEvent(\n                RTC.getEventDataForActiveDevice(device));\n        }\n    }\n\n    /**\n     * Executes callback with list of media devices connected.\n     * @param {function} callback\n     */\n    enumerateDevices(callback) {\n        RTC.enumerateDevices(callback);\n    }\n\n    /**\n     * Checks if its possible to enumerate available cameras/micropones.\n     * @returns {Promise<boolean>} a Promise which will be resolved only once\n     * the WebRTC stack is ready, either with true if the device listing is\n     * available available or with false otherwise.\n     */\n    isDeviceListAvailable() {\n        return RTC.isDeviceListAvailable();\n    }\n\n    /**\n     * Returns true if changing the input (camera / microphone) or output\n     * (audio) device is supported and false if not.\n     * @param {string} [deviceType] - type of device to change. Default is\n     *      undefined or 'input', 'output' - for audio output device change.\n     * @returns {boolean} true if available, false otherwise.\n     */\n    isDeviceChangeAvailable(deviceType) {\n        return RTC.isDeviceChangeAvailable(deviceType);\n    }\n\n    /**\n     * Checks if the permission for the given device was granted.\n     *\n     * @param {'audio'|'video'} [type] - type of devices to check,\n     *      undefined stands for both 'audio' and 'video' together\n     * @returns {Promise<boolean>}\n     */\n    isDevicePermissionGranted(type) {\n        return new Promise(resolve => {\n            // Shortcut: first check if we already know the permission was\n            // granted.\n            if (type in this._permissions) {\n                resolve(this._permissions[type]);\n\n                return;\n            }\n\n            // Check using the Permissions API.\n            this._permissionsApiSupported.then(supported => {\n                if (!supported) {\n                    resolve(false);\n\n                    return;\n                }\n\n                const promises = [];\n\n                switch (type) {\n                case MediaType.VIDEO:\n                    promises.push(\n                        navigator.permissions.query({\n                            name: VIDEO_PERMISSION_NAME\n                        }));\n                    break;\n                case MediaType.AUDIO:\n                    promises.push(\n                        navigator.permissions.query({\n                            name: AUDIO_PERMISSION_NAME\n                        }));\n                    break;\n                default:\n                    promises.push(\n                        navigator.permissions.query({\n                            name: VIDEO_PERMISSION_NAME\n                        }));\n                    promises.push(\n                        navigator.permissions.query({\n                            name: AUDIO_PERMISSION_NAME\n                        }));\n                }\n\n                Promise.all(promises).then(\n                    results => resolve(results.every(permissionStatus => {\n                        try {\n                            return this._parsePermissionState(permissionStatus);\n                        } catch {\n                            return false;\n                        }\n                    })),\n                    () => resolve(false)\n                );\n            });\n        });\n    }\n\n    /**\n     * Returns true if it is possible to be simultaneously capturing audio from more than one device.\n     *\n     * @returns {boolean}\n     */\n    isMultipleAudioInputSupported() {\n        return !(browser.isFirefox() || browser.isIosBrowser());\n    }\n\n    /**\n     * Returns currently used audio output device id, 'default' stands\n     * for default device\n     * @returns {string}\n     */\n    getAudioOutputDevice() {\n        return RTC.getAudioOutputDevice();\n    }\n\n    /**\n     * Sets current audio output device.\n     * @param {string} deviceId - id of 'audiooutput' device from\n     *      navigator.mediaDevices.enumerateDevices(), 'default' is for\n     *      default device\n     * @returns {Promise} - resolves when audio output is changed, is rejected\n     *      otherwise\n     */\n    setAudioOutputDevice(deviceId) {\n        const availableDevices = RTC.getCurrentlyAvailableMediaDevices();\n\n        if (availableDevices.length > 0) {\n            // if we have devices info report device to stats\n            // normally this will not happen on startup as this method is called\n            // too early. This will happen only on user selection of new device\n            this._logOutputDevice(\n                deviceId, RTC.getCurrentlyAvailableMediaDevices());\n        }\n\n        return RTC.setAudioOutputDevice(deviceId);\n    }\n\n    /**\n     * Adds an event handler.\n     * @param {string} event - event name\n     * @param {function} handler - event handler\n     */\n    addEventListener(event, handler) {\n        this._eventEmitter.addListener(event, handler);\n    }\n\n    /**\n     * Removes event handler.\n     * @param {string} event - event name\n     * @param {function} handler - event handler\n     */\n    removeEventListener(event, handler) {\n        this._eventEmitter.removeListener(event, handler);\n    }\n\n    /**\n     * Emits an event.\n     * @param {string} event - event name\n     */\n    emitEvent(event, ...args) {\n        this._eventEmitter.emit(event, ...args);\n    }\n}\n\nexport default new JitsiMediaDevices();\n","import { getLogger } from '@jitsi/logger';\n\nimport * as JitsiTrackEvents from '../../JitsiTrackEvents';\nimport RTC from '../RTC/RTC';\nimport Statistics from '../statistics/statistics';\n\n\nconst logger = getLogger(__filename);\n\n// If after 3000 ms the detector did not find any active devices consider that there aren't any usable ones available\n// i.e. audioLevel > 0.008\nconst DETECTION_TIMEOUT = 3000;\n\n\n/**\n * Go through all audio devices on the system and return one that is active, i.e. has audio signal.\n *\n * @returns Promise<Object> - Object containing information about the found device.\n */\nexport default function getActiveAudioDevice() {\n\n    return new Promise(resolve => {\n        RTC.enumerateDevices(devices => {\n            const audioDevices = devices.filter(device => device.kind === 'audioinput');\n            const devicePromiseArray = [];\n\n\n            for (const micDevice of audioDevices) {\n                const devicePromise = RTC.obtainAudioAndVideoPermissions({ devices: [ 'audio' ],\n                    micDeviceId: micDevice.deviceId }).then(tracks => {\n\n                    // We expect a single device to be available when obtained from obtainAudioAndVideoPermissions\n                    // that's  why only take p.value[0].\n                    const track = tracks[0];\n                    const originalStream = track.getOriginalStream();\n\n                    Statistics.startLocalStats(originalStream, track.setAudioLevel.bind(track));\n                    track.addEventListener(JitsiTrackEvents.LOCAL_TRACK_STOPPED, () => {\n                        Statistics.stopLocalStats(originalStream);\n                    });\n\n                    return track;\n                });\n\n                devicePromiseArray.push(devicePromise);\n            }\n\n            Promise.allSettled(devicePromiseArray).then(outcomeArray => {\n                const successfulPromises = outcomeArray.filter(p => p.status === 'fulfilled');\n                const rejectedPromises = outcomeArray.filter(p => p.status === 'rejected');\n\n\n                const availableDevices = successfulPromises.map(p => p.value);\n                const rejectReasons = rejectedPromises.map(p => p.value);\n\n                for (const reason of rejectReasons) {\n                    logger.error('Failed to acquire audio device with error: ', reason);\n                }\n\n                // Setup event handlers for monitored devices.\n                for (const device of availableDevices) {\n                    device.on(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED, audioLevel => {\n                        // This is a very naive approach but works, a more accurate one would be to use rnnoise in\n                        // order to limit  the number of false positives. The 0.008 constant is due to how\n                        // LocalStatsCollector from lib-jitsi-meet publishes audio-levels, in this case 0.008 denotes //\n                        // no input.\n                        if (audioLevel > 0.008) {\n                            stopActiveDevices(availableDevices);\n                            resolve({ deviceId: device.deviceId,\n                                deviceLabel: device.track.label });\n                        }\n                    });\n                }\n\n                // Cancel the detection in case no devices was found with audioLevel > 0 in the set timeout.\n                setTimeout(() => {\n                    stopActiveDevices(availableDevices);\n                    resolve({\n                        deviceId: '',\n                        deviceLabel: '' }\n                    );\n                }, DETECTION_TIMEOUT);\n\n            });\n\n        });\n    });\n}\n\n/**\n * Stop the streams of the provided JitsiLocalTracks.\n *\n * @param {Array<JitsiLocalTrack>} deviceList - Array of JitsiLocalTracks to stop.\n * @returns {void}\n */\nfunction stopActiveDevices(deviceList) {\n    for (const device of deviceList) {\n        device.stopStream();\n    }\n}\n","/**\n * The know jingle actions that can be sent and should be acted upon by\n * {@code ProxyConnectionService} and {@code ProxyConnectionPC}.\n */\nexport enum ACTIONS {\n    ACCEPT = 'session-accept',\n    CONNECTION_ERROR = 'connection-error-encountered',\n    INITIATE = 'session-initiate',\n    TERMINATE = 'session-terminate',\n    TRANSPORT_INFO = 'transport-info',\n    UNAVAILABLE = 'unavailable'\n};\n","import { getLogger } from '@jitsi/logger';\n\nimport RTCEvents from '../../service/RTC/RTCEvents';\nimport { XMPPEvents } from '../../service/xmpp/XMPPEvents';\nimport RTC from '../RTC/RTC';\nimport JingleSessionPC from '../xmpp/JingleSessionPC';\nimport SignalingLayerImpl from '../xmpp/SignalingLayerImpl';\nimport { DEFAULT_STUN_SERVERS } from '../xmpp/xmpp';\n\nimport { ACTIONS } from './constants';\n\nconst logger = getLogger(__filename);\n\n/**\n * An adapter around {@code JingleSessionPC} so its logic can be re-used without\n * an XMPP connection. It is being re-used for consistency with the rest of the\n * codebase and to leverage existing peer connection event handling. Also\n * this class provides a facade to hide most of the API for\n * {@code JingleSessionPC}.\n */\nexport default class ProxyConnectionPC {\n    /**\n     * Initializes a new {@code ProxyConnectionPC} instance.\n     *\n     * @param {Object} options - Values to initialize the instance with.\n     * @param {Object} [options.pcConfig] - The {@code RTCConfiguration} to use for the WebRTC peer connection.\n     * @param {boolean} [options.isInitiator] - If true, the local client should send offers. If false, the local\n     * client should send answers. Defaults to false.\n     * @param {Function} options.onRemoteStream - Callback to invoke when a remote media stream has been received\n     * through the peer connection.\n     * @param {string} options.peerJid - The jid of the remote client with which the peer connection is being establish\n     * and which should receive direct messages regarding peer connection updates.\n     * @param {boolean} [options.receiveVideo] - Whether or not the peer connection should accept incoming video\n     * streams. Defaults to false.\n     * @param {Function} options.onSendMessage - Callback to invoke when a message has to be sent (signaled) out.\n     */\n    constructor(options = {}) {\n        this._options = {\n            pcConfig: {},\n            isInitiator: false,\n            receiveAudio: false,\n            receiveVideo: false,\n            ...options\n        };\n\n        /**\n         * Instances of {@code JitsiTrack} associated with this instance of\n         * {@code ProxyConnectionPC}.\n         *\n         * @type {Array<JitsiTrack>}\n         */\n        this._tracks = [];\n\n        /**\n         * The active instance of {@code JingleSessionPC}.\n         *\n         * @type {JingleSessionPC|null}\n         */\n        this._peerConnection = null;\n\n        // Bind event handlers so they are only bound once for every instance.\n        this._onError = this._onError.bind(this);\n        this._onRemoteStream = this._onRemoteStream.bind(this);\n        this._onSendMessage = this._onSendMessage.bind(this);\n    }\n\n    /**\n     * Returns the jid of the remote peer with which this peer connection should\n     * be established with.\n     *\n     * @returns {string}\n     */\n    getPeerJid() {\n        return this._options.peerJid;\n    }\n\n    /**\n     * Updates the peer connection based on the passed in jingle.\n     *\n     * @param {Object} $jingle - An XML jingle element, wrapped in query,\n     * describing how the peer connection should be updated.\n     * @returns {void}\n     */\n    processMessage($jingle) {\n        switch ($jingle.attr('action')) {\n        case ACTIONS.ACCEPT:\n            this._onSessionAccept($jingle);\n            break;\n\n        case ACTIONS.INITIATE:\n            this._onSessionInitiate($jingle);\n            break;\n\n        case ACTIONS.TERMINATE:\n            this._onSessionTerminate($jingle);\n            break;\n\n        case ACTIONS.TRANSPORT_INFO:\n            this._onTransportInfo($jingle);\n            break;\n        }\n    }\n\n    /**\n     * Instantiates a peer connection and starts the offer/answer cycle to\n     * establish a connection with a remote peer.\n     *\n     * @param {Array<JitsiLocalTrack>} localTracks - Initial local tracks to add\n     * to add to the peer connection.\n     * @returns {void}\n     */\n    start(localTracks = []) {\n        if (this._peerConnection) {\n            return;\n        }\n\n        this._tracks = this._tracks.concat(localTracks);\n\n        this._peerConnection = this._createPeerConnection();\n\n        this._peerConnection.invite(localTracks);\n    }\n\n    /**\n     * Begins the process of disconnecting from a remote peer and cleaning up\n     * the peer connection.\n     *\n     * @returns {void}\n     */\n    stop() {\n        if (this._peerConnection) {\n            this._peerConnection.terminate();\n        }\n\n        this._onSessionTerminate();\n    }\n\n    /**\n     * Instantiates a new {@code JingleSessionPC} by stubbing out the various\n     * dependencies of {@code JingleSessionPC}.\n     *\n     * @private\n     * @returns {JingleSessionPC}\n     */\n    _createPeerConnection() {\n        /**\n         * {@code JingleSessionPC} takes in the entire jitsi-meet config.js\n         * object, which may not be accessible from the caller.\n         *\n         * @type {Object}\n         */\n        const configStub = {};\n\n        /**\n         * {@code JingleSessionPC} assumes an XMPP/Strophe connection object is\n         * passed through, which also has the jingle plugin initialized on it.\n         * This connection object is used to signal out peer connection updates\n         * via iqs, and those updates need to be piped back out to the remote\n         * peer.\n         *\n         * @type {Object}\n         */\n        const connectionStub = {\n            // At the time this is used for Spot and it's okay to say the connection is always connected, because if\n            // spot has no signalling it will not be in a meeting where this is used.\n            connected: true,\n            jingle: {\n                terminate: () => { /** no-op */ }\n            },\n            sendIQ: this._onSendMessage,\n\n            // Returns empty function, because it does not add any listeners for real\n            // eslint-disable-next-line no-empty-function\n            addEventListener: () => () => { }\n        };\n\n        /**\n         * {@code JingleSessionPC} can take in a custom ice configuration,\n         * depending on the peer connection type, peer-to-peer or other.\n         * However, {@code ProxyConnectionPC} always assume a peer-to-peer\n         * connection so the ice configuration is hard-coded with defaults.\n         *\n         * @type {Object}\n         */\n        const pcConfigStub = {\n            iceServers: DEFAULT_STUN_SERVERS,\n            ...this._options.pcConfig\n        };\n\n        /**\n         * {@code JingleSessionPC} expects an instance of\n         * {@code JitsiConference}, which has an event emitter that is used\n         * to signal various connection updates that the local client should\n         * act upon. The conference instance is not a dependency of a proxy\n         * connection, but the emitted events can be relevant to the proxy\n         * connection so the event emitter is stubbed.\n         *\n         * @param {string} event - The constant for the event type.\n         * @type {Function}\n         * @returns {void}\n         */\n        const emitter = event => {\n            switch (event) {\n            case XMPPEvents.CONNECTION_ICE_FAILED:\n            case XMPPEvents.CONNECTION_FAILED:\n                this._onError(ACTIONS.CONNECTION_ERROR, event);\n                break;\n            }\n        };\n\n        /**\n         * {@link JingleSessionPC} expects an instance of\n         * {@link ChatRoom} to be passed in. {@link ProxyConnectionPC}\n         * is instantiated outside of the {@code JitsiConference}, so it must be\n         * stubbed to prevent errors.\n         *\n         * @type {Object}\n         */\n        const roomStub = {\n            addPresenceListener: () => { /** no-op */ },\n            connectionTimes: [],\n            eventEmitter: { emit: emitter },\n            getMediaPresenceInfo: () => {\n                // Errors occur if this function does not return an object\n\n                return {};\n            },\n            removePresenceListener: () => { /** no-op */ },\n            supportsRestartByTerminate: () => false\n        };\n\n        /**\n         * A {@code JitsiConference} stub passed to the {@link RTC} module.\n         * @type {Object}\n         */\n        const conferenceStub = {\n            myUserId: () => ''\n        };\n\n        /**\n         * Create an instance of {@code RTC} as it is required for peer\n         * connection creation by {@code JingleSessionPC}. An existing instance\n         * of {@code RTC} from elsewhere should not be re-used because it is\n         * a stateful grouping of utilities.\n         */\n        this._rtc = new RTC(conferenceStub, {});\n\n        /**\n         * Add the remote track listener here as {@code JingleSessionPC} has\n         * {@code TraceablePeerConnection} which uses {@code RTC}'s event\n         * emitter.\n         */\n        this._rtc.addListener(\n            RTCEvents.REMOTE_TRACK_ADDED,\n            this._onRemoteStream\n        );\n\n        const peerConnection = new JingleSessionPC(\n            undefined, // sid\n            undefined, // localJid\n            this._options.peerJid, // remoteJid\n            connectionStub, // connection\n            {\n                offerToReceiveAudio: this._options.receiveAudio,\n                offerToReceiveVideo: this._options.receiveVideo\n            }, // mediaConstraints\n            pcConfigStub, // pcConfig\n            true, // isP2P\n            this._options.isInitiator // isInitiator\n        );\n\n        const signalingLayer = new SignalingLayerImpl();\n\n        signalingLayer.setChatRoom(roomStub);\n\n        /**\n         * An additional initialize call is necessary to properly set instance\n         * variable for calling.\n         */\n        peerConnection.initialize(roomStub, this._rtc, signalingLayer, configStub);\n\n        return peerConnection;\n    }\n\n    /**\n     * Invoked when a connection related issue has been encountered.\n     *\n     * @param {string} errorType - The constant indicating the type of the error\n     * that occured.\n     * @param {string} details - Optional additional data about the error.\n     * @private\n     * @returns {void}\n     */\n    _onError(errorType, details = '') {\n        this._options.onError(this._options.peerJid, errorType, details);\n    }\n\n    /**\n     * Callback invoked when the peer connection has received a remote media\n     * stream.\n     *\n     * @param {JitsiRemoteTrack} jitsiRemoteTrack - The remote media stream\n     * wrapped in {@code JitsiRemoteTrack}.\n     * @private\n     * @returns {void}\n     */\n    _onRemoteStream(jitsiRemoteTrack) {\n        this._tracks.push(jitsiRemoteTrack);\n\n        this._options.onRemoteStream(jitsiRemoteTrack);\n    }\n\n    /**\n     * Callback invoked when {@code JingleSessionPC} needs to signal a message\n     * out to the remote peer.\n     *\n     * @param {XML} iq - The message to signal out.\n     * @private\n     * @returns {void}\n     */\n    _onSendMessage(iq) {\n        this._options.onSendMessage(this._options.peerJid, iq);\n    }\n\n    /**\n     * Callback invoked in response to an agreement to start a proxy connection.\n     * The passed in jingle element should contain an SDP answer to a previously\n     * sent SDP offer.\n     *\n     * @param {Object} $jingle - The jingle element wrapped in jQuery.\n     * @private\n     * @returns {void}\n     */\n    _onSessionAccept($jingle) {\n        if (!this._peerConnection) {\n            logger.error('Received an answer when no peer connection exists.');\n\n            return;\n        }\n\n        this._peerConnection.setAnswer($jingle);\n    }\n\n    /**\n     * Callback invoked in response to a request to start a proxy connection.\n     * The passed in jingle element should contain an SDP offer.\n     *\n     * @param {Object} $jingle - The jingle element wrapped in jQuery.\n     * @private\n     * @returns {void}\n     */\n    _onSessionInitiate($jingle) {\n        if (this._peerConnection) {\n            logger.error('Received an offer when an offer was already sent.');\n\n            return;\n        }\n\n        this._peerConnection = this._createPeerConnection();\n\n        this._peerConnection.acceptOffer(\n            $jingle,\n            () => { /** no-op */ },\n            () => this._onError(\n                this._options.peerJid,\n                ACTIONS.CONNECTION_ERROR,\n                'session initiate error'\n            )\n        );\n    }\n\n    /**\n     * Callback invoked in response to a request to disconnect an active proxy\n     * connection. Cleans up tracks and the peer connection.\n     *\n     * @private\n     * @returns {void}\n     */\n    _onSessionTerminate() {\n        this._tracks.forEach(track => track.dispose());\n        this._tracks = [];\n\n        if (this._peerConnection) {\n            this._peerConnection.onTerminated();\n        }\n\n        if (this._rtc) {\n            this._rtc.removeListener(\n                RTCEvents.REMOTE_TRACK_ADDED,\n                this._onRemoteStream\n            );\n\n            this._rtc.destroy();\n        }\n    }\n\n    /**\n     * Callback invoked in response to ICE candidates from the remote peer.\n     * The passed in jingle element should contain an ICE candidate.\n     *\n     * @param {Object} $jingle - The jingle element wrapped in jQuery.\n     * @private\n     * @returns {void}\n     */\n    _onTransportInfo($jingle) {\n        this._peerConnection.addIceCandidates($jingle);\n    }\n}\n","import { getLogger } from '@jitsi/logger';\nimport $ from 'jquery';\nimport { $iq } from 'strophe.js';\n\nimport { MediaType } from '../../service/RTC/MediaType';\nimport { VideoType } from '../../service/RTC/VideoType';\nimport RTC from '../RTC/RTC';\n\nimport ProxyConnectionPC from './ProxyConnectionPC';\nimport { ACTIONS } from './constants';\n\nconst logger = getLogger(__filename);\n\n/**\n * Instantiates a new ProxyConnectionPC and ensures only one exists at a given\n * time. Currently it assumes ProxyConnectionPC is used only for screensharing\n * and assumes IQs to be used for communication.\n */\nexport default class ProxyConnectionService {\n    /**\n     * Initializes a new {@code ProxyConnectionService} instance.\n     *\n     * @param {Object} options - Values to initialize the instance with.\n     * @param {boolean} [options.convertVideoToDesktop] - Whether or not proxied video should be returned as a desktop\n     * stream. Defaults to false.\n     * @param {Object} [options.pcConfig] - The {@code RTCConfiguration} to use for the WebRTC peer connection.\n     * @param {JitsiConnection} [options.jitsiConnection] - The {@code JitsiConnection} which will be used to fetch\n     * TURN credentials for the P2P connection.\n     * @param {Function} options.onRemoteStream - Callback to invoke when a remote video stream has been received and\n     * converted to a {@code JitsiLocakTrack}. The {@code JitsiLocakTrack} will be passed in.\n     * @param {Function} options.onSendMessage - Callback to invoke when a message has to be sent (signaled) out. The\n     * arguments passed in are the jid to send the message to and the message.\n     */\n    constructor(options = {}) {\n        const {\n            jitsiConnection,\n            ...otherOptions\n        } = options;\n\n        /**\n         * Holds a reference to the collection of all callbacks.\n         *\n         * @type {Object}\n         */\n        this._options = {\n            pcConfig: jitsiConnection && jitsiConnection.xmpp.connection.jingle.p2pIceConfig,\n            ...otherOptions\n        };\n\n        /**\n         * The active instance of {@code ProxyConnectionService}.\n         *\n         * @type {ProxyConnectionPC|null}\n         */\n        this._peerConnection = null;\n\n        // Bind event handlers so they are only bound once for every instance.\n        this._onFatalError = this._onFatalError.bind(this);\n        this._onSendMessage = this._onSendMessage.bind(this);\n        this._onRemoteStream = this._onRemoteStream.bind(this);\n    }\n\n    /**\n     * Parses a message object regarding a proxy connection to create a new\n     * proxy connection or update and existing connection.\n     *\n     * @param {Object} message - A message object regarding establishing or\n     * updating a proxy connection.\n     * @param {Object} message.data - An object containing additional message\n     * details.\n     * @param {string} message.data.iq - The stringified iq which explains how\n     * and what to update regarding the proxy connection.\n     * @param {string} message.from - The message sender's full jid. Used for\n     * sending replies.\n     * @returns {void}\n     */\n    processMessage(message) {\n        const peerJid = message.from;\n\n        if (!peerJid) {\n            return;\n        }\n\n        // If a proxy connection has already been established and messages come\n        // from another peer jid then those messages should be replied to with\n        // a rejection.\n        if (this._peerConnection\n            && this._peerConnection.getPeerJid() !== peerJid) {\n            this._onFatalError(\n                peerJid,\n                ACTIONS.CONNECTION_ERROR,\n                'rejected'\n            );\n\n            return;\n        }\n\n        const iq = this._convertStringToXML(message.data.iq);\n        const $jingle = iq && iq.find('jingle');\n        const action = $jingle && $jingle.attr('action');\n\n        if (action === ACTIONS.INITIATE) {\n            this._peerConnection = this._createPeerConnection(peerJid, {\n                isInitiator: false,\n                receiveVideo: true\n            });\n        }\n\n        // Truthy check for peer connection added to protect against possibly\n        // receiving actions before an ACTIONS.INITIATE.\n        if (this._peerConnection) {\n            this._peerConnection.processMessage($jingle);\n        }\n\n        // Take additional steps to ensure the peer connection is cleaned up\n        // if it is to be closed.\n        if (action === ACTIONS.CONNECTION_ERROR\n            || action === ACTIONS.UNAVAILABLE\n            || action === ACTIONS.TERMINATE) {\n            this._selfCloseConnection();\n        }\n\n        return;\n    }\n\n    /**\n     * Instantiates and initiates a proxy peer connection.\n     *\n     * @param {string} peerJid - The jid of the remote client that should\n     * receive messages.\n     * @param {Array<JitsiLocalTrack>} localTracks - Initial media tracks to\n     * send through to the peer.\n     * @returns {void}\n     */\n    start(peerJid, localTracks = []) {\n        this._peerConnection = this._createPeerConnection(peerJid, {\n            isInitiator: true,\n            receiveVideo: false\n        });\n\n        this._peerConnection.start(localTracks);\n    }\n\n    /**\n     * Terminates any active proxy peer connection.\n     *\n     * @returns {void}\n     */\n    stop() {\n        if (this._peerConnection) {\n            this._peerConnection.stop();\n        }\n\n        this._peerConnection = null;\n    }\n\n    /**\n     * Transforms a stringified xML into a XML wrapped in jQuery.\n     *\n     * @param {string} xml - The XML in string form.\n     * @private\n     * @returns {Object|null} A jQuery version of the xml. Null will be returned\n     * if an error is encountered during transformation.\n     */\n    _convertStringToXML(xml) {\n        try {\n            const xmlDom = new DOMParser().parseFromString(xml, 'text/xml');\n\n            return $(xmlDom);\n        } catch (e) {\n            logger.error('Attempted to convert incorrectly formatted xml');\n\n            return null;\n        }\n    }\n\n    /**\n     * Helper for creating an instance of {@code ProxyConnectionPC}.\n     *\n     * @param {string} peerJid - The jid of the remote peer with which the\n     * {@code ProxyConnectionPC} will be established with.\n     * @param {Object} options - Additional defaults to instantiate the\n     * {@code ProxyConnectionPC} with. See the constructor of ProxyConnectionPC\n     * for more details.\n     * @private\n     * @returns {ProxyConnectionPC}\n     */\n    _createPeerConnection(peerJid, options = {}) {\n        if (!peerJid) {\n            throw new Error('Cannot create ProxyConnectionPC without a peer.');\n        }\n\n        const pcOptions = {\n            pcConfig: this._options.pcConfig,\n            onError: this._onFatalError,\n            onRemoteStream: this._onRemoteStream,\n            onSendMessage: this._onSendMessage,\n            peerJid,\n            ...options\n        };\n\n        return new ProxyConnectionPC(pcOptions);\n    }\n\n    /**\n     * Callback invoked when an error occurs that should cause\n     * {@code ProxyConnectionPC} to be closed if the peer is currently\n     * connected. Sends an error message/reply back to the peer.\n     *\n     * @param {string} peerJid - The peer jid with which the connection was\n     * attempted or started, and to which an iq with error details should be\n     * sent.\n     * @param {string} errorType - The constant indicating the type of the error\n     * that occured.\n     * @param {string} details - Optional additional data about the error.\n     * @private\n     * @returns {void}\n     */\n    _onFatalError(peerJid, errorType, details = '') {\n        logger.error(\n            'Received a proxy connection error', peerJid, errorType, details);\n\n        const iq = $iq({\n            to: peerJid,\n            type: 'set'\n        })\n            .c('jingle', {\n                xmlns: 'urn:xmpp:jingle:1',\n                action: errorType\n            })\n            .c('details')\n            .t(details)\n            .up();\n\n        this._onSendMessage(peerJid, iq);\n\n        if (this._peerConnection\n            && this._peerConnection.getPeerJid() === peerJid) {\n            this._selfCloseConnection();\n        }\n    }\n\n    /**\n     * Callback invoked when the remote peer of the {@code ProxyConnectionPC}\n     * has offered a media stream. The stream is converted into a\n     * {@code JitsiLocalTrack} for local usage if the {@code onRemoteStream}\n     * callback is defined.\n     *\n     * @param {JitsiRemoteTrack} jitsiRemoteTrack - The {@code JitsiRemoteTrack}\n     * for the peer's media stream.\n     * @private\n     * @returns {void}\n     */\n    _onRemoteStream(jitsiRemoteTrack) {\n        if (!this._options.onRemoteStream) {\n            logger.error('Remote track received without callback.');\n            jitsiRemoteTrack.dispose();\n\n            return;\n        }\n\n        const isVideo = jitsiRemoteTrack.isVideoTrack();\n        let videoType;\n\n        if (isVideo) {\n            videoType = this._options.convertVideoToDesktop\n                ? VideoType.DESKTOP : VideoType.CAMERA;\n        }\n\n        // Grab the webrtc media stream and pipe it through the same processing\n        // that would occur for a locally obtained media stream.\n        const mediaStream = jitsiRemoteTrack.getOriginalStream();\n        const jitsiLocalTracks = RTC.createLocalTracks(\n            [\n                {\n                    deviceId:\n                        `proxy:${this._peerConnection.getPeerJid()}`,\n                    mediaType: isVideo ? MediaType.VIDEO : MediaType.AUDIO,\n                    sourceType: 'proxy',\n                    stream: mediaStream,\n                    track: mediaStream.getVideoTracks()[0],\n                    videoType\n                }\n            ]);\n\n        this._options.onRemoteStream(jitsiLocalTracks[0]);\n    }\n\n    /**\n     * Formats and forwards a message an iq to be sent to a peer jid.\n     *\n     * @param {string} peerJid - The jid the iq should be sent to.\n     * @param {Object} iq - The iq which would be sent to the peer jid.\n     * @private\n     * @returns {void}\n     */\n    _onSendMessage(peerJid, iq) {\n        if (!this._options.onSendMessage) {\n            return;\n        }\n\n        try {\n            const stringifiedIq\n                = new XMLSerializer().serializeToString(iq.nodeTree || iq);\n\n            this._options.onSendMessage(peerJid, { iq: stringifiedIq });\n        } catch (e) {\n            logger.error('Attempted to send an incorrectly formatted iq.');\n        }\n    }\n\n    /**\n     * Invoked when preemptively closing the {@code ProxyConnectionPC}.\n     *\n     * @private\n     * @returns {void}\n     */\n    _selfCloseConnection() {\n        this.stop();\n\n        this._options.onConnectionClosed\n            && this._options.onConnectionClosed();\n    }\n}\n","import EventEmitter from 'events';\n\nimport browser from '../browser';\nimport Settings from '../settings/Settings';\nimport ScriptUtil from '../util/ScriptUtil';\n\nimport { CALLSTATS_SCRIPT_URL } from './constants';\n\nconst PRECALL_TEST_RESULTS = 'preCallTestResults';\nconst emitter = new EventEmitter();\nlet _initialized = false;\nlet api = null;\n\n/**\n * Loads the callstats io script.\n *\n * @returns {Promise<void>}\n */\nfunction _loadScript(options) {\n    if (browser.isReactNative()) {\n        return;\n    }\n\n    return new Promise(resolve => {\n        ScriptUtil.loadScript(\n            options.callStatsCustomScriptUrl || CALLSTATS_SCRIPT_URL,\n            /* async */ true,\n            /* prepend */ true,\n            /* relativeURL */ undefined,\n            /* loadCallback */ resolve);\n    });\n}\n\n/**\n * Initializes the callstats lib and registers a callback to be invoked\n * when there are 'preCallTestResults'.\n *\n * @typedef PrecallTestOptions\n * @type {Object}\n * @property {string} callStatsID - Callstats credentials - the id.\n * @property {string} callStatsSecret - Callstats credentials - the secret.\n * @property {string} statisticsId - The user name to use when initializing callstats.\n * @property {string} statisticsDisplayName - The user display name.\n *\n * @param { PrecallTestOptions} options - The init options.\n * @returns {Promise<void>}\n */\nfunction _initialize(options) {\n    return new Promise((resolve, reject) => {\n        const appId = options.callStatsID;\n        const appSecret = options.callStatsSecret;\n        const userId = options.statisticsId || options.statisticsDisplayName || Settings.callStatsUserName;\n\n        api.initialize(appId, appSecret, userId, (status, message) => {\n            if (status === 'success') {\n                api.on(PRECALL_TEST_RESULTS, (...args) => {\n                    emitter.emit(PRECALL_TEST_RESULTS, ...args);\n                });\n                _initialized = true;\n                resolve();\n            } else {\n                reject({\n                    status,\n                    message\n                });\n            }\n        }, null, { disablePrecalltest: true });\n    });\n}\n\n/**\n * Loads the callstats script and initializes the library.\n *\n * @param {Function} onResult - The callback to be invoked when results are received.\n * @returns {Promise<void>}\n */\nexport async function init(options) {\n    if (_initialized) {\n        throw new Error('Precall Test already initialized');\n    }\n\n    const { callStatsID, callStatsSecret, disableThirdPartyRequests } = options;\n\n    if (!callStatsID || !callStatsSecret || disableThirdPartyRequests) {\n        throw new Error('Callstats is disabled');\n    }\n\n    await _loadScript(options);\n    // eslint-disable-next-line new-cap\n    api = new window.callstats();\n\n    return _initialize(options);\n}\n\n/**\n * Executes a pre call test.\n *\n * @typedef PrecallTestResults\n * @type {Object}\n * @property {boolean} mediaConnectivity - If there is media connectivity or not.\n * @property {number} throughput  - The average throughput.\n * @property {number} fractionalLoss - The packet loss.\n * @property {number} rtt - The round trip time.\n * @property {string} provider - It is usually 'callstats'.\n *\n * @returns {Promise<{PrecallTestResults}>}\n */\nexport function execute() {\n    if (!_initialized) {\n        return Promise.reject('uninitialized');\n    }\n\n    return new Promise((resolve, reject) => {\n        emitter.on(PRECALL_TEST_RESULTS, (status, payload) => {\n            if (status === 'success') {\n                resolve(payload);\n            } else {\n                reject({\n                    status,\n                    payload\n                });\n            }\n\n        });\n\n        api.makePrecallTest();\n    });\n}\n\nexport default {\n    init,\n    execute\n};\n","import { getLogger } from '@jitsi/logger';\n\nimport { createAudioContext } from './WebAudioUtils';\n\nconst logger = getLogger(__filename);\n\n/**\n * The AudioMixer, as the name implies, mixes a number of MediaStreams containing audio tracks into a single\n * MediaStream.\n */\nexport default class AudioMixer {\n    /**\n     * Create AudioMixer instance.\n     */\n    constructor() {\n        this._started = false;\n        this._streamsToMix = [];\n        this._streamMSSArray = [];\n    }\n\n    /**\n     * Add audio MediaStream to be mixed, if the stream doesn't contain any audio tracks it will be ignored.\n     *\n     * @param {MediaStream} stream - MediaStream to be mixed.\n     */\n    addMediaStream(stream) {\n        if (!stream.getAudioTracks()) {\n            logger.warn('Added MediaStream doesn\\'t contain audio tracks.');\n        }\n\n        this._streamsToMix.push(stream);\n    }\n\n    /**\n     * At this point a WebAudio ChannelMergerNode is created and and the two associated MediaStreams are connected to\n     * it; the resulting mixed MediaStream is returned.\n     *\n     * @returns {MediaStream} - MediaStream containing added streams mixed together, or null if no MediaStream\n     * is added.\n     */\n    start() {\n        // If the mixer was already started just return the existing mixed stream.\n        if (this._started) {\n            return this._mixedMSD.stream;\n        }\n\n        this._audioContext = createAudioContext();\n\n        if (!this._streamsToMix.length) {\n            logger.warn('No MediaStream\\'s added to AudioMixer, nothing will happen.');\n\n            return null;\n        }\n\n        this._started = true;\n\n        this._mixedMSD = this._audioContext.createMediaStreamDestination();\n\n        for (const stream of this._streamsToMix) {\n            const streamMSS = this._audioContext.createMediaStreamSource(stream);\n\n            streamMSS.connect(this._mixedMSD);\n\n            // Maintain a list of MediaStreamAudioSourceNode so we can disconnect them on reset.\n            this._streamMSSArray.push(streamMSS);\n        }\n\n        return this._mixedMSD.stream;\n    }\n\n    /**\n     * Disconnect MediaStreamAudioSourceNode and clear references.\n     *\n     * @returns {void}\n     */\n    reset() {\n        this._started = false;\n        this._streamsToMix = [];\n\n        // Clean up created MediaStreamAudioSourceNode.\n        for (const streamMSS of this._streamMSSArray) {\n            streamMSS.disconnect();\n        }\n\n        this._streamMSSArray = [];\n\n        if (this._audioContext) {\n            this._audioContext = undefined;\n        }\n    }\n}\n","import Logger from '@jitsi/logger';\n\nimport * as JitsiConferenceErrors from './JitsiConferenceErrors';\nimport * as JitsiConferenceEvents from './JitsiConferenceEvents';\nimport JitsiConnection from './JitsiConnection';\nimport * as JitsiConnectionErrors from './JitsiConnectionErrors';\nimport * as JitsiConnectionEvents from './JitsiConnectionEvents';\nimport JitsiMediaDevices from './JitsiMediaDevices';\nimport * as JitsiMediaDevicesEvents from './JitsiMediaDevicesEvents';\nimport JitsiTrackError from './JitsiTrackError';\nimport * as JitsiTrackErrors from './JitsiTrackErrors';\nimport * as JitsiTrackEvents from './JitsiTrackEvents';\nimport * as JitsiTranscriptionStatus from './JitsiTranscriptionStatus';\nimport RTC from './modules/RTC/RTC';\nimport browser from './modules/browser';\nimport NetworkInfo from './modules/connectivity/NetworkInfo';\nimport { ParticipantConnectionStatus }\n    from './modules/connectivity/ParticipantConnectionStatus';\nimport { TrackStreamingStatus } from './modules/connectivity/TrackStreamingStatus';\nimport getActiveAudioDevice from './modules/detection/ActiveDeviceDetector';\nimport * as DetectionEvents from './modules/detection/DetectionEvents';\nimport TrackVADEmitter from './modules/detection/TrackVADEmitter';\nimport FeatureFlags from './modules/flags/FeatureFlags';\nimport ProxyConnectionService\n    from './modules/proxyconnection/ProxyConnectionService';\nimport recordingConstants from './modules/recording/recordingConstants';\nimport Settings from './modules/settings/Settings';\nimport LocalStatsCollector from './modules/statistics/LocalStatsCollector';\nimport precallTest from './modules/statistics/PrecallTest';\nimport Statistics from './modules/statistics/statistics';\nimport AuthUtil from './modules/util/AuthUtil';\nimport GlobalOnErrorHandler from './modules/util/GlobalOnErrorHandler';\nimport ScriptUtil from './modules/util/ScriptUtil';\nimport * as VideoSIPGWConstants from './modules/videosipgw/VideoSIPGWConstants';\nimport AudioMixer from './modules/webaudio/AudioMixer';\nimport { MediaType } from './service/RTC/MediaType';\nimport * as ConnectionQualityEvents\n    from './service/connectivity/ConnectionQualityEvents';\nimport * as E2ePingEvents from './service/e2eping/E2ePingEvents';\nimport { createGetUserMediaEvent } from './service/statistics/AnalyticsEvents';\n\nconst logger = Logger.getLogger(__filename);\n\n/**\n * The amount of time to wait until firing\n * {@link JitsiMediaDevicesEvents.PERMISSION_PROMPT_IS_SHOWN} event.\n */\nconst USER_MEDIA_SLOW_PROMISE_TIMEOUT = 1000;\n\n/**\n * Extracts from an 'options' objects with a specific format (TODO what IS the\n * format?) the attributes which are to be logged in analytics events.\n *\n * @param options gum options (???)\n * @returns {*} the attributes to attach to analytics events.\n */\nfunction getAnalyticsAttributesFromOptions(options) {\n    const attributes = {\n        'audio_requested':\n            options.devices.includes('audio'),\n        'video_requested':\n            options.devices.includes('video'),\n        'screen_sharing_requested':\n            options.devices.includes('desktop')\n    };\n\n    if (attributes.video_requested) {\n        attributes.resolution = options.resolution;\n    }\n\n    return attributes;\n}\n\n/**\n * Tries to deal with the following problem: {@code JitsiMeetJS} is not only\n * this module, it's also a global (i.e. attached to {@code window}) namespace\n * for all globals of the projects in the Jitsi Meet family. If lib-jitsi-meet\n * is loaded through an HTML {@code script} tag, {@code JitsiMeetJS} will\n * automatically be attached to {@code window} by webpack. Unfortunately,\n * webpack's source code does not check whether the global variable has already\n * been assigned and overwrites it. Which is OK for the module\n * {@code JitsiMeetJS} but is not OK for the namespace {@code JitsiMeetJS}\n * because it may already contain the values of other projects in the Jitsi Meet\n * family. The solution offered here works around webpack by merging all\n * existing values of the namespace {@code JitsiMeetJS} into the module\n * {@code JitsiMeetJS}.\n *\n * @param {Object} module - The module {@code JitsiMeetJS} (which will be\n * exported and may be attached to {@code window} by webpack later on).\n * @private\n * @returns {Object} - A {@code JitsiMeetJS} module which contains all existing\n * value of the namespace {@code JitsiMeetJS} (if any).\n */\nfunction _mergeNamespaceAndModule(module) {\n    return (\n        typeof window.JitsiMeetJS === 'object'\n            ? Object.assign({}, window.JitsiMeetJS, module)\n            : module);\n}\n\n/**\n * The public API of the Jitsi Meet library (a.k.a. {@code JitsiMeetJS}).\n */\nexport default _mergeNamespaceAndModule({\n\n    version: '{#COMMIT_HASH#}',\n\n    JitsiConnection,\n\n    /**\n     * {@code ProxyConnectionService} is used to connect a remote peer to a\n     * local Jitsi participant without going through a Jitsi conference. It is\n     * currently used for room integration development, specifically wireless\n     * screensharing. Its API is experimental and will likely change; usage of\n     * it is advised against.\n     */\n    ProxyConnectionService,\n\n    constants: {\n        participantConnectionStatus: ParticipantConnectionStatus,\n        recording: recordingConstants,\n        sipVideoGW: VideoSIPGWConstants,\n        transcriptionStatus: JitsiTranscriptionStatus,\n        trackStreamingStatus: TrackStreamingStatus\n    },\n    events: {\n        conference: JitsiConferenceEvents,\n        connection: JitsiConnectionEvents,\n        detection: DetectionEvents,\n        track: JitsiTrackEvents,\n        mediaDevices: JitsiMediaDevicesEvents,\n        connectionQuality: ConnectionQualityEvents,\n        e2eping: E2ePingEvents\n    },\n    errors: {\n        conference: JitsiConferenceErrors,\n        connection: JitsiConnectionErrors,\n        track: JitsiTrackErrors\n    },\n    errorTypes: {\n        JitsiTrackError\n    },\n    logLevels: Logger.levels,\n    mediaDevices: JitsiMediaDevices,\n    analytics: Statistics.analytics,\n    init(options = {}) {\n        Settings.init(options.externalStorage);\n        Statistics.init(options);\n\n        // Configure the feature flags.\n        FeatureFlags.init(options.flags || { });\n\n        // Initialize global window.connectionTimes\n        // FIXME do not use 'window'\n        if (!window.connectionTimes) {\n            window.connectionTimes = {};\n        }\n\n        if (options.enableAnalyticsLogging !== true) {\n            logger.warn('Analytics disabled, disposing.');\n            this.analytics.dispose();\n        }\n\n        if (options.enableWindowOnErrorHandler) {\n            GlobalOnErrorHandler.addHandler(\n                this.getGlobalOnErrorHandler.bind(this));\n        }\n\n        if (this.version) {\n            const logObject = {\n                id: 'component_version',\n                component: 'lib-jitsi-meet',\n                version: this.version\n            };\n\n            Statistics.sendLog(JSON.stringify(logObject));\n        }\n\n        return RTC.init(options);\n    },\n\n    /**\n     * Returns whether the desktop sharing is enabled or not.\n     *\n     * @returns {boolean}\n     */\n    isDesktopSharingEnabled() {\n        return RTC.isDesktopSharingEnabled();\n    },\n\n    /**\n     * Returns whether the current execution environment supports WebRTC (for\n     * use within this library).\n     *\n     * @returns {boolean} {@code true} if WebRTC is supported in the current\n     * execution environment (for use within this library); {@code false},\n     * otherwise.\n     */\n    isWebRtcSupported() {\n        return RTC.isWebRtcSupported();\n    },\n\n    setLogLevel(level) {\n        Logger.setLogLevel(level);\n    },\n\n    /**\n     * Sets the log level to the <tt>Logger</tt> instance with given id.\n     *\n     * @param {Logger.levels} level the logging level to be set\n     * @param {string} id the logger id to which new logging level will be set.\n     * Usually it's the name of the JavaScript source file including the path\n     * ex. \"modules/xmpp/ChatRoom.js\"\n     */\n    setLogLevelById(level, id) {\n        Logger.setLogLevelById(level, id);\n    },\n\n    /**\n     * Registers new global logger transport to the library logging framework.\n     *\n     * @param globalTransport\n     * @see Logger.addGlobalTransport\n     */\n    addGlobalLogTransport(globalTransport) {\n        Logger.addGlobalTransport(globalTransport);\n    },\n\n    /**\n     * Removes global logging transport from the library logging framework.\n     *\n     * @param globalTransport\n     * @see Logger.removeGlobalTransport\n     */\n    removeGlobalLogTransport(globalTransport) {\n        Logger.removeGlobalTransport(globalTransport);\n    },\n\n    /**\n    * Sets global options which will be used by all loggers. Changing these\n    * works even after other loggers are created.\n    *\n    * @param options\n    * @see Logger.setGlobalOptions\n    */\n    setGlobalLogOptions(options) {\n        Logger.setGlobalOptions(options);\n    },\n\n    /**\n     * Creates the media tracks and returns them trough the callback.\n     *\n     * @param options Object with properties / settings specifying the tracks\n     * which should be created. should be created or some additional\n     * configurations about resolution for example.\n     * @param {Array} options.effects optional effects array for the track\n     * @param {boolean} options.firePermissionPromptIsShownEvent - if event\n     * JitsiMediaDevicesEvents.PERMISSION_PROMPT_IS_SHOWN should be fired\n     * @param {boolean} options.fireSlowPromiseEvent - if event\n     * JitsiMediaDevicesEvents.USER_MEDIA_SLOW_PROMISE_TIMEOUT should be fired\n     * @param {Array} options.devices the devices that will be requested\n     * @param {string} options.resolution resolution constraints\n     * @param {string} options.cameraDeviceId\n     * @param {string} options.micDeviceId\n     * @param {intiger} interval - the interval (in ms) for\n     * checking whether the desktop sharing extension is installed or not\n     * @param {Function} checkAgain - returns boolean. While checkAgain()==true\n     * createLocalTracks will wait and check on every \"interval\" ms for the\n     * extension. If the desktop extension is not install and checkAgain()==true\n     * createLocalTracks will finish with rejected Promise.\n     * @param {Function} listener - The listener will be called to notify the\n     * user of lib-jitsi-meet that createLocalTracks is starting external\n     * extension installation process.\n     * NOTE: If the inline installation process is not possible and external\n     * installation is enabled the listener property will be called to notify\n     * the start of external installation process. After that createLocalTracks\n     * will start to check for the extension on every interval ms until the\n     * plugin is installed or until checkAgain return false. If the extension\n     * is found createLocalTracks will try to get the desktop sharing track and\n     * will finish the execution. If checkAgain returns false, createLocalTracks\n     * will finish the execution with rejected Promise.\n     *\n     * @deprecated old firePermissionPromptIsShownEvent\n     * @returns {Promise.<{Array.<JitsiLocalTrack>}, JitsiConferenceError>} A promise\n     * that returns an array of created JitsiTracks if resolved, or a\n     * JitsiConferenceError if rejected.\n     */\n    createLocalTracks(options = {}, oldfirePermissionPromptIsShownEvent) {\n        let promiseFulfilled = false;\n\n        const { firePermissionPromptIsShownEvent, fireSlowPromiseEvent, ...restOptions } = options;\n        const firePermissionPrompt = firePermissionPromptIsShownEvent || oldfirePermissionPromptIsShownEvent;\n\n        if (firePermissionPrompt && !RTC.arePermissionsGrantedForAvailableDevices()) {\n            JitsiMediaDevices.emitEvent(\n                JitsiMediaDevicesEvents.PERMISSION_PROMPT_IS_SHOWN,\n                browser.getName());\n        } else if (fireSlowPromiseEvent) {\n            window.setTimeout(() => {\n                if (!promiseFulfilled) {\n                    JitsiMediaDevices.emitEvent(JitsiMediaDevicesEvents.SLOW_GET_USER_MEDIA);\n                }\n            }, USER_MEDIA_SLOW_PROMISE_TIMEOUT);\n        }\n\n        if (!window.connectionTimes) {\n            window.connectionTimes = {};\n        }\n        window.connectionTimes['obtainPermissions.start']\n            = window.performance.now();\n\n        return RTC.obtainAudioAndVideoPermissions(restOptions)\n            .then(tracks => {\n                promiseFulfilled = true;\n\n                window.connectionTimes['obtainPermissions.end']\n                    = window.performance.now();\n\n                Statistics.sendAnalytics(\n                    createGetUserMediaEvent(\n                        'success',\n                        getAnalyticsAttributesFromOptions(restOptions)));\n\n                if (!RTC.options.disableAudioLevels) {\n                    for (let i = 0; i < tracks.length; i++) {\n                        const track = tracks[i];\n                        const mStream = track.getOriginalStream();\n\n                        if (track.getType() === MediaType.AUDIO) {\n                            Statistics.startLocalStats(mStream,\n                                track.setAudioLevel.bind(track));\n                            track.addEventListener(\n                                JitsiTrackEvents.LOCAL_TRACK_STOPPED,\n                                () => {\n                                    Statistics.stopLocalStats(mStream);\n                                });\n                        }\n                    }\n                }\n\n                // set real device ids\n                const currentlyAvailableMediaDevices\n                    = RTC.getCurrentlyAvailableMediaDevices();\n\n                if (currentlyAvailableMediaDevices) {\n                    for (let i = 0; i < tracks.length; i++) {\n                        const track = tracks[i];\n\n                        track._setRealDeviceIdFromDeviceList(\n                            currentlyAvailableMediaDevices);\n                    }\n                }\n\n                // set the contentHint to \"detail\" for desktop tracks\n                // eslint-disable-next-line prefer-const\n                for (const track of tracks) {\n                    if (track.type === MediaType.VIDEO\n                        && track.videoType === 'desktop') {\n                        this.setVideoTrackContentHints(track.track, 'detail');\n                    }\n                }\n\n                return tracks;\n            })\n            .catch(error => {\n                promiseFulfilled = true;\n\n                if (error.name === JitsiTrackErrors.SCREENSHARING_USER_CANCELED) {\n                    // User cancelled action is not really an error, so only\n                    // log it as an event to avoid having conference classified\n                    // as partially failed\n                    const logObject = {\n                        id: 'screensharing_user_canceled',\n                        message: error.message\n                    };\n\n                    Statistics.sendLog(JSON.stringify(logObject));\n\n                    Statistics.sendAnalytics(\n                        createGetUserMediaEvent(\n                            'warning',\n                            {\n                                reason: 'extension install user canceled'\n                            }));\n                } else if (error.name === JitsiTrackErrors.NOT_FOUND) {\n                    // logs not found devices with just application log to cs\n                    const logObject = {\n                        id: 'usermedia_missing_device',\n                        status: error.gum.devices\n                    };\n\n                    Statistics.sendLog(JSON.stringify(logObject));\n\n                    const attributes\n                        = getAnalyticsAttributesFromOptions(options);\n\n                    attributes.reason = 'device not found';\n                    attributes.devices = error.gum.devices.join('.');\n                    Statistics.sendAnalytics(\n                        createGetUserMediaEvent('error', attributes));\n                } else {\n                    // Report gUM failed to the stats\n                    Statistics.sendGetUserMediaFailed(error);\n\n                    const attributes\n                        = getAnalyticsAttributesFromOptions(options);\n\n                    attributes.reason = error.name;\n                    Statistics.sendAnalytics(\n                        createGetUserMediaEvent('error', attributes));\n                }\n\n                window.connectionTimes['obtainPermissions.end']\n                    = window.performance.now();\n\n                return Promise.reject(error);\n            });\n    },\n\n    /**\n     * Create a TrackVADEmitter service that connects an audio track to an VAD (voice activity detection) processor in\n     * order to obtain VAD scores for individual PCM audio samples.\n     * @param {string} localAudioDeviceId - The target local audio device.\n     * @param {number} sampleRate - Sample rate at which the emitter will operate. Possible values  256, 512, 1024,\n     * 4096, 8192, 16384. Passing other values will default to closes neighbor.\n     * I.e. Providing a value of 4096 means that the emitter will process 4096 PCM samples at a time, higher values mean\n     * longer calls, lowers values mean more calls but shorter.\n     * @param {Object} vadProcessor - VAD Processors that does the actual compute on a PCM sample.The processor needs\n     * to implement the following functions:\n     * - <tt>getSampleLength()</tt> - Returns the sample size accepted by calculateAudioFrameVAD.\n     * - <tt>getRequiredPCMFrequency()</tt> - Returns the PCM frequency at which the processor operates.\n     * i.e. (16KHz, 44.1 KHz etc.)\n     * - <tt>calculateAudioFrameVAD(pcmSample)</tt> - Process a 32 float pcm sample of getSampleLength size.\n     * @returns {Promise<TrackVADEmitter>}\n     */\n    createTrackVADEmitter(localAudioDeviceId, sampleRate, vadProcessor) {\n        return TrackVADEmitter.create(localAudioDeviceId, sampleRate, vadProcessor);\n    },\n\n    /**\n     * Create AudioMixer, which is essentially a wrapper over web audio ChannelMergerNode. It essentially allows the\n     * user to mix multiple MediaStreams into a single one.\n     *\n     * @returns {AudioMixer}\n     */\n    createAudioMixer() {\n        return new AudioMixer();\n    },\n\n    /**\n     * Go through all audio devices on the system and return one that is active, i.e. has audio signal.\n     *\n     * @returns Promise<Object> - Object containing information about the found device.\n     */\n    getActiveAudioDevice() {\n        return getActiveAudioDevice();\n    },\n\n    /**\n     * Checks if its possible to enumerate available cameras/microphones.\n     *\n     * @returns {Promise<boolean>} a Promise which will be resolved only once\n     * the WebRTC stack is ready, either with true if the device listing is\n     * available available or with false otherwise.\n     * @deprecated use JitsiMeetJS.mediaDevices.isDeviceListAvailable instead\n     */\n    isDeviceListAvailable() {\n        logger.warn('This method is deprecated, use '\n            + 'JitsiMeetJS.mediaDevices.isDeviceListAvailable instead');\n\n        return this.mediaDevices.isDeviceListAvailable();\n    },\n\n    /**\n     * Returns true if changing the input (camera / microphone) or output\n     * (audio) device is supported and false if not.\n     *\n     * @param {string} [deviceType] - type of device to change. Default is\n     * {@code undefined} or 'input', 'output' - for audio output device change.\n     * @returns {boolean} {@code true} if available; {@code false}, otherwise.\n     * @deprecated use JitsiMeetJS.mediaDevices.isDeviceChangeAvailable instead\n     */\n    isDeviceChangeAvailable(deviceType) {\n        logger.warn('This method is deprecated, use '\n            + 'JitsiMeetJS.mediaDevices.isDeviceChangeAvailable instead');\n\n        return this.mediaDevices.isDeviceChangeAvailable(deviceType);\n    },\n\n\n    /**\n     * Checks if the current environment supports having multiple audio\n     * input devices in use simultaneously.\n     *\n     * @returns {boolean} True if multiple audio input devices can be used.\n     */\n    isMultipleAudioInputSupported() {\n        return this.mediaDevices.isMultipleAudioInputSupported();\n    },\n\n    /**\n     * Checks if local tracks can collect stats and collection is enabled.\n     *\n     * @param {boolean} True if stats are being collected for local tracks.\n     */\n    isCollectingLocalStats() {\n        return Statistics.audioLevelsEnabled\n            && LocalStatsCollector.isLocalStatsSupported();\n    },\n\n    /**\n     * Executes callback with list of media devices connected.\n     *\n     * @param {function} callback\n     * @deprecated use JitsiMeetJS.mediaDevices.enumerateDevices instead\n     */\n    enumerateDevices(callback) {\n        logger.warn('This method is deprecated, use '\n            + 'JitsiMeetJS.mediaDevices.enumerateDevices instead');\n        this.mediaDevices.enumerateDevices(callback);\n    },\n\n    /* eslint-disable max-params */\n\n    /**\n     * @returns function that can be used to be attached to window.onerror and\n     * if options.enableWindowOnErrorHandler is enabled returns\n     * the function used by the lib.\n     * (function(message, source, lineno, colno, error)).\n     */\n    getGlobalOnErrorHandler(message, source, lineno, colno, error) {\n        logger.error(\n            `UnhandledError: ${message}`,\n            `Script: ${source}`,\n            `Line: ${lineno}`,\n            `Column: ${colno}`,\n            'StackTrace: ', error);\n        Statistics.reportGlobalError(error);\n    },\n\n    /**\n     * Informs lib-jitsi-meet about the current network status.\n     *\n     * @param {boolean} isOnline - {@code true} if the internet connectivity is online or {@code false}\n     * otherwise.\n     */\n    setNetworkInfo({ isOnline }) {\n        NetworkInfo.updateNetworkInfo({ isOnline });\n    },\n\n    /**\n     * Set the contentHint on the transmitted stream track to indicate\n     * charaterstics in the video stream, which informs PeerConnection\n     * on how to encode the track (to prefer motion or individual frame detail)\n     * @param {MediaStreamTrack} track - the track that is transmitted\n     * @param {String} hint - contentHint value that needs to be set on the track\n     */\n    setVideoTrackContentHints(track, hint) {\n        if ('contentHint' in track) {\n            track.contentHint = hint;\n            if (track.contentHint !== hint) {\n                logger.debug('Invalid video track contentHint');\n            }\n        } else {\n            logger.debug('MediaStreamTrack contentHint attribute not supported');\n        }\n    },\n\n    precallTest,\n\n    /* eslint-enable max-params */\n\n    /**\n     * Represents a hub/namespace for utility functionality which may be of\n     * interest to lib-jitsi-meet clients.\n     */\n    util: {\n        AuthUtil,\n        ScriptUtil,\n        browser\n    }\n});\n","export default {\n    error: {\n        BUSY: 'busy',\n        ERROR: 'error',\n        RESOURCE_CONSTRAINT: 'resource-constraint',\n        UNEXPECTED_REQUEST: 'unexpected-request',\n        SERVICE_UNAVAILABLE: 'service-unavailable'\n    },\n    mode: {\n        FILE: 'file',\n        STREAM: 'stream'\n    },\n    status: {\n        OFF: 'off',\n        ON: 'on',\n        PENDING: 'pending'\n    }\n};\n","(function (global, factory) {\n            typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :\n            typeof define === 'function' && define.amd ? define(['exports'], factory) :\n            (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.strophe = {}));\n})(this, (function (exports) { 'use strict';\n\n            var global$1 = typeof global !== \"undefined\" ? global : typeof self !== \"undefined\" ? self : typeof window !== \"undefined\" ? window : {};\n\n            /*\n             * This module provides uniform\n             * Shims APIs and globals that are not present in all JS environments,\n             * the most common example for Strophe being browser APIs like WebSocket\n             * and DOM that don't exist under nodejs.\n             *\n             * Usually these will be supplied in nodejs by conditionally requiring a\n             * NPM module that provides a compatible implementation.\n             */\n\n            /* global global */\n\n            /**\n             * WHATWG WebSockets API\n             * https://www.w3.org/TR/websockets/\n             *\n             * Interface to use the web socket protocol\n             *\n             * Used implementations:\n             * - supported browsers: built-in in WebSocket global\n             *   https://developer.mozilla.org/en-US/docs/Web/API/WebSocket#Browser_compatibility\n             * - nodejs: use standard-compliant 'ws' module\n             *   https://www.npmjs.com/package/ws\n             */\n            function getWebSocketImplementation() {\n              let WebSocketImplementation = global$1.WebSocket;\n\n              if (typeof WebSocketImplementation === 'undefined') {\n                try {\n                  WebSocketImplementation = require('ws');\n                } catch (err) {\n                  throw new Error('You must install the \"ws\" package to use Strophe in nodejs.');\n                }\n              }\n\n              return WebSocketImplementation;\n            }\n\n            const WebSocket = getWebSocketImplementation();\n            /**\n             * DOMParser\n             * https://w3c.github.io/DOM-Parsing/#the-domparser-interface\n             *\n             * Interface to parse XML strings into Document objects\n             *\n             * Used implementations:\n             * - supported browsers: built-in in DOMParser global\n             *   https://developer.mozilla.org/en-US/docs/Web/API/DOMParser#Browser_compatibility\n             * - nodejs: use '@xmldom/xmldom' module\n             *   https://www.npmjs.com/package/@xmldom/xmldom\n             */\n\n            function getDOMParserImplementation() {\n              let DOMParserImplementation = global$1.DOMParser;\n\n              if (typeof DOMParserImplementation === 'undefined') {\n                try {\n                  DOMParserImplementation = require('@xmldom/xmldom').DOMParser;\n                } catch (err) {\n                  throw new Error('You must install the \"@xmldom/xmldom\" package to use Strophe in nodejs.');\n                }\n              }\n\n              return DOMParserImplementation;\n            }\n\n            const DOMParser = getDOMParserImplementation();\n            /**\n             *  Gets IE xml doc object. Used by getDummyXMLDocument shim.\n             *\n             *  Returns:\n             *    A Microsoft XML DOM Object\n             *  See Also:\n             *    http://msdn.microsoft.com/en-us/library/ms757837%28VS.85%29.aspx\n             */\n\n            function _getIEXmlDom() {\n              const docStrings = [\"Msxml2.DOMDocument.6.0\", \"Msxml2.DOMDocument.5.0\", \"Msxml2.DOMDocument.4.0\", \"MSXML2.DOMDocument.3.0\", \"MSXML2.DOMDocument\", \"MSXML.DOMDocument\", \"Microsoft.XMLDOM\"];\n\n              for (let d = 0; d < docStrings.length; d++) {\n                try {\n                  // eslint-disable-next-line no-undef\n                  const doc = new ActiveXObject(docStrings[d]);\n                  return doc;\n                } catch (e) {// Try next one\n                }\n              }\n            }\n            /**\n             * Creates a dummy XML DOM document to serve as an element and text node generator.\n             *\n             * Used implementations:\n             *  - IE < 10: avoid using createDocument() due to a memory leak, use ie-specific\n             *    workaround\n             *  - other supported browsers: use document's createDocument\n             *  - nodejs: use '@xmldom/xmldom'\n             */\n\n\n            function getDummyXMLDOMDocument() {\n              // nodejs\n              if (typeof document === 'undefined') {\n                try {\n                  const DOMImplementation = require('@xmldom/xmldom').DOMImplementation;\n\n                  return new DOMImplementation().createDocument('jabber:client', 'strophe', null);\n                } catch (err) {\n                  throw new Error('You must install the \"@xmldom/xmldom\" package to use Strophe in nodejs.');\n                }\n              } // IE < 10\n\n\n              if (document.implementation.createDocument === undefined || document.implementation.createDocument && document.documentMode && document.documentMode < 10) {\n                const doc = _getIEXmlDom();\n\n                doc.appendChild(doc.createElement('strophe'));\n                return doc;\n              } // All other supported browsers\n\n\n              return document.implementation.createDocument('jabber:client', 'strophe', null);\n            }\n\n            /*\n             * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message\n             * Digest Algorithm, as defined in RFC 1321.\n             * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.\n             * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet\n             * Distributed under the BSD License\n             * See http://pajhome.org.uk/crypt/md5 for more info.\n             */\n\n            /*\n             * Everything that isn't used by Strophe has been stripped here!\n             */\n\n            /*\n             * Add integers, wrapping at 2^32. This uses 16-bit operations internally\n             * to work around bugs in some JS interpreters.\n             */\n            const safe_add$1 = function (x, y) {\n              const lsw = (x & 0xFFFF) + (y & 0xFFFF);\n              const msw = (x >> 16) + (y >> 16) + (lsw >> 16);\n              return msw << 16 | lsw & 0xFFFF;\n            };\n            /*\n             * Bitwise rotate a 32-bit number to the left.\n             */\n\n\n            const bit_rol = function (num, cnt) {\n              return num << cnt | num >>> 32 - cnt;\n            };\n            /*\n             * Convert a string to an array of little-endian words\n             */\n\n\n            const str2binl = function (str) {\n              if (typeof str !== \"string\") {\n                throw new Error(\"str2binl was passed a non-string\");\n              }\n\n              const bin = [];\n\n              for (let i = 0; i < str.length * 8; i += 8) {\n                bin[i >> 5] |= (str.charCodeAt(i / 8) & 255) << i % 32;\n              }\n\n              return bin;\n            };\n            /*\n             * Convert an array of little-endian words to a string\n             */\n\n\n            const binl2str = function (bin) {\n              let str = \"\";\n\n              for (let i = 0; i < bin.length * 32; i += 8) {\n                str += String.fromCharCode(bin[i >> 5] >>> i % 32 & 255);\n              }\n\n              return str;\n            };\n            /*\n             * Convert an array of little-endian words to a hex string.\n             */\n\n\n            const binl2hex = function (binarray) {\n              const hex_tab = \"0123456789abcdef\";\n              let str = \"\";\n\n              for (let i = 0; i < binarray.length * 4; i++) {\n                str += hex_tab.charAt(binarray[i >> 2] >> i % 4 * 8 + 4 & 0xF) + hex_tab.charAt(binarray[i >> 2] >> i % 4 * 8 & 0xF);\n              }\n\n              return str;\n            };\n            /*\n             * These functions implement the four basic operations the algorithm uses.\n             */\n\n\n            const md5_cmn = function (q, a, b, x, s, t) {\n              return safe_add$1(bit_rol(safe_add$1(safe_add$1(a, q), safe_add$1(x, t)), s), b);\n            };\n\n            const md5_ff = function (a, b, c, d, x, s, t) {\n              return md5_cmn(b & c | ~b & d, a, b, x, s, t);\n            };\n\n            const md5_gg = function (a, b, c, d, x, s, t) {\n              return md5_cmn(b & d | c & ~d, a, b, x, s, t);\n            };\n\n            const md5_hh = function (a, b, c, d, x, s, t) {\n              return md5_cmn(b ^ c ^ d, a, b, x, s, t);\n            };\n\n            const md5_ii = function (a, b, c, d, x, s, t) {\n              return md5_cmn(c ^ (b | ~d), a, b, x, s, t);\n            };\n            /*\n             * Calculate the MD5 of an array of little-endian words, and a bit length\n             */\n\n\n            const core_md5 = function (x, len) {\n              /* append padding */\n              x[len >> 5] |= 0x80 << len % 32;\n              x[(len + 64 >>> 9 << 4) + 14] = len;\n              let a = 1732584193;\n              let b = -271733879;\n              let c = -1732584194;\n              let d = 271733878;\n              let olda, oldb, oldc, oldd;\n\n              for (let i = 0; i < x.length; i += 16) {\n                olda = a;\n                oldb = b;\n                oldc = c;\n                oldd = d;\n                a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936);\n                d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);\n                c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);\n                b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);\n                a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);\n                d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);\n                c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);\n                b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);\n                a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);\n                d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);\n                c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);\n                b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);\n                a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);\n                d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);\n                c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);\n                b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);\n                a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);\n                d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);\n                c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);\n                b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302);\n                a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);\n                d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);\n                c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);\n                b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);\n                a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);\n                d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);\n                c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);\n                b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);\n                a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);\n                d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);\n                c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);\n                b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);\n                a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);\n                d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);\n                c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);\n                b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);\n                a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);\n                d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);\n                c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);\n                b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);\n                a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);\n                d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222);\n                c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);\n                b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);\n                a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);\n                d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);\n                c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);\n                b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);\n                a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844);\n                d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);\n                c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);\n                b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);\n                a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);\n                d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);\n                c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);\n                b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);\n                a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);\n                d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);\n                c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);\n                b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);\n                a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);\n                d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);\n                c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);\n                b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);\n                a = safe_add$1(a, olda);\n                b = safe_add$1(b, oldb);\n                c = safe_add$1(c, oldc);\n                d = safe_add$1(d, oldd);\n              }\n\n              return [a, b, c, d];\n            };\n            /*\n             * These are the functions you'll usually want to call.\n             * They take string arguments and return either hex or base-64 encoded\n             * strings.\n             */\n\n\n            const MD5 = {\n              hexdigest: function (s) {\n                return binl2hex(core_md5(str2binl(s), s.length * 8));\n              },\n              hash: function (s) {\n                return binl2str(core_md5(str2binl(s), s.length * 8));\n              }\n            };\n\n            /** Class: Strophe.SASLMechanism\n             *\n             *  Encapsulates an SASL authentication mechanism.\n             *\n             *  User code may override the priority for each mechanism or disable it completely.\n             *  See <priority> for information about changing priority and <test> for informatian on\n             *  how to disable a mechanism.\n             *\n             *  By default, all mechanisms are enabled and the priorities are\n             *\n             *      SCRAM-SHA-1 - 60\n             *      PLAIN       - 50\n             *      OAUTHBEARER - 40\n             *      X-OAUTH2    - 30\n             *      ANONYMOUS   - 20\n             *      EXTERNAL    - 10\n             *\n             *  See: Strophe.Connection.addSupportedSASLMechanisms\n             */\n            class SASLMechanism {\n              /**\n               * PrivateConstructor: Strophe.SASLMechanism\n               * SASL auth mechanism abstraction.\n               *\n               *  Parameters:\n               *    (String) name - SASL Mechanism name.\n               *    (Boolean) isClientFirst - If client should send response first without challenge.\n               *    (Number) priority - Priority.\n               *\n               *  Returns:\n               *    A new Strophe.SASLMechanism object.\n               */\n              constructor(name, isClientFirst, priority) {\n                /** PrivateVariable: mechname\n                 *  Mechanism name.\n                 */\n                this.mechname = name;\n                /** PrivateVariable: isClientFirst\n                 *  If client sends response without initial server challenge.\n                 */\n\n                this.isClientFirst = isClientFirst;\n                /** Variable: priority\n                 *  Determines which <SASLMechanism> is chosen for authentication (Higher is better).\n                 *  Users may override this to prioritize mechanisms differently.\n                 *\n                 *  Example: (This will cause Strophe to choose the mechanism that the server sent first)\n                 *\n                 *  > Strophe.SASLPlain.priority = Strophe.SASLSHA1.priority;\n                 *\n                 *  See <SASL mechanisms> for a list of available mechanisms.\n                 *\n                 */\n\n                this.priority = priority;\n              }\n              /**\n               *  Function: test\n               *  Checks if mechanism able to run.\n               *  To disable a mechanism, make this return false;\n               *\n               *  To disable plain authentication run\n               *  > Strophe.SASLPlain.test = function() {\n               *  >   return false;\n               *  > }\n               *\n               *  See <SASL mechanisms> for a list of available mechanisms.\n               *\n               *  Parameters:\n               *    (Strophe.Connection) connection - Target Connection.\n               *\n               *  Returns:\n               *    (Boolean) If mechanism was able to run.\n               */\n\n\n              test() {\n                // eslint-disable-line class-methods-use-this\n                return true;\n              }\n              /** PrivateFunction: onStart\n               *  Called before starting mechanism on some connection.\n               *\n               *  Parameters:\n               *    (Strophe.Connection) connection - Target Connection.\n               */\n\n\n              onStart(connection) {\n                this._connection = connection;\n              }\n              /** PrivateFunction: onChallenge\n               *  Called by protocol implementation on incoming challenge.\n               *\n               *  By deafult, if the client is expected to send data first (isClientFirst === true),\n               *  this method is called with `challenge` as null on the first call,\n               *  unless `clientChallenge` is overridden in the relevant subclass.\n               *\n               *  Parameters:\n               *    (Strophe.Connection) connection - Target Connection.\n               *    (String) challenge - current challenge to handle.\n               *\n               *  Returns:\n               *    (String) Mechanism response.\n               */\n\n\n              onChallenge(connection, challenge) {\n                // eslint-disable-line\n                throw new Error(\"You should implement challenge handling!\");\n              }\n              /** PrivateFunction: clientChallenge\n               *  Called by the protocol implementation if the client is expected to send\n               *  data first in the authentication exchange (i.e. isClientFirst === true).\n               *\n               *  Parameters:\n               *    (Strophe.Connection) connection - Target Connection.\n               *\n               *  Returns:\n               *    (String) Mechanism response.\n               */\n\n\n              clientChallenge(connection) {\n                if (!this.isClientFirst) {\n                  throw new Error(\"clientChallenge should not be called if isClientFirst is false!\");\n                }\n\n                return this.onChallenge(connection);\n              }\n              /** PrivateFunction: onFailure\n               *  Protocol informs mechanism implementation about SASL failure.\n               */\n\n\n              onFailure() {\n                this._connection = null;\n              }\n              /** PrivateFunction: onSuccess\n               *  Protocol informs mechanism implementation about SASL success.\n               */\n\n\n              onSuccess() {\n                this._connection = null;\n              }\n\n            }\n\n            class SASLAnonymous extends SASLMechanism {\n              /** PrivateConstructor: SASLAnonymous\n               *  SASL ANONYMOUS authentication.\n               */\n              constructor(mechname = 'ANONYMOUS', isClientFirst = false, priority = 20) {\n                super(mechname, isClientFirst, priority);\n              }\n\n              test(connection) {\n                // eslint-disable-line class-methods-use-this\n                return connection.authcid === null;\n              }\n\n            }\n\n            class SASLExternal extends SASLMechanism {\n              /** PrivateConstructor: SASLExternal\n               *  SASL EXTERNAL authentication.\n               *\n               *  The EXTERNAL mechanism allows a client to request the server to use\n               *  credentials established by means external to the mechanism to\n               *  authenticate the client. The external means may be, for instance,\n               *  TLS services.\n               */\n              constructor(mechname = 'EXTERNAL', isClientFirst = true, priority = 10) {\n                super(mechname, isClientFirst, priority);\n              }\n\n              onChallenge(connection) {\n                // eslint-disable-line class-methods-use-this\n\n                /** According to XEP-178, an authzid SHOULD NOT be presented when the\n                 * authcid contained or implied in the client certificate is the JID (i.e.\n                 * authzid) with which the user wants to log in as.\n                 *\n                 * To NOT send the authzid, the user should therefore set the authcid equal\n                 * to the JID when instantiating a new Strophe.Connection object.\n                 */\n                return connection.authcid === connection.authzid ? '' : connection.authzid;\n              }\n\n            }\n\n            const utils = {\n              utf16to8: function (str) {\n                var i, c;\n                var out = \"\";\n                var len = str.length;\n\n                for (i = 0; i < len; i++) {\n                  c = str.charCodeAt(i);\n\n                  if (c >= 0x0000 && c <= 0x007F) {\n                    out += str.charAt(i);\n                  } else if (c > 0x07FF) {\n                    out += String.fromCharCode(0xE0 | c >> 12 & 0x0F);\n                    out += String.fromCharCode(0x80 | c >> 6 & 0x3F);\n                    out += String.fromCharCode(0x80 | c >> 0 & 0x3F);\n                  } else {\n                    out += String.fromCharCode(0xC0 | c >> 6 & 0x1F);\n                    out += String.fromCharCode(0x80 | c >> 0 & 0x3F);\n                  }\n                }\n\n                return out;\n              },\n              addCookies: function (cookies) {\n                /* Parameters:\n                 *  (Object) cookies - either a map of cookie names\n                 *    to string values or to maps of cookie values.\n                 *\n                 * For example:\n                 * { \"myCookie\": \"1234\" }\n                 *\n                 * or:\n                 * { \"myCookie\": {\n                 *      \"value\": \"1234\",\n                 *      \"domain\": \".example.org\",\n                 *      \"path\": \"/\",\n                 *      \"expires\": expirationDate\n                 *      }\n                 *  }\n                 *\n                 *  These values get passed to Strophe.Connection via\n                 *   options.cookies\n                 */\n                cookies = cookies || {};\n\n                for (const cookieName in cookies) {\n                  if (Object.prototype.hasOwnProperty.call(cookies, cookieName)) {\n                    let expires = '';\n                    let domain = '';\n                    let path = '';\n                    const cookieObj = cookies[cookieName];\n                    const isObj = typeof cookieObj === \"object\";\n                    const cookieValue = escape(unescape(isObj ? cookieObj.value : cookieObj));\n\n                    if (isObj) {\n                      expires = cookieObj.expires ? \";expires=\" + cookieObj.expires : '';\n                      domain = cookieObj.domain ? \";domain=\" + cookieObj.domain : '';\n                      path = cookieObj.path ? \";path=\" + cookieObj.path : '';\n                    }\n\n                    document.cookie = cookieName + '=' + cookieValue + expires + domain + path;\n                  }\n                }\n              }\n            };\n\n            class SASLOAuthBearer extends SASLMechanism {\n              /** PrivateConstructor: SASLOAuthBearer\n               *  SASL OAuth Bearer authentication.\n               */\n              constructor(mechname = 'OAUTHBEARER', isClientFirst = true, priority = 40) {\n                super(mechname, isClientFirst, priority);\n              }\n\n              test(connection) {\n                // eslint-disable-line class-methods-use-this\n                return connection.pass !== null;\n              }\n\n              onChallenge(connection) {\n                // eslint-disable-line class-methods-use-this\n                let auth_str = 'n,';\n\n                if (connection.authcid !== null) {\n                  auth_str = auth_str + 'a=' + connection.authzid;\n                }\n\n                auth_str = auth_str + ',';\n                auth_str = auth_str + \"\\u0001\";\n                auth_str = auth_str + 'auth=Bearer ';\n                auth_str = auth_str + connection.pass;\n                auth_str = auth_str + \"\\u0001\";\n                auth_str = auth_str + \"\\u0001\";\n                return utils.utf16to8(auth_str);\n              }\n\n            }\n\n            class SASLPlain extends SASLMechanism {\n              /** PrivateConstructor: SASLPlain\n               *  SASL PLAIN authentication.\n               */\n              constructor(mechname = 'PLAIN', isClientFirst = true, priority = 50) {\n                super(mechname, isClientFirst, priority);\n              }\n\n              test(connection) {\n                // eslint-disable-line class-methods-use-this\n                return connection.authcid !== null;\n              }\n\n              onChallenge(connection) {\n                // eslint-disable-line class-methods-use-this\n                const {\n                  authcid,\n                  authzid,\n                  domain,\n                  pass\n                } = connection;\n\n                if (!domain) {\n                  throw new Error(\"SASLPlain onChallenge: domain is not defined!\");\n                } // Only include authzid if it differs from authcid.\n                // See: https://tools.ietf.org/html/rfc6120#section-6.3.8\n\n\n                let auth_str = authzid !== `${authcid}@${domain}` ? authzid : '';\n                auth_str = auth_str + \"\\u0000\";\n                auth_str = auth_str + authcid;\n                auth_str = auth_str + \"\\u0000\";\n                auth_str = auth_str + pass;\n                return utils.utf16to8(auth_str);\n              }\n\n            }\n\n            /*\n             * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined\n             * in FIPS PUB 180-1\n             * Version 2.1a Copyright Paul Johnston 2000 - 2002.\n             * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet\n             * Distributed under the BSD License\n             * See http://pajhome.org.uk/crypt/md5 for details.\n             */\n\n            /* global define */\n\n            /* Some functions and variables have been stripped for use with Strophe */\n\n            /*\n             * Calculate the SHA-1 of an array of big-endian words, and a bit length\n             */\n            function core_sha1(x, len) {\n              /* append padding */\n              x[len >> 5] |= 0x80 << 24 - len % 32;\n              x[(len + 64 >> 9 << 4) + 15] = len;\n              var w = new Array(80);\n              var a = 1732584193;\n              var b = -271733879;\n              var c = -1732584194;\n              var d = 271733878;\n              var e = -1009589776;\n              var i, j, t, olda, oldb, oldc, oldd, olde;\n\n              for (i = 0; i < x.length; i += 16) {\n                olda = a;\n                oldb = b;\n                oldc = c;\n                oldd = d;\n                olde = e;\n\n                for (j = 0; j < 80; j++) {\n                  if (j < 16) {\n                    w[j] = x[i + j];\n                  } else {\n                    w[j] = rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);\n                  }\n\n                  t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)), safe_add(safe_add(e, w[j]), sha1_kt(j)));\n                  e = d;\n                  d = c;\n                  c = rol(b, 30);\n                  b = a;\n                  a = t;\n                }\n\n                a = safe_add(a, olda);\n                b = safe_add(b, oldb);\n                c = safe_add(c, oldc);\n                d = safe_add(d, oldd);\n                e = safe_add(e, olde);\n              }\n\n              return [a, b, c, d, e];\n            }\n            /*\n             * Perform the appropriate triplet combination function for the current\n             * iteration\n             */\n\n\n            function sha1_ft(t, b, c, d) {\n              if (t < 20) {\n                return b & c | ~b & d;\n              }\n\n              if (t < 40) {\n                return b ^ c ^ d;\n              }\n\n              if (t < 60) {\n                return b & c | b & d | c & d;\n              }\n\n              return b ^ c ^ d;\n            }\n            /*\n             * Determine the appropriate additive constant for the current iteration\n             */\n\n\n            function sha1_kt(t) {\n              return t < 20 ? 1518500249 : t < 40 ? 1859775393 : t < 60 ? -1894007588 : -899497514;\n            }\n            /*\n             * Calculate the HMAC-SHA1 of a key and some data\n             */\n\n\n            function core_hmac_sha1(key, data) {\n              var bkey = str2binb(key);\n\n              if (bkey.length > 16) {\n                bkey = core_sha1(bkey, key.length * 8);\n              }\n\n              var ipad = new Array(16),\n                  opad = new Array(16);\n\n              for (var i = 0; i < 16; i++) {\n                ipad[i] = bkey[i] ^ 0x36363636;\n                opad[i] = bkey[i] ^ 0x5C5C5C5C;\n              }\n\n              var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * 8);\n              return core_sha1(opad.concat(hash), 512 + 160);\n            }\n            /*\n             * Add integers, wrapping at 2^32. This uses 16-bit operations internally\n             * to work around bugs in some JS interpreters.\n             */\n\n\n            function safe_add(x, y) {\n              var lsw = (x & 0xFFFF) + (y & 0xFFFF);\n              var msw = (x >> 16) + (y >> 16) + (lsw >> 16);\n              return msw << 16 | lsw & 0xFFFF;\n            }\n            /*\n             * Bitwise rotate a 32-bit number to the left.\n             */\n\n\n            function rol(num, cnt) {\n              return num << cnt | num >>> 32 - cnt;\n            }\n            /*\n             * Convert an 8-bit or 16-bit string to an array of big-endian words\n             * In 8-bit function, characters >255 have their hi-byte silently ignored.\n             */\n\n\n            function str2binb(str) {\n              var bin = [];\n              var mask = 255;\n\n              for (var i = 0; i < str.length * 8; i += 8) {\n                bin[i >> 5] |= (str.charCodeAt(i / 8) & mask) << 24 - i % 32;\n              }\n\n              return bin;\n            }\n            /*\n             * Convert an array of big-endian words to a base-64 string\n             */\n\n\n            function binb2b64(binarray) {\n              var tab = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n              var str = \"\";\n              var triplet, j;\n\n              for (var i = 0; i < binarray.length * 4; i += 3) {\n                triplet = (binarray[i >> 2] >> 8 * (3 - i % 4) & 0xFF) << 16 | (binarray[i + 1 >> 2] >> 8 * (3 - (i + 1) % 4) & 0xFF) << 8 | binarray[i + 2 >> 2] >> 8 * (3 - (i + 2) % 4) & 0xFF;\n\n                for (j = 0; j < 4; j++) {\n                  if (i * 8 + j * 6 > binarray.length * 32) {\n                    str += \"=\";\n                  } else {\n                    str += tab.charAt(triplet >> 6 * (3 - j) & 0x3F);\n                  }\n                }\n              }\n\n              return str;\n            }\n            /*\n             * Convert an array of big-endian words to a string\n             */\n\n\n            function binb2str(bin) {\n              var str = \"\";\n              var mask = 255;\n\n              for (var i = 0; i < bin.length * 32; i += 8) {\n                str += String.fromCharCode(bin[i >> 5] >>> 24 - i % 32 & mask);\n              }\n\n              return str;\n            }\n            /*\n             * These are the functions you'll usually want to call\n             * They take string arguments and return either hex or base-64 encoded strings\n             */\n\n\n            const SHA1 = {\n              b64_hmac_sha1: function (key, data) {\n                return binb2b64(core_hmac_sha1(key, data));\n              },\n              b64_sha1: function (s) {\n                return binb2b64(core_sha1(str2binb(s), s.length * 8));\n              },\n              binb2str: binb2str,\n              core_hmac_sha1: core_hmac_sha1,\n              str_hmac_sha1: function (key, data) {\n                return binb2str(core_hmac_sha1(key, data));\n              },\n              str_sha1: function (s) {\n                return binb2str(core_sha1(str2binb(s), s.length * 8));\n              }\n            };\n\n            class SASLSHA1 extends SASLMechanism {\n              /** PrivateConstructor: SASLSHA1\n               *  SASL SCRAM SHA 1 authentication.\n               */\n              constructor(mechname = 'SCRAM-SHA-1', isClientFirst = true, priority = 60) {\n                super(mechname, isClientFirst, priority);\n              }\n\n              test(connection) {\n                // eslint-disable-line class-methods-use-this\n                return connection.authcid !== null;\n              }\n\n              onChallenge(connection, challenge) {\n                // eslint-disable-line class-methods-use-this\n                let nonce, salt, iter, Hi, U, U_old, i, k;\n                let responseText = \"c=biws,\";\n                let authMessage = `${connection._sasl_data[\"client-first-message-bare\"]},${challenge},`;\n                const cnonce = connection._sasl_data.cnonce;\n                const attribMatch = /([a-z]+)=([^,]+)(,|$)/;\n\n                while (challenge.match(attribMatch)) {\n                  const matches = challenge.match(attribMatch);\n                  challenge = challenge.replace(matches[0], \"\");\n\n                  switch (matches[1]) {\n                    case \"r\":\n                      nonce = matches[2];\n                      break;\n\n                    case \"s\":\n                      salt = matches[2];\n                      break;\n\n                    case \"i\":\n                      iter = matches[2];\n                      break;\n                  }\n                }\n\n                if (nonce.substr(0, cnonce.length) !== cnonce) {\n                  connection._sasl_data = {};\n                  return connection._sasl_failure_cb();\n                }\n\n                responseText += \"r=\" + nonce;\n                authMessage += responseText;\n                salt = atob(salt);\n                salt += \"\\x00\\x00\\x00\\x01\";\n                const pass = utils.utf16to8(connection.pass);\n                Hi = U_old = SHA1.core_hmac_sha1(pass, salt);\n\n                for (i = 1; i < iter; i++) {\n                  U = SHA1.core_hmac_sha1(pass, SHA1.binb2str(U_old));\n\n                  for (k = 0; k < 5; k++) {\n                    Hi[k] ^= U[k];\n                  }\n\n                  U_old = U;\n                }\n\n                Hi = SHA1.binb2str(Hi);\n                const clientKey = SHA1.core_hmac_sha1(Hi, \"Client Key\");\n                const serverKey = SHA1.str_hmac_sha1(Hi, \"Server Key\");\n                const clientSignature = SHA1.core_hmac_sha1(SHA1.str_sha1(SHA1.binb2str(clientKey)), authMessage);\n                connection._sasl_data[\"server-signature\"] = SHA1.b64_hmac_sha1(serverKey, authMessage);\n\n                for (k = 0; k < 5; k++) {\n                  clientKey[k] ^= clientSignature[k];\n                }\n\n                responseText += \",p=\" + btoa(SHA1.binb2str(clientKey));\n                return responseText;\n              }\n\n              clientChallenge(connection, test_cnonce) {\n                // eslint-disable-line class-methods-use-this\n                const cnonce = test_cnonce || MD5.hexdigest(\"\" + Math.random() * 1234567890);\n                let auth_str = \"n=\" + utils.utf16to8(connection.authcid);\n                auth_str += \",r=\";\n                auth_str += cnonce;\n                connection._sasl_data.cnonce = cnonce;\n                connection._sasl_data[\"client-first-message-bare\"] = auth_str;\n                auth_str = \"n,,\" + auth_str;\n                return auth_str;\n              }\n\n            }\n\n            class SASLXOAuth2 extends SASLMechanism {\n              /** PrivateConstructor: SASLXOAuth2\n               *  SASL X-OAuth2 authentication.\n               */\n              constructor(mechname = 'X-OAUTH2', isClientFirst = true, priority = 30) {\n                super(mechname, isClientFirst, priority);\n              }\n\n              test(connection) {\n                // eslint-disable-line class-methods-use-this\n                return connection.pass !== null;\n              }\n\n              onChallenge(connection) {\n                // eslint-disable-line class-methods-use-this\n                let auth_str = '\\u0000';\n\n                if (connection.authcid !== null) {\n                  auth_str = auth_str + connection.authzid;\n                }\n\n                auth_str = auth_str + \"\\u0000\";\n                auth_str = auth_str + connection.pass;\n                return utils.utf16to8(auth_str);\n              }\n\n            }\n\n            /**\n             * Implementation of atob() according to the HTML and Infra specs, except that\n             * instead of throwing INVALID_CHARACTER_ERR we return null.\n             */\n\n            function atob$1(data) {\n              // Web IDL requires DOMStrings to just be converted using ECMAScript\n              // ToString, which in our case amounts to using a template literal.\n              data = `${data}`; // \"Remove all ASCII whitespace from data.\"\n\n              data = data.replace(/[ \\t\\n\\f\\r]/g, \"\"); // \"If data's length divides by 4 leaving no remainder, then: if data ends\n              // with one or two U+003D (=) code points, then remove them from data.\"\n\n              if (data.length % 4 === 0) {\n                data = data.replace(/==?$/, \"\");\n              } // \"If data's length divides by 4 leaving a remainder of 1, then return\n              // failure.\"\n              //\n              // \"If data contains a code point that is not one of\n              //\n              // U+002B (+)\n              // U+002F (/)\n              // ASCII alphanumeric\n              //\n              // then return failure.\"\n\n\n              if (data.length % 4 === 1 || /[^+/0-9A-Za-z]/.test(data)) {\n                return null;\n              } // \"Let output be an empty byte sequence.\"\n\n\n              let output = \"\"; // \"Let buffer be an empty buffer that can have bits appended to it.\"\n              //\n              // We append bits via left-shift and or.  accumulatedBits is used to track\n              // when we've gotten to 24 bits.\n\n              let buffer = 0;\n              let accumulatedBits = 0; // \"Let position be a position variable for data, initially pointing at the\n              // start of data.\"\n              //\n              // \"While position does not point past the end of data:\"\n\n              for (let i = 0; i < data.length; i++) {\n                // \"Find the code point pointed to by position in the second column of\n                // Table 1: The Base 64 Alphabet of RFC 4648. Let n be the number given in\n                // the first cell of the same row.\n                //\n                // \"Append to buffer the six bits corresponding to n, most significant bit\n                // first.\"\n                //\n                // atobLookup() implements the table from RFC 4648.\n                buffer <<= 6;\n                buffer |= atobLookup(data[i]);\n                accumulatedBits += 6; // \"If buffer has accumulated 24 bits, interpret them as three 8-bit\n                // big-endian numbers. Append three bytes with values equal to those\n                // numbers to output, in the same order, and then empty buffer.\"\n\n                if (accumulatedBits === 24) {\n                  output += String.fromCharCode((buffer & 0xff0000) >> 16);\n                  output += String.fromCharCode((buffer & 0xff00) >> 8);\n                  output += String.fromCharCode(buffer & 0xff);\n                  buffer = accumulatedBits = 0;\n                } // \"Advance position by 1.\"\n\n              } // \"If buffer is not empty, it contains either 12 or 18 bits. If it contains\n              // 12 bits, then discard the last four and interpret the remaining eight as\n              // an 8-bit big-endian number. If it contains 18 bits, then discard the last\n              // two and interpret the remaining 16 as two 8-bit big-endian numbers. Append\n              // the one or two bytes with values equal to those one or two numbers to\n              // output, in the same order.\"\n\n\n              if (accumulatedBits === 12) {\n                buffer >>= 4;\n                output += String.fromCharCode(buffer);\n              } else if (accumulatedBits === 18) {\n                buffer >>= 2;\n                output += String.fromCharCode((buffer & 0xff00) >> 8);\n                output += String.fromCharCode(buffer & 0xff);\n              } // \"Return output.\"\n\n\n              return output;\n            }\n            /**\n             * A lookup table for atob(), which converts an ASCII character to the\n             * corresponding six-bit number.\n             */\n\n\n            function atobLookup(chr) {\n              if (/[A-Z]/.test(chr)) {\n                return chr.charCodeAt(0) - \"A\".charCodeAt(0);\n              }\n\n              if (/[a-z]/.test(chr)) {\n                return chr.charCodeAt(0) - \"a\".charCodeAt(0) + 26;\n              }\n\n              if (/[0-9]/.test(chr)) {\n                return chr.charCodeAt(0) - \"0\".charCodeAt(0) + 52;\n              }\n\n              if (chr === \"+\") {\n                return 62;\n              }\n\n              if (chr === \"/\") {\n                return 63;\n              } // Throw exception; should not be hit in tests\n\n\n              return undefined;\n            }\n\n            var atob_1 = atob$1;\n\n            /**\n             * btoa() as defined by the HTML and Infra specs, which mostly just references\n             * RFC 4648.\n             */\n\n            function btoa$1(s) {\n              let i; // String conversion as required by Web IDL.\n\n              s = `${s}`; // \"The btoa() method must throw an \"InvalidCharacterError\" DOMException if\n              // data contains any character whose code point is greater than U+00FF.\"\n\n              for (i = 0; i < s.length; i++) {\n                if (s.charCodeAt(i) > 255) {\n                  return null;\n                }\n              }\n\n              let out = \"\";\n\n              for (i = 0; i < s.length; i += 3) {\n                const groupsOfSix = [undefined, undefined, undefined, undefined];\n                groupsOfSix[0] = s.charCodeAt(i) >> 2;\n                groupsOfSix[1] = (s.charCodeAt(i) & 0x03) << 4;\n\n                if (s.length > i + 1) {\n                  groupsOfSix[1] |= s.charCodeAt(i + 1) >> 4;\n                  groupsOfSix[2] = (s.charCodeAt(i + 1) & 0x0f) << 2;\n                }\n\n                if (s.length > i + 2) {\n                  groupsOfSix[2] |= s.charCodeAt(i + 2) >> 6;\n                  groupsOfSix[3] = s.charCodeAt(i + 2) & 0x3f;\n                }\n\n                for (let j = 0; j < groupsOfSix.length; j++) {\n                  if (typeof groupsOfSix[j] === \"undefined\") {\n                    out += \"=\";\n                  } else {\n                    out += btoaLookup(groupsOfSix[j]);\n                  }\n                }\n              }\n\n              return out;\n            }\n            /**\n             * Lookup table for btoa(), which converts a six-bit number into the\n             * corresponding ASCII character.\n             */\n\n\n            function btoaLookup(idx) {\n              if (idx < 26) {\n                return String.fromCharCode(idx + \"A\".charCodeAt(0));\n              }\n\n              if (idx < 52) {\n                return String.fromCharCode(idx - 26 + \"a\".charCodeAt(0));\n              }\n\n              if (idx < 62) {\n                return String.fromCharCode(idx - 52 + \"0\".charCodeAt(0));\n              }\n\n              if (idx === 62) {\n                return \"+\";\n              }\n\n              if (idx === 63) {\n                return \"/\";\n              } // Throw INVALID_CHARACTER_ERR exception here -- won't be hit in the tests.\n\n\n              return undefined;\n            }\n\n            var btoa_1 = btoa$1;\n\n            var abab = {\n              atob: atob_1,\n              btoa: btoa_1\n            };\n\n            /*\n                This program is distributed under the terms of the MIT license.\n                Please see the LICENSE file for details.\n\n                Copyright 2006-2018, OGG, LLC\n            */\n            /** Function: $build\n             *  Create a Strophe.Builder.\n             *  This is an alias for 'new Strophe.Builder(name, attrs)'.\n             *\n             *  Parameters:\n             *    (String) name - The root element name.\n             *    (Object) attrs - The attributes for the root element in object notation.\n             *\n             *  Returns:\n             *    A new Strophe.Builder object.\n             */\n\n            function $build(name, attrs) {\n              return new Strophe.Builder(name, attrs);\n            }\n            /** Function: $msg\n             *  Create a Strophe.Builder with a <message/> element as the root.\n             *\n             *  Parameters:\n             *    (Object) attrs - The <message/> element attributes in object notation.\n             *\n             *  Returns:\n             *    A new Strophe.Builder object.\n             */\n\n            function $msg(attrs) {\n              return new Strophe.Builder(\"message\", attrs);\n            }\n            /** Function: $iq\n             *  Create a Strophe.Builder with an <iq/> element as the root.\n             *\n             *  Parameters:\n             *    (Object) attrs - The <iq/> element attributes in object notation.\n             *\n             *  Returns:\n             *    A new Strophe.Builder object.\n             */\n\n            function $iq(attrs) {\n              return new Strophe.Builder(\"iq\", attrs);\n            }\n            /** Function: $pres\n             *  Create a Strophe.Builder with a <presence/> element as the root.\n             *\n             *  Parameters:\n             *    (Object) attrs - The <presence/> element attributes in object notation.\n             *\n             *  Returns:\n             *    A new Strophe.Builder object.\n             */\n\n            function $pres(attrs) {\n              return new Strophe.Builder(\"presence\", attrs);\n            }\n            /** Class: Strophe\n             *  An object container for all Strophe library functions.\n             *\n             *  This class is just a container for all the objects and constants\n             *  used in the library.  It is not meant to be instantiated, but to\n             *  provide a namespace for library objects, constants, and functions.\n             */\n\n            const Strophe = {\n              /** Constant: VERSION */\n              VERSION: \"1.4.4\",\n\n              /** Constants: XMPP Namespace Constants\n               *  Common namespace constants from the XMPP RFCs and XEPs.\n               *\n               *  NS.HTTPBIND - HTTP BIND namespace from XEP 124.\n               *  NS.BOSH - BOSH namespace from XEP 206.\n               *  NS.CLIENT - Main XMPP client namespace.\n               *  NS.AUTH - Legacy authentication namespace.\n               *  NS.ROSTER - Roster operations namespace.\n               *  NS.PROFILE - Profile namespace.\n               *  NS.DISCO_INFO - Service discovery info namespace from XEP 30.\n               *  NS.DISCO_ITEMS - Service discovery items namespace from XEP 30.\n               *  NS.MUC - Multi-User Chat namespace from XEP 45.\n               *  NS.SASL - XMPP SASL namespace from RFC 3920.\n               *  NS.STREAM - XMPP Streams namespace from RFC 3920.\n               *  NS.BIND - XMPP Binding namespace from RFC 3920 and RFC 6120.\n               *  NS.SESSION - XMPP Session namespace from RFC 3920.\n               *  NS.XHTML_IM - XHTML-IM namespace from XEP 71.\n               *  NS.XHTML - XHTML body namespace from XEP 71.\n               */\n              NS: {\n                HTTPBIND: \"http://jabber.org/protocol/httpbind\",\n                BOSH: \"urn:xmpp:xbosh\",\n                CLIENT: \"jabber:client\",\n                AUTH: \"jabber:iq:auth\",\n                ROSTER: \"jabber:iq:roster\",\n                PROFILE: \"jabber:iq:profile\",\n                DISCO_INFO: \"http://jabber.org/protocol/disco#info\",\n                DISCO_ITEMS: \"http://jabber.org/protocol/disco#items\",\n                MUC: \"http://jabber.org/protocol/muc\",\n                SASL: \"urn:ietf:params:xml:ns:xmpp-sasl\",\n                STREAM: \"http://etherx.jabber.org/streams\",\n                FRAMING: \"urn:ietf:params:xml:ns:xmpp-framing\",\n                BIND: \"urn:ietf:params:xml:ns:xmpp-bind\",\n                SESSION: \"urn:ietf:params:xml:ns:xmpp-session\",\n                VERSION: \"jabber:iq:version\",\n                STANZAS: \"urn:ietf:params:xml:ns:xmpp-stanzas\",\n                XHTML_IM: \"http://jabber.org/protocol/xhtml-im\",\n                XHTML: \"http://www.w3.org/1999/xhtml\"\n              },\n\n              /** Constants: XHTML_IM Namespace\n               *  contains allowed tags, tag attributes, and css properties.\n               *  Used in the createHtml function to filter incoming html into the allowed XHTML-IM subset.\n               *  See http://xmpp.org/extensions/xep-0071.html#profile-summary for the list of recommended\n               *  allowed tags and their attributes.\n               */\n              XHTML: {\n                tags: ['a', 'blockquote', 'br', 'cite', 'em', 'img', 'li', 'ol', 'p', 'span', 'strong', 'ul', 'body'],\n                attributes: {\n                  'a': ['href'],\n                  'blockquote': ['style'],\n                  'br': [],\n                  'cite': ['style'],\n                  'em': [],\n                  'img': ['src', 'alt', 'style', 'height', 'width'],\n                  'li': ['style'],\n                  'ol': ['style'],\n                  'p': ['style'],\n                  'span': ['style'],\n                  'strong': [],\n                  'ul': ['style'],\n                  'body': []\n                },\n                css: ['background-color', 'color', 'font-family', 'font-size', 'font-style', 'font-weight', 'margin-left', 'margin-right', 'text-align', 'text-decoration'],\n\n                /** Function: XHTML.validTag\n                 *\n                 * Utility method to determine whether a tag is allowed\n                 * in the XHTML_IM namespace.\n                 *\n                 * XHTML tag names are case sensitive and must be lower case.\n                 */\n                validTag(tag) {\n                  for (let i = 0; i < Strophe.XHTML.tags.length; i++) {\n                    if (tag === Strophe.XHTML.tags[i]) {\n                      return true;\n                    }\n                  }\n\n                  return false;\n                },\n\n                /** Function: XHTML.validAttribute\n                 *\n                 * Utility method to determine whether an attribute is allowed\n                 * as recommended per XEP-0071\n                 *\n                 * XHTML attribute names are case sensitive and must be lower case.\n                 */\n                validAttribute(tag, attribute) {\n                  if (typeof Strophe.XHTML.attributes[tag] !== 'undefined' && Strophe.XHTML.attributes[tag].length > 0) {\n                    for (let i = 0; i < Strophe.XHTML.attributes[tag].length; i++) {\n                      if (attribute === Strophe.XHTML.attributes[tag][i]) {\n                        return true;\n                      }\n                    }\n                  }\n\n                  return false;\n                },\n\n                validCSS(style) {\n                  for (let i = 0; i < Strophe.XHTML.css.length; i++) {\n                    if (style === Strophe.XHTML.css[i]) {\n                      return true;\n                    }\n                  }\n\n                  return false;\n                }\n\n              },\n\n              /** Constants: Connection Status Constants\n               *  Connection status constants for use by the connection handler\n               *  callback.\n               *\n               *  Status.ERROR - An error has occurred\n               *  Status.CONNECTING - The connection is currently being made\n               *  Status.CONNFAIL - The connection attempt failed\n               *  Status.AUTHENTICATING - The connection is authenticating\n               *  Status.AUTHFAIL - The authentication attempt failed\n               *  Status.CONNECTED - The connection has succeeded\n               *  Status.DISCONNECTED - The connection has been terminated\n               *  Status.DISCONNECTING - The connection is currently being terminated\n               *  Status.ATTACHED - The connection has been attached\n               *  Status.REDIRECT - The connection has been redirected\n               *  Status.CONNTIMEOUT - The connection has timed out\n               */\n              Status: {\n                ERROR: 0,\n                CONNECTING: 1,\n                CONNFAIL: 2,\n                AUTHENTICATING: 3,\n                AUTHFAIL: 4,\n                CONNECTED: 5,\n                DISCONNECTED: 6,\n                DISCONNECTING: 7,\n                ATTACHED: 8,\n                REDIRECT: 9,\n                CONNTIMEOUT: 10,\n                BINDREQUIRED: 11,\n                ATTACHFAIL: 12\n              },\n              ErrorCondition: {\n                BAD_FORMAT: \"bad-format\",\n                CONFLICT: \"conflict\",\n                MISSING_JID_NODE: \"x-strophe-bad-non-anon-jid\",\n                NO_AUTH_MECH: \"no-auth-mech\",\n                UNKNOWN_REASON: \"unknown\"\n              },\n\n              /** Constants: Log Level Constants\n               *  Logging level indicators.\n               *\n               *  LogLevel.DEBUG - Debug output\n               *  LogLevel.INFO - Informational output\n               *  LogLevel.WARN - Warnings\n               *  LogLevel.ERROR - Errors\n               *  LogLevel.FATAL - Fatal errors\n               */\n              LogLevel: {\n                DEBUG: 0,\n                INFO: 1,\n                WARN: 2,\n                ERROR: 3,\n                FATAL: 4\n              },\n\n              /** PrivateConstants: DOM Element Type Constants\n               *  DOM element types.\n               *\n               *  ElementType.NORMAL - Normal element.\n               *  ElementType.TEXT - Text data element.\n               *  ElementType.FRAGMENT - XHTML fragment element.\n               */\n              ElementType: {\n                NORMAL: 1,\n                TEXT: 3,\n                CDATA: 4,\n                FRAGMENT: 11\n              },\n\n              /** PrivateConstants: Timeout Values\n               *  Timeout values for error states.  These values are in seconds.\n               *  These should not be changed unless you know exactly what you are\n               *  doing.\n               *\n               *  TIMEOUT - Timeout multiplier. A waiting request will be considered\n               *      failed after Math.floor(TIMEOUT * wait) seconds have elapsed.\n               *      This defaults to 1.1, and with default wait, 66 seconds.\n               *  SECONDARY_TIMEOUT - Secondary timeout multiplier. In cases where\n               *      Strophe can detect early failure, it will consider the request\n               *      failed if it doesn't return after\n               *      Math.floor(SECONDARY_TIMEOUT * wait) seconds have elapsed.\n               *      This defaults to 0.1, and with default wait, 6 seconds.\n               */\n              TIMEOUT: 1.1,\n              SECONDARY_TIMEOUT: 0.1,\n\n              /** Function: addNamespace\n               *  This function is used to extend the current namespaces in\n               *  Strophe.NS.  It takes a key and a value with the key being the\n               *  name of the new namespace, with its actual value.\n               *  For example:\n               *  Strophe.addNamespace('PUBSUB', \"http://jabber.org/protocol/pubsub\");\n               *\n               *  Parameters:\n               *    (String) name - The name under which the namespace will be\n               *      referenced under Strophe.NS\n               *    (String) value - The actual namespace.\n               */\n              addNamespace(name, value) {\n                Strophe.NS[name] = value;\n              },\n\n              /** Function: forEachChild\n               *  Map a function over some or all child elements of a given element.\n               *\n               *  This is a small convenience function for mapping a function over\n               *  some or all of the children of an element.  If elemName is null, all\n               *  children will be passed to the function, otherwise only children\n               *  whose tag names match elemName will be passed.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - The element to operate on.\n               *    (String) elemName - The child element tag name filter.\n               *    (Function) func - The function to apply to each child.  This\n               *      function should take a single argument, a DOM element.\n               */\n              forEachChild(elem, elemName, func) {\n                for (let i = 0; i < elem.childNodes.length; i++) {\n                  const childNode = elem.childNodes[i];\n\n                  if (childNode.nodeType === Strophe.ElementType.NORMAL && (!elemName || this.isTagEqual(childNode, elemName))) {\n                    func(childNode);\n                  }\n                }\n              },\n\n              /** Function: isTagEqual\n               *  Compare an element's tag name with a string.\n               *\n               *  This function is case sensitive.\n               *\n               *  Parameters:\n               *    (XMLElement) el - A DOM element.\n               *    (String) name - The element name.\n               *\n               *  Returns:\n               *    true if the element's tag name matches _el_, and false\n               *    otherwise.\n               */\n              isTagEqual(el, name) {\n                return el.tagName === name;\n              },\n\n              /** PrivateVariable: _xmlGenerator\n               *  _Private_ variable that caches a DOM document to\n               *  generate elements.\n               */\n              _xmlGenerator: null,\n\n              /** Function: xmlGenerator\n               *  Get the DOM document to generate elements.\n               *\n               *  Returns:\n               *    The currently used DOM document.\n               */\n              xmlGenerator() {\n                if (!Strophe._xmlGenerator) {\n                  Strophe._xmlGenerator = getDummyXMLDOMDocument();\n                }\n\n                return Strophe._xmlGenerator;\n              },\n\n              /** Function: xmlElement\n               *  Create an XML DOM element.\n               *\n               *  This function creates an XML DOM element correctly across all\n               *  implementations. Note that these are not HTML DOM elements, which\n               *  aren't appropriate for XMPP stanzas.\n               *\n               *  Parameters:\n               *    (String) name - The name for the element.\n               *    (Array|Object) attrs - An optional array or object containing\n               *      key/value pairs to use as element attributes. The object should\n               *      be in the format {'key': 'value'} or {key: 'value'}. The array\n               *      should have the format [['key1', 'value1'], ['key2', 'value2']].\n               *    (String) text - The text child data for the element.\n               *\n               *  Returns:\n               *    A new XML DOM element.\n               */\n              xmlElement(name) {\n                if (!name) {\n                  return null;\n                }\n\n                const node = Strophe.xmlGenerator().createElement(name); // FIXME: this should throw errors if args are the wrong type or\n                // there are more than two optional args\n\n                for (let a = 1; a < arguments.length; a++) {\n                  const arg = arguments[a];\n\n                  if (!arg) {\n                    continue;\n                  }\n\n                  if (typeof arg === \"string\" || typeof arg === \"number\") {\n                    node.appendChild(Strophe.xmlTextNode(arg));\n                  } else if (typeof arg === \"object\" && typeof arg.sort === \"function\") {\n                    for (let i = 0; i < arg.length; i++) {\n                      const attr = arg[i];\n\n                      if (typeof attr === \"object\" && typeof attr.sort === \"function\" && attr[1] !== undefined && attr[1] !== null) {\n                        node.setAttribute(attr[0], attr[1]);\n                      }\n                    }\n                  } else if (typeof arg === \"object\") {\n                    for (const k in arg) {\n                      if (Object.prototype.hasOwnProperty.call(arg, k) && arg[k] !== undefined && arg[k] !== null) {\n                        node.setAttribute(k, arg[k]);\n                      }\n                    }\n                  }\n                }\n\n                return node;\n              },\n\n              /*  Function: xmlescape\n               *  Excapes invalid xml characters.\n               *\n               *  Parameters:\n               *     (String) text - text to escape.\n               *\n               *  Returns:\n               *      Escaped text.\n               */\n              xmlescape(text) {\n                text = text.replace(/\\&/g, \"&amp;\");\n                text = text.replace(/</g, \"&lt;\");\n                text = text.replace(/>/g, \"&gt;\");\n                text = text.replace(/'/g, \"&apos;\");\n                text = text.replace(/\"/g, \"&quot;\");\n                return text;\n              },\n\n              /*  Function: xmlunescape\n              *  Unexcapes invalid xml characters.\n              *\n              *  Parameters:\n              *     (String) text - text to unescape.\n              *\n              *  Returns:\n              *      Unescaped text.\n              */\n              xmlunescape(text) {\n                text = text.replace(/\\&amp;/g, \"&\");\n                text = text.replace(/&lt;/g, \"<\");\n                text = text.replace(/&gt;/g, \">\");\n                text = text.replace(/&apos;/g, \"'\");\n                text = text.replace(/&quot;/g, \"\\\"\");\n                return text;\n              },\n\n              /** Function: xmlTextNode\n               *  Creates an XML DOM text node.\n               *\n               *  Provides a cross implementation version of document.createTextNode.\n               *\n               *  Parameters:\n               *    (String) text - The content of the text node.\n               *\n               *  Returns:\n               *    A new XML DOM text node.\n               */\n              xmlTextNode(text) {\n                return Strophe.xmlGenerator().createTextNode(text);\n              },\n\n              /** Function: xmlHtmlNode\n               *  Creates an XML DOM html node.\n               *\n               *  Parameters:\n               *    (String) html - The content of the html node.\n               *\n               *  Returns:\n               *    A new XML DOM text node.\n               */\n              xmlHtmlNode(html) {\n                let node; //ensure text is escaped\n\n                if (DOMParser) {\n                  const parser = new DOMParser();\n                  node = parser.parseFromString(html, \"text/xml\");\n                } else {\n                  node = new ActiveXObject(\"Microsoft.XMLDOM\");\n                  node.async = \"false\";\n                  node.loadXML(html);\n                }\n\n                return node;\n              },\n\n              /** Function: getText\n               *  Get the concatenation of all text children of an element.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - A DOM element.\n               *\n               *  Returns:\n               *    A String with the concatenated text of all text element children.\n               */\n              getText(elem) {\n                if (!elem) {\n                  return null;\n                }\n\n                let str = \"\";\n\n                if (elem.childNodes.length === 0 && elem.nodeType === Strophe.ElementType.TEXT) {\n                  str += elem.nodeValue;\n                }\n\n                for (let i = 0; i < elem.childNodes.length; i++) {\n                  if (elem.childNodes[i].nodeType === Strophe.ElementType.TEXT) {\n                    str += elem.childNodes[i].nodeValue;\n                  }\n                }\n\n                return Strophe.xmlescape(str);\n              },\n\n              /** Function: copyElement\n               *  Copy an XML DOM element.\n               *\n               *  This function copies a DOM element and all its descendants and returns\n               *  the new copy.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - A DOM element.\n               *\n               *  Returns:\n               *    A new, copied DOM element tree.\n               */\n              copyElement(elem) {\n                let el;\n\n                if (elem.nodeType === Strophe.ElementType.NORMAL) {\n                  el = Strophe.xmlElement(elem.tagName);\n\n                  for (let i = 0; i < elem.attributes.length; i++) {\n                    el.setAttribute(elem.attributes[i].nodeName, elem.attributes[i].value);\n                  }\n\n                  for (let i = 0; i < elem.childNodes.length; i++) {\n                    el.appendChild(Strophe.copyElement(elem.childNodes[i]));\n                  }\n                } else if (elem.nodeType === Strophe.ElementType.TEXT) {\n                  el = Strophe.xmlGenerator().createTextNode(elem.nodeValue);\n                }\n\n                return el;\n              },\n\n              /** Function: createHtml\n               *  Copy an HTML DOM element into an XML DOM.\n               *\n               *  This function copies a DOM element and all its descendants and returns\n               *  the new copy.\n               *\n               *  Parameters:\n               *    (HTMLElement) elem - A DOM element.\n               *\n               *  Returns:\n               *    A new, copied DOM element tree.\n               */\n              createHtml(elem) {\n                let el;\n\n                if (elem.nodeType === Strophe.ElementType.NORMAL) {\n                  const tag = elem.nodeName.toLowerCase(); // XHTML tags must be lower case.\n\n                  if (Strophe.XHTML.validTag(tag)) {\n                    try {\n                      el = Strophe.xmlElement(tag);\n\n                      for (let i = 0; i < Strophe.XHTML.attributes[tag].length; i++) {\n                        const attribute = Strophe.XHTML.attributes[tag][i];\n                        let value = elem.getAttribute(attribute);\n\n                        if (typeof value === 'undefined' || value === null || value === '' || value === false || value === 0) {\n                          continue;\n                        }\n\n                        if (attribute === 'style' && typeof value === 'object' && typeof value.cssText !== 'undefined') {\n                          value = value.cssText; // we're dealing with IE, need to get CSS out\n                        } // filter out invalid css styles\n\n\n                        if (attribute === 'style') {\n                          const css = [];\n                          const cssAttrs = value.split(';');\n\n                          for (let j = 0; j < cssAttrs.length; j++) {\n                            const attr = cssAttrs[j].split(':');\n                            const cssName = attr[0].replace(/^\\s*/, \"\").replace(/\\s*$/, \"\").toLowerCase();\n\n                            if (Strophe.XHTML.validCSS(cssName)) {\n                              const cssValue = attr[1].replace(/^\\s*/, \"\").replace(/\\s*$/, \"\");\n                              css.push(cssName + ': ' + cssValue);\n                            }\n                          }\n\n                          if (css.length > 0) {\n                            value = css.join('; ');\n                            el.setAttribute(attribute, value);\n                          }\n                        } else {\n                          el.setAttribute(attribute, value);\n                        }\n                      }\n\n                      for (let i = 0; i < elem.childNodes.length; i++) {\n                        el.appendChild(Strophe.createHtml(elem.childNodes[i]));\n                      }\n                    } catch (e) {\n                      // invalid elements\n                      el = Strophe.xmlTextNode('');\n                    }\n                  } else {\n                    el = Strophe.xmlGenerator().createDocumentFragment();\n\n                    for (let i = 0; i < elem.childNodes.length; i++) {\n                      el.appendChild(Strophe.createHtml(elem.childNodes[i]));\n                    }\n                  }\n                } else if (elem.nodeType === Strophe.ElementType.FRAGMENT) {\n                  el = Strophe.xmlGenerator().createDocumentFragment();\n\n                  for (let i = 0; i < elem.childNodes.length; i++) {\n                    el.appendChild(Strophe.createHtml(elem.childNodes[i]));\n                  }\n                } else if (elem.nodeType === Strophe.ElementType.TEXT) {\n                  el = Strophe.xmlTextNode(elem.nodeValue);\n                }\n\n                return el;\n              },\n\n              /** Function: escapeNode\n               *  Escape the node part (also called local part) of a JID.\n               *\n               *  Parameters:\n               *    (String) node - A node (or local part).\n               *\n               *  Returns:\n               *    An escaped node (or local part).\n               */\n              escapeNode(node) {\n                if (typeof node !== \"string\") {\n                  return node;\n                }\n\n                return node.replace(/^\\s+|\\s+$/g, '').replace(/\\\\/g, \"\\\\5c\").replace(/ /g, \"\\\\20\").replace(/\\\"/g, \"\\\\22\").replace(/\\&/g, \"\\\\26\").replace(/\\'/g, \"\\\\27\").replace(/\\//g, \"\\\\2f\").replace(/:/g, \"\\\\3a\").replace(/</g, \"\\\\3c\").replace(/>/g, \"\\\\3e\").replace(/@/g, \"\\\\40\");\n              },\n\n              /** Function: unescapeNode\n               *  Unescape a node part (also called local part) of a JID.\n               *\n               *  Parameters:\n               *    (String) node - A node (or local part).\n               *\n               *  Returns:\n               *    An unescaped node (or local part).\n               */\n              unescapeNode(node) {\n                if (typeof node !== \"string\") {\n                  return node;\n                }\n\n                return node.replace(/\\\\20/g, \" \").replace(/\\\\22/g, '\"').replace(/\\\\26/g, \"&\").replace(/\\\\27/g, \"'\").replace(/\\\\2f/g, \"/\").replace(/\\\\3a/g, \":\").replace(/\\\\3c/g, \"<\").replace(/\\\\3e/g, \">\").replace(/\\\\40/g, \"@\").replace(/\\\\5c/g, \"\\\\\");\n              },\n\n              /** Function: getNodeFromJid\n               *  Get the node portion of a JID String.\n               *\n               *  Parameters:\n               *    (String) jid - A JID.\n               *\n               *  Returns:\n               *    A String containing the node.\n               */\n              getNodeFromJid(jid) {\n                if (jid.indexOf(\"@\") < 0) {\n                  return null;\n                }\n\n                return jid.split(\"@\")[0];\n              },\n\n              /** Function: getDomainFromJid\n               *  Get the domain portion of a JID String.\n               *\n               *  Parameters:\n               *    (String) jid - A JID.\n               *\n               *  Returns:\n               *    A String containing the domain.\n               */\n              getDomainFromJid(jid) {\n                const bare = Strophe.getBareJidFromJid(jid);\n\n                if (bare.indexOf(\"@\") < 0) {\n                  return bare;\n                } else {\n                  const parts = bare.split(\"@\");\n                  parts.splice(0, 1);\n                  return parts.join('@');\n                }\n              },\n\n              /** Function: getResourceFromJid\n               *  Get the resource portion of a JID String.\n               *\n               *  Parameters:\n               *    (String) jid - A JID.\n               *\n               *  Returns:\n               *    A String containing the resource.\n               */\n              getResourceFromJid(jid) {\n                if (!jid) {\n                  return null;\n                }\n\n                const s = jid.split(\"/\");\n\n                if (s.length < 2) {\n                  return null;\n                }\n\n                s.splice(0, 1);\n                return s.join('/');\n              },\n\n              /** Function: getBareJidFromJid\n               *  Get the bare JID from a JID String.\n               *\n               *  Parameters:\n               *    (String) jid - A JID.\n               *\n               *  Returns:\n               *    A String containing the bare JID.\n               */\n              getBareJidFromJid(jid) {\n                return jid ? jid.split(\"/\")[0] : null;\n              },\n\n              /** PrivateFunction: _handleError\n               *  _Private_ function that properly logs an error to the console\n               */\n              _handleError(e) {\n                if (typeof e.stack !== \"undefined\") {\n                  Strophe.fatal(e.stack);\n                }\n\n                if (e.sourceURL) {\n                  Strophe.fatal(\"error: \" + this.handler + \" \" + e.sourceURL + \":\" + e.line + \" - \" + e.name + \": \" + e.message);\n                } else if (e.fileName) {\n                  Strophe.fatal(\"error: \" + this.handler + \" \" + e.fileName + \":\" + e.lineNumber + \" - \" + e.name + \": \" + e.message);\n                } else {\n                  Strophe.fatal(\"error: \" + e.message);\n                }\n              },\n\n              /** Function: log\n               *  User overrideable logging function.\n               *\n               *  This function is called whenever the Strophe library calls any\n               *  of the logging functions.  The default implementation of this\n               *  function logs only fatal errors.  If client code wishes to handle the logging\n               *  messages, it should override this with\n               *  > Strophe.log = function (level, msg) {\n               *  >   (user code here)\n               *  > };\n               *\n               *  Please note that data sent and received over the wire is logged\n               *  via Strophe.Connection.rawInput() and Strophe.Connection.rawOutput().\n               *\n               *  The different levels and their meanings are\n               *\n               *    DEBUG - Messages useful for debugging purposes.\n               *    INFO - Informational messages.  This is mostly information like\n               *      'disconnect was called' or 'SASL auth succeeded'.\n               *    WARN - Warnings about potential problems.  This is mostly used\n               *      to report transient connection errors like request timeouts.\n               *    ERROR - Some error occurred.\n               *    FATAL - A non-recoverable fatal error occurred.\n               *\n               *  Parameters:\n               *    (Integer) level - The log level of the log message.  This will\n               *      be one of the values in Strophe.LogLevel.\n               *    (String) msg - The log message.\n               */\n              log(level, msg) {\n                if (level === this.LogLevel.FATAL) {\n                  var _console;\n\n                  (_console = console) === null || _console === void 0 ? void 0 : _console.error(msg);\n                }\n              },\n\n              /** Function: debug\n               *  Log a message at the Strophe.LogLevel.DEBUG level.\n               *\n               *  Parameters:\n               *    (String) msg - The log message.\n               */\n              debug(msg) {\n                this.log(this.LogLevel.DEBUG, msg);\n              },\n\n              /** Function: info\n               *  Log a message at the Strophe.LogLevel.INFO level.\n               *\n               *  Parameters:\n               *    (String) msg - The log message.\n               */\n              info(msg) {\n                this.log(this.LogLevel.INFO, msg);\n              },\n\n              /** Function: warn\n               *  Log a message at the Strophe.LogLevel.WARN level.\n               *\n               *  Parameters:\n               *    (String) msg - The log message.\n               */\n              warn(msg) {\n                this.log(this.LogLevel.WARN, msg);\n              },\n\n              /** Function: error\n               *  Log a message at the Strophe.LogLevel.ERROR level.\n               *\n               *  Parameters:\n               *    (String) msg - The log message.\n               */\n              error(msg) {\n                this.log(this.LogLevel.ERROR, msg);\n              },\n\n              /** Function: fatal\n               *  Log a message at the Strophe.LogLevel.FATAL level.\n               *\n               *  Parameters:\n               *    (String) msg - The log message.\n               */\n              fatal(msg) {\n                this.log(this.LogLevel.FATAL, msg);\n              },\n\n              /** Function: serialize\n               *  Render a DOM element and all descendants to a String.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - A DOM element.\n               *\n               *  Returns:\n               *    The serialized element tree as a String.\n               */\n              serialize(elem) {\n                if (!elem) {\n                  return null;\n                }\n\n                if (typeof elem.tree === \"function\") {\n                  elem = elem.tree();\n                }\n\n                const names = [...Array(elem.attributes.length).keys()].map(i => elem.attributes[i].nodeName);\n                names.sort();\n                let result = names.reduce((a, n) => `${a} ${n}=\"${Strophe.xmlescape(elem.attributes.getNamedItem(n).value)}\"`, `<${elem.nodeName}`);\n\n                if (elem.childNodes.length > 0) {\n                  result += \">\";\n\n                  for (let i = 0; i < elem.childNodes.length; i++) {\n                    const child = elem.childNodes[i];\n\n                    switch (child.nodeType) {\n                      case Strophe.ElementType.NORMAL:\n                        // normal element, so recurse\n                        result += Strophe.serialize(child);\n                        break;\n\n                      case Strophe.ElementType.TEXT:\n                        // text element to escape values\n                        result += Strophe.xmlescape(child.nodeValue);\n                        break;\n\n                      case Strophe.ElementType.CDATA:\n                        // cdata section so don't escape values\n                        result += \"<![CDATA[\" + child.nodeValue + \"]]>\";\n                    }\n                  }\n\n                  result += \"</\" + elem.nodeName + \">\";\n                } else {\n                  result += \"/>\";\n                }\n\n                return result;\n              },\n\n              /** PrivateVariable: _requestId\n               *  _Private_ variable that keeps track of the request ids for\n               *  connections.\n               */\n              _requestId: 0,\n\n              /** PrivateVariable: Strophe.connectionPlugins\n               *  _Private_ variable Used to store plugin names that need\n               *  initialization on Strophe.Connection construction.\n               */\n              _connectionPlugins: {},\n\n              /** Function: addConnectionPlugin\n               *  Extends the Strophe.Connection object with the given plugin.\n               *\n               *  Parameters:\n               *    (String) name - The name of the extension.\n               *    (Object) ptype - The plugin's prototype.\n               */\n              addConnectionPlugin(name, ptype) {\n                Strophe._connectionPlugins[name] = ptype;\n              }\n\n            };\n            /** Class: Strophe.Builder\n             *  XML DOM builder.\n             *\n             *  This object provides an interface similar to JQuery but for building\n             *  DOM elements easily and rapidly.  All the functions except for toString()\n             *  and tree() return the object, so calls can be chained.  Here's an\n             *  example using the $iq() builder helper.\n             *  > $iq({to: 'you', from: 'me', type: 'get', id: '1'})\n             *  >     .c('query', {xmlns: 'strophe:example'})\n             *  >     .c('example')\n             *  >     .toString()\n             *\n             *  The above generates this XML fragment\n             *  > <iq to='you' from='me' type='get' id='1'>\n             *  >   <query xmlns='strophe:example'>\n             *  >     <example/>\n             *  >   </query>\n             *  > </iq>\n             *  The corresponding DOM manipulations to get a similar fragment would be\n             *  a lot more tedious and probably involve several helper variables.\n             *\n             *  Since adding children makes new operations operate on the child, up()\n             *  is provided to traverse up the tree.  To add two children, do\n             *  > builder.c('child1', ...).up().c('child2', ...)\n             *  The next operation on the Builder will be relative to the second child.\n             */\n\n            /** Constructor: Strophe.Builder\n             *  Create a Strophe.Builder object.\n             *\n             *  The attributes should be passed in object notation.  For example\n             *  > let b = new Builder('message', {to: 'you', from: 'me'});\n             *  or\n             *  > let b = new Builder('messsage', {'xml:lang': 'en'});\n             *\n             *  Parameters:\n             *    (String) name - The name of the root element.\n             *    (Object) attrs - The attributes for the root element in object notation.\n             *\n             *  Returns:\n             *    A new Strophe.Builder.\n             */\n\n            Strophe.Builder = class Builder {\n              constructor(name, attrs) {\n                // Set correct namespace for jabber:client elements\n                if (name === \"presence\" || name === \"message\" || name === \"iq\") {\n                  if (attrs && !attrs.xmlns) {\n                    attrs.xmlns = Strophe.NS.CLIENT;\n                  } else if (!attrs) {\n                    attrs = {\n                      xmlns: Strophe.NS.CLIENT\n                    };\n                  }\n                } // Holds the tree being built.\n\n\n                this.nodeTree = Strophe.xmlElement(name, attrs); // Points to the current operation node.\n\n                this.node = this.nodeTree;\n              }\n              /** Function: tree\n               *  Return the DOM tree.\n               *\n               *  This function returns the current DOM tree as an element object.  This\n               *  is suitable for passing to functions like Strophe.Connection.send().\n               *\n               *  Returns:\n               *    The DOM tree as a element object.\n               */\n\n\n              tree() {\n                return this.nodeTree;\n              }\n              /** Function: toString\n               *  Serialize the DOM tree to a String.\n               *\n               *  This function returns a string serialization of the current DOM\n               *  tree.  It is often used internally to pass data to a\n               *  Strophe.Request object.\n               *\n               *  Returns:\n               *    The serialized DOM tree in a String.\n               */\n\n\n              toString() {\n                return Strophe.serialize(this.nodeTree);\n              }\n              /** Function: up\n               *  Make the current parent element the new current element.\n               *\n               *  This function is often used after c() to traverse back up the tree.\n               *  For example, to add two children to the same element\n               *  > builder.c('child1', {}).up().c('child2', {});\n               *\n               *  Returns:\n               *    The Stophe.Builder object.\n               */\n\n\n              up() {\n                this.node = this.node.parentNode;\n                return this;\n              }\n              /** Function: root\n               *  Make the root element the new current element.\n               *\n               *  When at a deeply nested element in the tree, this function can be used\n               *  to jump back to the root of the tree, instead of having to repeatedly\n               *  call up().\n               *\n               *  Returns:\n               *    The Stophe.Builder object.\n               */\n\n\n              root() {\n                this.node = this.nodeTree;\n                return this;\n              }\n              /** Function: attrs\n               *  Add or modify attributes of the current element.\n               *\n               *  The attributes should be passed in object notation.  This function\n               *  does not move the current element pointer.\n               *\n               *  Parameters:\n               *    (Object) moreattrs - The attributes to add/modify in object notation.\n               *\n               *  Returns:\n               *    The Strophe.Builder object.\n               */\n\n\n              attrs(moreattrs) {\n                for (const k in moreattrs) {\n                  if (Object.prototype.hasOwnProperty.call(moreattrs, k)) {\n                    if (moreattrs[k] === undefined) {\n                      this.node.removeAttribute(k);\n                    } else {\n                      this.node.setAttribute(k, moreattrs[k]);\n                    }\n                  }\n                }\n\n                return this;\n              }\n              /** Function: c\n               *  Add a child to the current element and make it the new current\n               *  element.\n               *\n               *  This function moves the current element pointer to the child,\n               *  unless text is provided.  If you need to add another child, it\n               *  is necessary to use up() to go back to the parent in the tree.\n               *\n               *  Parameters:\n               *    (String) name - The name of the child.\n               *    (Object) attrs - The attributes of the child in object notation.\n               *    (String) text - The text to add to the child.\n               *\n               *  Returns:\n               *    The Strophe.Builder object.\n               */\n\n\n              c(name, attrs, text) {\n                const child = Strophe.xmlElement(name, attrs, text);\n                this.node.appendChild(child);\n\n                if (typeof text !== \"string\" && typeof text !== \"number\") {\n                  this.node = child;\n                }\n\n                return this;\n              }\n              /** Function: cnode\n               *  Add a child to the current element and make it the new current\n               *  element.\n               *\n               *  This function is the same as c() except that instead of using a\n               *  name and an attributes object to create the child it uses an\n               *  existing DOM element object.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - A DOM element.\n               *\n               *  Returns:\n               *    The Strophe.Builder object.\n               */\n\n\n              cnode(elem) {\n                let impNode;\n                const xmlGen = Strophe.xmlGenerator();\n\n                try {\n                  impNode = xmlGen.importNode !== undefined;\n                } catch (e) {\n                  impNode = false;\n                }\n\n                const newElem = impNode ? xmlGen.importNode(elem, true) : Strophe.copyElement(elem);\n                this.node.appendChild(newElem);\n                this.node = newElem;\n                return this;\n              }\n              /** Function: t\n               *  Add a child text element.\n               *\n               *  This *does not* make the child the new current element since there\n               *  are no children of text elements.\n               *\n               *  Parameters:\n               *    (String) text - The text data to append to the current element.\n               *\n               *  Returns:\n               *    The Strophe.Builder object.\n               */\n\n\n              t(text) {\n                const child = Strophe.xmlTextNode(text);\n                this.node.appendChild(child);\n                return this;\n              }\n              /** Function: h\n               *  Replace current element contents with the HTML passed in.\n               *\n               *  This *does not* make the child the new current element\n               *\n               *  Parameters:\n               *    (String) html - The html to insert as contents of current element.\n               *\n               *  Returns:\n               *    The Strophe.Builder object.\n               */\n\n\n              h(html) {\n                const fragment = Strophe.xmlGenerator().createElement('body'); // force the browser to try and fix any invalid HTML tags\n\n                fragment.innerHTML = html; // copy cleaned html into an xml dom\n\n                const xhtml = Strophe.createHtml(fragment);\n\n                while (xhtml.childNodes.length > 0) {\n                  this.node.appendChild(xhtml.childNodes[0]);\n                }\n\n                return this;\n              }\n\n            };\n            /** PrivateClass: Strophe.Handler\n             *  _Private_ helper class for managing stanza handlers.\n             *\n             *  A Strophe.Handler encapsulates a user provided callback function to be\n             *  executed when matching stanzas are received by the connection.\n             *  Handlers can be either one-off or persistant depending on their\n             *  return value. Returning true will cause a Handler to remain active, and\n             *  returning false will remove the Handler.\n             *\n             *  Users will not use Strophe.Handler objects directly, but instead they\n             *  will use Strophe.Connection.addHandler() and\n             *  Strophe.Connection.deleteHandler().\n             */\n\n            /** PrivateConstructor: Strophe.Handler\n             *  Create and initialize a new Strophe.Handler.\n             *\n             *  Parameters:\n             *    (Function) handler - A function to be executed when the handler is run.\n             *    (String) ns - The namespace to match.\n             *    (String) name - The element name to match.\n             *    (String) type - The element type to match.\n             *    (String) id - The element id attribute to match.\n             *    (String) from - The element from attribute to match.\n             *    (Object) options - Handler options\n             *\n             *  Returns:\n             *    A new Strophe.Handler object.\n             */\n\n            Strophe.Handler = function (handler, ns, name, type, id, from, options) {\n              this.handler = handler;\n              this.ns = ns;\n              this.name = name;\n              this.type = type;\n              this.id = id;\n              this.options = options || {\n                'matchBareFromJid': false,\n                'ignoreNamespaceFragment': false\n              }; // BBB: Maintain backward compatibility with old `matchBare` option\n\n              if (this.options.matchBare) {\n                Strophe.warn('The \"matchBare\" option is deprecated, use \"matchBareFromJid\" instead.');\n                this.options.matchBareFromJid = this.options.matchBare;\n                delete this.options.matchBare;\n              }\n\n              if (this.options.matchBareFromJid) {\n                this.from = from ? Strophe.getBareJidFromJid(from) : null;\n              } else {\n                this.from = from;\n              } // whether the handler is a user handler or a system handler\n\n\n              this.user = true;\n            };\n\n            Strophe.Handler.prototype = {\n              /** PrivateFunction: getNamespace\n               *  Returns the XML namespace attribute on an element.\n               *  If `ignoreNamespaceFragment` was passed in for this handler, then the\n               *  URL fragment will be stripped.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - The XML element with the namespace.\n               *\n               *  Returns:\n               *    The namespace, with optionally the fragment stripped.\n               */\n              getNamespace(elem) {\n                let elNamespace = elem.getAttribute(\"xmlns\");\n\n                if (elNamespace && this.options.ignoreNamespaceFragment) {\n                  elNamespace = elNamespace.split('#')[0];\n                }\n\n                return elNamespace;\n              },\n\n              /** PrivateFunction: namespaceMatch\n               *  Tests if a stanza matches the namespace set for this Strophe.Handler.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - The XML element to test.\n               *\n               *  Returns:\n               *    true if the stanza matches and false otherwise.\n               */\n              namespaceMatch(elem) {\n                let nsMatch = false;\n\n                if (!this.ns) {\n                  return true;\n                } else {\n                  Strophe.forEachChild(elem, null, elem => {\n                    if (this.getNamespace(elem) === this.ns) {\n                      nsMatch = true;\n                    }\n                  });\n                  return nsMatch || this.getNamespace(elem) === this.ns;\n                }\n              },\n\n              /** PrivateFunction: isMatch\n               *  Tests if a stanza matches the Strophe.Handler.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - The XML element to test.\n               *\n               *  Returns:\n               *    true if the stanza matches and false otherwise.\n               */\n              isMatch(elem) {\n                let from = elem.getAttribute('from');\n\n                if (this.options.matchBareFromJid) {\n                  from = Strophe.getBareJidFromJid(from);\n                }\n\n                const elem_type = elem.getAttribute(\"type\");\n\n                if (this.namespaceMatch(elem) && (!this.name || Strophe.isTagEqual(elem, this.name)) && (!this.type || (Array.isArray(this.type) ? this.type.indexOf(elem_type) !== -1 : elem_type === this.type)) && (!this.id || elem.getAttribute(\"id\") === this.id) && (!this.from || from === this.from)) {\n                  return true;\n                }\n\n                return false;\n              },\n\n              /** PrivateFunction: run\n               *  Run the callback on a matching stanza.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - The DOM element that triggered the\n               *      Strophe.Handler.\n               *\n               *  Returns:\n               *    A boolean indicating if the handler should remain active.\n               */\n              run(elem) {\n                let result = null;\n\n                try {\n                  result = this.handler(elem);\n                } catch (e) {\n                  Strophe._handleError(e);\n\n                  throw e;\n                }\n\n                return result;\n              },\n\n              /** PrivateFunction: toString\n               *  Get a String representation of the Strophe.Handler object.\n               *\n               *  Returns:\n               *    A String.\n               */\n              toString() {\n                return \"{Handler: \" + this.handler + \"(\" + this.name + \",\" + this.id + \",\" + this.ns + \")}\";\n              }\n\n            };\n            /** PrivateClass: Strophe.TimedHandler\n             *  _Private_ helper class for managing timed handlers.\n             *\n             *  A Strophe.TimedHandler encapsulates a user provided callback that\n             *  should be called after a certain period of time or at regular\n             *  intervals.  The return value of the callback determines whether the\n             *  Strophe.TimedHandler will continue to fire.\n             *\n             *  Users will not use Strophe.TimedHandler objects directly, but instead\n             *  they will use Strophe.Connection.addTimedHandler() and\n             *  Strophe.Connection.deleteTimedHandler().\n             */\n\n            Strophe.TimedHandler = class TimedHandler {\n              /** PrivateConstructor: Strophe.TimedHandler\n               *  Create and initialize a new Strophe.TimedHandler object.\n               *\n               *  Parameters:\n               *    (Integer) period - The number of milliseconds to wait before the\n               *      handler is called.\n               *    (Function) handler - The callback to run when the handler fires.  This\n               *      function should take no arguments.\n               *\n               *  Returns:\n               *    A new Strophe.TimedHandler object.\n               */\n              constructor(period, handler) {\n                this.period = period;\n                this.handler = handler;\n                this.lastCalled = new Date().getTime();\n                this.user = true;\n              }\n              /** PrivateFunction: run\n               *  Run the callback for the Strophe.TimedHandler.\n               *\n               *  Returns:\n               *    true if the Strophe.TimedHandler should be called again, and false\n               *      otherwise.\n               */\n\n\n              run() {\n                this.lastCalled = new Date().getTime();\n                return this.handler();\n              }\n              /** PrivateFunction: reset\n               *  Reset the last called time for the Strophe.TimedHandler.\n               */\n\n\n              reset() {\n                this.lastCalled = new Date().getTime();\n              }\n              /** PrivateFunction: toString\n               *  Get a string representation of the Strophe.TimedHandler object.\n               *\n               *  Returns:\n               *    The string representation.\n               */\n\n\n              toString() {\n                return \"{TimedHandler: \" + this.handler + \"(\" + this.period + \")}\";\n              }\n\n            };\n            /** Class: Strophe.Connection\n             *  XMPP Connection manager.\n             *\n             *  This class is the main part of Strophe.  It manages a BOSH or websocket\n             *  connection to an XMPP server and dispatches events to the user callbacks\n             *  as data arrives. It supports SASL PLAIN, SASL SCRAM-SHA-1\n             *  and legacy authentication.\n             *\n             *  After creating a Strophe.Connection object, the user will typically\n             *  call connect() with a user supplied callback to handle connection level\n             *  events like authentication failure, disconnection, or connection\n             *  complete.\n             *\n             *  The user will also have several event handlers defined by using\n             *  addHandler() and addTimedHandler().  These will allow the user code to\n             *  respond to interesting stanzas or do something periodically with the\n             *  connection. These handlers will be active once authentication is\n             *  finished.\n             *\n             *  To send data to the connection, use send().\n             */\n\n            /** Constructor: Strophe.Connection\n             *  Create and initialize a Strophe.Connection object.\n             *\n             *  The transport-protocol for this connection will be chosen automatically\n             *  based on the given service parameter. URLs starting with \"ws://\" or\n             *  \"wss://\" will use WebSockets, URLs starting with \"http://\", \"https://\"\n             *  or without a protocol will use BOSH.\n             *\n             *  To make Strophe connect to the current host you can leave out the protocol\n             *  and host part and just pass the path, e.g.\n             *\n             *  > let conn = new Strophe.Connection(\"/http-bind/\");\n             *\n             *  Options common to both Websocket and BOSH:\n             *  ------------------------------------------\n             *\n             *  cookies:\n             *\n             *  The *cookies* option allows you to pass in cookies to be added to the\n             *  document. These cookies will then be included in the BOSH XMLHttpRequest\n             *  or in the websocket connection.\n             *\n             *  The passed in value must be a map of cookie names and string values.\n             *\n             *  > { \"myCookie\": {\n             *  >     \"value\": \"1234\",\n             *  >     \"domain\": \".example.org\",\n             *  >     \"path\": \"/\",\n             *  >     \"expires\": expirationDate\n             *  >     }\n             *  > }\n             *\n             *  Note that cookies can't be set in this way for other domains (i.e. cross-domain).\n             *  Those cookies need to be set under those domains, for example they can be\n             *  set server-side by making a XHR call to that domain to ask it to set any\n             *  necessary cookies.\n             *\n             *  mechanisms:\n             *\n             *  The *mechanisms* option allows you to specify the SASL mechanisms that this\n             *  instance of Strophe.Connection (and therefore your XMPP client) will\n             *  support.\n             *\n             *  The value must be an array of objects with Strophe.SASLMechanism\n             *  prototypes.\n             *\n             *  If nothing is specified, then the following mechanisms (and their\n             *  priorities) are registered:\n             *\n             *      SCRAM-SHA-1 - 60\n             *      PLAIN       - 50\n             *      OAUTHBEARER - 40\n             *      X-OAUTH2    - 30\n             *      ANONYMOUS   - 20\n             *      EXTERNAL    - 10\n             *\n             *  explicitResourceBinding:\n             *\n             *  If `explicitResourceBinding` is set to a truthy value, then the XMPP client\n             *  needs to explicitly call `Strophe.Connection.prototype.bind` once the XMPP\n             *  server has advertised the \"urn:ietf:params:xml:ns:xmpp-bind\" feature.\n             *\n             *  Making this step explicit allows client authors to first finish other\n             *  stream related tasks, such as setting up an XEP-0198 Stream Management\n             *  session, before binding the JID resource for this session.\n             *\n             *  WebSocket options:\n             *  ------------------\n             *\n             *  protocol:\n             *\n             *  If you want to connect to the current host with a WebSocket connection you\n             *  can tell Strophe to use WebSockets through a \"protocol\" attribute in the\n             *  optional options parameter. Valid values are \"ws\" for WebSocket and \"wss\"\n             *  for Secure WebSocket.\n             *  So to connect to \"wss://CURRENT_HOSTNAME/xmpp-websocket\" you would call\n             *\n             *  > let conn = new Strophe.Connection(\"/xmpp-websocket/\", {protocol: \"wss\"});\n             *\n             *  Note that relative URLs _NOT_ starting with a \"/\" will also include the path\n             *  of the current site.\n             *\n             *  Also because downgrading security is not permitted by browsers, when using\n             *  relative URLs both BOSH and WebSocket connections will use their secure\n             *  variants if the current connection to the site is also secure (https).\n             *\n             *  worker:\n             *\n             *  Set this option to URL from where the shared worker script should be loaded.\n             *\n             *  To run the websocket connection inside a shared worker.\n             *  This allows you to share a single websocket-based connection between\n             *  multiple Strophe.Connection instances, for example one per browser tab.\n             *\n             *  The script to use is the one in `src/shared-connection-worker.js`.\n             *\n             *  BOSH options:\n             *  -------------\n             *\n             *  By adding \"sync\" to the options, you can control if requests will\n             *  be made synchronously or not. The default behaviour is asynchronous.\n             *  If you want to make requests synchronous, make \"sync\" evaluate to true.\n             *  > let conn = new Strophe.Connection(\"/http-bind/\", {sync: true});\n             *\n             *  You can also toggle this on an already established connection.\n             *  > conn.options.sync = true;\n             *\n             *  The *customHeaders* option can be used to provide custom HTTP headers to be\n             *  included in the XMLHttpRequests made.\n             *\n             *  The *keepalive* option can be used to instruct Strophe to maintain the\n             *  current BOSH session across interruptions such as webpage reloads.\n             *\n             *  It will do this by caching the sessions tokens in sessionStorage, and when\n             *  \"restore\" is called it will check whether there are cached tokens with\n             *  which it can resume an existing session.\n             *\n             *  The *withCredentials* option should receive a Boolean value and is used to\n             *  indicate wether cookies should be included in ajax requests (by default\n             *  they're not).\n             *  Set this value to true if you are connecting to a BOSH service\n             *  and for some reason need to send cookies to it.\n             *  In order for this to work cross-domain, the server must also enable\n             *  credentials by setting the Access-Control-Allow-Credentials response header\n             *  to \"true\". For most usecases however this setting should be false (which\n             *  is the default).\n             *  Additionally, when using Access-Control-Allow-Credentials, the\n             *  Access-Control-Allow-Origin header can't be set to the wildcard \"*\", but\n             *  instead must be restricted to actual domains.\n             *\n             *  The *contentType* option can be set to change the default Content-Type\n             *  of \"text/xml; charset=utf-8\", which can be useful to reduce the amount of\n             *  CORS preflight requests that are sent to the server.\n             *\n             *  Parameters:\n             *    (String) service - The BOSH or WebSocket service URL.\n             *    (Object) options - A hash of configuration options\n             *\n             *  Returns:\n             *    A new Strophe.Connection object.\n             */\n\n            Strophe.Connection = class Connection {\n              constructor(service, options) {\n                // The service URL\n                this.service = service; // Configuration options\n\n                this.options = options || {};\n                this.setProtocol();\n                /* The connected JID. */\n\n                this.jid = \"\";\n                /* the JIDs domain */\n\n                this.domain = null;\n                /* stream:features */\n\n                this.features = null; // SASL\n\n                this._sasl_data = {};\n                this.do_bind = false;\n                this.do_session = false;\n                this.mechanisms = {}; // handler lists\n\n                this.timedHandlers = [];\n                this.handlers = [];\n                this.removeTimeds = [];\n                this.removeHandlers = [];\n                this.addTimeds = [];\n                this.addHandlers = [];\n                this.protocolErrorHandlers = {\n                  'HTTP': {},\n                  'websocket': {}\n                };\n                this._idleTimeout = null;\n                this._disconnectTimeout = null;\n                this.authenticated = false;\n                this.connected = false;\n                this.disconnecting = false;\n                this.do_authentication = true;\n                this.paused = false;\n                this.restored = false;\n                this._data = [];\n                this._uniqueId = 0;\n                this._sasl_success_handler = null;\n                this._sasl_failure_handler = null;\n                this._sasl_challenge_handler = null; // Max retries before disconnecting\n\n                this.maxRetries = 5; // Call onIdle callback every 1/10th of a second\n\n                this._idleTimeout = setTimeout(() => this._onIdle(), 100);\n                utils.addCookies(this.options.cookies);\n                this.registerSASLMechanisms(this.options.mechanisms); // initialize plugins\n\n                for (const k in Strophe._connectionPlugins) {\n                  if (Object.prototype.hasOwnProperty.call(Strophe._connectionPlugins, k)) {\n                    const F = function () {};\n\n                    F.prototype = Strophe._connectionPlugins[k];\n                    this[k] = new F();\n                    this[k].init(this);\n                  }\n                }\n              }\n              /** Function: setProtocol\n               *  Select protocal based on this.options or this.service\n               */\n\n\n              setProtocol() {\n                const proto = this.options.protocol || \"\";\n\n                if (this.options.worker) {\n                  this._proto = new Strophe.WorkerWebsocket(this);\n                } else if (this.service.indexOf(\"ws:\") === 0 || this.service.indexOf(\"wss:\") === 0 || proto.indexOf(\"ws\") === 0) {\n                  this._proto = new Strophe.Websocket(this);\n                } else {\n                  this._proto = new Strophe.Bosh(this);\n                }\n              }\n              /** Function: reset\n               *  Reset the connection.\n               *\n               *  This function should be called after a connection is disconnected\n               *  before that connection is reused.\n               */\n\n\n              reset() {\n                this._proto._reset(); // SASL\n\n\n                this.do_session = false;\n                this.do_bind = false; // handler lists\n\n                this.timedHandlers = [];\n                this.handlers = [];\n                this.removeTimeds = [];\n                this.removeHandlers = [];\n                this.addTimeds = [];\n                this.addHandlers = [];\n                this.authenticated = false;\n                this.connected = false;\n                this.disconnecting = false;\n                this.restored = false;\n                this._data = [];\n                this._requests = [];\n                this._uniqueId = 0;\n              }\n              /** Function: pause\n               *  Pause the request manager.\n               *\n               *  This will prevent Strophe from sending any more requests to the\n               *  server.  This is very useful for temporarily pausing\n               *  BOSH-Connections while a lot of send() calls are happening quickly.\n               *  This causes Strophe to send the data in a single request, saving\n               *  many request trips.\n               */\n\n\n              pause() {\n                this.paused = true;\n              }\n              /** Function: resume\n               *  Resume the request manager.\n               *\n               *  This resumes after pause() has been called.\n               */\n\n\n              resume() {\n                this.paused = false;\n              }\n              /** Function: getUniqueId\n               *  Generate a unique ID for use in <iq/> elements.\n               *\n               *  All <iq/> stanzas are required to have unique id attributes.  This\n               *  function makes creating these easy.  Each connection instance has\n               *  a counter which starts from zero, and the value of this counter\n               *  plus a colon followed by the suffix becomes the unique id. If no\n               *  suffix is supplied, the counter is used as the unique id.\n               *\n               *  Suffixes are used to make debugging easier when reading the stream\n               *  data, and their use is recommended.  The counter resets to 0 for\n               *  every new connection for the same reason.  For connections to the\n               *  same server that authenticate the same way, all the ids should be\n               *  the same, which makes it easy to see changes.  This is useful for\n               *  automated testing as well.\n               *\n               *  Parameters:\n               *    (String) suffix - A optional suffix to append to the id.\n               *\n               *  Returns:\n               *    A unique string to be used for the id attribute.\n               */\n\n\n              getUniqueId(suffix) {\n                // eslint-disable-line class-methods-use-this\n                const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {\n                  const r = Math.random() * 16 | 0,\n                        v = c === 'x' ? r : r & 0x3 | 0x8;\n                  return v.toString(16);\n                });\n\n                if (typeof suffix === \"string\" || typeof suffix === \"number\") {\n                  return uuid + \":\" + suffix;\n                } else {\n                  return uuid + \"\";\n                }\n              }\n              /** Function: addProtocolErrorHandler\n               *  Register a handler function for when a protocol (websocker or HTTP)\n               *  error occurs.\n               *\n               *  NOTE: Currently only HTTP errors for BOSH requests are handled.\n               *  Patches that handle websocket errors would be very welcome.\n               *\n               *  Parameters:\n               *    (String) protocol - 'HTTP' or 'websocket'\n               *    (Integer) status_code - Error status code (e.g 500, 400 or 404)\n               *    (Function) callback - Function that will fire on Http error\n               *\n               *  Example:\n               *  function onError(err_code){\n               *    //do stuff\n               *  }\n               *\n               *  let conn = Strophe.connect('http://example.com/http-bind');\n               *  conn.addProtocolErrorHandler('HTTP', 500, onError);\n               *  // Triggers HTTP 500 error and onError handler will be called\n               *  conn.connect('user_jid@incorrect_jabber_host', 'secret', onConnect);\n               */\n\n\n              addProtocolErrorHandler(protocol, status_code, callback) {\n                this.protocolErrorHandlers[protocol][status_code] = callback;\n              }\n              /** Function: connect\n               *  Starts the connection process.\n               *\n               *  As the connection process proceeds, the user supplied callback will\n               *  be triggered multiple times with status updates.  The callback\n               *  should take two arguments - the status code and the error condition.\n               *\n               *  The status code will be one of the values in the Strophe.Status\n               *  constants.  The error condition will be one of the conditions\n               *  defined in RFC 3920 or the condition 'strophe-parsererror'.\n               *\n               *  The Parameters _wait_, _hold_ and _route_ are optional and only relevant\n               *  for BOSH connections. Please see XEP 124 for a more detailed explanation\n               *  of the optional parameters.\n               *\n               *  Parameters:\n               *    (String) jid - The user's JID.  This may be a bare JID,\n               *      or a full JID.  If a node is not supplied, SASL OAUTHBEARER or\n               *      SASL ANONYMOUS authentication will be attempted (OAUTHBEARER will\n               *      process the provided password value as an access token).\n               *    (String) pass - The user's password.\n               *    (Function) callback - The connect callback function.\n               *    (Integer) wait - The optional HTTPBIND wait value.  This is the\n               *      time the server will wait before returning an empty result for\n               *      a request.  The default setting of 60 seconds is recommended.\n               *    (Integer) hold - The optional HTTPBIND hold value.  This is the\n               *      number of connections the server will hold at one time.  This\n               *      should almost always be set to 1 (the default).\n               *    (String) route - The optional route value.\n               *    (String) authcid - The optional alternative authentication identity\n               *      (username) if intending to impersonate another user.\n               *      When using the SASL-EXTERNAL authentication mechanism, for example\n               *      with client certificates, then the authcid value is used to\n               *      determine whether an authorization JID (authzid) should be sent to\n               *      the server. The authzid should NOT be sent to the server if the\n               *      authzid and authcid are the same. So to prevent it from being sent\n               *      (for example when the JID is already contained in the client\n               *      certificate), set authcid to that same JID. See XEP-178 for more\n               *      details.\n               *     (Integer) disconnection_timeout - The optional disconnection timeout\n               *      in milliseconds before _doDisconnect will be called.\n               */\n\n\n              connect(jid, pass, callback, wait, hold, route, authcid, disconnection_timeout = 3000) {\n                this.jid = jid;\n                /** Variable: authzid\n                 *  Authorization identity.\n                 */\n\n                this.authzid = Strophe.getBareJidFromJid(this.jid);\n                /** Variable: authcid\n                 *  Authentication identity (User name).\n                 */\n\n                this.authcid = authcid || Strophe.getNodeFromJid(this.jid);\n                /** Variable: pass\n                 *  Authentication identity (User password).\n                 */\n\n                this.pass = pass;\n                this.connect_callback = callback;\n                this.disconnecting = false;\n                this.connected = false;\n                this.authenticated = false;\n                this.restored = false;\n                this.disconnection_timeout = disconnection_timeout; // parse jid for domain\n\n                this.domain = Strophe.getDomainFromJid(this.jid);\n\n                this._changeConnectStatus(Strophe.Status.CONNECTING, null);\n\n                this._proto._connect(wait, hold, route);\n              }\n              /** Function: attach\n               *  Attach to an already created and authenticated BOSH session.\n               *\n               *  This function is provided to allow Strophe to attach to BOSH\n               *  sessions which have been created externally, perhaps by a Web\n               *  application.  This is often used to support auto-login type features\n               *  without putting user credentials into the page.\n               *\n               *  Parameters:\n               *    (String) jid - The full JID that is bound by the session.\n               *    (String) sid - The SID of the BOSH session.\n               *    (String) rid - The current RID of the BOSH session.  This RID\n               *      will be used by the next request.\n               *    (Function) callback The connect callback function.\n               *    (Integer) wait - The optional HTTPBIND wait value.  This is the\n               *      time the server will wait before returning an empty result for\n               *      a request.  The default setting of 60 seconds is recommended.\n               *      Other settings will require tweaks to the Strophe.TIMEOUT value.\n               *    (Integer) hold - The optional HTTPBIND hold value.  This is the\n               *      number of connections the server will hold at one time.  This\n               *      should almost always be set to 1 (the default).\n               *    (Integer) wind - The optional HTTBIND window value.  This is the\n               *      allowed range of request ids that are valid.  The default is 5.\n               */\n\n\n              attach(jid, sid, rid, callback, wait, hold, wind) {\n                if (this._proto._attach) {\n                  return this._proto._attach(jid, sid, rid, callback, wait, hold, wind);\n                } else {\n                  const error = new Error('The \"attach\" method is not available for your connection protocol');\n                  error.name = 'StropheSessionError';\n                  throw error;\n                }\n              }\n              /** Function: restore\n               *  Attempt to restore a cached BOSH session.\n               *\n               *  This function is only useful in conjunction with providing the\n               *  \"keepalive\":true option when instantiating a new Strophe.Connection.\n               *\n               *  When \"keepalive\" is set to true, Strophe will cache the BOSH tokens\n               *  RID (Request ID) and SID (Session ID) and then when this function is\n               *  called, it will attempt to restore the session from those cached\n               *  tokens.\n               *\n               *  This function must therefore be called instead of connect or attach.\n               *\n               *  For an example on how to use it, please see examples/restore.js\n               *\n               *  Parameters:\n               *    (String) jid - The user's JID.  This may be a bare JID or a full JID.\n               *    (Function) callback - The connect callback function.\n               *    (Integer) wait - The optional HTTPBIND wait value.  This is the\n               *      time the server will wait before returning an empty result for\n               *      a request.  The default setting of 60 seconds is recommended.\n               *    (Integer) hold - The optional HTTPBIND hold value.  This is the\n               *      number of connections the server will hold at one time.  This\n               *      should almost always be set to 1 (the default).\n               *    (Integer) wind - The optional HTTBIND window value.  This is the\n               *      allowed range of request ids that are valid.  The default is 5.\n               */\n\n\n              restore(jid, callback, wait, hold, wind) {\n                if (this._sessionCachingSupported()) {\n                  this._proto._restore(jid, callback, wait, hold, wind);\n                } else {\n                  const error = new Error('The \"restore\" method can only be used with a BOSH connection.');\n                  error.name = 'StropheSessionError';\n                  throw error;\n                }\n              }\n              /** PrivateFunction: _sessionCachingSupported\n               * Checks whether sessionStorage and JSON are supported and whether we're\n               * using BOSH.\n               */\n\n\n              _sessionCachingSupported() {\n                if (this._proto instanceof Strophe.Bosh) {\n                  if (!JSON) {\n                    return false;\n                  }\n\n                  try {\n                    sessionStorage.setItem('_strophe_', '_strophe_');\n                    sessionStorage.removeItem('_strophe_');\n                  } catch (e) {\n                    return false;\n                  }\n\n                  return true;\n                }\n\n                return false;\n              }\n              /** Function: xmlInput\n               *  User overrideable function that receives XML data coming into the\n               *  connection.\n               *\n               *  The default function does nothing.  User code can override this with\n               *  > Strophe.Connection.xmlInput = function (elem) {\n               *  >   (user code)\n               *  > };\n               *\n               *  Due to limitations of current Browsers' XML-Parsers the opening and closing\n               *  <stream> tag for WebSocket-Connoctions will be passed as selfclosing here.\n               *\n               *  BOSH-Connections will have all stanzas wrapped in a <body> tag. See\n               *  <Strophe.Bosh.strip> if you want to strip this tag.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - The XML data received by the connection.\n               */\n\n\n              xmlInput(elem) {\n                // eslint-disable-line\n                return;\n              }\n              /** Function: xmlOutput\n               *  User overrideable function that receives XML data sent to the\n               *  connection.\n               *\n               *  The default function does nothing.  User code can override this with\n               *  > Strophe.Connection.xmlOutput = function (elem) {\n               *  >   (user code)\n               *  > };\n               *\n               *  Due to limitations of current Browsers' XML-Parsers the opening and closing\n               *  <stream> tag for WebSocket-Connoctions will be passed as selfclosing here.\n               *\n               *  BOSH-Connections will have all stanzas wrapped in a <body> tag. See\n               *  <Strophe.Bosh.strip> if you want to strip this tag.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - The XMLdata sent by the connection.\n               */\n\n\n              xmlOutput(elem) {\n                // eslint-disable-line\n                return;\n              }\n              /** Function: rawInput\n               *  User overrideable function that receives raw data coming into the\n               *  connection.\n               *\n               *  The default function does nothing.  User code can override this with\n               *  > Strophe.Connection.rawInput = function (data) {\n               *  >   (user code)\n               *  > };\n               *\n               *  Parameters:\n               *    (String) data - The data received by the connection.\n               */\n\n\n              rawInput(data) {\n                // eslint-disable-line\n                return;\n              }\n              /** Function: rawOutput\n               *  User overrideable function that receives raw data sent to the\n               *  connection.\n               *\n               *  The default function does nothing.  User code can override this with\n               *  > Strophe.Connection.rawOutput = function (data) {\n               *  >   (user code)\n               *  > };\n               *\n               *  Parameters:\n               *    (String) data - The data sent by the connection.\n               */\n\n\n              rawOutput(data) {\n                // eslint-disable-line\n                return;\n              }\n              /** Function: nextValidRid\n               *  User overrideable function that receives the new valid rid.\n               *\n               *  The default function does nothing. User code can override this with\n               *  > Strophe.Connection.nextValidRid = function (rid) {\n               *  >    (user code)\n               *  > };\n               *\n               *  Parameters:\n               *    (Number) rid - The next valid rid\n               */\n\n\n              nextValidRid(rid) {\n                // eslint-disable-line\n                return;\n              }\n              /** Function: send\n               *  Send a stanza.\n               *\n               *  This function is called to push data onto the send queue to\n               *  go out over the wire.  Whenever a request is sent to the BOSH\n               *  server, all pending data is sent and the queue is flushed.\n               *\n               *  Parameters:\n               *    (XMLElement |\n               *     [XMLElement] |\n               *     Strophe.Builder) elem - The stanza to send.\n               */\n\n\n              send(elem) {\n                if (elem === null) {\n                  return;\n                }\n\n                if (typeof elem.sort === \"function\") {\n                  for (let i = 0; i < elem.length; i++) {\n                    this._queueData(elem[i]);\n                  }\n                } else if (typeof elem.tree === \"function\") {\n                  this._queueData(elem.tree());\n                } else {\n                  this._queueData(elem);\n                }\n\n                this._proto._send();\n              }\n              /** Function: flush\n               *  Immediately send any pending outgoing data.\n               *\n               *  Normally send() queues outgoing data until the next idle period\n               *  (100ms), which optimizes network use in the common cases when\n               *  several send()s are called in succession. flush() can be used to\n               *  immediately send all pending data.\n               */\n\n\n              flush() {\n                // cancel the pending idle period and run the idle function\n                // immediately\n                clearTimeout(this._idleTimeout);\n\n                this._onIdle();\n              }\n              /** Function: sendPresence\n               *  Helper function to send presence stanzas. The main benefit is for\n               *  sending presence stanzas for which you expect a responding presence\n               *  stanza with the same id (for example when leaving a chat room).\n               *\n               *  Parameters:\n               *    (XMLElement) elem - The stanza to send.\n               *    (Function) callback - The callback function for a successful request.\n               *    (Function) errback - The callback function for a failed or timed\n               *      out request.  On timeout, the stanza will be null.\n               *    (Integer) timeout - The time specified in milliseconds for a\n               *      timeout to occur.\n               *\n               *  Returns:\n               *    The id used to send the presence.\n               */\n\n\n              sendPresence(elem, callback, errback, timeout) {\n                let timeoutHandler = null;\n\n                if (typeof elem.tree === \"function\") {\n                  elem = elem.tree();\n                }\n\n                let id = elem.getAttribute('id');\n\n                if (!id) {\n                  // inject id if not found\n                  id = this.getUniqueId(\"sendPresence\");\n                  elem.setAttribute(\"id\", id);\n                }\n\n                if (typeof callback === \"function\" || typeof errback === \"function\") {\n                  const handler = this.addHandler(stanza => {\n                    // remove timeout handler if there is one\n                    if (timeoutHandler) {\n                      this.deleteTimedHandler(timeoutHandler);\n                    }\n\n                    if (stanza.getAttribute('type') === 'error') {\n                      if (errback) {\n                        errback(stanza);\n                      }\n                    } else if (callback) {\n                      callback(stanza);\n                    }\n                  }, null, 'presence', null, id); // if timeout specified, set up a timeout handler.\n\n                  if (timeout) {\n                    timeoutHandler = this.addTimedHandler(timeout, () => {\n                      // get rid of normal handler\n                      this.deleteHandler(handler); // call errback on timeout with null stanza\n\n                      if (errback) {\n                        errback(null);\n                      }\n\n                      return false;\n                    });\n                  }\n                }\n\n                this.send(elem);\n                return id;\n              }\n              /** Function: sendIQ\n               *  Helper function to send IQ stanzas.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - The stanza to send.\n               *    (Function) callback - The callback function for a successful request.\n               *    (Function) errback - The callback function for a failed or timed\n               *      out request.  On timeout, the stanza will be null.\n               *    (Integer) timeout - The time specified in milliseconds for a\n               *      timeout to occur.\n               *\n               *  Returns:\n               *    The id used to send the IQ.\n              */\n\n\n              sendIQ(elem, callback, errback, timeout) {\n                let timeoutHandler = null;\n\n                if (typeof elem.tree === \"function\") {\n                  elem = elem.tree();\n                }\n\n                let id = elem.getAttribute('id');\n\n                if (!id) {\n                  // inject id if not found\n                  id = this.getUniqueId(\"sendIQ\");\n                  elem.setAttribute(\"id\", id);\n                }\n\n                if (typeof callback === \"function\" || typeof errback === \"function\") {\n                  const handler = this.addHandler(stanza => {\n                    // remove timeout handler if there is one\n                    if (timeoutHandler) {\n                      this.deleteTimedHandler(timeoutHandler);\n                    }\n\n                    const iqtype = stanza.getAttribute('type');\n\n                    if (iqtype === 'result') {\n                      if (callback) {\n                        callback(stanza);\n                      }\n                    } else if (iqtype === 'error') {\n                      if (errback) {\n                        errback(stanza);\n                      }\n                    } else {\n                      const error = new Error(`Got bad IQ type of ${iqtype}`);\n                      error.name = \"StropheError\";\n                      throw error;\n                    }\n                  }, null, 'iq', ['error', 'result'], id); // if timeout specified, set up a timeout handler.\n\n                  if (timeout) {\n                    timeoutHandler = this.addTimedHandler(timeout, () => {\n                      // get rid of normal handler\n                      this.deleteHandler(handler); // call errback on timeout with null stanza\n\n                      if (errback) {\n                        errback(null);\n                      }\n\n                      return false;\n                    });\n                  }\n                }\n\n                this.send(elem);\n                return id;\n              }\n              /** PrivateFunction: _queueData\n               *  Queue outgoing data for later sending.  Also ensures that the data\n               *  is a DOMElement.\n               */\n\n\n              _queueData(element) {\n                if (element === null || !element.tagName || !element.childNodes) {\n                  const error = new Error(\"Cannot queue non-DOMElement.\");\n                  error.name = \"StropheError\";\n                  throw error;\n                }\n\n                this._data.push(element);\n              }\n              /** PrivateFunction: _sendRestart\n               *  Send an xmpp:restart stanza.\n               */\n\n\n              _sendRestart() {\n                this._data.push(\"restart\");\n\n                this._proto._sendRestart();\n\n                this._idleTimeout = setTimeout(() => this._onIdle(), 100);\n              }\n              /** Function: addTimedHandler\n               *  Add a timed handler to the connection.\n               *\n               *  This function adds a timed handler.  The provided handler will\n               *  be called every period milliseconds until it returns false,\n               *  the connection is terminated, or the handler is removed.  Handlers\n               *  that wish to continue being invoked should return true.\n               *\n               *  Because of method binding it is necessary to save the result of\n               *  this function if you wish to remove a handler with\n               *  deleteTimedHandler().\n               *\n               *  Note that user handlers are not active until authentication is\n               *  successful.\n               *\n               *  Parameters:\n               *    (Integer) period - The period of the handler.\n               *    (Function) handler - The callback function.\n               *\n               *  Returns:\n               *    A reference to the handler that can be used to remove it.\n               */\n\n\n              addTimedHandler(period, handler) {\n                const thand = new Strophe.TimedHandler(period, handler);\n                this.addTimeds.push(thand);\n                return thand;\n              }\n              /** Function: deleteTimedHandler\n               *  Delete a timed handler for a connection.\n               *\n               *  This function removes a timed handler from the connection.  The\n               *  handRef parameter is *not* the function passed to addTimedHandler(),\n               *  but is the reference returned from addTimedHandler().\n               *\n               *  Parameters:\n               *    (Strophe.TimedHandler) handRef - The handler reference.\n               */\n\n\n              deleteTimedHandler(handRef) {\n                // this must be done in the Idle loop so that we don't change\n                // the handlers during iteration\n                this.removeTimeds.push(handRef);\n              }\n              /** Function: addHandler\n               *  Add a stanza handler for the connection.\n               *\n               *  This function adds a stanza handler to the connection.  The\n               *  handler callback will be called for any stanza that matches\n               *  the parameters.  Note that if multiple parameters are supplied,\n               *  they must all match for the handler to be invoked.\n               *\n               *  The handler will receive the stanza that triggered it as its argument.\n               *  *The handler should return true if it is to be invoked again;\n               *  returning false will remove the handler after it returns.*\n               *\n               *  As a convenience, the ns parameters applies to the top level element\n               *  and also any of its immediate children.  This is primarily to make\n               *  matching /iq/query elements easy.\n               *\n               *  Options\n               *  ~~~~~~~\n               *  With the options argument, you can specify boolean flags that affect how\n               *  matches are being done.\n               *\n               *  Currently two flags exist:\n               *\n               *  - matchBareFromJid:\n               *      When set to true, the from parameter and the\n               *      from attribute on the stanza will be matched as bare JIDs instead\n               *      of full JIDs. To use this, pass {matchBareFromJid: true} as the\n               *      value of options. The default value for matchBareFromJid is false.\n               *\n               *  - ignoreNamespaceFragment:\n               *      When set to true, a fragment specified on the stanza's namespace\n               *      URL will be ignored when it's matched with the one configured for\n               *      the handler.\n               *\n               *      This means that if you register like this:\n               *      >   connection.addHandler(\n               *      >       handler,\n               *      >       'http://jabber.org/protocol/muc',\n               *      >       null, null, null, null,\n               *      >       {'ignoreNamespaceFragment': true}\n               *      >   );\n               *\n               *      Then a stanza with XML namespace of\n               *      'http://jabber.org/protocol/muc#user' will also be matched. If\n               *      'ignoreNamespaceFragment' is false, then only stanzas with\n               *      'http://jabber.org/protocol/muc' will be matched.\n               *\n               *  Deleting the handler\n               *  ~~~~~~~~~~~~~~~~~~~~\n               *  The return value should be saved if you wish to remove the handler\n               *  with deleteHandler().\n               *\n               *  Parameters:\n               *    (Function) handler - The user callback.\n               *    (String) ns - The namespace to match.\n               *    (String) name - The stanza name to match.\n               *    (String|Array) type - The stanza type (or types if an array) to match.\n               *    (String) id - The stanza id attribute to match.\n               *    (String) from - The stanza from attribute to match.\n               *    (String) options - The handler options\n               *\n               *  Returns:\n               *    A reference to the handler that can be used to remove it.\n               */\n\n\n              addHandler(handler, ns, name, type, id, from, options) {\n                const hand = new Strophe.Handler(handler, ns, name, type, id, from, options);\n                this.addHandlers.push(hand);\n                return hand;\n              }\n              /** Function: deleteHandler\n               *  Delete a stanza handler for a connection.\n               *\n               *  This function removes a stanza handler from the connection.  The\n               *  handRef parameter is *not* the function passed to addHandler(),\n               *  but is the reference returned from addHandler().\n               *\n               *  Parameters:\n               *    (Strophe.Handler) handRef - The handler reference.\n               */\n\n\n              deleteHandler(handRef) {\n                // this must be done in the Idle loop so that we don't change\n                // the handlers during iteration\n                this.removeHandlers.push(handRef); // If a handler is being deleted while it is being added,\n                // prevent it from getting added\n\n                const i = this.addHandlers.indexOf(handRef);\n\n                if (i >= 0) {\n                  this.addHandlers.splice(i, 1);\n                }\n              }\n              /** Function: registerSASLMechanisms\n               *\n               * Register the SASL mechanisms which will be supported by this instance of\n               * Strophe.Connection (i.e. which this XMPP client will support).\n               *\n               *  Parameters:\n               *    (Array) mechanisms - Array of objects with Strophe.SASLMechanism prototypes\n               *\n               */\n\n\n              registerSASLMechanisms(mechanisms) {\n                this.mechanisms = {};\n                mechanisms = mechanisms || [Strophe.SASLAnonymous, Strophe.SASLExternal, Strophe.SASLOAuthBearer, Strophe.SASLXOAuth2, Strophe.SASLPlain, Strophe.SASLSHA1];\n                mechanisms.forEach(m => this.registerSASLMechanism(m));\n              }\n              /** Function: registerSASLMechanism\n               *\n               * Register a single SASL mechanism, to be supported by this client.\n               *\n               *  Parameters:\n               *    (Object) mechanism - Object with a Strophe.SASLMechanism prototype\n               *\n               */\n\n\n              registerSASLMechanism(Mechanism) {\n                const mechanism = new Mechanism();\n                this.mechanisms[mechanism.mechname] = mechanism;\n              }\n              /** Function: disconnect\n               *  Start the graceful disconnection process.\n               *\n               *  This function starts the disconnection process.  This process starts\n               *  by sending unavailable presence and sending BOSH body of type\n               *  terminate.  A timeout handler makes sure that disconnection happens\n               *  even if the BOSH server does not respond.\n               *  If the Connection object isn't connected, at least tries to abort all pending requests\n               *  so the connection object won't generate successful requests (which were already opened).\n               *\n               *  The user supplied connection callback will be notified of the\n               *  progress as this process happens.\n               *\n               *  Parameters:\n               *    (String) reason - The reason the disconnect is occuring.\n               */\n\n\n              disconnect(reason) {\n                this._changeConnectStatus(Strophe.Status.DISCONNECTING, reason);\n\n                if (reason) {\n                  Strophe.warn(\"Disconnect was called because: \" + reason);\n                } else {\n                  Strophe.info(\"Disconnect was called\");\n                }\n\n                if (this.connected) {\n                  let pres = false;\n                  this.disconnecting = true;\n\n                  if (this.authenticated) {\n                    pres = $pres({\n                      'xmlns': Strophe.NS.CLIENT,\n                      'type': 'unavailable'\n                    });\n                  } // setup timeout handler\n\n\n                  this._disconnectTimeout = this._addSysTimedHandler(this.disconnection_timeout, this._onDisconnectTimeout.bind(this));\n\n                  this._proto._disconnect(pres);\n                } else {\n                  Strophe.warn(\"Disconnect was called before Strophe connected to the server\");\n\n                  this._proto._abortAllRequests();\n\n                  this._doDisconnect();\n                }\n              }\n              /** PrivateFunction: _changeConnectStatus\n               *  _Private_ helper function that makes sure plugins and the user's\n               *  callback are notified of connection status changes.\n               *\n               *  Parameters:\n               *    (Integer) status - the new connection status, one of the values\n               *      in Strophe.Status\n               *    (String) condition - the error condition or null\n               *    (XMLElement) elem - The triggering stanza.\n               */\n\n\n              _changeConnectStatus(status, condition, elem) {\n                // notify all plugins listening for status changes\n                for (const k in Strophe._connectionPlugins) {\n                  if (Object.prototype.hasOwnProperty.call(Strophe._connectionPlugins, k)) {\n                    const plugin = this[k];\n\n                    if (plugin.statusChanged) {\n                      try {\n                        plugin.statusChanged(status, condition);\n                      } catch (err) {\n                        Strophe.error(`${k} plugin caused an exception changing status: ${err}`);\n                      }\n                    }\n                  }\n                } // notify the user's callback\n\n\n                if (this.connect_callback) {\n                  try {\n                    this.connect_callback(status, condition, elem);\n                  } catch (e) {\n                    Strophe._handleError(e);\n\n                    Strophe.error(`User connection callback caused an exception: ${e}`);\n                  }\n                }\n              }\n              /** PrivateFunction: _doDisconnect\n               *  _Private_ function to disconnect.\n               *\n               *  This is the last piece of the disconnection logic.  This resets the\n               *  connection and alerts the user's connection callback.\n               */\n\n\n              _doDisconnect(condition) {\n                if (typeof this._idleTimeout === \"number\") {\n                  clearTimeout(this._idleTimeout);\n                } // Cancel Disconnect Timeout\n\n\n                if (this._disconnectTimeout !== null) {\n                  this.deleteTimedHandler(this._disconnectTimeout);\n                  this._disconnectTimeout = null;\n                }\n\n                Strophe.debug(\"_doDisconnect was called\");\n\n                this._proto._doDisconnect();\n\n                this.authenticated = false;\n                this.disconnecting = false;\n                this.restored = false; // delete handlers\n\n                this.handlers = [];\n                this.timedHandlers = [];\n                this.removeTimeds = [];\n                this.removeHandlers = [];\n                this.addTimeds = [];\n                this.addHandlers = []; // tell the parent we disconnected\n\n                this._changeConnectStatus(Strophe.Status.DISCONNECTED, condition);\n\n                this.connected = false;\n              }\n              /** PrivateFunction: _dataRecv\n               *  _Private_ handler to processes incoming data from the the connection.\n               *\n               *  Except for _connect_cb handling the initial connection request,\n               *  this function handles the incoming data for all requests.  This\n               *  function also fires stanza handlers that match each incoming\n               *  stanza.\n               *\n               *  Parameters:\n               *    (Strophe.Request) req - The request that has data ready.\n               *    (string) req - The stanza a raw string (optiona).\n               */\n\n\n              _dataRecv(req, raw) {\n                const elem = this._proto._reqToData(req);\n\n                if (elem === null) {\n                  return;\n                }\n\n                if (this.xmlInput !== Strophe.Connection.prototype.xmlInput) {\n                  if (elem.nodeName === this._proto.strip && elem.childNodes.length) {\n                    this.xmlInput(elem.childNodes[0]);\n                  } else {\n                    this.xmlInput(elem);\n                  }\n                }\n\n                if (this.rawInput !== Strophe.Connection.prototype.rawInput) {\n                  if (raw) {\n                    this.rawInput(raw);\n                  } else {\n                    this.rawInput(Strophe.serialize(elem));\n                  }\n                } // remove handlers scheduled for deletion\n\n\n                while (this.removeHandlers.length > 0) {\n                  const hand = this.removeHandlers.pop();\n                  const i = this.handlers.indexOf(hand);\n\n                  if (i >= 0) {\n                    this.handlers.splice(i, 1);\n                  }\n                } // add handlers scheduled for addition\n\n\n                while (this.addHandlers.length > 0) {\n                  this.handlers.push(this.addHandlers.pop());\n                } // handle graceful disconnect\n\n\n                if (this.disconnecting && this._proto._emptyQueue()) {\n                  this._doDisconnect();\n\n                  return;\n                }\n\n                const type = elem.getAttribute(\"type\");\n\n                if (type !== null && type === \"terminate\") {\n                  // Don't process stanzas that come in after disconnect\n                  if (this.disconnecting) {\n                    return;\n                  } // an error occurred\n\n\n                  let cond = elem.getAttribute(\"condition\");\n                  const conflict = elem.getElementsByTagName(\"conflict\");\n\n                  if (cond !== null) {\n                    if (cond === \"remote-stream-error\" && conflict.length > 0) {\n                      cond = \"conflict\";\n                    }\n\n                    this._changeConnectStatus(Strophe.Status.CONNFAIL, cond);\n                  } else {\n                    this._changeConnectStatus(Strophe.Status.CONNFAIL, Strophe.ErrorCondition.UNKOWN_REASON);\n                  }\n\n                  this._doDisconnect(cond);\n\n                  return;\n                } // send each incoming stanza through the handler chain\n\n\n                Strophe.forEachChild(elem, null, child => {\n                  // process handlers\n                  const newList = this.handlers;\n                  this.handlers = [];\n\n                  for (let i = 0; i < newList.length; i++) {\n                    const hand = newList[i]; // encapsulate 'handler.run' not to lose the whole handler list if\n                    // one of the handlers throws an exception\n\n                    try {\n                      if (hand.isMatch(child) && (this.authenticated || !hand.user)) {\n                        if (hand.run(child)) {\n                          this.handlers.push(hand);\n                        }\n                      } else {\n                        this.handlers.push(hand);\n                      }\n                    } catch (e) {\n                      // if the handler throws an exception, we consider it as false\n                      Strophe.warn('Removing Strophe handlers due to uncaught exception: ' + e.message);\n                    }\n                  }\n                });\n              }\n              /** PrivateFunction: _connect_cb\n               *  _Private_ handler for initial connection request.\n               *\n               *  This handler is used to process the initial connection request\n               *  response from the BOSH server. It is used to set up authentication\n               *  handlers and start the authentication process.\n               *\n               *  SASL authentication will be attempted if available, otherwise\n               *  the code will fall back to legacy authentication.\n               *\n               *  Parameters:\n               *    (Strophe.Request) req - The current request.\n               *    (Function) _callback - low level (xmpp) connect callback function.\n               *      Useful for plugins with their own xmpp connect callback (when they\n               *      want to do something special).\n               */\n\n\n              _connect_cb(req, _callback, raw) {\n                Strophe.debug(\"_connect_cb was called\");\n                this.connected = true;\n                let bodyWrap;\n\n                try {\n                  bodyWrap = this._proto._reqToData(req);\n                } catch (e) {\n                  if (e.name !== Strophe.ErrorCondition.BAD_FORMAT) {\n                    throw e;\n                  }\n\n                  this._changeConnectStatus(Strophe.Status.CONNFAIL, Strophe.ErrorCondition.BAD_FORMAT);\n\n                  this._doDisconnect(Strophe.ErrorCondition.BAD_FORMAT);\n                }\n\n                if (!bodyWrap) {\n                  return;\n                }\n\n                if (this.xmlInput !== Strophe.Connection.prototype.xmlInput) {\n                  if (bodyWrap.nodeName === this._proto.strip && bodyWrap.childNodes.length) {\n                    this.xmlInput(bodyWrap.childNodes[0]);\n                  } else {\n                    this.xmlInput(bodyWrap);\n                  }\n                }\n\n                if (this.rawInput !== Strophe.Connection.prototype.rawInput) {\n                  if (raw) {\n                    this.rawInput(raw);\n                  } else {\n                    this.rawInput(Strophe.serialize(bodyWrap));\n                  }\n                }\n\n                const conncheck = this._proto._connect_cb(bodyWrap);\n\n                if (conncheck === Strophe.Status.CONNFAIL) {\n                  return;\n                } // Check for the stream:features tag\n\n\n                let hasFeatures;\n\n                if (bodyWrap.getElementsByTagNameNS) {\n                  hasFeatures = bodyWrap.getElementsByTagNameNS(Strophe.NS.STREAM, \"features\").length > 0;\n                } else {\n                  hasFeatures = bodyWrap.getElementsByTagName(\"stream:features\").length > 0 || bodyWrap.getElementsByTagName(\"features\").length > 0;\n                }\n\n                if (!hasFeatures) {\n                  this._proto._no_auth_received(_callback);\n\n                  return;\n                }\n\n                const matched = Array.from(bodyWrap.getElementsByTagName(\"mechanism\")).map(m => this.mechanisms[m.textContent]).filter(m => m);\n\n                if (matched.length === 0) {\n                  if (bodyWrap.getElementsByTagName(\"auth\").length === 0) {\n                    // There are no matching SASL mechanisms and also no legacy\n                    // auth available.\n                    this._proto._no_auth_received(_callback);\n\n                    return;\n                  }\n                }\n\n                if (this.do_authentication !== false) {\n                  this.authenticate(matched);\n                }\n              }\n              /** Function: sortMechanismsByPriority\n               *\n               *  Sorts an array of objects with prototype SASLMechanism according to\n               *  their priorities.\n               *\n               *  Parameters:\n               *    (Array) mechanisms - Array of SASL mechanisms.\n               *\n               */\n\n\n              sortMechanismsByPriority(mechanisms) {\n                // eslint-disable-line class-methods-use-this\n                // Sorting mechanisms according to priority.\n                for (let i = 0; i < mechanisms.length - 1; ++i) {\n                  let higher = i;\n\n                  for (let j = i + 1; j < mechanisms.length; ++j) {\n                    if (mechanisms[j].priority > mechanisms[higher].priority) {\n                      higher = j;\n                    }\n                  }\n\n                  if (higher !== i) {\n                    const swap = mechanisms[i];\n                    mechanisms[i] = mechanisms[higher];\n                    mechanisms[higher] = swap;\n                  }\n                }\n\n                return mechanisms;\n              }\n              /** Function: authenticate\n               * Set up authentication\n               *\n               *  Continues the initial connection request by setting up authentication\n               *  handlers and starting the authentication process.\n               *\n               *  SASL authentication will be attempted if available, otherwise\n               *  the code will fall back to legacy authentication.\n               *\n               *  Parameters:\n               *    (Array) matched - Array of SASL mechanisms supported.\n               *\n               */\n\n\n              authenticate(matched) {\n                if (!this._attemptSASLAuth(matched)) {\n                  this._attemptLegacyAuth();\n                }\n              }\n              /** PrivateFunction: _attemptSASLAuth\n               *\n               *  Iterate through an array of SASL mechanisms and attempt authentication\n               *  with the highest priority (enabled) mechanism.\n               *\n               *  Parameters:\n               *    (Array) mechanisms - Array of SASL mechanisms.\n               *\n               *  Returns:\n               *    (Boolean) mechanism_found - true or false, depending on whether a\n               *          valid SASL mechanism was found with which authentication could be\n               *          started.\n               */\n\n\n              _attemptSASLAuth(mechanisms) {\n                mechanisms = this.sortMechanismsByPriority(mechanisms || []);\n                let mechanism_found = false;\n\n                for (let i = 0; i < mechanisms.length; ++i) {\n                  if (!mechanisms[i].test(this)) {\n                    continue;\n                  }\n\n                  this._sasl_success_handler = this._addSysHandler(this._sasl_success_cb.bind(this), null, \"success\", null, null);\n                  this._sasl_failure_handler = this._addSysHandler(this._sasl_failure_cb.bind(this), null, \"failure\", null, null);\n                  this._sasl_challenge_handler = this._addSysHandler(this._sasl_challenge_cb.bind(this), null, \"challenge\", null, null);\n                  this._sasl_mechanism = mechanisms[i];\n\n                  this._sasl_mechanism.onStart(this);\n\n                  const request_auth_exchange = $build(\"auth\", {\n                    'xmlns': Strophe.NS.SASL,\n                    'mechanism': this._sasl_mechanism.mechname\n                  });\n\n                  if (this._sasl_mechanism.isClientFirst) {\n                    const response = this._sasl_mechanism.clientChallenge(this);\n\n                    request_auth_exchange.t(abab.btoa(response));\n                  }\n\n                  this.send(request_auth_exchange.tree());\n                  mechanism_found = true;\n                  break;\n                }\n\n                return mechanism_found;\n              }\n              /** PrivateFunction: _sasl_challenge_cb\n               *  _Private_ handler for the SASL challenge\n               *\n               */\n\n\n              _sasl_challenge_cb(elem) {\n                const challenge = abab.atob(Strophe.getText(elem));\n\n                const response = this._sasl_mechanism.onChallenge(this, challenge);\n\n                const stanza = $build('response', {\n                  'xmlns': Strophe.NS.SASL\n                });\n\n                if (response !== \"\") {\n                  stanza.t(abab.btoa(response));\n                }\n\n                this.send(stanza.tree());\n                return true;\n              }\n              /** PrivateFunction: _attemptLegacyAuth\n               *\n               *  Attempt legacy (i.e. non-SASL) authentication.\n               */\n\n\n              _attemptLegacyAuth() {\n                if (Strophe.getNodeFromJid(this.jid) === null) {\n                  // we don't have a node, which is required for non-anonymous\n                  // client connections\n                  this._changeConnectStatus(Strophe.Status.CONNFAIL, Strophe.ErrorCondition.MISSING_JID_NODE);\n\n                  this.disconnect(Strophe.ErrorCondition.MISSING_JID_NODE);\n                } else {\n                  // Fall back to legacy authentication\n                  this._changeConnectStatus(Strophe.Status.AUTHENTICATING, null);\n\n                  this._addSysHandler(this._onLegacyAuthIQResult.bind(this), null, null, null, \"_auth_1\");\n\n                  this.send($iq({\n                    'type': \"get\",\n                    'to': this.domain,\n                    'id': \"_auth_1\"\n                  }).c(\"query\", {\n                    xmlns: Strophe.NS.AUTH\n                  }).c(\"username\", {}).t(Strophe.getNodeFromJid(this.jid)).tree());\n                }\n              }\n              /** PrivateFunction: _onLegacyAuthIQResult\n               *  _Private_ handler for legacy authentication.\n               *\n               *  This handler is called in response to the initial <iq type='get'/>\n               *  for legacy authentication.  It builds an authentication <iq/> and\n               *  sends it, creating a handler (calling back to _auth2_cb()) to\n               *  handle the result\n               *\n               *  Parameters:\n               *    (XMLElement) elem - The stanza that triggered the callback.\n               *\n               *  Returns:\n               *    false to remove the handler.\n               */\n\n\n              _onLegacyAuthIQResult(elem) {\n                // eslint-disable-line no-unused-vars\n                // build plaintext auth iq\n                const iq = $iq({\n                  type: \"set\",\n                  id: \"_auth_2\"\n                }).c('query', {\n                  xmlns: Strophe.NS.AUTH\n                }).c('username', {}).t(Strophe.getNodeFromJid(this.jid)).up().c('password').t(this.pass);\n\n                if (!Strophe.getResourceFromJid(this.jid)) {\n                  // since the user has not supplied a resource, we pick\n                  // a default one here.  unlike other auth methods, the server\n                  // cannot do this for us.\n                  this.jid = Strophe.getBareJidFromJid(this.jid) + '/strophe';\n                }\n\n                iq.up().c('resource', {}).t(Strophe.getResourceFromJid(this.jid));\n\n                this._addSysHandler(this._auth2_cb.bind(this), null, null, null, \"_auth_2\");\n\n                this.send(iq.tree());\n                return false;\n              }\n              /** PrivateFunction: _sasl_success_cb\n               *  _Private_ handler for succesful SASL authentication.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - The matching stanza.\n               *\n               *  Returns:\n               *    false to remove the handler.\n               */\n\n\n              _sasl_success_cb(elem) {\n                if (this._sasl_data[\"server-signature\"]) {\n                  let serverSignature;\n                  const success = abab.atob(Strophe.getText(elem));\n                  const attribMatch = /([a-z]+)=([^,]+)(,|$)/;\n                  const matches = success.match(attribMatch);\n\n                  if (matches[1] === \"v\") {\n                    serverSignature = matches[2];\n                  }\n\n                  if (serverSignature !== this._sasl_data[\"server-signature\"]) {\n                    // remove old handlers\n                    this.deleteHandler(this._sasl_failure_handler);\n                    this._sasl_failure_handler = null;\n\n                    if (this._sasl_challenge_handler) {\n                      this.deleteHandler(this._sasl_challenge_handler);\n                      this._sasl_challenge_handler = null;\n                    }\n\n                    this._sasl_data = {};\n                    return this._sasl_failure_cb(null);\n                  }\n                }\n\n                Strophe.info(\"SASL authentication succeeded.\");\n\n                if (this._sasl_mechanism) {\n                  this._sasl_mechanism.onSuccess();\n                } // remove old handlers\n\n\n                this.deleteHandler(this._sasl_failure_handler);\n                this._sasl_failure_handler = null;\n\n                if (this._sasl_challenge_handler) {\n                  this.deleteHandler(this._sasl_challenge_handler);\n                  this._sasl_challenge_handler = null;\n                }\n\n                const streamfeature_handlers = [];\n\n                const wrapper = (handlers, elem) => {\n                  while (handlers.length) {\n                    this.deleteHandler(handlers.pop());\n                  }\n\n                  this._onStreamFeaturesAfterSASL(elem);\n\n                  return false;\n                };\n\n                streamfeature_handlers.push(this._addSysHandler(elem => wrapper(streamfeature_handlers, elem), null, \"stream:features\", null, null));\n                streamfeature_handlers.push(this._addSysHandler(elem => wrapper(streamfeature_handlers, elem), Strophe.NS.STREAM, \"features\", null, null)); // we must send an xmpp:restart now\n\n                this._sendRestart();\n\n                return false;\n              }\n              /** PrivateFunction: _onStreamFeaturesAfterSASL\n               *  Parameters:\n               *    (XMLElement) elem - The matching stanza.\n               *\n               *  Returns:\n               *    false to remove the handler.\n               */\n\n\n              _onStreamFeaturesAfterSASL(elem) {\n                // save stream:features for future usage\n                this.features = elem;\n\n                for (let i = 0; i < elem.childNodes.length; i++) {\n                  const child = elem.childNodes[i];\n\n                  if (child.nodeName === 'bind') {\n                    this.do_bind = true;\n                  }\n\n                  if (child.nodeName === 'session') {\n                    this.do_session = true;\n                  }\n                }\n\n                if (!this.do_bind) {\n                  this._changeConnectStatus(Strophe.Status.AUTHFAIL, null);\n\n                  return false;\n                } else if (!this.options.explicitResourceBinding) {\n                  this.bind();\n                } else {\n                  this._changeConnectStatus(Strophe.Status.BINDREQUIRED, null);\n                }\n\n                return false;\n              }\n              /** Function: bind\n               *\n               *  Sends an IQ to the XMPP server to bind a JID resource for this session.\n               *\n               *  https://tools.ietf.org/html/rfc6120#section-7.5\n               *\n               *  If `explicitResourceBinding` was set to a truthy value in the options\n               *  passed to the Strophe.Connection constructor, then this function needs\n               *  to be called explicitly by the client author.\n               *\n               *  Otherwise it'll be called automatically as soon as the XMPP server\n               *  advertises the \"urn:ietf:params:xml:ns:xmpp-bind\" stream feature.\n               */\n\n\n              bind() {\n                if (!this.do_bind) {\n                  Strophe.log(Strophe.LogLevel.INFO, `Strophe.Connection.prototype.bind called but \"do_bind\" is false`);\n                  return;\n                }\n\n                this._addSysHandler(this._onResourceBindResultIQ.bind(this), null, null, null, \"_bind_auth_2\");\n\n                const resource = Strophe.getResourceFromJid(this.jid);\n\n                if (resource) {\n                  this.send($iq({\n                    type: \"set\",\n                    id: \"_bind_auth_2\"\n                  }).c('bind', {\n                    xmlns: Strophe.NS.BIND\n                  }).c('resource', {}).t(resource).tree());\n                } else {\n                  this.send($iq({\n                    type: \"set\",\n                    id: \"_bind_auth_2\"\n                  }).c('bind', {\n                    xmlns: Strophe.NS.BIND\n                  }).tree());\n                }\n              }\n              /** PrivateFunction: _onResourceBindIQ\n               *  _Private_ handler for binding result and session start.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - The matching stanza.\n               *\n               *  Returns:\n               *    false to remove the handler.\n               */\n\n\n              _onResourceBindResultIQ(elem) {\n                if (elem.getAttribute(\"type\") === \"error\") {\n                  Strophe.warn(\"Resource binding failed.\");\n                  const conflict = elem.getElementsByTagName(\"conflict\");\n                  let condition;\n\n                  if (conflict.length > 0) {\n                    condition = Strophe.ErrorCondition.CONFLICT;\n                  }\n\n                  this._changeConnectStatus(Strophe.Status.AUTHFAIL, condition, elem);\n\n                  return false;\n                } // TODO - need to grab errors\n\n\n                const bind = elem.getElementsByTagName(\"bind\");\n\n                if (bind.length > 0) {\n                  const jidNode = bind[0].getElementsByTagName(\"jid\");\n\n                  if (jidNode.length > 0) {\n                    this.authenticated = true;\n                    this.jid = Strophe.getText(jidNode[0]);\n\n                    if (this.do_session) {\n                      this._establishSession();\n                    } else {\n                      this._changeConnectStatus(Strophe.Status.CONNECTED, null);\n                    }\n                  }\n                } else {\n                  Strophe.warn(\"Resource binding failed.\");\n\n                  this._changeConnectStatus(Strophe.Status.AUTHFAIL, null, elem);\n\n                  return false;\n                }\n              }\n              /** PrivateFunction: _establishSession\n               *  Send IQ request to establish a session with the XMPP server.\n               *\n               *  See https://xmpp.org/rfcs/rfc3921.html#session\n               *\n               *  Note: The protocol for session establishment has been determined as\n               *  unnecessary and removed in RFC-6121.\n               */\n\n\n              _establishSession() {\n                if (!this.do_session) {\n                  throw new Error(`Strophe.Connection.prototype._establishSession ` + `called but apparently ${Strophe.NS.SESSION} wasn't advertised by the server`);\n                }\n\n                this._addSysHandler(this._onSessionResultIQ.bind(this), null, null, null, \"_session_auth_2\");\n\n                this.send($iq({\n                  type: \"set\",\n                  id: \"_session_auth_2\"\n                }).c('session', {\n                  xmlns: Strophe.NS.SESSION\n                }).tree());\n              }\n              /** PrivateFunction: _onSessionResultIQ\n               *  _Private_ handler for the server's IQ response to a client's session\n               *  request.\n               *\n               *  This sets Connection.authenticated to true on success, which\n               *  starts the processing of user handlers.\n               *\n               *  See https://xmpp.org/rfcs/rfc3921.html#session\n               *\n               *  Note: The protocol for session establishment has been determined as\n               *  unnecessary and removed in RFC-6121.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - The matching stanza.\n               *\n               *  Returns:\n               *    false to remove the handler.\n               */\n\n\n              _onSessionResultIQ(elem) {\n                if (elem.getAttribute(\"type\") === \"result\") {\n                  this.authenticated = true;\n\n                  this._changeConnectStatus(Strophe.Status.CONNECTED, null);\n                } else if (elem.getAttribute(\"type\") === \"error\") {\n                  this.authenticated = false;\n                  Strophe.warn(\"Session creation failed.\");\n\n                  this._changeConnectStatus(Strophe.Status.AUTHFAIL, null, elem);\n\n                  return false;\n                }\n\n                return false;\n              }\n              /** PrivateFunction: _sasl_failure_cb\n               *  _Private_ handler for SASL authentication failure.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - The matching stanza.\n               *\n               *  Returns:\n               *    false to remove the handler.\n               */\n\n\n              _sasl_failure_cb(elem) {\n                // delete unneeded handlers\n                if (this._sasl_success_handler) {\n                  this.deleteHandler(this._sasl_success_handler);\n                  this._sasl_success_handler = null;\n                }\n\n                if (this._sasl_challenge_handler) {\n                  this.deleteHandler(this._sasl_challenge_handler);\n                  this._sasl_challenge_handler = null;\n                }\n\n                if (this._sasl_mechanism) this._sasl_mechanism.onFailure();\n\n                this._changeConnectStatus(Strophe.Status.AUTHFAIL, null, elem);\n\n                return false;\n              }\n              /** PrivateFunction: _auth2_cb\n               *  _Private_ handler to finish legacy authentication.\n               *\n               *  This handler is called when the result from the jabber:iq:auth\n               *  <iq/> stanza is returned.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - The stanza that triggered the callback.\n               *\n               *  Returns:\n               *    false to remove the handler.\n               */\n\n\n              _auth2_cb(elem) {\n                if (elem.getAttribute(\"type\") === \"result\") {\n                  this.authenticated = true;\n\n                  this._changeConnectStatus(Strophe.Status.CONNECTED, null);\n                } else if (elem.getAttribute(\"type\") === \"error\") {\n                  this._changeConnectStatus(Strophe.Status.AUTHFAIL, null, elem);\n\n                  this.disconnect('authentication failed');\n                }\n\n                return false;\n              }\n              /** PrivateFunction: _addSysTimedHandler\n               *  _Private_ function to add a system level timed handler.\n               *\n               *  This function is used to add a Strophe.TimedHandler for the\n               *  library code.  System timed handlers are allowed to run before\n               *  authentication is complete.\n               *\n               *  Parameters:\n               *    (Integer) period - The period of the handler.\n               *    (Function) handler - The callback function.\n               */\n\n\n              _addSysTimedHandler(period, handler) {\n                const thand = new Strophe.TimedHandler(period, handler);\n                thand.user = false;\n                this.addTimeds.push(thand);\n                return thand;\n              }\n              /** PrivateFunction: _addSysHandler\n               *  _Private_ function to add a system level stanza handler.\n               *\n               *  This function is used to add a Strophe.Handler for the\n               *  library code.  System stanza handlers are allowed to run before\n               *  authentication is complete.\n               *\n               *  Parameters:\n               *    (Function) handler - The callback function.\n               *    (String) ns - The namespace to match.\n               *    (String) name - The stanza name to match.\n               *    (String) type - The stanza type attribute to match.\n               *    (String) id - The stanza id attribute to match.\n               */\n\n\n              _addSysHandler(handler, ns, name, type, id) {\n                const hand = new Strophe.Handler(handler, ns, name, type, id);\n                hand.user = false;\n                this.addHandlers.push(hand);\n                return hand;\n              }\n              /** PrivateFunction: _onDisconnectTimeout\n               *  _Private_ timeout handler for handling non-graceful disconnection.\n               *\n               *  If the graceful disconnect process does not complete within the\n               *  time allotted, this handler finishes the disconnect anyway.\n               *\n               *  Returns:\n               *    false to remove the handler.\n               */\n\n\n              _onDisconnectTimeout() {\n                Strophe.debug(\"_onDisconnectTimeout was called\");\n\n                this._changeConnectStatus(Strophe.Status.CONNTIMEOUT, null);\n\n                this._proto._onDisconnectTimeout(); // actually disconnect\n\n\n                this._doDisconnect();\n\n                return false;\n              }\n              /** PrivateFunction: _onIdle\n               *  _Private_ handler to process events during idle cycle.\n               *\n               *  This handler is called every 100ms to fire timed handlers that\n               *  are ready and keep poll requests going.\n               */\n\n\n              _onIdle() {\n                // add timed handlers scheduled for addition\n                // NOTE: we add before remove in the case a timed handler is\n                // added and then deleted before the next _onIdle() call.\n                while (this.addTimeds.length > 0) {\n                  this.timedHandlers.push(this.addTimeds.pop());\n                } // remove timed handlers that have been scheduled for deletion\n\n\n                while (this.removeTimeds.length > 0) {\n                  const thand = this.removeTimeds.pop();\n                  const i = this.timedHandlers.indexOf(thand);\n\n                  if (i >= 0) {\n                    this.timedHandlers.splice(i, 1);\n                  }\n                } // call ready timed handlers\n\n\n                const now = new Date().getTime();\n                const newList = [];\n\n                for (let i = 0; i < this.timedHandlers.length; i++) {\n                  const thand = this.timedHandlers[i];\n\n                  if (this.authenticated || !thand.user) {\n                    const since = thand.lastCalled + thand.period;\n\n                    if (since - now <= 0) {\n                      if (thand.run()) {\n                        newList.push(thand);\n                      }\n                    } else {\n                      newList.push(thand);\n                    }\n                  }\n                }\n\n                this.timedHandlers = newList;\n                clearTimeout(this._idleTimeout);\n\n                this._proto._onIdle(); // reactivate the timer only if connected\n\n\n                if (this.connected) {\n                  this._idleTimeout = setTimeout(() => this._onIdle(), 100);\n                }\n              }\n\n            };\n            Strophe.SASLMechanism = SASLMechanism;\n            /** Constants: SASL mechanisms\n             *  Available authentication mechanisms\n             *\n             *  Strophe.SASLAnonymous   - SASL ANONYMOUS authentication.\n             *  Strophe.SASLPlain       - SASL PLAIN authentication.\n             *  Strophe.SASLSHA1        - SASL SCRAM-SHA-1 authentication\n             *  Strophe.SASLOAuthBearer - SASL OAuth Bearer authentication\n             *  Strophe.SASLExternal    - SASL EXTERNAL authentication\n             *  Strophe.SASLXOAuth2     - SASL X-OAuth2 authentication\n             */\n\n            Strophe.SASLAnonymous = SASLAnonymous;\n            Strophe.SASLPlain = SASLPlain;\n            Strophe.SASLSHA1 = SASLSHA1;\n            Strophe.SASLOAuthBearer = SASLOAuthBearer;\n            Strophe.SASLExternal = SASLExternal;\n            Strophe.SASLXOAuth2 = SASLXOAuth2;\n            var core = {\n              'Strophe': Strophe,\n              '$build': $build,\n              '$iq': $iq,\n              '$msg': $msg,\n              '$pres': $pres,\n              'SHA1': SHA1,\n              'MD5': MD5,\n              'b64_hmac_sha1': SHA1.b64_hmac_sha1,\n              'b64_sha1': SHA1.b64_sha1,\n              'str_hmac_sha1': SHA1.str_hmac_sha1,\n              'str_sha1': SHA1.str_sha1\n            };\n\n            /*\n                This program is distributed under the terms of the MIT license.\n                Please see the LICENSE file for details.\n\n                Copyright 2006-2008, OGG, LLC\n            */\n            /** PrivateClass: Strophe.Request\n             *  _Private_ helper class that provides a cross implementation abstraction\n             *  for a BOSH related XMLHttpRequest.\n             *\n             *  The Strophe.Request class is used internally to encapsulate BOSH request\n             *  information.  It is not meant to be used from user's code.\n             */\n\n            Strophe.Request = class Request {\n              /** PrivateConstructor: Strophe.Request\n               *  Create and initialize a new Strophe.Request object.\n               *\n               *  Parameters:\n               *    (XMLElement) elem - The XML data to be sent in the request.\n               *    (Function) func - The function that will be called when the\n               *      XMLHttpRequest readyState changes.\n               *    (Integer) rid - The BOSH rid attribute associated with this request.\n               *    (Integer) sends - The number of times this same request has been sent.\n               */\n              constructor(elem, func, rid, sends) {\n                this.id = ++Strophe._requestId;\n                this.xmlData = elem;\n                this.data = Strophe.serialize(elem); // save original function in case we need to make a new request\n                // from this one.\n\n                this.origFunc = func;\n                this.func = func;\n                this.rid = rid;\n                this.date = NaN;\n                this.sends = sends || 0;\n                this.abort = false;\n                this.dead = null;\n\n                this.age = function () {\n                  if (!this.date) {\n                    return 0;\n                  }\n\n                  const now = new Date();\n                  return (now - this.date) / 1000;\n                };\n\n                this.timeDead = function () {\n                  if (!this.dead) {\n                    return 0;\n                  }\n\n                  const now = new Date();\n                  return (now - this.dead) / 1000;\n                };\n\n                this.xhr = this._newXHR();\n              }\n              /** PrivateFunction: getResponse\n               *  Get a response from the underlying XMLHttpRequest.\n               *\n               *  This function attempts to get a response from the request and checks\n               *  for errors.\n               *\n               *  Throws:\n               *    \"parsererror\" - A parser error occured.\n               *    \"bad-format\" - The entity has sent XML that cannot be processed.\n               *\n               *  Returns:\n               *    The DOM element tree of the response.\n               */\n\n\n              getResponse() {\n                let node = null;\n\n                if (this.xhr.responseXML && this.xhr.responseXML.documentElement) {\n                  node = this.xhr.responseXML.documentElement;\n\n                  if (node.tagName === \"parsererror\") {\n                    Strophe.error(\"invalid response received\");\n                    Strophe.error(\"responseText: \" + this.xhr.responseText);\n                    Strophe.error(\"responseXML: \" + Strophe.serialize(this.xhr.responseXML));\n                    throw new Error(\"parsererror\");\n                  }\n                } else if (this.xhr.responseText) {\n                  // In React Native, we may get responseText but no responseXML.  We can try to parse it manually.\n                  Strophe.debug(\"Got responseText but no responseXML; attempting to parse it with DOMParser...\");\n                  node = new DOMParser().parseFromString(this.xhr.responseText, 'application/xml').documentElement;\n\n                  if (!node) {\n                    throw new Error('Parsing produced null node');\n                  } else if (node.querySelector('parsererror')) {\n                    Strophe.error(\"invalid response received: \" + node.querySelector('parsererror').textContent);\n                    Strophe.error(\"responseText: \" + this.xhr.responseText);\n                    const error = new Error();\n                    error.name = Strophe.ErrorCondition.BAD_FORMAT;\n                    throw error;\n                  }\n                }\n\n                return node;\n              }\n              /** PrivateFunction: _newXHR\n               *  _Private_ helper function to create XMLHttpRequests.\n               *\n               *  This function creates XMLHttpRequests across all implementations.\n               *\n               *  Returns:\n               *    A new XMLHttpRequest.\n               */\n\n\n              _newXHR() {\n                let xhr = null;\n\n                if (window.XMLHttpRequest) {\n                  xhr = new XMLHttpRequest();\n\n                  if (xhr.overrideMimeType) {\n                    xhr.overrideMimeType(\"text/xml; charset=utf-8\");\n                  }\n                } else if (window.ActiveXObject) {\n                  xhr = new ActiveXObject(\"Microsoft.XMLHTTP\");\n                } // use Function.bind() to prepend ourselves as an argument\n\n\n                xhr.onreadystatechange = this.func.bind(null, this);\n                return xhr;\n              }\n\n            };\n            /** Class: Strophe.Bosh\n             *  _Private_ helper class that handles BOSH Connections\n             *\n             *  The Strophe.Bosh class is used internally by Strophe.Connection\n             *  to encapsulate BOSH sessions. It is not meant to be used from user's code.\n             */\n\n            /** File: bosh.js\n             *  A JavaScript library to enable BOSH in Strophejs.\n             *\n             *  this library uses Bidirectional-streams Over Synchronous HTTP (BOSH)\n             *  to emulate a persistent, stateful, two-way connection to an XMPP server.\n             *  More information on BOSH can be found in XEP 124.\n             */\n\n            /** PrivateConstructor: Strophe.Bosh\n             *  Create and initialize a Strophe.Bosh object.\n             *\n             *  Parameters:\n             *    (Strophe.Connection) connection - The Strophe.Connection that will use BOSH.\n             *\n             *  Returns:\n             *    A new Strophe.Bosh object.\n             */\n\n            Strophe.Bosh = class Bosh {\n              constructor(connection) {\n                this._conn = connection;\n                /* request id for body tags */\n\n                this.rid = Math.floor(Math.random() * 4294967295);\n                /* The current session ID. */\n\n                this.sid = null; // default BOSH values\n\n                this.hold = 1;\n                this.wait = 60;\n                this.window = 5;\n                this.errors = 0;\n                this.inactivity = null;\n                this.lastResponseHeaders = null;\n                this._requests = [];\n              }\n              /** PrivateFunction: _buildBody\n               *  _Private_ helper function to generate the <body/> wrapper for BOSH.\n               *\n               *  Returns:\n               *    A Strophe.Builder with a <body/> element.\n               */\n\n\n              _buildBody() {\n                const bodyWrap = $build('body', {\n                  'rid': this.rid++,\n                  'xmlns': Strophe.NS.HTTPBIND\n                });\n\n                if (this.sid !== null) {\n                  bodyWrap.attrs({\n                    'sid': this.sid\n                  });\n                }\n\n                if (this._conn.options.keepalive && this._conn._sessionCachingSupported()) {\n                  this._cacheSession();\n                }\n\n                return bodyWrap;\n              }\n              /** PrivateFunction: _reset\n               *  Reset the connection.\n               *\n               *  This function is called by the reset function of the Strophe Connection\n               */\n\n\n              _reset() {\n                this.rid = Math.floor(Math.random() * 4294967295);\n                this.sid = null;\n                this.errors = 0;\n\n                if (this._conn._sessionCachingSupported()) {\n                  window.sessionStorage.removeItem('strophe-bosh-session');\n                }\n\n                this._conn.nextValidRid(this.rid);\n              }\n              /** PrivateFunction: _connect\n               *  _Private_ function that initializes the BOSH connection.\n               *\n               *  Creates and sends the Request that initializes the BOSH connection.\n               */\n\n\n              _connect(wait, hold, route) {\n                this.wait = wait || this.wait;\n                this.hold = hold || this.hold;\n                this.errors = 0;\n\n                const body = this._buildBody().attrs({\n                  \"to\": this._conn.domain,\n                  \"xml:lang\": \"en\",\n                  \"wait\": this.wait,\n                  \"hold\": this.hold,\n                  \"content\": \"text/xml; charset=utf-8\",\n                  \"ver\": \"1.6\",\n                  \"xmpp:version\": \"1.0\",\n                  \"xmlns:xmpp\": Strophe.NS.BOSH\n                });\n\n                if (route) {\n                  body.attrs({\n                    'route': route\n                  });\n                }\n\n                const _connect_cb = this._conn._connect_cb;\n\n                this._requests.push(new Strophe.Request(body.tree(), this._onRequestStateChange.bind(this, _connect_cb.bind(this._conn)), body.tree().getAttribute(\"rid\")));\n\n                this._throttledRequestHandler();\n              }\n              /** PrivateFunction: _attach\n               *  Attach to an already created and authenticated BOSH session.\n               *\n               *  This function is provided to allow Strophe to attach to BOSH\n               *  sessions which have been created externally, perhaps by a Web\n               *  application.  This is often used to support auto-login type features\n               *  without putting user credentials into the page.\n               *\n               *  Parameters:\n               *    (String) jid - The full JID that is bound by the session.\n               *    (String) sid - The SID of the BOSH session.\n               *    (String) rid - The current RID of the BOSH session.  This RID\n               *      will be used by the next request.\n               *    (Function) callback The connect callback function.\n               *    (Integer) wait - The optional HTTPBIND wait value.  This is the\n               *      time the server will wait before returning an empty result for\n               *      a request.  The default setting of 60 seconds is recommended.\n               *      Other settings will require tweaks to the Strophe.TIMEOUT value.\n               *    (Integer) hold - The optional HTTPBIND hold value.  This is the\n               *      number of connections the server will hold at one time.  This\n               *      should almost always be set to 1 (the default).\n               *    (Integer) wind - The optional HTTBIND window value.  This is the\n               *      allowed range of request ids that are valid.  The default is 5.\n               */\n\n\n              _attach(jid, sid, rid, callback, wait, hold, wind) {\n                this._conn.jid = jid;\n                this.sid = sid;\n                this.rid = rid;\n                this._conn.connect_callback = callback;\n                this._conn.domain = Strophe.getDomainFromJid(this._conn.jid);\n                this._conn.authenticated = true;\n                this._conn.connected = true;\n                this.wait = wait || this.wait;\n                this.hold = hold || this.hold;\n                this.window = wind || this.window;\n\n                this._conn._changeConnectStatus(Strophe.Status.ATTACHED, null);\n              }\n              /** PrivateFunction: _restore\n               *  Attempt to restore a cached BOSH session\n               *\n               *  Parameters:\n               *    (String) jid - The full JID that is bound by the session.\n               *      This parameter is optional but recommended, specifically in cases\n               *      where prebinded BOSH sessions are used where it's important to know\n               *      that the right session is being restored.\n               *    (Function) callback The connect callback function.\n               *    (Integer) wait - The optional HTTPBIND wait value.  This is the\n               *      time the server will wait before returning an empty result for\n               *      a request.  The default setting of 60 seconds is recommended.\n               *      Other settings will require tweaks to the Strophe.TIMEOUT value.\n               *    (Integer) hold - The optional HTTPBIND hold value.  This is the\n               *      number of connections the server will hold at one time.  This\n               *      should almost always be set to 1 (the default).\n               *    (Integer) wind - The optional HTTBIND window value.  This is the\n               *      allowed range of request ids that are valid.  The default is 5.\n               */\n\n\n              _restore(jid, callback, wait, hold, wind) {\n                const session = JSON.parse(window.sessionStorage.getItem('strophe-bosh-session'));\n\n                if (typeof session !== \"undefined\" && session !== null && session.rid && session.sid && session.jid && (typeof jid === \"undefined\" || jid === null || Strophe.getBareJidFromJid(session.jid) === Strophe.getBareJidFromJid(jid) || // If authcid is null, then it's an anonymous login, so\n                // we compare only the domains:\n                Strophe.getNodeFromJid(jid) === null && Strophe.getDomainFromJid(session.jid) === jid)) {\n                  this._conn.restored = true;\n\n                  this._attach(session.jid, session.sid, session.rid, callback, wait, hold, wind);\n                } else {\n                  const error = new Error(\"_restore: no restoreable session.\");\n                  error.name = \"StropheSessionError\";\n                  throw error;\n                }\n              }\n              /** PrivateFunction: _cacheSession\n               *  _Private_ handler for the beforeunload event.\n               *\n               *  This handler is used to process the Bosh-part of the initial request.\n               *  Parameters:\n               *    (Strophe.Request) bodyWrap - The received stanza.\n               */\n\n\n              _cacheSession() {\n                if (this._conn.authenticated) {\n                  if (this._conn.jid && this.rid && this.sid) {\n                    window.sessionStorage.setItem('strophe-bosh-session', JSON.stringify({\n                      'jid': this._conn.jid,\n                      'rid': this.rid,\n                      'sid': this.sid\n                    }));\n                  }\n                } else {\n                  window.sessionStorage.removeItem('strophe-bosh-session');\n                }\n              }\n              /** PrivateFunction: _connect_cb\n               *  _Private_ handler for initial connection request.\n               *\n               *  This handler is used to process the Bosh-part of the initial request.\n               *  Parameters:\n               *    (Strophe.Request) bodyWrap - The received stanza.\n               */\n\n\n              _connect_cb(bodyWrap) {\n                const typ = bodyWrap.getAttribute(\"type\");\n\n                if (typ !== null && typ === \"terminate\") {\n                  // an error occurred\n                  let cond = bodyWrap.getAttribute(\"condition\");\n                  Strophe.error(\"BOSH-Connection failed: \" + cond);\n                  const conflict = bodyWrap.getElementsByTagName(\"conflict\");\n\n                  if (cond !== null) {\n                    if (cond === \"remote-stream-error\" && conflict.length > 0) {\n                      cond = \"conflict\";\n                    }\n\n                    this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, cond);\n                  } else {\n                    this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, \"unknown\");\n                  }\n\n                  this._conn._doDisconnect(cond);\n\n                  return Strophe.Status.CONNFAIL;\n                } // check to make sure we don't overwrite these if _connect_cb is\n                // called multiple times in the case of missing stream:features\n\n\n                if (!this.sid) {\n                  this.sid = bodyWrap.getAttribute(\"sid\");\n                }\n\n                const wind = bodyWrap.getAttribute('requests');\n\n                if (wind) {\n                  this.window = parseInt(wind, 10);\n                }\n\n                const hold = bodyWrap.getAttribute('hold');\n\n                if (hold) {\n                  this.hold = parseInt(hold, 10);\n                }\n\n                const wait = bodyWrap.getAttribute('wait');\n\n                if (wait) {\n                  this.wait = parseInt(wait, 10);\n                }\n\n                const inactivity = bodyWrap.getAttribute('inactivity');\n\n                if (inactivity) {\n                  this.inactivity = parseInt(inactivity, 10);\n                }\n              }\n              /** PrivateFunction: _disconnect\n               *  _Private_ part of Connection.disconnect for Bosh\n               *\n               *  Parameters:\n               *    (Request) pres - This stanza will be sent before disconnecting.\n               */\n\n\n              _disconnect(pres) {\n                this._sendTerminate(pres);\n              }\n              /** PrivateFunction: _doDisconnect\n               *  _Private_ function to disconnect.\n               *\n               *  Resets the SID and RID.\n               */\n\n\n              _doDisconnect() {\n                this.sid = null;\n                this.rid = Math.floor(Math.random() * 4294967295);\n\n                if (this._conn._sessionCachingSupported()) {\n                  window.sessionStorage.removeItem('strophe-bosh-session');\n                }\n\n                this._conn.nextValidRid(this.rid);\n              }\n              /** PrivateFunction: _emptyQueue\n               * _Private_ function to check if the Request queue is empty.\n               *\n               *  Returns:\n               *    True, if there are no Requests queued, False otherwise.\n               */\n\n\n              _emptyQueue() {\n                return this._requests.length === 0;\n              }\n              /** PrivateFunction: _callProtocolErrorHandlers\n               *  _Private_ function to call error handlers registered for HTTP errors.\n               *\n               *  Parameters:\n               *    (Strophe.Request) req - The request that is changing readyState.\n               */\n\n\n              _callProtocolErrorHandlers(req) {\n                const reqStatus = Bosh._getRequestStatus(req);\n\n                const err_callback = this._conn.protocolErrorHandlers.HTTP[reqStatus];\n\n                if (err_callback) {\n                  err_callback.call(this, reqStatus);\n                }\n              }\n              /** PrivateFunction: _hitError\n               *  _Private_ function to handle the error count.\n               *\n               *  Requests are resent automatically until their error count reaches\n               *  5.  Each time an error is encountered, this function is called to\n               *  increment the count and disconnect if the count is too high.\n               *\n               *  Parameters:\n               *    (Integer) reqStatus - The request status.\n               */\n\n\n              _hitError(reqStatus) {\n                this.errors++;\n                Strophe.warn(\"request errored, status: \" + reqStatus + \", number of errors: \" + this.errors);\n\n                if (this.errors > 4) {\n                  this._conn._onDisconnectTimeout();\n                }\n              }\n              /** PrivateFunction: _no_auth_received\n               *\n               * Called on stream start/restart when no stream:features\n               * has been received and sends a blank poll request.\n               */\n\n\n              _no_auth_received(callback) {\n                Strophe.warn(\"Server did not yet offer a supported authentication \" + \"mechanism. Sending a blank poll request.\");\n\n                if (callback) {\n                  callback = callback.bind(this._conn);\n                } else {\n                  callback = this._conn._connect_cb.bind(this._conn);\n                }\n\n                const body = this._buildBody();\n\n                this._requests.push(new Strophe.Request(body.tree(), this._onRequestStateChange.bind(this, callback), body.tree().getAttribute(\"rid\")));\n\n                this._throttledRequestHandler();\n              }\n              /** PrivateFunction: _onDisconnectTimeout\n               *  _Private_ timeout handler for handling non-graceful disconnection.\n               *\n               *  Cancels all remaining Requests and clears the queue.\n               */\n\n\n              _onDisconnectTimeout() {\n                this._abortAllRequests();\n              }\n              /** PrivateFunction: _abortAllRequests\n               *  _Private_ helper function that makes sure all pending requests are aborted.\n               */\n\n\n              _abortAllRequests() {\n                while (this._requests.length > 0) {\n                  const req = this._requests.pop();\n\n                  req.abort = true;\n                  req.xhr.abort();\n\n                  req.xhr.onreadystatechange = function () {};\n                }\n              }\n              /** PrivateFunction: _onIdle\n               *  _Private_ handler called by Strophe.Connection._onIdle\n               *\n               *  Sends all queued Requests or polls with empty Request if there are none.\n               */\n\n\n              _onIdle() {\n                const data = this._conn._data; // if no requests are in progress, poll\n\n                if (this._conn.authenticated && this._requests.length === 0 && data.length === 0 && !this._conn.disconnecting) {\n                  Strophe.debug(\"no requests during idle cycle, sending blank request\");\n                  data.push(null);\n                }\n\n                if (this._conn.paused) {\n                  return;\n                }\n\n                if (this._requests.length < 2 && data.length > 0) {\n                  const body = this._buildBody();\n\n                  for (let i = 0; i < data.length; i++) {\n                    if (data[i] !== null) {\n                      if (data[i] === \"restart\") {\n                        body.attrs({\n                          \"to\": this._conn.domain,\n                          \"xml:lang\": \"en\",\n                          \"xmpp:restart\": \"true\",\n                          \"xmlns:xmpp\": Strophe.NS.BOSH\n                        });\n                      } else {\n                        body.cnode(data[i]).up();\n                      }\n                    }\n                  }\n\n                  delete this._conn._data;\n                  this._conn._data = [];\n\n                  this._requests.push(new Strophe.Request(body.tree(), this._onRequestStateChange.bind(this, this._conn._dataRecv.bind(this._conn)), body.tree().getAttribute(\"rid\")));\n\n                  this._throttledRequestHandler();\n                }\n\n                if (this._requests.length > 0) {\n                  const time_elapsed = this._requests[0].age();\n\n                  if (this._requests[0].dead !== null) {\n                    if (this._requests[0].timeDead() > Math.floor(Strophe.SECONDARY_TIMEOUT * this.wait)) {\n                      this._throttledRequestHandler();\n                    }\n                  }\n\n                  if (time_elapsed > Math.floor(Strophe.TIMEOUT * this.wait)) {\n                    Strophe.warn(\"Request \" + this._requests[0].id + \" timed out, over \" + Math.floor(Strophe.TIMEOUT * this.wait) + \" seconds since last activity\");\n\n                    this._throttledRequestHandler();\n                  }\n                }\n              }\n              /** PrivateFunction: _getRequestStatus\n               *\n               *  Returns the HTTP status code from a Strophe.Request\n               *\n               *  Parameters:\n               *    (Strophe.Request) req - The Strophe.Request instance.\n               *    (Integer) def - The default value that should be returned if no\n               *          status value was found.\n               */\n\n\n              static _getRequestStatus(req, def) {\n                let reqStatus;\n\n                if (req.xhr.readyState === 4) {\n                  try {\n                    reqStatus = req.xhr.status;\n                  } catch (e) {\n                    // ignore errors from undefined status attribute. Works\n                    // around a browser bug\n                    Strophe.error(\"Caught an error while retrieving a request's status, \" + \"reqStatus: \" + reqStatus);\n                  }\n                }\n\n                if (typeof reqStatus === \"undefined\") {\n                  reqStatus = typeof def === 'number' ? def : 0;\n                }\n\n                return reqStatus;\n              }\n              /** PrivateFunction: _onRequestStateChange\n               *  _Private_ handler for Strophe.Request state changes.\n               *\n               *  This function is called when the XMLHttpRequest readyState changes.\n               *  It contains a lot of error handling logic for the many ways that\n               *  requests can fail, and calls the request callback when requests\n               *  succeed.\n               *\n               *  Parameters:\n               *    (Function) func - The handler for the request.\n               *    (Strophe.Request) req - The request that is changing readyState.\n               */\n\n\n              _onRequestStateChange(func, req) {\n                Strophe.debug(\"request id \" + req.id + \".\" + req.sends + \" state changed to \" + req.xhr.readyState);\n\n                if (req.abort) {\n                  req.abort = false;\n                  return;\n                }\n\n                if (req.xhr.readyState !== 4) {\n                  // The request is not yet complete\n                  return;\n                }\n\n                const reqStatus = Bosh._getRequestStatus(req);\n\n                this.lastResponseHeaders = req.xhr.getAllResponseHeaders();\n\n                if (this._conn.disconnecting && reqStatus >= 400) {\n                  this._hitError(reqStatus);\n\n                  this._callProtocolErrorHandlers(req);\n\n                  return;\n                }\n\n                const valid_request = reqStatus > 0 && reqStatus < 500;\n                const too_many_retries = req.sends > this._conn.maxRetries;\n\n                if (valid_request || too_many_retries) {\n                  // remove from internal queue\n                  this._removeRequest(req);\n\n                  Strophe.debug(\"request id \" + req.id + \" should now be removed\");\n                }\n\n                if (reqStatus === 200) {\n                  // request succeeded\n                  const reqIs0 = this._requests[0] === req;\n                  const reqIs1 = this._requests[1] === req; // if request 1 finished, or request 0 finished and request\n                  // 1 is over Strophe.SECONDARY_TIMEOUT seconds old, we need to\n                  // restart the other - both will be in the first spot, as the\n                  // completed request has been removed from the queue already\n\n                  if (reqIs1 || reqIs0 && this._requests.length > 0 && this._requests[0].age() > Math.floor(Strophe.SECONDARY_TIMEOUT * this.wait)) {\n                    this._restartRequest(0);\n                  }\n\n                  this._conn.nextValidRid(Number(req.rid) + 1);\n\n                  Strophe.debug(\"request id \" + req.id + \".\" + req.sends + \" got 200\");\n                  func(req); // call handler\n\n                  this.errors = 0;\n                } else if (reqStatus === 0 || reqStatus >= 400 && reqStatus < 600 || reqStatus >= 12000) {\n                  // request failed\n                  Strophe.error(\"request id \" + req.id + \".\" + req.sends + \" error \" + reqStatus + \" happened\");\n\n                  this._hitError(reqStatus);\n\n                  this._callProtocolErrorHandlers(req);\n\n                  if (reqStatus >= 400 && reqStatus < 500) {\n                    this._conn._changeConnectStatus(Strophe.Status.DISCONNECTING, null);\n\n                    this._conn._doDisconnect();\n                  }\n                } else {\n                  Strophe.error(\"request id \" + req.id + \".\" + req.sends + \" error \" + reqStatus + \" happened\");\n                }\n\n                if (!valid_request && !too_many_retries) {\n                  this._throttledRequestHandler();\n                } else if (too_many_retries && !this._conn.connected) {\n                  this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, \"giving-up\");\n                }\n              }\n              /** PrivateFunction: _processRequest\n               *  _Private_ function to process a request in the queue.\n               *\n               *  This function takes requests off the queue and sends them and\n               *  restarts dead requests.\n               *\n               *  Parameters:\n               *    (Integer) i - The index of the request in the queue.\n               */\n\n\n              _processRequest(i) {\n                let req = this._requests[i];\n\n                const reqStatus = Bosh._getRequestStatus(req, -1); // make sure we limit the number of retries\n\n\n                if (req.sends > this._conn.maxRetries) {\n                  this._conn._onDisconnectTimeout();\n\n                  return;\n                }\n\n                const time_elapsed = req.age();\n                const primary_timeout = !isNaN(time_elapsed) && time_elapsed > Math.floor(Strophe.TIMEOUT * this.wait);\n                const secondary_timeout = req.dead !== null && req.timeDead() > Math.floor(Strophe.SECONDARY_TIMEOUT * this.wait);\n                const server_error = req.xhr.readyState === 4 && (reqStatus < 1 || reqStatus >= 500);\n\n                if (primary_timeout || secondary_timeout || server_error) {\n                  if (secondary_timeout) {\n                    Strophe.error(`Request ${this._requests[i].id} timed out (secondary), restarting`);\n                  }\n\n                  req.abort = true;\n                  req.xhr.abort(); // setting to null fails on IE6, so set to empty function\n\n                  req.xhr.onreadystatechange = function () {};\n\n                  this._requests[i] = new Strophe.Request(req.xmlData, req.origFunc, req.rid, req.sends);\n                  req = this._requests[i];\n                }\n\n                if (req.xhr.readyState === 0) {\n                  Strophe.debug(\"request id \" + req.id + \".\" + req.sends + \" posting\");\n\n                  try {\n                    const content_type = this._conn.options.contentType || \"text/xml; charset=utf-8\";\n                    req.xhr.open(\"POST\", this._conn.service, this._conn.options.sync ? false : true);\n\n                    if (typeof req.xhr.setRequestHeader !== 'undefined') {\n                      // IE9 doesn't have setRequestHeader\n                      req.xhr.setRequestHeader(\"Content-Type\", content_type);\n                    }\n\n                    if (this._conn.options.withCredentials) {\n                      req.xhr.withCredentials = true;\n                    }\n                  } catch (e2) {\n                    Strophe.error(\"XHR open failed: \" + e2.toString());\n\n                    if (!this._conn.connected) {\n                      this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, \"bad-service\");\n                    }\n\n                    this._conn.disconnect();\n\n                    return;\n                  } // Fires the XHR request -- may be invoked immediately\n                  // or on a gradually expanding retry window for reconnects\n\n\n                  const sendFunc = () => {\n                    req.date = new Date();\n\n                    if (this._conn.options.customHeaders) {\n                      const headers = this._conn.options.customHeaders;\n\n                      for (const header in headers) {\n                        if (Object.prototype.hasOwnProperty.call(headers, header)) {\n                          req.xhr.setRequestHeader(header, headers[header]);\n                        }\n                      }\n                    }\n\n                    req.xhr.send(req.data);\n                  }; // Implement progressive backoff for reconnects --\n                  // First retry (send === 1) should also be instantaneous\n\n\n                  if (req.sends > 1) {\n                    // Using a cube of the retry number creates a nicely\n                    // expanding retry window\n                    const backoff = Math.min(Math.floor(Strophe.TIMEOUT * this.wait), Math.pow(req.sends, 3)) * 1000;\n                    setTimeout(function () {\n                      // XXX: setTimeout should be called only with function expressions (23974bc1)\n                      sendFunc();\n                    }, backoff);\n                  } else {\n                    sendFunc();\n                  }\n\n                  req.sends++;\n\n                  if (this._conn.xmlOutput !== Strophe.Connection.prototype.xmlOutput) {\n                    if (req.xmlData.nodeName === this.strip && req.xmlData.childNodes.length) {\n                      this._conn.xmlOutput(req.xmlData.childNodes[0]);\n                    } else {\n                      this._conn.xmlOutput(req.xmlData);\n                    }\n                  }\n\n                  if (this._conn.rawOutput !== Strophe.Connection.prototype.rawOutput) {\n                    this._conn.rawOutput(req.data);\n                  }\n                } else {\n                  Strophe.debug(\"_processRequest: \" + (i === 0 ? \"first\" : \"second\") + \" request has readyState of \" + req.xhr.readyState);\n                }\n              }\n              /** PrivateFunction: _removeRequest\n               *  _Private_ function to remove a request from the queue.\n               *\n               *  Parameters:\n               *    (Strophe.Request) req - The request to remove.\n               */\n\n\n              _removeRequest(req) {\n                Strophe.debug(\"removing request\");\n\n                for (let i = this._requests.length - 1; i >= 0; i--) {\n                  if (req === this._requests[i]) {\n                    this._requests.splice(i, 1);\n                  }\n                } // IE6 fails on setting to null, so set to empty function\n\n\n                req.xhr.onreadystatechange = function () {};\n\n                this._throttledRequestHandler();\n              }\n              /** PrivateFunction: _restartRequest\n               *  _Private_ function to restart a request that is presumed dead.\n               *\n               *  Parameters:\n               *    (Integer) i - The index of the request in the queue.\n               */\n\n\n              _restartRequest(i) {\n                const req = this._requests[i];\n\n                if (req.dead === null) {\n                  req.dead = new Date();\n                }\n\n                this._processRequest(i);\n              }\n              /** PrivateFunction: _reqToData\n               * _Private_ function to get a stanza out of a request.\n               *\n               * Tries to extract a stanza out of a Request Object.\n               * When this fails the current connection will be disconnected.\n               *\n               *  Parameters:\n               *    (Object) req - The Request.\n               *\n               *  Returns:\n               *    The stanza that was passed.\n               */\n\n\n              _reqToData(req) {\n                try {\n                  return req.getResponse();\n                } catch (e) {\n                  if (e.message !== \"parsererror\") {\n                    throw e;\n                  }\n\n                  this._conn.disconnect(\"strophe-parsererror\");\n                }\n              }\n              /** PrivateFunction: _sendTerminate\n               *  _Private_ function to send initial disconnect sequence.\n               *\n               *  This is the first step in a graceful disconnect.  It sends\n               *  the BOSH server a terminate body and includes an unavailable\n               *  presence if authentication has completed.\n               */\n\n\n              _sendTerminate(pres) {\n                Strophe.debug(\"_sendTerminate was called\");\n\n                const body = this._buildBody().attrs({\n                  type: \"terminate\"\n                });\n\n                if (pres) {\n                  body.cnode(pres.tree());\n                }\n\n                const req = new Strophe.Request(body.tree(), this._onRequestStateChange.bind(this, this._conn._dataRecv.bind(this._conn)), body.tree().getAttribute(\"rid\"));\n\n                this._requests.push(req);\n\n                this._throttledRequestHandler();\n              }\n              /** PrivateFunction: _send\n               *  _Private_ part of the Connection.send function for BOSH\n               *\n               * Just triggers the RequestHandler to send the messages that are in the queue\n               */\n\n\n              _send() {\n                clearTimeout(this._conn._idleTimeout);\n\n                this._throttledRequestHandler();\n\n                this._conn._idleTimeout = setTimeout(() => this._conn._onIdle(), 100);\n              }\n              /** PrivateFunction: _sendRestart\n               *\n               *  Send an xmpp:restart stanza.\n               */\n\n\n              _sendRestart() {\n                this._throttledRequestHandler();\n\n                clearTimeout(this._conn._idleTimeout);\n              }\n              /** PrivateFunction: _throttledRequestHandler\n               *  _Private_ function to throttle requests to the connection window.\n               *\n               *  This function makes sure we don't send requests so fast that the\n               *  request ids overflow the connection window in the case that one\n               *  request died.\n               */\n\n\n              _throttledRequestHandler() {\n                if (!this._requests) {\n                  Strophe.debug(\"_throttledRequestHandler called with \" + \"undefined requests\");\n                } else {\n                  Strophe.debug(\"_throttledRequestHandler called with \" + this._requests.length + \" requests\");\n                }\n\n                if (!this._requests || this._requests.length === 0) {\n                  return;\n                }\n\n                if (this._requests.length > 0) {\n                  this._processRequest(0);\n                }\n\n                if (this._requests.length > 1 && Math.abs(this._requests[0].rid - this._requests[1].rid) < this.window) {\n                  this._processRequest(1);\n                }\n              }\n\n            };\n            /** Variable: strip\n             *\n             *  BOSH-Connections will have all stanzas wrapped in a <body> tag when\n             *  passed to <Strophe.Connection.xmlInput> or <Strophe.Connection.xmlOutput>.\n             *  To strip this tag, User code can set <Strophe.Bosh.strip> to \"body\":\n             *\n             *  > Strophe.Bosh.prototype.strip = \"body\";\n             *\n             *  This will enable stripping of the body tag in both\n             *  <Strophe.Connection.xmlInput> and <Strophe.Connection.xmlOutput>.\n             */\n\n            Strophe.Bosh.prototype.strip = null;\n\n            /*\n                This program is distributed under the terms of the MIT license.\n                Please see the LICENSE file for details.\n\n                Copyright 2006-2008, OGG, LLC\n            */\n            /** Class: Strophe.WebSocket\n             *  _Private_ helper class that handles WebSocket Connections\n             *\n             *  The Strophe.WebSocket class is used internally by Strophe.Connection\n             *  to encapsulate WebSocket sessions. It is not meant to be used from user's code.\n             */\n\n            /** File: websocket.js\n             *  A JavaScript library to enable XMPP over Websocket in Strophejs.\n             *\n             *  This file implements XMPP over WebSockets for Strophejs.\n             *  If a Connection is established with a Websocket url (ws://...)\n             *  Strophe will use WebSockets.\n             *  For more information on XMPP-over-WebSocket see RFC 7395:\n             *  http://tools.ietf.org/html/rfc7395\n             *\n             *  WebSocket support implemented by Andreas Guth (andreas.guth@rwth-aachen.de)\n             */\n\n            Strophe.Websocket = class Websocket {\n              /** PrivateConstructor: Strophe.Websocket\n               *  Create and initialize a Strophe.WebSocket object.\n               *  Currently only sets the connection Object.\n               *\n               *  Parameters:\n               *    (Strophe.Connection) connection - The Strophe.Connection that will use WebSockets.\n               *\n               *  Returns:\n               *    A new Strophe.WebSocket object.\n               */\n              constructor(connection) {\n                this._conn = connection;\n                this.strip = \"wrapper\";\n                const service = connection.service;\n\n                if (service.indexOf(\"ws:\") !== 0 && service.indexOf(\"wss:\") !== 0) {\n                  // If the service is not an absolute URL, assume it is a path and put the absolute\n                  // URL together from options, current URL and the path.\n                  let new_service = \"\";\n\n                  if (connection.options.protocol === \"ws\" && window.location.protocol !== \"https:\") {\n                    new_service += \"ws\";\n                  } else {\n                    new_service += \"wss\";\n                  }\n\n                  new_service += \"://\" + window.location.host;\n\n                  if (service.indexOf(\"/\") !== 0) {\n                    new_service += window.location.pathname + service;\n                  } else {\n                    new_service += service;\n                  }\n\n                  connection.service = new_service;\n                }\n              }\n              /** PrivateFunction: _buildStream\n               *  _Private_ helper function to generate the <stream> start tag for WebSockets\n               *\n               *  Returns:\n               *    A Strophe.Builder with a <stream> element.\n               */\n\n\n              _buildStream() {\n                return $build(\"open\", {\n                  \"xmlns\": Strophe.NS.FRAMING,\n                  \"to\": this._conn.domain,\n                  \"version\": '1.0'\n                });\n              }\n              /** PrivateFunction: _checkStreamError\n               * _Private_ checks a message for stream:error\n               *\n               *  Parameters:\n               *    (Strophe.Request) bodyWrap - The received stanza.\n               *    connectstatus - The ConnectStatus that will be set on error.\n               *  Returns:\n               *     true if there was a streamerror, false otherwise.\n               */\n\n\n              _checkStreamError(bodyWrap, connectstatus) {\n                let errors;\n\n                if (bodyWrap.getElementsByTagNameNS) {\n                  errors = bodyWrap.getElementsByTagNameNS(Strophe.NS.STREAM, \"error\");\n                } else {\n                  errors = bodyWrap.getElementsByTagName(\"stream:error\");\n                }\n\n                if (errors.length === 0) {\n                  return false;\n                }\n\n                const error = errors[0];\n                let condition = \"\";\n                let text = \"\";\n                const ns = \"urn:ietf:params:xml:ns:xmpp-streams\";\n\n                for (let i = 0; i < error.childNodes.length; i++) {\n                  const e = error.childNodes[i];\n\n                  if (e.getAttribute(\"xmlns\") !== ns) {\n                    break;\n                  }\n\n                  if (e.nodeName === \"text\") {\n                    text = e.textContent;\n                  } else {\n                    condition = e.nodeName;\n                  }\n                }\n\n                let errorString = \"WebSocket stream error: \";\n\n                if (condition) {\n                  errorString += condition;\n                } else {\n                  errorString += \"unknown\";\n                }\n\n                if (text) {\n                  errorString += \" - \" + text;\n                }\n\n                Strophe.error(errorString); // close the connection on stream_error\n\n                this._conn._changeConnectStatus(connectstatus, condition);\n\n                this._conn._doDisconnect();\n\n                return true;\n              }\n              /** PrivateFunction: _reset\n               *  Reset the connection.\n               *\n               *  This function is called by the reset function of the Strophe Connection.\n               *  Is not needed by WebSockets.\n               */\n\n\n              _reset() {\n                // eslint-disable-line class-methods-use-this\n                return;\n              }\n              /** PrivateFunction: _connect\n               *  _Private_ function called by Strophe.Connection.connect\n               *\n               *  Creates a WebSocket for a connection and assigns Callbacks to it.\n               *  Does nothing if there already is a WebSocket.\n               */\n\n\n              _connect() {\n                // Ensure that there is no open WebSocket from a previous Connection.\n                this._closeSocket();\n\n                this.socket = new WebSocket(this._conn.service, \"xmpp\");\n\n                this.socket.onopen = () => this._onOpen();\n\n                this.socket.onerror = e => this._onError(e);\n\n                this.socket.onclose = e => this._onClose(e); // Gets replaced with this._onMessage once _onInitialMessage is called\n\n\n                this.socket.onmessage = message => this._onInitialMessage(message);\n              }\n              /** PrivateFunction: _connect_cb\n               *  _Private_ function called by Strophe.Connection._connect_cb\n               *\n               * checks for stream:error\n               *\n               *  Parameters:\n               *    (Strophe.Request) bodyWrap - The received stanza.\n               */\n\n\n              _connect_cb(bodyWrap) {\n                const error = this._checkStreamError(bodyWrap, Strophe.Status.CONNFAIL);\n\n                if (error) {\n                  return Strophe.Status.CONNFAIL;\n                }\n              }\n              /** PrivateFunction: _handleStreamStart\n               * _Private_ function that checks the opening <open /> tag for errors.\n               *\n               * Disconnects if there is an error and returns false, true otherwise.\n               *\n               *  Parameters:\n               *    (Node) message - Stanza containing the <open /> tag.\n               */\n\n\n              _handleStreamStart(message) {\n                let error = false; // Check for errors in the <open /> tag\n\n                const ns = message.getAttribute(\"xmlns\");\n\n                if (typeof ns !== \"string\") {\n                  error = \"Missing xmlns in <open />\";\n                } else if (ns !== Strophe.NS.FRAMING) {\n                  error = \"Wrong xmlns in <open />: \" + ns;\n                }\n\n                const ver = message.getAttribute(\"version\");\n\n                if (typeof ver !== \"string\") {\n                  error = \"Missing version in <open />\";\n                } else if (ver !== \"1.0\") {\n                  error = \"Wrong version in <open />: \" + ver;\n                }\n\n                if (error) {\n                  this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, error);\n\n                  this._conn._doDisconnect();\n\n                  return false;\n                }\n\n                return true;\n              }\n              /** PrivateFunction: _onInitialMessage\n               * _Private_ function that handles the first connection messages.\n               *\n               * On receiving an opening stream tag this callback replaces itself with the real\n               * message handler. On receiving a stream error the connection is terminated.\n               */\n\n\n              _onInitialMessage(message) {\n                if (message.data.indexOf(\"<open \") === 0 || message.data.indexOf(\"<?xml\") === 0) {\n                  // Strip the XML Declaration, if there is one\n                  const data = message.data.replace(/^(<\\?.*?\\?>\\s*)*/, \"\");\n                  if (data === '') return;\n                  const streamStart = new DOMParser().parseFromString(data, \"text/xml\").documentElement;\n\n                  this._conn.xmlInput(streamStart);\n\n                  this._conn.rawInput(message.data); //_handleStreamSteart will check for XML errors and disconnect on error\n\n\n                  if (this._handleStreamStart(streamStart)) {\n                    //_connect_cb will check for stream:error and disconnect on error\n                    this._connect_cb(streamStart);\n                  }\n                } else if (message.data.indexOf(\"<close \") === 0) {\n                  // <close xmlns=\"urn:ietf:params:xml:ns:xmpp-framing />\n                  // Parse the raw string to an XML element\n                  const parsedMessage = new DOMParser().parseFromString(message.data, \"text/xml\").documentElement; // Report this input to the raw and xml handlers\n\n                  this._conn.xmlInput(parsedMessage);\n\n                  this._conn.rawInput(message.data);\n\n                  const see_uri = parsedMessage.getAttribute(\"see-other-uri\");\n\n                  if (see_uri) {\n                    const service = this._conn.service; // Valid scenarios: WSS->WSS, WS->ANY\n\n                    const isSecureRedirect = service.indexOf(\"wss:\") >= 0 && see_uri.indexOf(\"wss:\") >= 0 || service.indexOf(\"ws:\") >= 0;\n\n                    if (isSecureRedirect) {\n                      this._conn._changeConnectStatus(Strophe.Status.REDIRECT, \"Received see-other-uri, resetting connection\");\n\n                      this._conn.reset();\n\n                      this._conn.service = see_uri;\n\n                      this._connect();\n                    }\n                  } else {\n                    this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, \"Received closing stream\");\n\n                    this._conn._doDisconnect();\n                  }\n                } else {\n                  this._replaceMessageHandler();\n\n                  const string = this._streamWrap(message.data);\n\n                  const elem = new DOMParser().parseFromString(string, \"text/xml\").documentElement;\n\n                  this._conn._connect_cb(elem, null, message.data);\n                }\n              }\n              /** PrivateFunction: _replaceMessageHandler\n               *\n               * Called by _onInitialMessage in order to replace itself with the general message handler.\n               * This method is overridden by Strophe.WorkerWebsocket, which manages a\n               * websocket connection via a service worker and doesn't have direct access\n               * to the socket.\n               */\n\n\n              _replaceMessageHandler() {\n                this.socket.onmessage = m => this._onMessage(m);\n              }\n              /** PrivateFunction: _disconnect\n               *  _Private_ function called by Strophe.Connection.disconnect\n               *\n               *  Disconnects and sends a last stanza if one is given\n               *\n               *  Parameters:\n               *    (Request) pres - This stanza will be sent before disconnecting.\n               */\n\n\n              _disconnect(pres) {\n                if (this.socket && this.socket.readyState !== WebSocket.CLOSED) {\n                  if (pres) {\n                    this._conn.send(pres);\n                  }\n\n                  const close = $build(\"close\", {\n                    \"xmlns\": Strophe.NS.FRAMING\n                  });\n\n                  this._conn.xmlOutput(close.tree());\n\n                  const closeString = Strophe.serialize(close);\n\n                  this._conn.rawOutput(closeString);\n\n                  try {\n                    this.socket.send(closeString);\n                  } catch (e) {\n                    Strophe.warn(\"Couldn't send <close /> tag.\");\n                  }\n                }\n\n                setTimeout(() => this._conn._doDisconnect, 0);\n              }\n              /** PrivateFunction: _doDisconnect\n               *  _Private_ function to disconnect.\n               *\n               *  Just closes the Socket for WebSockets\n               */\n\n\n              _doDisconnect() {\n                Strophe.debug(\"WebSockets _doDisconnect was called\");\n\n                this._closeSocket();\n              }\n              /** PrivateFunction _streamWrap\n               *  _Private_ helper function to wrap a stanza in a <stream> tag.\n               *  This is used so Strophe can process stanzas from WebSockets like BOSH\n               */\n\n\n              _streamWrap(stanza) {\n                // eslint-disable-line class-methods-use-this\n                return \"<wrapper>\" + stanza + '</wrapper>';\n              }\n              /** PrivateFunction: _closeSocket\n               *  _Private_ function to close the WebSocket.\n               *\n               *  Closes the socket if it is still open and deletes it\n               */\n\n\n              _closeSocket() {\n                if (this.socket) {\n                  try {\n                    this.socket.onclose = null;\n                    this.socket.onerror = null;\n                    this.socket.onmessage = null;\n                    this.socket.close();\n                  } catch (e) {\n                    Strophe.debug(e.message);\n                  }\n                }\n\n                this.socket = null;\n              }\n              /** PrivateFunction: _emptyQueue\n               * _Private_ function to check if the message queue is empty.\n               *\n               *  Returns:\n               *    True, because WebSocket messages are send immediately after queueing.\n               */\n\n\n              _emptyQueue() {\n                // eslint-disable-line class-methods-use-this\n                return true;\n              }\n              /** PrivateFunction: _onClose\n               * _Private_ function to handle websockets closing.\n               */\n\n\n              _onClose(e) {\n                if (this._conn.connected && !this._conn.disconnecting) {\n                  Strophe.error(\"Websocket closed unexpectedly\");\n\n                  this._conn._doDisconnect();\n                } else if (e && e.code === 1006 && !this._conn.connected && this.socket) {\n                  // in case the onError callback was not called (Safari 10 does not\n                  // call onerror when the initial connection fails) we need to\n                  // dispatch a CONNFAIL status update to be consistent with the\n                  // behavior on other browsers.\n                  Strophe.error(\"Websocket closed unexcectedly\");\n\n                  this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, \"The WebSocket connection could not be established or was disconnected.\");\n\n                  this._conn._doDisconnect();\n                } else {\n                  Strophe.debug(\"Websocket closed\");\n                }\n              }\n              /** PrivateFunction: _no_auth_received\n               *\n               * Called on stream start/restart when no stream:features\n               * has been received.\n               */\n\n\n              _no_auth_received(callback) {\n                Strophe.error(\"Server did not offer a supported authentication mechanism\");\n\n                this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, Strophe.ErrorCondition.NO_AUTH_MECH);\n\n                if (callback) {\n                  callback.call(this._conn);\n                }\n\n                this._conn._doDisconnect();\n              }\n              /** PrivateFunction: _onDisconnectTimeout\n               *  _Private_ timeout handler for handling non-graceful disconnection.\n               *\n               *  This does nothing for WebSockets\n               */\n\n\n              _onDisconnectTimeout() {} // eslint-disable-line class-methods-use-this\n\n              /** PrivateFunction: _abortAllRequests\n               *  _Private_ helper function that makes sure all pending requests are aborted.\n               */\n\n\n              _abortAllRequests() {} // eslint-disable-line class-methods-use-this\n\n              /** PrivateFunction: _onError\n               * _Private_ function to handle websockets errors.\n               *\n               * Parameters:\n               * (Object) error - The websocket error.\n               */\n\n\n              _onError(error) {\n                Strophe.error(\"Websocket error \" + JSON.stringify(error));\n\n                this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, \"The WebSocket connection could not be established or was disconnected.\");\n\n                this._disconnect();\n              }\n              /** PrivateFunction: _onIdle\n               *  _Private_ function called by Strophe.Connection._onIdle\n               *\n               *  sends all queued stanzas\n               */\n\n\n              _onIdle() {\n                const data = this._conn._data;\n\n                if (data.length > 0 && !this._conn.paused) {\n                  for (let i = 0; i < data.length; i++) {\n                    if (data[i] !== null) {\n                      let stanza;\n\n                      if (data[i] === \"restart\") {\n                        stanza = this._buildStream().tree();\n                      } else {\n                        stanza = data[i];\n                      }\n\n                      const rawStanza = Strophe.serialize(stanza);\n\n                      this._conn.xmlOutput(stanza);\n\n                      this._conn.rawOutput(rawStanza);\n\n                      this.socket.send(rawStanza);\n                    }\n                  }\n\n                  this._conn._data = [];\n                }\n              }\n              /** PrivateFunction: _onMessage\n               * _Private_ function to handle websockets messages.\n               *\n               * This function parses each of the messages as if they are full documents.\n               * [TODO : We may actually want to use a SAX Push parser].\n               *\n               * Since all XMPP traffic starts with\n               *  <stream:stream version='1.0'\n               *                 xml:lang='en'\n               *                 xmlns='jabber:client'\n               *                 xmlns:stream='http://etherx.jabber.org/streams'\n               *                 id='3697395463'\n               *                 from='SERVER'>\n               *\n               * The first stanza will always fail to be parsed.\n               *\n               * Additionally, the seconds stanza will always be <stream:features> with\n               * the stream NS defined in the previous stanza, so we need to 'force'\n               * the inclusion of the NS in this stanza.\n               *\n               * Parameters:\n               * (string) message - The websocket message.\n               */\n\n\n              _onMessage(message) {\n                let elem; // check for closing stream\n\n                const close = '<close xmlns=\"urn:ietf:params:xml:ns:xmpp-framing\" />';\n\n                if (message.data === close) {\n                  this._conn.rawInput(close);\n\n                  this._conn.xmlInput(message);\n\n                  if (!this._conn.disconnecting) {\n                    this._conn._doDisconnect();\n                  }\n\n                  return;\n                } else if (message.data.search(\"<open \") === 0) {\n                  // This handles stream restarts\n                  elem = new DOMParser().parseFromString(message.data, \"text/xml\").documentElement;\n\n                  if (!this._handleStreamStart(elem)) {\n                    return;\n                  }\n                } else {\n                  const data = this._streamWrap(message.data);\n\n                  elem = new DOMParser().parseFromString(data, \"text/xml\").documentElement;\n                }\n\n                if (this._checkStreamError(elem, Strophe.Status.ERROR)) {\n                  return;\n                } //handle unavailable presence stanza before disconnecting\n\n\n                if (this._conn.disconnecting && elem.firstChild.nodeName === \"presence\" && elem.firstChild.getAttribute(\"type\") === \"unavailable\") {\n                  this._conn.xmlInput(elem);\n\n                  this._conn.rawInput(Strophe.serialize(elem)); // if we are already disconnecting we will ignore the unavailable stanza and\n                  // wait for the </stream:stream> tag before we close the connection\n\n\n                  return;\n                }\n\n                this._conn._dataRecv(elem, message.data);\n              }\n              /** PrivateFunction: _onOpen\n               * _Private_ function to handle websockets connection setup.\n               *\n               * The opening stream tag is sent here.\n               */\n\n\n              _onOpen() {\n                Strophe.debug(\"Websocket open\");\n\n                const start = this._buildStream();\n\n                this._conn.xmlOutput(start.tree());\n\n                const startString = Strophe.serialize(start);\n\n                this._conn.rawOutput(startString);\n\n                this.socket.send(startString);\n              }\n              /** PrivateFunction: _reqToData\n               * _Private_ function to get a stanza out of a request.\n               *\n               * WebSockets don't use requests, so the passed argument is just returned.\n               *\n               *  Parameters:\n               *    (Object) stanza - The stanza.\n               *\n               *  Returns:\n               *    The stanza that was passed.\n               */\n\n\n              _reqToData(stanza) {\n                // eslint-disable-line class-methods-use-this\n                return stanza;\n              }\n              /** PrivateFunction: _send\n               *  _Private_ part of the Connection.send function for WebSocket\n               *\n               * Just flushes the messages that are in the queue\n               */\n\n\n              _send() {\n                this._conn.flush();\n              }\n              /** PrivateFunction: _sendRestart\n               *\n               *  Send an xmpp:restart stanza.\n               */\n\n\n              _sendRestart() {\n                clearTimeout(this._conn._idleTimeout);\n\n                this._conn._onIdle.bind(this._conn)();\n              }\n\n            };\n\n            /*\n                This program is distributed under the terms of the MIT license.\n                Please see the LICENSE file for details.\n\n                Copyright 2020, JC Brand\n            */\n            const lmap = {};\n            lmap['debug'] = Strophe.LogLevel.DEBUG;\n            lmap['info'] = Strophe.LogLevel.INFO;\n            lmap['warn'] = Strophe.LogLevel.WARN;\n            lmap['error'] = Strophe.LogLevel.ERROR;\n            lmap['fatal'] = Strophe.LogLevel.FATAL;\n            /** Class: Strophe.WorkerWebsocket\n             *  _Private_ helper class that handles a websocket connection inside a shared worker.\n             */\n\n            Strophe.WorkerWebsocket = class WorkerWebsocket extends Strophe.Websocket {\n              /** PrivateConstructor: Strophe.WorkerWebsocket\n               *  Create and initialize a Strophe.WorkerWebsocket object.\n               *\n               *  Parameters:\n               *    (Strophe.Connection) connection - The Strophe.Connection\n               *\n               *  Returns:\n               *    A new Strophe.WorkerWebsocket object.\n               */\n              constructor(connection) {\n                super(connection);\n                this._conn = connection;\n                this.worker = new SharedWorker(this._conn.options.worker, 'Strophe XMPP Connection');\n\n                this.worker.onerror = e => {\n                  var _console;\n\n                  (_console = console) === null || _console === void 0 ? void 0 : _console.error(e);\n                  Strophe.log(Strophe.LogLevel.ERROR, `Shared Worker Error: ${e}`);\n                };\n              }\n\n              get socket() {\n                return {\n                  'send': str => this.worker.port.postMessage(['send', str])\n                };\n              }\n\n              _connect() {\n                this._messageHandler = m => this._onInitialMessage(m);\n\n                this.worker.port.start();\n\n                this.worker.port.onmessage = ev => this._onWorkerMessage(ev);\n\n                this.worker.port.postMessage(['_connect', this._conn.service, this._conn.jid]);\n              }\n\n              _attach(callback) {\n                this._messageHandler = m => this._onMessage(m);\n\n                this._conn.connect_callback = callback;\n                this.worker.port.start();\n\n                this.worker.port.onmessage = ev => this._onWorkerMessage(ev);\n\n                this.worker.port.postMessage(['_attach', this._conn.service]);\n              }\n\n              _attachCallback(status, jid) {\n                if (status === Strophe.Status.ATTACHED) {\n                  this._conn.jid = jid;\n                  this._conn.authenticated = true;\n                  this._conn.connected = true;\n                  this._conn.restored = true;\n\n                  this._conn._changeConnectStatus(Strophe.Status.ATTACHED);\n                } else if (status === Strophe.Status.ATTACHFAIL) {\n                  this._conn.authenticated = false;\n                  this._conn.connected = false;\n                  this._conn.restored = false;\n\n                  this._conn._changeConnectStatus(Strophe.Status.ATTACHFAIL);\n                }\n              }\n\n              _disconnect(readyState, pres) {\n                pres && this._conn.send(pres);\n                const close = $build(\"close\", {\n                  \"xmlns\": Strophe.NS.FRAMING\n                });\n\n                this._conn.xmlOutput(close.tree());\n\n                const closeString = Strophe.serialize(close);\n\n                this._conn.rawOutput(closeString);\n\n                this.worker.port.postMessage(['send', closeString]);\n\n                this._conn._doDisconnect();\n              }\n\n              _onClose(e) {\n                if (this._conn.connected && !this._conn.disconnecting) {\n                  Strophe.error(\"Websocket closed unexpectedly\");\n\n                  this._conn._doDisconnect();\n                } else if (e && e.code === 1006 && !this._conn.connected) {\n                  // in case the onError callback was not called (Safari 10 does not\n                  // call onerror when the initial connection fails) we need to\n                  // dispatch a CONNFAIL status update to be consistent with the\n                  // behavior on other browsers.\n                  Strophe.error(\"Websocket closed unexcectedly\");\n\n                  this._conn._changeConnectStatus(Strophe.Status.CONNFAIL, \"The WebSocket connection could not be established or was disconnected.\");\n\n                  this._conn._doDisconnect();\n                } else {\n                  Strophe.debug(\"Websocket closed\");\n                }\n              }\n\n              _closeSocket() {\n                this.worker.port.postMessage(['_closeSocket']);\n              }\n              /** PrivateFunction: _replaceMessageHandler\n               *\n               * Called by _onInitialMessage in order to replace itself with the general message handler.\n               * This method is overridden by Strophe.WorkerWebsocket, which manages a\n               * websocket connection via a service worker and doesn't have direct access\n               * to the socket.\n               */\n\n\n              _replaceMessageHandler() {\n                this._messageHandler = m => this._onMessage(m);\n              }\n              /** PrivateFunction: _onWorkerMessage\n               * _Private_ function that handles messages received from the service worker\n               */\n\n\n              _onWorkerMessage(ev) {\n                const {\n                  data\n                } = ev;\n                const method_name = data[0];\n\n                if (method_name === '_onMessage') {\n                  this._messageHandler(data[1]);\n                } else if (method_name in this) {\n                  try {\n                    this[method_name].apply(this, ev.data.slice(1));\n                  } catch (e) {\n                    Strophe.log(Strophe.LogLevel.ERROR, e);\n                  }\n                } else if (method_name === 'log') {\n                  const level = data[1];\n                  const msg = data[2];\n                  Strophe.log(lmap[level], msg);\n                } else {\n                  Strophe.log(Strophe.LogLevel.ERROR, `Found unhandled service worker message: ${data}`);\n                }\n              }\n\n            };\n\n            global$1.$build = core.$build;\n            global$1.$iq = core.$iq;\n            global$1.$msg = core.$msg;\n            global$1.$pres = core.$pres;\n            global$1.Strophe = core.Strophe;\n            const {\n              b64_sha1\n            } = SHA1;\n\n            exports.$build = $build;\n            exports.$iq = $iq;\n            exports.$msg = $msg;\n            exports.$pres = $pres;\n            exports.Strophe = Strophe;\n            exports.b64_sha1 = b64_sha1;\n\n            Object.defineProperty(exports, '__esModule', { value: true });\n\n}));\n","(function (global, factory) {\n\ttypeof exports === 'object' && typeof module !== 'undefined' ? factory(require('strophe.js')) :\n\ttypeof define === 'function' && define.amd ? define(['strophe.js'], factory) :\n\t(factory(global.window));\n}(this, (function (strophe_js) { 'use strict';\n\nstrophe_js.Strophe.addConnectionPlugin('disco',\n{\n    _connection: null,\n    _identities : [],\n    _features : [],\n    _items : [],\n    /** Function: init\n     * Plugin init\n     *\n     * Parameters:\n     *   (Strophe.Connection) conn - Strophe connection\n     */\n    init: function(conn)\n    {\n    this._connection = conn;\n        this._identities = [];\n        this._features   = [];\n        this._items      = [];\n        // disco info\n        conn.addHandler(this._onDiscoInfo.bind(this), strophe_js.Strophe.NS.DISCO_INFO, 'iq', 'get', null, null);\n        // disco items\n        conn.addHandler(this._onDiscoItems.bind(this), strophe_js.Strophe.NS.DISCO_ITEMS, 'iq', 'get', null, null);\n    },\n    /** Function: addIdentity\n     * See http://xmpp.org/registrar/disco-categories.html\n     * Parameters:\n     *   (String) category - category of identity (like client, automation, etc ...)\n     *   (String) type - type of identity (like pc, web, bot , etc ...)\n     *   (String) name - name of identity in natural language\n     *   (String) lang - lang of name parameter\n     *\n     * Returns:\n     *   Boolean\n     */\n    addIdentity: function(category, type, name, lang)\n    {\n        for (var i=0; i<this._identities.length; i++)\n        {\n            if (this._identities[i].category == category &&\n                this._identities[i].type == type &&\n                this._identities[i].name == name &&\n                this._identities[i].lang == lang)\n            {\n                return false;\n            }\n        }\n        this._identities.push({category: category, type: type, name: name, lang: lang});\n        return true;\n    },\n    /** Function: addFeature\n     *\n     * Parameters:\n     *   (String) var_name - feature name (like jabber:iq:version)\n     *\n     * Returns:\n     *   boolean\n     */\n    addFeature: function(var_name)\n    {\n        for (var i=0; i<this._features.length; i++)\n        {\n             if (this._features[i] == var_name)\n                 return false;\n        }\n        this._features.push(var_name);\n        return true;\n    },\n    /** Function: removeFeature\n     *\n     * Parameters:\n     *   (String) var_name - feature name (like jabber:iq:version)\n     *\n     * Returns:\n     *   boolean\n     */\n    removeFeature: function(var_name)\n    {\n        for (var i=0; i<this._features.length; i++)\n        {\n             if (this._features[i] === var_name){\n                 this._features.splice(i,1);\n                 return true;\n             }\n        }\n        return false;\n    },\n    /** Function: addItem\n     *\n     * Parameters:\n     *   (String) jid\n     *   (String) name\n     *   (String) node\n     *   (Function) call_back\n     *\n     * Returns:\n     *   boolean\n     */\n    addItem: function(jid, name, node, call_back)\n    {\n        if (node && !call_back)\n            return false;\n        this._items.push({jid: jid, name: name, node: node, call_back: call_back});\n        return true;\n    },\n    /** Function: info\n     * Info query\n     *\n     * Parameters:\n     *   (Function) call_back\n     *   (String) jid\n     *   (String) node\n     */\n    info: function(jid, node, success, error, timeout)\n    {\n        var attrs = {xmlns: strophe_js.Strophe.NS.DISCO_INFO};\n        if (node)\n            attrs.node = node;\n\n        var info = strophe_js.$iq({from:this._connection.jid,\n                         to:jid, type:'get'}).c('query', attrs);\n        this._connection.sendIQ(info, success, error, timeout);\n    },\n    /** Function: items\n     * Items query\n     *\n     * Parameters:\n     *   (Function) call_back\n     *   (String) jid\n     *   (String) node\n     */\n    items: function(jid, node, success, error, timeout)\n    {\n        var attrs = {xmlns: strophe_js.Strophe.NS.DISCO_ITEMS};\n        if (node)\n            attrs.node = node;\n\n        var items = strophe_js.$iq({from:this._connection.jid,\n                         to:jid, type:'get'}).c('query', attrs);\n        this._connection.sendIQ(items, success, error, timeout);\n    },\n\n    /** PrivateFunction: _buildIQResult\n     */\n    _buildIQResult: function(stanza, query_attrs)\n    {\n        var id   =  stanza.getAttribute('id');\n        var from = stanza.getAttribute('from');\n        var iqresult = strophe_js.$iq({type: 'result', id: id});\n\n        if (from !== null) {\n            iqresult.attrs({to: from});\n        }\n\n        return iqresult.c('query', query_attrs);\n    },\n\n    /** PrivateFunction: _onDiscoInfo\n     * Called when receive info request\n     */\n    _onDiscoInfo: function(stanza)\n    {\n        var node = stanza.getElementsByTagName('query')[0].getAttribute('node');\n        var attrs = {xmlns: strophe_js.Strophe.NS.DISCO_INFO};\n        var i;\n        if (node)\n        {\n            attrs.node = node;\n        }\n        var iqresult = this._buildIQResult(stanza, attrs);\n        for (i=0; i<this._identities.length; i++)\n        {\n            attrs = {category: this._identities[i].category,\n                         type    : this._identities[i].type};\n            if (this._identities[i].name)\n                attrs.name = this._identities[i].name;\n            if (this._identities[i].lang)\n                attrs['xml:lang'] = this._identities[i].lang;\n            iqresult.c('identity', attrs).up();\n        }\n        for (i=0; i<this._features.length; i++)\n        {\n            iqresult.c('feature', {'var':this._features[i]}).up();\n        }\n        this._connection.send(iqresult.tree());\n        return true;\n    },\n    /** PrivateFunction: _onDiscoItems\n     * Called when receive items request\n     */\n    _onDiscoItems: function(stanza)\n    {\n        var query_attrs = {xmlns: strophe_js.Strophe.NS.DISCO_ITEMS};\n        var node = stanza.getElementsByTagName('query')[0].getAttribute('node');\n        var items, i;\n        if (node)\n        {\n            query_attrs.node = node;\n            items = [];\n            for (i = 0; i < this._items.length; i++)\n            {\n                if (this._items[i].node == node)\n                {\n                    items = this._items[i].call_back(stanza);\n                    break;\n                }\n            }\n        }\n        else\n        {\n            items = this._items;\n        }\n        var iqresult = this._buildIQResult(stanza, query_attrs);\n        for (i = 0; i < items.length; i++)\n        {\n            var attrs = {jid:  items[i].jid};\n            if (items[i].name)\n                attrs.name = items[i].name;\n            if (items[i].node)\n                attrs.node = items[i].node;\n            iqresult.c('item', attrs).up();\n        }\n        this._connection.send(iqresult.tree());\n        return true;\n    }\n});\n\n})));\n//# sourceMappingURL=strophe.disco.js.map\n","(function (global, factory) {\n\ttypeof exports === 'object' && typeof module !== 'undefined' ? factory(require('strophe.js')) :\n\ttypeof define === 'function' && define.amd ? define(['strophe.js'], factory) :\n\t(global = global || self, factory(global.window));\n}(this, (function (strophe_js) { 'use strict';\n\n\t/**\n\t* StropheJS - Stream Management XEP-0198\n\t*\n\t* This plugin implements stream management ACK capabilities of the specs XEP-0198.\n\t* Note: Resumption is not supported in this current implementation.\n\t*\n\t* Reference: http://xmpp.org/extensions/xep-0198.html\n\t*\n\t* @class streamManagement\n\t*/\n\tstrophe_js.Strophe.addConnectionPlugin('streamManagement', {\n\n\t\t/**\n\t\t* @property {Boolean} logging: Set to true to enable logging regarding out of sync stanzas.\n\t\t*/\n\t\tlogging: false,\n\n\t\t/**\n\t\t* @property {Boolean} autoSendCountOnEveryIncomingStanza: Set to true to send an 'a' response after every stanza.\n\t\t* @default false\n\t\t* @public\n\t\t*/\n\t\tautoSendCountOnEveryIncomingStanza: false,\n\n\t\t/**\n\t\t* @property {Integer} requestResponseInterval: Set this value to send a request for counter on very interval\n\t\t* number of stanzas sent. Set to 0 to disable.\n\t\t* @default 5\n\t\t* @public\n\t\t*/\n\t\trequestResponseInterval: 5,\n\n\t\t/**\n\t\t* @property {Pointer} _c: Strophe connection instance.\n\t\t* @private\n\t\t*/\n\t\t_c: null,\n\n\t\t/**\n\t\t* @property {String} _NS XMPP Namespace.\n\t\t* @private\n\t\t*/\n\t\t_NS: 'urn:xmpp:sm:3',\n\n\t\t/**\n\t\t* @property {Boolean} _isStreamManagementEnabled\n\t\t* @private\n\t\t*/\n\t\t_isStreamManagementEnabled: false,\n\n\t\t/**\n\t\t* @property {Integer} _serverProcesssedStanzasCounter: Keeps count of stanzas confirmed processed by the server.\n\t\t* The server is the source of truth of this value. It is the 'h' attribute on the latest 'a' element received\n\t\t* from the server.\n\t\t* @private\n\t\t*/\n\t\t_serverProcesssedStanzasCounter: null,\n\n\t\t/**\n\t\t* @property {Integer} _clientProcessedStanzasCounter: Counter of stanzas received by the client from the server.\n\t\t* Client is the source of truth of this value. It is the 'h' attribute in the 'a' sent from the client to\n\t\t* the server.\n\t\t* @private\n\t\t*/\n\t\t_clientProcessedStanzasCounter: null,\n\n\t\t/**\n\t\t* @property {Integer} _clientSentStanzasCounter\n\t\t* @private\n\t\t*/\n\t\t_clientSentStanzasCounter: null,\n\n\t\t/**\n\t\t* Stores a reference to Strophe connection xmlOutput function to wrap counting functionality.\n\t\t* @method _originalXMLOutput\n\t\t* @type {Handler}\n\t\t* @private\n\t\t*/\n\t\t_originalXMLOutput: null,\n\n\t\t/**\n\t\t* @property {Handler} _requestHandler: Stores reference to handler that process count request from server.\n\t\t* @private\n\t\t*/\n\t\t_requestHandler: null,\n\n\t\t/**\n\t\t* @property {Handler} _incomingHandler: Stores reference to handler that processes incoming stanzas count.\n\t\t* @private\n\t\t*/\n\t\t_incomingHandler: null,\n\n\t\t/**\n\t\t* @property {Integer} _requestResponseIntervalCount: Counts sent stanzas since last response request.\n\t\t*/\n\t\t_requestResponseIntervalCount: 0,\n\n\t\t/**\n\t\t * @property {boolean} _isSupported: indicates whether or not the server has advertised support for the stream\n\t\t * management namespace.\n\t\t */\n\t\t_isSupported: false,\n\n\t\t/**\n\t\t* @property {Queue} _unacknowledgedStanzas: Maintains a list of packet ids for stanzas which have yet to be acknowledged.\n\t\t*/\n\t\t_unacknowledgedStanzas: [],\n\n\t\t/**\n\t\t* @property {Array} _acknowledgedStanzaListeners: Stores callbacks for each stanza acknowledged by the server.\n\t\t* Provides the packet id of the stanza as a parameter.\n\t\t* @private\n\t\t*/\n\t\t_acknowledgedStanzaListeners: [],\n\n\t\taddAcknowledgedStanzaListener: function(listener) {\n\t\t\tthis._acknowledgedStanzaListeners.push(listener);\n\t\t},\n\n\t\tenable: function(resume) {\n\t\t\tif (!this._isSupported) {\n\t\t\t\tthrow new Error('The server doesn\\'t support urn:xmpp:sm:3 namespace');\n\t\t\t} else if (this._connectionStatus !== strophe_js.Strophe.Status.CONNECTED) {\n\t\t\t\tthrow new Error('enable() can only be called in the CONNECTED state');\n\t\t\t}\n\t\t\tthis._c.send(strophe_js.$build('enable', { xmlns: this._NS, resume }));\n\t\t\tthis._c.flush();\n\t\t\tthis._c.pause();\n\t\t},\n\n\t\tgetResumeToken: function() {\n\t\t\treturn this._resumeToken;\n\t\t},\n\n\t\tisSupported() {\n\t\t\treturn this._isSupported;\n\t\t},\n\n\t\tresume: function() {\n\t\t\tif (!this.getResumeToken()) {\n\t\t\t\tthrow new Error('No resume token');\n\t\t\t}\n\t\t\tif (this._connectionStatus !== strophe_js.Strophe.Status.DISCONNECTED) {\n\t\t\t\tthrow new Error('resume() can only be called in the DISCONNECTED state');\n\t\t\t}\n\n\t\t\tthis._c.options.explicitResourceBinding = true;\n\t\t\tthis._resuming = true;\n\n\t\t\tthis._originalConnect.apply(this._c, this._connectArgs);\n\t\t},\n\n\t\trequestAcknowledgement: function() {\n\t\t\tif (this._connectionStatus !== strophe_js.Strophe.Status.CONNECTED) {\n\t\t\t\tthrow new Error('requestAcknowledgement() can only be called in the CONNECTED state');\n\t\t\t}\n\t\t\tthis._requestResponseIntervalCount = 0;\n\t\t\tthis._c.send(strophe_js.$build('r', { xmlns: this._NS }));\n\t\t},\n\n\t\tgetOutgoingCounter: function() {\n\t\t\treturn this._clientSentStanzasCounter;\n\t\t},\n\n\t\tgetIncomingCounter: function() {\n\t\t\treturn this._clientProcessedStanzasCounter;\n\t\t},\n\n\t\tinit: function(conn) {\n\t\t\tthis._c = conn;\n\t\t\tstrophe_js.Strophe.addNamespace('SM', this._NS);\n\n\t\t\t// Storing original xmlOutput function to use additional logic\n\t\t\tthis._originalXMLOutput = this._c.xmlOutput;\n\t\t\tthis._c.xmlOutput = this.xmlOutput.bind(this);\n\n\t\t\tthis._originalConnect = this._c.connect;\n\t\t\tthis._c.connect = this._interceptConnectArgs.bind(this);\n\n\t\t\tthis._originalOnStreamFeaturesAfterSASL = this._c._onStreamFeaturesAfterSASL;\n\t\t\tthis._c._onStreamFeaturesAfterSASL = this._onStreamFeaturesAfterSASL.bind(this);\n\n\t\t\tthis._originalDoDisconnect = this._c._doDisconnect;\n\t\t\tthis._c._doDisconnect = this._interceptDoDisconnect.bind(this);\n\n\t\t\tthis._originalDisconnect = this._c.disconnect;\n\t\t\tthis._c.disconnect = this._interceptDisconnect.bind(this);\n\t\t},\n\n\t\t_interceptDisconnect: function() {\n\t\t\tthis._resumeToken = undefined;\n\t\t\tthis._originalDisconnect.apply(this._c, arguments);\n\t\t},\n\n\t\t_interceptDoDisconnect: function() {\n\t\t\tif (this.getResumeToken()\n\t\t\t\t\t&& !this._resuming\n\t\t\t\t\t&& this._c.connected && !this._c.disconnecting) {\n\t\t\t\tthis._resumeState = {\n\t\t\t\t\thandlers: this._c.handlers,\n\t\t\t\t\ttimedHandlers: this._c.timedHandlers,\n\t\t\t\t\tremoveTimeds: this._c.removeTimeds,\n\t\t\t\t\tremoveHandlers: this._c.removeHandlers,\n\t\t\t\t\taddTimeds: this._c.addTimeds,\n\t\t\t\t\taddHandlers: this._c.addHandlers\n\t\t\t\t};\n\t\t\t\tthis._storedJid = this._c.jid;\n\n\t\t\t\tthis.logging && strophe_js.Strophe.debug('SM stored resume state, handler count: ' + this._resumeState.handlers.length);\n\t\t\t}\n\n\t\t\t// Remove any queued stanzas from the buffer that have failed to send while the socket was closed,\n\t\t\t// as they would interfere with the resume flow. They will be resent anyway.\n\t\t\tthis._c._data = [];\n\n\t\t\tthis._originalDoDisconnect.apply(this._c, arguments);\n\t\t},\n\n\t\t_interceptConnectArgs: function() {\n\t\t\tthis._connectArgs = arguments;\n\n\t\t\tthis._originalConnect.apply(this._c, arguments);\n\t\t},\n\n\t\t_onStreamFeaturesAfterSASL: function(elem) {\n\t\t\tthis._isSupported = elem.getElementsByTagNameNS(this._NS, \"sm\").length > 0;\n\n\t\t\treturn this._originalOnStreamFeaturesAfterSASL.apply(this._c, arguments);\n\t\t},\n\n\t\tstatusChanged: function (status) {\n\t\t\tthis._connectionStatus = status;\n\t\t\tif (!this.getResumeToken()\n\t\t\t\t&& (status === strophe_js.Strophe.Status.CONNECTED || status === strophe_js.Strophe.Status.DISCONNECTED)) {\n\t\t\t\tthis.logging && strophe_js.Strophe.debug('SM reset state');\n\n\t\t\t\tthis._serverProcesssedStanzasCounter = 0;\n\t\t\t\tthis._clientProcessedStanzasCounter = 0;\n\n\t\t\t\tthis._clientSentStanzasCounter = 0;\n\n\t\t\t\tthis._isStreamManagementEnabled = false;\n\t\t\t\tthis._requestResponseIntervalCount = 0;\n\n\t\t\t\t// FIXME not described in JSDocs\n\t\t\t\tthis._resuming = false;\n\n\t\t\t\tif (status === strophe_js.Strophe.Status.DISCONNECTED) {\n\t\t\t\t\tthis._isSupported = false;\n\t\t\t\t}\n\n\t\t\t\tthis._unacknowledgedStanzas = [];\n\n\t\t\t\tif (this._requestHandler) {\n\t\t\t\t\tthis._c.deleteHandler(this._requestHandler);\n\t\t\t\t}\n\n\t\t\t\tif (this._incomingHandler) {\n\t\t\t\t\tthis._c.deleteHandler(this._incomingHandler);\n\t\t\t\t}\n\n\t\t\t\tthis._requestHandler = this._c.addHandler(this._handleServerRequestHandler.bind(this), this._NS, 'r');\n\t\t\t\tthis._ackHandler = this._c.addHandler(this._handleServerAck.bind(this), this._NS, 'a');\n\t\t\t\tthis._incomingHandler = this._c.addHandler(this._incomingStanzaHandler.bind(this));\n\n\t\t\t\t// FIXME handler instances stored, but never used\n\t\t\t\tthis._enabledHandler = this._c._addSysHandler(this._handleEnabled.bind(this), this._NS, 'enabled');\n\t\t\t\tthis._resumeFailedHandler = this._c._addSysHandler(this._handleResumeFailed.bind(this), this._NS, 'failed');\n\t\t\t\tthis._resumedHandler =  this._c._addSysHandler(this._handleResumed.bind(this), this._NS,'resumed');\n\n\t\t\t} else if (status === strophe_js.Strophe.Status.BINDREQUIRED)  {\n\t\t\t\tthis._c.jid = this._storedJid;\n\n\t\t\t\t// Restore Strophe handlers\n\t\t\t\tfor (const property in this._resumeState) {\n\t\t\t\t\tthis._c[property] = this._resumeState[property];\n\t\t\t\t}\n\n\t\t\t\t// FIXME check conditions if there's session ID and if enabled\n\t\t\t\tthis._c.send(strophe_js.$build('resume', {\n\t\t\t\t\txmlns: this._NS,\n\t\t\t\t\th: this._clientProcessedStanzasCounter,\n\t\t\t\t\tprevid: this._resumeToken\n\t\t\t\t}));\n\t\t\t\tthis._c.flush();\n\t\t\t} else if (status === strophe_js.Strophe.Status.ERROR) {\n\t\t\t\tthis.logging && strophe_js.Strophe.debug('SM cleared resume token on error');\n\t\t\t\tthis._resumeToken = undefined;\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t* This method overrides the send method implemented by Strophe.Connection\n\t\t* to count outgoing stanzas\n\t\t*\n\t\t* @method Send\n\t\t* @public\n\t\t*/\n\t\txmlOutput: function(elem) {\n\t\t\tif (strophe_js.Strophe.isTagEqual(elem, 'iq') ||\n\t\t\t\tstrophe_js.Strophe.isTagEqual(elem, 'presence') ||\n\t\t\t\tstrophe_js.Strophe.isTagEqual(elem, 'message')) {\n\t\t\t\tthis._increaseSentStanzasCounter(elem);\n\t\t\t}\n\n\t\t\treturn this._originalXMLOutput.call(this._c, elem);\n\t\t},\n\n\t\t_handleEnabled: function(elem) {\n\t\t\tthis._isStreamManagementEnabled = true;\n\t\t\t// FIXME fail if requested, but not enabled\n\t\t\tthis._resumeToken = elem.getAttribute('resume') === 'true' && elem.getAttribute('id');\n\n\t\t\tthis._c.resume();\n\n\t\t\treturn true;\n\t\t},\n\n\t\t_handleResumeFailed: function(elem) {\n\t\t\tconst error = elem && elem.firstElementChild && elem.firstElementChild.tagName;\n\n\t\t\tthis._c._changeConnectStatus(strophe_js.Strophe.Status.ERROR, error, elem);\n\t\t\tthis._c._doDisconnect();\n\n\t\t\treturn true;\n\t\t},\n\n\t\t_handleResumed: function(elem) {\n\t\t\t// FIXME check if in the correct state\n\t\t\tvar handledCount = parseInt(elem.getAttribute('h'));\n\t\t\tthis._handleAcknowledgedStanzas(handledCount, this._serverProcesssedStanzasCounter);\n\n\t\t\tthis._resuming = false;\n\t\t\tthis._c.do_bind = false; // No need to bind our resource anymore\n\t\t\tthis._c.authenticated = true;\n\t\t\tthis._c.restored = true;\n\n\t\t\tif (this._unacknowledgedStanzas.length > 0) {\n\t\t\t\tthis.logging && strophe_js.Strophe.debug('SM Sending unacknowledged stanzas', this._unacknowledgedStanzas);\n\t\t\t\tfor(const stanza of this._unacknowledgedStanzas) {\n\t\t\t\t\tthis._c.send(stanza);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.logging && strophe_js.Strophe.debug('SM No unacknowledged stanzas', this._unacknowledgedStanzas);\n\t\t\t}\n\n\t\t\tthis._c._changeConnectStatus(strophe_js.Strophe.Status.CONNECTED, null);\n\n\t\t\treturn true;\n\t\t},\n\n\t\t_incomingStanzaHandler: function(elem) {\n\t\t\tif (strophe_js.Strophe.isTagEqual(elem, 'iq') || strophe_js.Strophe.isTagEqual(elem, 'presence') || strophe_js.Strophe.isTagEqual(elem, 'message'))  {\n\t\t\t\tthis._increaseReceivedStanzasCounter();\n\n\t\t\t\tif (this.autoSendCountOnEveryIncomingStanza) {\n\t\t\t\t\tthis._answerProcessedStanzas();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn true;\n\t\t},\n\n\t\t_handleAcknowledgedStanzas: function(reportedHandledCount, lastKnownHandledCount) {\n\t\t\tvar delta = reportedHandledCount - lastKnownHandledCount;\n\n\t\t\tif (delta < 0) {\n\t\t\t\tthis._throwError('New reported stanza count lower than previous. New: ' + reportedHandledCount + ' - Previous: ' + lastKnownHandledCount);\n\t\t\t}\n\n\t\t\tif (delta > this._unacknowledgedStanzas.length) {\n\t\t\t\tthis._throwError('Higher reported acknowledge count than unacknowledged stanzas. Reported Acknowledge Count: ' + delta + ' - Unacknowledge Stanza Count: ' + this._unacknowledgedStanzas.length + ' - New: ' + reportedHandledCount + ' - Previous: ' + lastKnownHandledCount);\n\t\t\t}\n\n\t\t\tfor(var i = 0; i < delta; i++) {\n\t\t\t\tvar stanza = this._unacknowledgedStanzas.shift();\n\t\t\t\tfor (var j = 0; j < this._acknowledgedStanzaListeners.length; j++) {\n\t\t\t\t\tthis._acknowledgedStanzaListeners[j](stanza);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (this.logging && this._unacknowledgedStanzas.length > 0) {\n\t\t\t\tstrophe_js.Strophe.warn('SM Unacknowledged stanzas', this._unacknowledgedStanzas);\n\t\t\t}\n\n\t\t\tthis._serverProcesssedStanzasCounter = reportedHandledCount;\n\n\t\t\tif (this.requestResponseInterval > 0) {\n\t\t\t\tthis._requestResponseIntervalCount = 0;\n\t\t\t}\n\t\t},\n\n\t\t_handleServerRequestHandler: function() {\n\t\t\tthis._answerProcessedStanzas();\n\n\t\t\treturn true;\n\t\t},\n\n\t\t_handleServerAck: function(elem){\n\t\t\tvar handledCount = parseInt(elem.getAttribute('h'));\n\t\t\tthis._handleAcknowledgedStanzas(handledCount, this._serverProcesssedStanzasCounter);\n\n\t\t\treturn true;\n\t\t},\n\n\t\t_answerProcessedStanzas: function() {\n\t\t\tif (this._isStreamManagementEnabled) {\n\t\t\t\tthis._c.send(strophe_js.$build('a', { xmlns: this._NS, h: this._clientProcessedStanzasCounter }));\n\t\t\t}\n\t\t},\n\n\t\t_increaseSentStanzasCounter: function(elem) {\n\t\t\tif (this._isStreamManagementEnabled) {\n\t\t\t\tif (this._unacknowledgedStanzas.indexOf(elem) !== -1) {\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis._unacknowledgedStanzas.push(elem);\n\t\t\t\tthis._clientSentStanzasCounter++;\n\n\t\t\t\tif (this.requestResponseInterval > 0) {\n\t\t\t\t\tthis._requestResponseIntervalCount++;\n\n\t\t\t\t\tif (this._requestResponseIntervalCount === this.requestResponseInterval) {\n\t\t\t\t\t\t// FIXME Can not call send from onIdle.\n\t\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\t\tif (this._connectionStatus === strophe_js.Strophe.Status.CONNECTED) {\n\t\t\t\t\t\t\t\tthis.requestAcknowledgement();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}, 1);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t_increaseReceivedStanzasCounter: function() {\n\t\t\tif (this._isStreamManagementEnabled) {\n\t\t\t\tthis._clientProcessedStanzasCounter++;\n\t\t\t}\n\t\t},\n\n\t\t_throwError: function(msg) {\n\t\t\tstrophe_js.Strophe.error(msg);\n\t\t\tthrow new Error(msg);\n\t\t}\n\n\t});\n\n})));\n//# sourceMappingURL=strophe.stream-management.js.map\n","/*\n *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.\n *\n *  Use of this source code is governed by a BSD-style license\n *  that can be found in the LICENSE file in the root of the source\n *  tree.\n */\n /* eslint-env node */\n'use strict';\n\nlet logDisabled_ = true;\nlet deprecationWarnings_ = true;\n\n/**\n * Extract browser version out of the provided user agent string.\n *\n * @param {!string} uastring userAgent string.\n * @param {!string} expr Regular expression used as match criteria.\n * @param {!number} pos position in the version string to be returned.\n * @return {!number} browser version.\n */\nexport function extractVersion(uastring, expr, pos) {\n  const match = uastring.match(expr);\n  return match && match.length >= pos && parseInt(match[pos], 10);\n}\n\n// Wraps the peerconnection event eventNameToWrap in a function\n// which returns the modified event object (or false to prevent\n// the event).\nexport function wrapPeerConnectionEvent(window, eventNameToWrap, wrapper) {\n  if (!window.RTCPeerConnection) {\n    return;\n  }\n  const proto = window.RTCPeerConnection.prototype;\n  const nativeAddEventListener = proto.addEventListener;\n  proto.addEventListener = function(nativeEventName, cb) {\n    if (nativeEventName !== eventNameToWrap) {\n      return nativeAddEventListener.apply(this, arguments);\n    }\n    const wrappedCallback = (e) => {\n      const modifiedEvent = wrapper(e);\n      if (modifiedEvent) {\n        if (cb.handleEvent) {\n          cb.handleEvent(modifiedEvent);\n        } else {\n          cb(modifiedEvent);\n        }\n      }\n    };\n    this._eventMap = this._eventMap || {};\n    if (!this._eventMap[eventNameToWrap]) {\n      this._eventMap[eventNameToWrap] = new Map();\n    }\n    this._eventMap[eventNameToWrap].set(cb, wrappedCallback);\n    return nativeAddEventListener.apply(this, [nativeEventName,\n      wrappedCallback]);\n  };\n\n  const nativeRemoveEventListener = proto.removeEventListener;\n  proto.removeEventListener = function(nativeEventName, cb) {\n    if (nativeEventName !== eventNameToWrap || !this._eventMap\n        || !this._eventMap[eventNameToWrap]) {\n      return nativeRemoveEventListener.apply(this, arguments);\n    }\n    if (!this._eventMap[eventNameToWrap].has(cb)) {\n      return nativeRemoveEventListener.apply(this, arguments);\n    }\n    const unwrappedCb = this._eventMap[eventNameToWrap].get(cb);\n    this._eventMap[eventNameToWrap].delete(cb);\n    if (this._eventMap[eventNameToWrap].size === 0) {\n      delete this._eventMap[eventNameToWrap];\n    }\n    if (Object.keys(this._eventMap).length === 0) {\n      delete this._eventMap;\n    }\n    return nativeRemoveEventListener.apply(this, [nativeEventName,\n      unwrappedCb]);\n  };\n\n  Object.defineProperty(proto, 'on' + eventNameToWrap, {\n    get() {\n      return this['_on' + eventNameToWrap];\n    },\n    set(cb) {\n      if (this['_on' + eventNameToWrap]) {\n        this.removeEventListener(eventNameToWrap,\n            this['_on' + eventNameToWrap]);\n        delete this['_on' + eventNameToWrap];\n      }\n      if (cb) {\n        this.addEventListener(eventNameToWrap,\n            this['_on' + eventNameToWrap] = cb);\n      }\n    },\n    enumerable: true,\n    configurable: true\n  });\n}\n\nexport function disableLog(bool) {\n  if (typeof bool !== 'boolean') {\n    return new Error('Argument type: ' + typeof bool +\n        '. Please use a boolean.');\n  }\n  logDisabled_ = bool;\n  return (bool) ? 'adapter.js logging disabled' :\n      'adapter.js logging enabled';\n}\n\n/**\n * Disable or enable deprecation warnings\n * @param {!boolean} bool set to true to disable warnings.\n */\nexport function disableWarnings(bool) {\n  if (typeof bool !== 'boolean') {\n    return new Error('Argument type: ' + typeof bool +\n        '. Please use a boolean.');\n  }\n  deprecationWarnings_ = !bool;\n  return 'adapter.js deprecation warnings ' + (bool ? 'disabled' : 'enabled');\n}\n\nexport function log() {\n  if (typeof window === 'object') {\n    if (logDisabled_) {\n      return;\n    }\n    if (typeof console !== 'undefined' && typeof console.log === 'function') {\n      console.log.apply(console, arguments);\n    }\n  }\n}\n\n/**\n * Shows a deprecation warning suggesting the modern and spec-compatible API.\n */\nexport function deprecated(oldMethod, newMethod) {\n  if (!deprecationWarnings_) {\n    return;\n  }\n  console.warn(oldMethod + ' is deprecated, please use ' + newMethod +\n      ' instead.');\n}\n\n/**\n * Browser detector.\n *\n * @return {object} result containing browser and version\n *     properties.\n */\nexport function detectBrowser(window) {\n  // Returned result object.\n  const result = {browser: null, version: null};\n\n  // Fail early if it's not a browser\n  if (typeof window === 'undefined' || !window.navigator) {\n    result.browser = 'Not a browser.';\n    return result;\n  }\n\n  const {navigator} = window;\n\n  if (navigator.mozGetUserMedia) { // Firefox.\n    result.browser = 'firefox';\n    result.version = extractVersion(navigator.userAgent,\n        /Firefox\\/(\\d+)\\./, 1);\n  } else if (navigator.webkitGetUserMedia ||\n      (window.isSecureContext === false && window.webkitRTCPeerConnection &&\n       !window.RTCIceGatherer)) {\n    // Chrome, Chromium, Webview, Opera.\n    // Version matches Chrome/WebRTC version.\n    // Chrome 74 removed webkitGetUserMedia on http as well so we need the\n    // more complicated fallback to webkitRTCPeerConnection.\n    result.browser = 'chrome';\n    result.version = extractVersion(navigator.userAgent,\n        /Chrom(e|ium)\\/(\\d+)\\./, 2);\n  } else if (window.RTCPeerConnection &&\n      navigator.userAgent.match(/AppleWebKit\\/(\\d+)\\./)) { // Safari.\n    result.browser = 'safari';\n    result.version = extractVersion(navigator.userAgent,\n        /AppleWebKit\\/(\\d+)\\./, 1);\n    result.supportsUnifiedPlan = window.RTCRtpTransceiver &&\n        'currentDirection' in window.RTCRtpTransceiver.prototype;\n  } else { // Default fallthrough: not supported.\n    result.browser = 'Not a supported browser.';\n    return result;\n  }\n\n  return result;\n}\n\n/**\n * Checks if something is an object.\n *\n * @param {*} val The something you want to check.\n * @return true if val is an object, false otherwise.\n */\nfunction isObject(val) {\n  return Object.prototype.toString.call(val) === '[object Object]';\n}\n\n/**\n * Remove all empty objects and undefined values\n * from a nested object -- an enhanced and vanilla version\n * of Lodash's `compact`.\n */\nexport function compactObject(data) {\n  if (!isObject(data)) {\n    return data;\n  }\n\n  return Object.keys(data).reduce(function(accumulator, key) {\n    const isObj = isObject(data[key]);\n    const value = isObj ? compactObject(data[key]) : data[key];\n    const isEmptyObject = isObj && !Object.keys(value).length;\n    if (value === undefined || isEmptyObject) {\n      return accumulator;\n    }\n    return Object.assign(accumulator, {[key]: value});\n  }, {});\n}\n\n/* iterates the stats graph recursively. */\nexport function walkStats(stats, base, resultSet) {\n  if (!base || resultSet.has(base.id)) {\n    return;\n  }\n  resultSet.set(base.id, base);\n  Object.keys(base).forEach(name => {\n    if (name.endsWith('Id')) {\n      walkStats(stats, stats.get(base[name]), resultSet);\n    } else if (name.endsWith('Ids')) {\n      base[name].forEach(id => {\n        walkStats(stats, stats.get(id), resultSet);\n      });\n    }\n  });\n}\n\n/* filter getStats for a sender/receiver track. */\nexport function filterStats(result, track, outbound) {\n  const streamStatsType = outbound ? 'outbound-rtp' : 'inbound-rtp';\n  const filteredResult = new Map();\n  if (track === null) {\n    return filteredResult;\n  }\n  const trackStats = [];\n  result.forEach(value => {\n    if (value.type === 'track' &&\n        value.trackIdentifier === track.id) {\n      trackStats.push(value);\n    }\n  });\n  trackStats.forEach(trackStat => {\n    result.forEach(stats => {\n      if (stats.type === streamStatsType && stats.trackId === trackStat.id) {\n        walkStats(result, stats, filteredResult);\n      }\n    });\n  });\n  return filteredResult;\n}\n\n","/*\n *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.\n *\n *  Use of this source code is governed by a BSD-style license\n *  that can be found in the LICENSE file in the root of the source\n *  tree.\n */\n/* eslint-env node */\n'use strict';\nimport * as utils from '../utils.js';\nconst logging = utils.log;\n\nexport function shimGetUserMedia(window, browserDetails) {\n  const navigator = window && window.navigator;\n\n  if (!navigator.mediaDevices) {\n    return;\n  }\n\n  const constraintsToChrome_ = function(c) {\n    if (typeof c !== 'object' || c.mandatory || c.optional) {\n      return c;\n    }\n    const cc = {};\n    Object.keys(c).forEach(key => {\n      if (key === 'require' || key === 'advanced' || key === 'mediaSource') {\n        return;\n      }\n      const r = (typeof c[key] === 'object') ? c[key] : {ideal: c[key]};\n      if (r.exact !== undefined && typeof r.exact === 'number') {\n        r.min = r.max = r.exact;\n      }\n      const oldname_ = function(prefix, name) {\n        if (prefix) {\n          return prefix + name.charAt(0).toUpperCase() + name.slice(1);\n        }\n        return (name === 'deviceId') ? 'sourceId' : name;\n      };\n      if (r.ideal !== undefined) {\n        cc.optional = cc.optional || [];\n        let oc = {};\n        if (typeof r.ideal === 'number') {\n          oc[oldname_('min', key)] = r.ideal;\n          cc.optional.push(oc);\n          oc = {};\n          oc[oldname_('max', key)] = r.ideal;\n          cc.optional.push(oc);\n        } else {\n          oc[oldname_('', key)] = r.ideal;\n          cc.optional.push(oc);\n        }\n      }\n      if (r.exact !== undefined && typeof r.exact !== 'number') {\n        cc.mandatory = cc.mandatory || {};\n        cc.mandatory[oldname_('', key)] = r.exact;\n      } else {\n        ['min', 'max'].forEach(mix => {\n          if (r[mix] !== undefined) {\n            cc.mandatory = cc.mandatory || {};\n            cc.mandatory[oldname_(mix, key)] = r[mix];\n          }\n        });\n      }\n    });\n    if (c.advanced) {\n      cc.optional = (cc.optional || []).concat(c.advanced);\n    }\n    return cc;\n  };\n\n  const shimConstraints_ = function(constraints, func) {\n    if (browserDetails.version >= 61) {\n      return func(constraints);\n    }\n    constraints = JSON.parse(JSON.stringify(constraints));\n    if (constraints && typeof constraints.audio === 'object') {\n      const remap = function(obj, a, b) {\n        if (a in obj && !(b in obj)) {\n          obj[b] = obj[a];\n          delete obj[a];\n        }\n      };\n      constraints = JSON.parse(JSON.stringify(constraints));\n      remap(constraints.audio, 'autoGainControl', 'googAutoGainControl');\n      remap(constraints.audio, 'noiseSuppression', 'googNoiseSuppression');\n      constraints.audio = constraintsToChrome_(constraints.audio);\n    }\n    if (constraints && typeof constraints.video === 'object') {\n      // Shim facingMode for mobile & surface pro.\n      let face = constraints.video.facingMode;\n      face = face && ((typeof face === 'object') ? face : {ideal: face});\n      const getSupportedFacingModeLies = browserDetails.version < 66;\n\n      if ((face && (face.exact === 'user' || face.exact === 'environment' ||\n                    face.ideal === 'user' || face.ideal === 'environment')) &&\n          !(navigator.mediaDevices.getSupportedConstraints &&\n            navigator.mediaDevices.getSupportedConstraints().facingMode &&\n            !getSupportedFacingModeLies)) {\n        delete constraints.video.facingMode;\n        let matches;\n        if (face.exact === 'environment' || face.ideal === 'environment') {\n          matches = ['back', 'rear'];\n        } else if (face.exact === 'user' || face.ideal === 'user') {\n          matches = ['front'];\n        }\n        if (matches) {\n          // Look for matches in label, or use last cam for back (typical).\n          return navigator.mediaDevices.enumerateDevices()\n          .then(devices => {\n            devices = devices.filter(d => d.kind === 'videoinput');\n            let dev = devices.find(d => matches.some(match =>\n              d.label.toLowerCase().includes(match)));\n            if (!dev && devices.length && matches.includes('back')) {\n              dev = devices[devices.length - 1]; // more likely the back cam\n            }\n            if (dev) {\n              constraints.video.deviceId = face.exact ? {exact: dev.deviceId} :\n                                                        {ideal: dev.deviceId};\n            }\n            constraints.video = constraintsToChrome_(constraints.video);\n            logging('chrome: ' + JSON.stringify(constraints));\n            return func(constraints);\n          });\n        }\n      }\n      constraints.video = constraintsToChrome_(constraints.video);\n    }\n    logging('chrome: ' + JSON.stringify(constraints));\n    return func(constraints);\n  };\n\n  const shimError_ = function(e) {\n    if (browserDetails.version >= 64) {\n      return e;\n    }\n    return {\n      name: {\n        PermissionDeniedError: 'NotAllowedError',\n        PermissionDismissedError: 'NotAllowedError',\n        InvalidStateError: 'NotAllowedError',\n        DevicesNotFoundError: 'NotFoundError',\n        ConstraintNotSatisfiedError: 'OverconstrainedError',\n        TrackStartError: 'NotReadableError',\n        MediaDeviceFailedDueToShutdown: 'NotAllowedError',\n        MediaDeviceKillSwitchOn: 'NotAllowedError',\n        TabCaptureError: 'AbortError',\n        ScreenCaptureError: 'AbortError',\n        DeviceCaptureError: 'AbortError'\n      }[e.name] || e.name,\n      message: e.message,\n      constraint: e.constraint || e.constraintName,\n      toString() {\n        return this.name + (this.message && ': ') + this.message;\n      }\n    };\n  };\n\n  const getUserMedia_ = function(constraints, onSuccess, onError) {\n    shimConstraints_(constraints, c => {\n      navigator.webkitGetUserMedia(c, onSuccess, e => {\n        if (onError) {\n          onError(shimError_(e));\n        }\n      });\n    });\n  };\n  navigator.getUserMedia = getUserMedia_.bind(navigator);\n\n  // Even though Chrome 45 has navigator.mediaDevices and a getUserMedia\n  // function which returns a Promise, it does not accept spec-style\n  // constraints.\n  if (navigator.mediaDevices.getUserMedia) {\n    const origGetUserMedia = navigator.mediaDevices.getUserMedia.\n        bind(navigator.mediaDevices);\n    navigator.mediaDevices.getUserMedia = function(cs) {\n      return shimConstraints_(cs, c => origGetUserMedia(c).then(stream => {\n        if (c.audio && !stream.getAudioTracks().length ||\n            c.video && !stream.getVideoTracks().length) {\n          stream.getTracks().forEach(track => {\n            track.stop();\n          });\n          throw new DOMException('', 'NotFoundError');\n        }\n        return stream;\n      }, e => Promise.reject(shimError_(e))));\n    };\n  }\n}\n","/*\n *  Copyright (c) 2018 The adapter.js project authors. All Rights Reserved.\n *\n *  Use of this source code is governed by a BSD-style license\n *  that can be found in the LICENSE file in the root of the source\n *  tree.\n */\n/* eslint-env node */\n'use strict';\nexport function shimGetDisplayMedia(window, getSourceId) {\n  if (window.navigator.mediaDevices &&\n    'getDisplayMedia' in window.navigator.mediaDevices) {\n    return;\n  }\n  if (!(window.navigator.mediaDevices)) {\n    return;\n  }\n  // getSourceId is a function that returns a promise resolving with\n  // the sourceId of the screen/window/tab to be shared.\n  if (typeof getSourceId !== 'function') {\n    console.error('shimGetDisplayMedia: getSourceId argument is not ' +\n        'a function');\n    return;\n  }\n  window.navigator.mediaDevices.getDisplayMedia =\n    function getDisplayMedia(constraints) {\n      return getSourceId(constraints)\n        .then(sourceId => {\n          const widthSpecified = constraints.video && constraints.video.width;\n          const heightSpecified = constraints.video &&\n            constraints.video.height;\n          const frameRateSpecified = constraints.video &&\n            constraints.video.frameRate;\n          constraints.video = {\n            mandatory: {\n              chromeMediaSource: 'desktop',\n              chromeMediaSourceId: sourceId,\n              maxFrameRate: frameRateSpecified || 3\n            }\n          };\n          if (widthSpecified) {\n            constraints.video.mandatory.maxWidth = widthSpecified;\n          }\n          if (heightSpecified) {\n            constraints.video.mandatory.maxHeight = heightSpecified;\n          }\n          return window.navigator.mediaDevices.getUserMedia(constraints);\n        });\n    };\n}\n","/*\n *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.\n *\n *  Use of this source code is governed by a BSD-style license\n *  that can be found in the LICENSE file in the root of the source\n *  tree.\n */\n /* eslint-env node */\n'use strict';\nimport * as utils from '../utils.js';\n\nexport {shimGetUserMedia} from './getusermedia';\nexport {shimGetDisplayMedia} from './getdisplaymedia';\n\nexport function shimMediaStream(window) {\n  window.MediaStream = window.MediaStream || window.webkitMediaStream;\n}\n\nexport function shimOnTrack(window) {\n  if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in\n      window.RTCPeerConnection.prototype)) {\n    Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', {\n      get() {\n        return this._ontrack;\n      },\n      set(f) {\n        if (this._ontrack) {\n          this.removeEventListener('track', this._ontrack);\n        }\n        this.addEventListener('track', this._ontrack = f);\n      },\n      enumerable: true,\n      configurable: true\n    });\n    const origSetRemoteDescription =\n        window.RTCPeerConnection.prototype.setRemoteDescription;\n    window.RTCPeerConnection.prototype.setRemoteDescription =\n      function setRemoteDescription() {\n        if (!this._ontrackpoly) {\n          this._ontrackpoly = (e) => {\n            // onaddstream does not fire when a track is added to an existing\n            // stream. But stream.onaddtrack is implemented so we use that.\n            e.stream.addEventListener('addtrack', te => {\n              let receiver;\n              if (window.RTCPeerConnection.prototype.getReceivers) {\n                receiver = this.getReceivers()\n                  .find(r => r.track && r.track.id === te.track.id);\n              } else {\n                receiver = {track: te.track};\n              }\n\n              const event = new Event('track');\n              event.track = te.track;\n              event.receiver = receiver;\n              event.transceiver = {receiver};\n              event.streams = [e.stream];\n              this.dispatchEvent(event);\n            });\n            e.stream.getTracks().forEach(track => {\n              let receiver;\n              if (window.RTCPeerConnection.prototype.getReceivers) {\n                receiver = this.getReceivers()\n                  .find(r => r.track && r.track.id === track.id);\n              } else {\n                receiver = {track};\n              }\n              const event = new Event('track');\n              event.track = track;\n              event.receiver = receiver;\n              event.transceiver = {receiver};\n              event.streams = [e.stream];\n              this.dispatchEvent(event);\n            });\n          };\n          this.addEventListener('addstream', this._ontrackpoly);\n        }\n        return origSetRemoteDescription.apply(this, arguments);\n      };\n  } else {\n    // even if RTCRtpTransceiver is in window, it is only used and\n    // emitted in unified-plan. Unfortunately this means we need\n    // to unconditionally wrap the event.\n    utils.wrapPeerConnectionEvent(window, 'track', e => {\n      if (!e.transceiver) {\n        Object.defineProperty(e, 'transceiver',\n          {value: {receiver: e.receiver}});\n      }\n      return e;\n    });\n  }\n}\n\nexport function shimGetSendersWithDtmf(window) {\n  // Overrides addTrack/removeTrack, depends on shimAddTrackRemoveTrack.\n  if (typeof window === 'object' && window.RTCPeerConnection &&\n      !('getSenders' in window.RTCPeerConnection.prototype) &&\n      'createDTMFSender' in window.RTCPeerConnection.prototype) {\n    const shimSenderWithDtmf = function(pc, track) {\n      return {\n        track,\n        get dtmf() {\n          if (this._dtmf === undefined) {\n            if (track.kind === 'audio') {\n              this._dtmf = pc.createDTMFSender(track);\n            } else {\n              this._dtmf = null;\n            }\n          }\n          return this._dtmf;\n        },\n        _pc: pc\n      };\n    };\n\n    // augment addTrack when getSenders is not available.\n    if (!window.RTCPeerConnection.prototype.getSenders) {\n      window.RTCPeerConnection.prototype.getSenders = function getSenders() {\n        this._senders = this._senders || [];\n        return this._senders.slice(); // return a copy of the internal state.\n      };\n      const origAddTrack = window.RTCPeerConnection.prototype.addTrack;\n      window.RTCPeerConnection.prototype.addTrack =\n        function addTrack(track, stream) {\n          let sender = origAddTrack.apply(this, arguments);\n          if (!sender) {\n            sender = shimSenderWithDtmf(this, track);\n            this._senders.push(sender);\n          }\n          return sender;\n        };\n\n      const origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack;\n      window.RTCPeerConnection.prototype.removeTrack =\n        function removeTrack(sender) {\n          origRemoveTrack.apply(this, arguments);\n          const idx = this._senders.indexOf(sender);\n          if (idx !== -1) {\n            this._senders.splice(idx, 1);\n          }\n        };\n    }\n    const origAddStream = window.RTCPeerConnection.prototype.addStream;\n    window.RTCPeerConnection.prototype.addStream = function addStream(stream) {\n      this._senders = this._senders || [];\n      origAddStream.apply(this, [stream]);\n      stream.getTracks().forEach(track => {\n        this._senders.push(shimSenderWithDtmf(this, track));\n      });\n    };\n\n    const origRemoveStream = window.RTCPeerConnection.prototype.removeStream;\n    window.RTCPeerConnection.prototype.removeStream =\n      function removeStream(stream) {\n        this._senders = this._senders || [];\n        origRemoveStream.apply(this, [stream]);\n\n        stream.getTracks().forEach(track => {\n          const sender = this._senders.find(s => s.track === track);\n          if (sender) { // remove sender\n            this._senders.splice(this._senders.indexOf(sender), 1);\n          }\n        });\n      };\n  } else if (typeof window === 'object' && window.RTCPeerConnection &&\n             'getSenders' in window.RTCPeerConnection.prototype &&\n             'createDTMFSender' in window.RTCPeerConnection.prototype &&\n             window.RTCRtpSender &&\n             !('dtmf' in window.RTCRtpSender.prototype)) {\n    const origGetSenders = window.RTCPeerConnection.prototype.getSenders;\n    window.RTCPeerConnection.prototype.getSenders = function getSenders() {\n      const senders = origGetSenders.apply(this, []);\n      senders.forEach(sender => sender._pc = this);\n      return senders;\n    };\n\n    Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', {\n      get() {\n        if (this._dtmf === undefined) {\n          if (this.track.kind === 'audio') {\n            this._dtmf = this._pc.createDTMFSender(this.track);\n          } else {\n            this._dtmf = null;\n          }\n        }\n        return this._dtmf;\n      }\n    });\n  }\n}\n\nexport function shimGetStats(window) {\n  if (!window.RTCPeerConnection) {\n    return;\n  }\n\n  const origGetStats = window.RTCPeerConnection.prototype.getStats;\n  window.RTCPeerConnection.prototype.getStats = function getStats() {\n    const [selector, onSucc, onErr] = arguments;\n\n    // If selector is a function then we are in the old style stats so just\n    // pass back the original getStats format to avoid breaking old users.\n    if (arguments.length > 0 && typeof selector === 'function') {\n      return origGetStats.apply(this, arguments);\n    }\n\n    // When spec-style getStats is supported, return those when called with\n    // either no arguments or the selector argument is null.\n    if (origGetStats.length === 0 && (arguments.length === 0 ||\n        typeof selector !== 'function')) {\n      return origGetStats.apply(this, []);\n    }\n\n    const fixChromeStats_ = function(response) {\n      const standardReport = {};\n      const reports = response.result();\n      reports.forEach(report => {\n        const standardStats = {\n          id: report.id,\n          timestamp: report.timestamp,\n          type: {\n            localcandidate: 'local-candidate',\n            remotecandidate: 'remote-candidate'\n          }[report.type] || report.type\n        };\n        report.names().forEach(name => {\n          standardStats[name] = report.stat(name);\n        });\n        standardReport[standardStats.id] = standardStats;\n      });\n\n      return standardReport;\n    };\n\n    // shim getStats with maplike support\n    const makeMapStats = function(stats) {\n      return new Map(Object.keys(stats).map(key => [key, stats[key]]));\n    };\n\n    if (arguments.length >= 2) {\n      const successCallbackWrapper_ = function(response) {\n        onSucc(makeMapStats(fixChromeStats_(response)));\n      };\n\n      return origGetStats.apply(this, [successCallbackWrapper_,\n        selector]);\n    }\n\n    // promise-support\n    return new Promise((resolve, reject) => {\n      origGetStats.apply(this, [\n        function(response) {\n          resolve(makeMapStats(fixChromeStats_(response)));\n        }, reject]);\n    }).then(onSucc, onErr);\n  };\n}\n\nexport function shimSenderReceiverGetStats(window) {\n  if (!(typeof window === 'object' && window.RTCPeerConnection &&\n      window.RTCRtpSender && window.RTCRtpReceiver)) {\n    return;\n  }\n\n  // shim sender stats.\n  if (!('getStats' in window.RTCRtpSender.prototype)) {\n    const origGetSenders = window.RTCPeerConnection.prototype.getSenders;\n    if (origGetSenders) {\n      window.RTCPeerConnection.prototype.getSenders = function getSenders() {\n        const senders = origGetSenders.apply(this, []);\n        senders.forEach(sender => sender._pc = this);\n        return senders;\n      };\n    }\n\n    const origAddTrack = window.RTCPeerConnection.prototype.addTrack;\n    if (origAddTrack) {\n      window.RTCPeerConnection.prototype.addTrack = function addTrack() {\n        const sender = origAddTrack.apply(this, arguments);\n        sender._pc = this;\n        return sender;\n      };\n    }\n    window.RTCRtpSender.prototype.getStats = function getStats() {\n      const sender = this;\n      return this._pc.getStats().then(result =>\n        /* Note: this will include stats of all senders that\n         *   send a track with the same id as sender.track as\n         *   it is not possible to identify the RTCRtpSender.\n         */\n        utils.filterStats(result, sender.track, true));\n    };\n  }\n\n  // shim receiver stats.\n  if (!('getStats' in window.RTCRtpReceiver.prototype)) {\n    const origGetReceivers = window.RTCPeerConnection.prototype.getReceivers;\n    if (origGetReceivers) {\n      window.RTCPeerConnection.prototype.getReceivers =\n        function getReceivers() {\n          const receivers = origGetReceivers.apply(this, []);\n          receivers.forEach(receiver => receiver._pc = this);\n          return receivers;\n        };\n    }\n    utils.wrapPeerConnectionEvent(window, 'track', e => {\n      e.receiver._pc = e.srcElement;\n      return e;\n    });\n    window.RTCRtpReceiver.prototype.getStats = function getStats() {\n      const receiver = this;\n      return this._pc.getStats().then(result =>\n        utils.filterStats(result, receiver.track, false));\n    };\n  }\n\n  if (!('getStats' in window.RTCRtpSender.prototype &&\n      'getStats' in window.RTCRtpReceiver.prototype)) {\n    return;\n  }\n\n  // shim RTCPeerConnection.getStats(track).\n  const origGetStats = window.RTCPeerConnection.prototype.getStats;\n  window.RTCPeerConnection.prototype.getStats = function getStats() {\n    if (arguments.length > 0 &&\n        arguments[0] instanceof window.MediaStreamTrack) {\n      const track = arguments[0];\n      let sender;\n      let receiver;\n      let err;\n      this.getSenders().forEach(s => {\n        if (s.track === track) {\n          if (sender) {\n            err = true;\n          } else {\n            sender = s;\n          }\n        }\n      });\n      this.getReceivers().forEach(r => {\n        if (r.track === track) {\n          if (receiver) {\n            err = true;\n          } else {\n            receiver = r;\n          }\n        }\n        return r.track === track;\n      });\n      if (err || (sender && receiver)) {\n        return Promise.reject(new DOMException(\n          'There are more than one sender or receiver for the track.',\n          'InvalidAccessError'));\n      } else if (sender) {\n        return sender.getStats();\n      } else if (receiver) {\n        return receiver.getStats();\n      }\n      return Promise.reject(new DOMException(\n        'There is no sender or receiver for the track.',\n        'InvalidAccessError'));\n    }\n    return origGetStats.apply(this, arguments);\n  };\n}\n\nexport function shimAddTrackRemoveTrackWithNative(window) {\n  // shim addTrack/removeTrack with native variants in order to make\n  // the interactions with legacy getLocalStreams behave as in other browsers.\n  // Keeps a mapping stream.id => [stream, rtpsenders...]\n  window.RTCPeerConnection.prototype.getLocalStreams =\n    function getLocalStreams() {\n      this._shimmedLocalStreams = this._shimmedLocalStreams || {};\n      return Object.keys(this._shimmedLocalStreams)\n        .map(streamId => this._shimmedLocalStreams[streamId][0]);\n    };\n\n  const origAddTrack = window.RTCPeerConnection.prototype.addTrack;\n  window.RTCPeerConnection.prototype.addTrack =\n    function addTrack(track, stream) {\n      if (!stream) {\n        return origAddTrack.apply(this, arguments);\n      }\n      this._shimmedLocalStreams = this._shimmedLocalStreams || {};\n\n      const sender = origAddTrack.apply(this, arguments);\n      if (!this._shimmedLocalStreams[stream.id]) {\n        this._shimmedLocalStreams[stream.id] = [stream, sender];\n      } else if (this._shimmedLocalStreams[stream.id].indexOf(sender) === -1) {\n        this._shimmedLocalStreams[stream.id].push(sender);\n      }\n      return sender;\n    };\n\n  const origAddStream = window.RTCPeerConnection.prototype.addStream;\n  window.RTCPeerConnection.prototype.addStream = function addStream(stream) {\n    this._shimmedLocalStreams = this._shimmedLocalStreams || {};\n\n    stream.getTracks().forEach(track => {\n      const alreadyExists = this.getSenders().find(s => s.track === track);\n      if (alreadyExists) {\n        throw new DOMException('Track already exists.',\n            'InvalidAccessError');\n      }\n    });\n    const existingSenders = this.getSenders();\n    origAddStream.apply(this, arguments);\n    const newSenders = this.getSenders()\n      .filter(newSender => existingSenders.indexOf(newSender) === -1);\n    this._shimmedLocalStreams[stream.id] = [stream].concat(newSenders);\n  };\n\n  const origRemoveStream = window.RTCPeerConnection.prototype.removeStream;\n  window.RTCPeerConnection.prototype.removeStream =\n    function removeStream(stream) {\n      this._shimmedLocalStreams = this._shimmedLocalStreams || {};\n      delete this._shimmedLocalStreams[stream.id];\n      return origRemoveStream.apply(this, arguments);\n    };\n\n  const origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack;\n  window.RTCPeerConnection.prototype.removeTrack =\n    function removeTrack(sender) {\n      this._shimmedLocalStreams = this._shimmedLocalStreams || {};\n      if (sender) {\n        Object.keys(this._shimmedLocalStreams).forEach(streamId => {\n          const idx = this._shimmedLocalStreams[streamId].indexOf(sender);\n          if (idx !== -1) {\n            this._shimmedLocalStreams[streamId].splice(idx, 1);\n          }\n          if (this._shimmedLocalStreams[streamId].length === 1) {\n            delete this._shimmedLocalStreams[streamId];\n          }\n        });\n      }\n      return origRemoveTrack.apply(this, arguments);\n    };\n}\n\nexport function shimAddTrackRemoveTrack(window, browserDetails) {\n  if (!window.RTCPeerConnection) {\n    return;\n  }\n  // shim addTrack and removeTrack.\n  if (window.RTCPeerConnection.prototype.addTrack &&\n      browserDetails.version >= 65) {\n    return shimAddTrackRemoveTrackWithNative(window);\n  }\n\n  // also shim pc.getLocalStreams when addTrack is shimmed\n  // to return the original streams.\n  const origGetLocalStreams = window.RTCPeerConnection.prototype\n      .getLocalStreams;\n  window.RTCPeerConnection.prototype.getLocalStreams =\n    function getLocalStreams() {\n      const nativeStreams = origGetLocalStreams.apply(this);\n      this._reverseStreams = this._reverseStreams || {};\n      return nativeStreams.map(stream => this._reverseStreams[stream.id]);\n    };\n\n  const origAddStream = window.RTCPeerConnection.prototype.addStream;\n  window.RTCPeerConnection.prototype.addStream = function addStream(stream) {\n    this._streams = this._streams || {};\n    this._reverseStreams = this._reverseStreams || {};\n\n    stream.getTracks().forEach(track => {\n      const alreadyExists = this.getSenders().find(s => s.track === track);\n      if (alreadyExists) {\n        throw new DOMException('Track already exists.',\n            'InvalidAccessError');\n      }\n    });\n    // Add identity mapping for consistency with addTrack.\n    // Unless this is being used with a stream from addTrack.\n    if (!this._reverseStreams[stream.id]) {\n      const newStream = new window.MediaStream(stream.getTracks());\n      this._streams[stream.id] = newStream;\n      this._reverseStreams[newStream.id] = stream;\n      stream = newStream;\n    }\n    origAddStream.apply(this, [stream]);\n  };\n\n  const origRemoveStream = window.RTCPeerConnection.prototype.removeStream;\n  window.RTCPeerConnection.prototype.removeStream =\n    function removeStream(stream) {\n      this._streams = this._streams || {};\n      this._reverseStreams = this._reverseStreams || {};\n\n      origRemoveStream.apply(this, [(this._streams[stream.id] || stream)]);\n      delete this._reverseStreams[(this._streams[stream.id] ?\n          this._streams[stream.id].id : stream.id)];\n      delete this._streams[stream.id];\n    };\n\n  window.RTCPeerConnection.prototype.addTrack =\n    function addTrack(track, stream) {\n      if (this.signalingState === 'closed') {\n        throw new DOMException(\n          'The RTCPeerConnection\\'s signalingState is \\'closed\\'.',\n          'InvalidStateError');\n      }\n      const streams = [].slice.call(arguments, 1);\n      if (streams.length !== 1 ||\n          !streams[0].getTracks().find(t => t === track)) {\n        // this is not fully correct but all we can manage without\n        // [[associated MediaStreams]] internal slot.\n        throw new DOMException(\n          'The adapter.js addTrack polyfill only supports a single ' +\n          ' stream which is associated with the specified track.',\n          'NotSupportedError');\n      }\n\n      const alreadyExists = this.getSenders().find(s => s.track === track);\n      if (alreadyExists) {\n        throw new DOMException('Track already exists.',\n            'InvalidAccessError');\n      }\n\n      this._streams = this._streams || {};\n      this._reverseStreams = this._reverseStreams || {};\n      const oldStream = this._streams[stream.id];\n      if (oldStream) {\n        // this is using odd Chrome behaviour, use with caution:\n        // https://bugs.chromium.org/p/webrtc/issues/detail?id=7815\n        // Note: we rely on the high-level addTrack/dtmf shim to\n        // create the sender with a dtmf sender.\n        oldStream.addTrack(track);\n\n        // Trigger ONN async.\n        Promise.resolve().then(() => {\n          this.dispatchEvent(new Event('negotiationneeded'));\n        });\n      } else {\n        const newStream = new window.MediaStream([track]);\n        this._streams[stream.id] = newStream;\n        this._reverseStreams[newStream.id] = stream;\n        this.addStream(newStream);\n      }\n      return this.getSenders().find(s => s.track === track);\n    };\n\n  // replace the internal stream id with the external one and\n  // vice versa.\n  function replaceInternalStreamId(pc, description) {\n    let sdp = description.sdp;\n    Object.keys(pc._reverseStreams || []).forEach(internalId => {\n      const externalStream = pc._reverseStreams[internalId];\n      const internalStream = pc._streams[externalStream.id];\n      sdp = sdp.replace(new RegExp(internalStream.id, 'g'),\n          externalStream.id);\n    });\n    return new RTCSessionDescription({\n      type: description.type,\n      sdp\n    });\n  }\n  function replaceExternalStreamId(pc, description) {\n    let sdp = description.sdp;\n    Object.keys(pc._reverseStreams || []).forEach(internalId => {\n      const externalStream = pc._reverseStreams[internalId];\n      const internalStream = pc._streams[externalStream.id];\n      sdp = sdp.replace(new RegExp(externalStream.id, 'g'),\n          internalStream.id);\n    });\n    return new RTCSessionDescription({\n      type: description.type,\n      sdp\n    });\n  }\n  ['createOffer', 'createAnswer'].forEach(function(method) {\n    const nativeMethod = window.RTCPeerConnection.prototype[method];\n    const methodObj = {[method]() {\n      const args = arguments;\n      const isLegacyCall = arguments.length &&\n          typeof arguments[0] === 'function';\n      if (isLegacyCall) {\n        return nativeMethod.apply(this, [\n          (description) => {\n            const desc = replaceInternalStreamId(this, description);\n            args[0].apply(null, [desc]);\n          },\n          (err) => {\n            if (args[1]) {\n              args[1].apply(null, err);\n            }\n          }, arguments[2]\n        ]);\n      }\n      return nativeMethod.apply(this, arguments)\n      .then(description => replaceInternalStreamId(this, description));\n    }};\n    window.RTCPeerConnection.prototype[method] = methodObj[method];\n  });\n\n  const origSetLocalDescription =\n      window.RTCPeerConnection.prototype.setLocalDescription;\n  window.RTCPeerConnection.prototype.setLocalDescription =\n    function setLocalDescription() {\n      if (!arguments.length || !arguments[0].type) {\n        return origSetLocalDescription.apply(this, arguments);\n      }\n      arguments[0] = replaceExternalStreamId(this, arguments[0]);\n      return origSetLocalDescription.apply(this, arguments);\n    };\n\n  // TODO: mangle getStats: https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamstats-streamidentifier\n\n  const origLocalDescription = Object.getOwnPropertyDescriptor(\n      window.RTCPeerConnection.prototype, 'localDescription');\n  Object.defineProperty(window.RTCPeerConnection.prototype,\n      'localDescription', {\n        get() {\n          const description = origLocalDescription.get.apply(this);\n          if (description.type === '') {\n            return description;\n          }\n          return replaceInternalStreamId(this, description);\n        }\n      });\n\n  window.RTCPeerConnection.prototype.removeTrack =\n    function removeTrack(sender) {\n      if (this.signalingState === 'closed') {\n        throw new DOMException(\n          'The RTCPeerConnection\\'s signalingState is \\'closed\\'.',\n          'InvalidStateError');\n      }\n      // We can not yet check for sender instanceof RTCRtpSender\n      // since we shim RTPSender. So we check if sender._pc is set.\n      if (!sender._pc) {\n        throw new DOMException('Argument 1 of RTCPeerConnection.removeTrack ' +\n            'does not implement interface RTCRtpSender.', 'TypeError');\n      }\n      const isLocal = sender._pc === this;\n      if (!isLocal) {\n        throw new DOMException('Sender was not created by this connection.',\n            'InvalidAccessError');\n      }\n\n      // Search for the native stream the senders track belongs to.\n      this._streams = this._streams || {};\n      let stream;\n      Object.keys(this._streams).forEach(streamid => {\n        const hasTrack = this._streams[streamid].getTracks()\n          .find(track => sender.track === track);\n        if (hasTrack) {\n          stream = this._streams[streamid];\n        }\n      });\n\n      if (stream) {\n        if (stream.getTracks().length === 1) {\n          // if this is the last track of the stream, remove the stream. This\n          // takes care of any shimmed _senders.\n          this.removeStream(this._reverseStreams[stream.id]);\n        } else {\n          // relying on the same odd chrome behaviour as above.\n          stream.removeTrack(sender.track);\n        }\n        this.dispatchEvent(new Event('negotiationneeded'));\n      }\n    };\n}\n\nexport function shimPeerConnection(window, browserDetails) {\n  if (!window.RTCPeerConnection && window.webkitRTCPeerConnection) {\n    // very basic support for old versions.\n    window.RTCPeerConnection = window.webkitRTCPeerConnection;\n  }\n  if (!window.RTCPeerConnection) {\n    return;\n  }\n\n  // shim implicit creation of RTCSessionDescription/RTCIceCandidate\n  if (browserDetails.version < 53) {\n    ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate']\n        .forEach(function(method) {\n          const nativeMethod = window.RTCPeerConnection.prototype[method];\n          const methodObj = {[method]() {\n            arguments[0] = new ((method === 'addIceCandidate') ?\n                window.RTCIceCandidate :\n                window.RTCSessionDescription)(arguments[0]);\n            return nativeMethod.apply(this, arguments);\n          }};\n          window.RTCPeerConnection.prototype[method] = methodObj[method];\n        });\n  }\n}\n\n// Attempt to fix ONN in plan-b mode.\nexport function fixNegotiationNeeded(window, browserDetails) {\n  utils.wrapPeerConnectionEvent(window, 'negotiationneeded', e => {\n    const pc = e.target;\n    if (browserDetails.version < 72 || (pc.getConfiguration &&\n        pc.getConfiguration().sdpSemantics === 'plan-b')) {\n      if (pc.signalingState !== 'stable') {\n        return;\n      }\n    }\n    return e;\n  });\n}\n","/*\n *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.\n *\n *  Use of this source code is governed by a BSD-style license\n *  that can be found in the LICENSE file in the root of the source\n *  tree.\n */\n/* eslint-env node */\n'use strict';\n\nimport * as utils from '../utils';\n\nexport function shimGetUserMedia(window, browserDetails) {\n  const navigator = window && window.navigator;\n  const MediaStreamTrack = window && window.MediaStreamTrack;\n\n  navigator.getUserMedia = function(constraints, onSuccess, onError) {\n    // Replace Firefox 44+'s deprecation warning with unprefixed version.\n    utils.deprecated('navigator.getUserMedia',\n        'navigator.mediaDevices.getUserMedia');\n    navigator.mediaDevices.getUserMedia(constraints).then(onSuccess, onError);\n  };\n\n  if (!(browserDetails.version > 55 &&\n      'autoGainControl' in navigator.mediaDevices.getSupportedConstraints())) {\n    const remap = function(obj, a, b) {\n      if (a in obj && !(b in obj)) {\n        obj[b] = obj[a];\n        delete obj[a];\n      }\n    };\n\n    const nativeGetUserMedia = navigator.mediaDevices.getUserMedia.\n        bind(navigator.mediaDevices);\n    navigator.mediaDevices.getUserMedia = function(c) {\n      if (typeof c === 'object' && typeof c.audio === 'object') {\n        c = JSON.parse(JSON.stringify(c));\n        remap(c.audio, 'autoGainControl', 'mozAutoGainControl');\n        remap(c.audio, 'noiseSuppression', 'mozNoiseSuppression');\n      }\n      return nativeGetUserMedia(c);\n    };\n\n    if (MediaStreamTrack && MediaStreamTrack.prototype.getSettings) {\n      const nativeGetSettings = MediaStreamTrack.prototype.getSettings;\n      MediaStreamTrack.prototype.getSettings = function() {\n        const obj = nativeGetSettings.apply(this, arguments);\n        remap(obj, 'mozAutoGainControl', 'autoGainControl');\n        remap(obj, 'mozNoiseSuppression', 'noiseSuppression');\n        return obj;\n      };\n    }\n\n    if (MediaStreamTrack && MediaStreamTrack.prototype.applyConstraints) {\n      const nativeApplyConstraints =\n        MediaStreamTrack.prototype.applyConstraints;\n      MediaStreamTrack.prototype.applyConstraints = function(c) {\n        if (this.kind === 'audio' && typeof c === 'object') {\n          c = JSON.parse(JSON.stringify(c));\n          remap(c, 'autoGainControl', 'mozAutoGainControl');\n          remap(c, 'noiseSuppression', 'mozNoiseSuppression');\n        }\n        return nativeApplyConstraints.apply(this, [c]);\n      };\n    }\n  }\n}\n","/*\n *  Copyright (c) 2018 The adapter.js project authors. All Rights Reserved.\n *\n *  Use of this source code is governed by a BSD-style license\n *  that can be found in the LICENSE file in the root of the source\n *  tree.\n */\n/* eslint-env node */\n'use strict';\n\nexport function shimGetDisplayMedia(window, preferredMediaSource) {\n  if (window.navigator.mediaDevices &&\n    'getDisplayMedia' in window.navigator.mediaDevices) {\n    return;\n  }\n  if (!(window.navigator.mediaDevices)) {\n    return;\n  }\n  window.navigator.mediaDevices.getDisplayMedia =\n    function getDisplayMedia(constraints) {\n      if (!(constraints && constraints.video)) {\n        const err = new DOMException('getDisplayMedia without video ' +\n            'constraints is undefined');\n        err.name = 'NotFoundError';\n        // from https://heycam.github.io/webidl/#idl-DOMException-error-names\n        err.code = 8;\n        return Promise.reject(err);\n      }\n      if (constraints.video === true) {\n        constraints.video = {mediaSource: preferredMediaSource};\n      } else {\n        constraints.video.mediaSource = preferredMediaSource;\n      }\n      return window.navigator.mediaDevices.getUserMedia(constraints);\n    };\n}\n","/*\n *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.\n *\n *  Use of this source code is governed by a BSD-style license\n *  that can be found in the LICENSE file in the root of the source\n *  tree.\n */\n/* eslint-env node */\n'use strict';\n\nimport * as utils from '../utils';\nexport {shimGetUserMedia} from './getusermedia';\nexport {shimGetDisplayMedia} from './getdisplaymedia';\n\nexport function shimOnTrack(window) {\n  if (typeof window === 'object' && window.RTCTrackEvent &&\n      ('receiver' in window.RTCTrackEvent.prototype) &&\n      !('transceiver' in window.RTCTrackEvent.prototype)) {\n    Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', {\n      get() {\n        return {receiver: this.receiver};\n      }\n    });\n  }\n}\n\nexport function shimPeerConnection(window, browserDetails) {\n  if (typeof window !== 'object' ||\n      !(window.RTCPeerConnection || window.mozRTCPeerConnection)) {\n    return; // probably media.peerconnection.enabled=false in about:config\n  }\n  if (!window.RTCPeerConnection && window.mozRTCPeerConnection) {\n    // very basic support for old versions.\n    window.RTCPeerConnection = window.mozRTCPeerConnection;\n  }\n\n  if (browserDetails.version < 53) {\n    // shim away need for obsolete RTCIceCandidate/RTCSessionDescription.\n    ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate']\n        .forEach(function(method) {\n          const nativeMethod = window.RTCPeerConnection.prototype[method];\n          const methodObj = {[method]() {\n            arguments[0] = new ((method === 'addIceCandidate') ?\n                window.RTCIceCandidate :\n                window.RTCSessionDescription)(arguments[0]);\n            return nativeMethod.apply(this, arguments);\n          }};\n          window.RTCPeerConnection.prototype[method] = methodObj[method];\n        });\n  }\n\n  const modernStatsTypes = {\n    inboundrtp: 'inbound-rtp',\n    outboundrtp: 'outbound-rtp',\n    candidatepair: 'candidate-pair',\n    localcandidate: 'local-candidate',\n    remotecandidate: 'remote-candidate'\n  };\n\n  const nativeGetStats = window.RTCPeerConnection.prototype.getStats;\n  window.RTCPeerConnection.prototype.getStats = function getStats() {\n    const [selector, onSucc, onErr] = arguments;\n    return nativeGetStats.apply(this, [selector || null])\n      .then(stats => {\n        if (browserDetails.version < 53 && !onSucc) {\n          // Shim only promise getStats with spec-hyphens in type names\n          // Leave callback version alone; misc old uses of forEach before Map\n          try {\n            stats.forEach(stat => {\n              stat.type = modernStatsTypes[stat.type] || stat.type;\n            });\n          } catch (e) {\n            if (e.name !== 'TypeError') {\n              throw e;\n            }\n            // Avoid TypeError: \"type\" is read-only, in old versions. 34-43ish\n            stats.forEach((stat, i) => {\n              stats.set(i, Object.assign({}, stat, {\n                type: modernStatsTypes[stat.type] || stat.type\n              }));\n            });\n          }\n        }\n        return stats;\n      })\n      .then(onSucc, onErr);\n  };\n}\n\nexport function shimSenderGetStats(window) {\n  if (!(typeof window === 'object' && window.RTCPeerConnection &&\n      window.RTCRtpSender)) {\n    return;\n  }\n  if (window.RTCRtpSender && 'getStats' in window.RTCRtpSender.prototype) {\n    return;\n  }\n  const origGetSenders = window.RTCPeerConnection.prototype.getSenders;\n  if (origGetSenders) {\n    window.RTCPeerConnection.prototype.getSenders = function getSenders() {\n      const senders = origGetSenders.apply(this, []);\n      senders.forEach(sender => sender._pc = this);\n      return senders;\n    };\n  }\n\n  const origAddTrack = window.RTCPeerConnection.prototype.addTrack;\n  if (origAddTrack) {\n    window.RTCPeerConnection.prototype.addTrack = function addTrack() {\n      const sender = origAddTrack.apply(this, arguments);\n      sender._pc = this;\n      return sender;\n    };\n  }\n  window.RTCRtpSender.prototype.getStats = function getStats() {\n    return this.track ? this._pc.getStats(this.track) :\n        Promise.resolve(new Map());\n  };\n}\n\nexport function shimReceiverGetStats(window) {\n  if (!(typeof window === 'object' && window.RTCPeerConnection &&\n      window.RTCRtpSender)) {\n    return;\n  }\n  if (window.RTCRtpSender && 'getStats' in window.RTCRtpReceiver.prototype) {\n    return;\n  }\n  const origGetReceivers = window.RTCPeerConnection.prototype.getReceivers;\n  if (origGetReceivers) {\n    window.RTCPeerConnection.prototype.getReceivers = function getReceivers() {\n      const receivers = origGetReceivers.apply(this, []);\n      receivers.forEach(receiver => receiver._pc = this);\n      return receivers;\n    };\n  }\n  utils.wrapPeerConnectionEvent(window, 'track', e => {\n    e.receiver._pc = e.srcElement;\n    return e;\n  });\n  window.RTCRtpReceiver.prototype.getStats = function getStats() {\n    return this._pc.getStats(this.track);\n  };\n}\n\nexport function shimRemoveStream(window) {\n  if (!window.RTCPeerConnection ||\n      'removeStream' in window.RTCPeerConnection.prototype) {\n    return;\n  }\n  window.RTCPeerConnection.prototype.removeStream =\n    function removeStream(stream) {\n      utils.deprecated('removeStream', 'removeTrack');\n      this.getSenders().forEach(sender => {\n        if (sender.track && stream.getTracks().includes(sender.track)) {\n          this.removeTrack(sender);\n        }\n      });\n    };\n}\n\nexport function shimRTCDataChannel(window) {\n  // rename DataChannel to RTCDataChannel (native fix in FF60):\n  // https://bugzilla.mozilla.org/show_bug.cgi?id=1173851\n  if (window.DataChannel && !window.RTCDataChannel) {\n    window.RTCDataChannel = window.DataChannel;\n  }\n}\n\nexport function shimAddTransceiver(window) {\n  // https://github.com/webrtcHacks/adapter/issues/998#issuecomment-516921647\n  // Firefox ignores the init sendEncodings options passed to addTransceiver\n  // https://bugzilla.mozilla.org/show_bug.cgi?id=1396918\n  if (!(typeof window === 'object' && window.RTCPeerConnection)) {\n    return;\n  }\n  const origAddTransceiver = window.RTCPeerConnection.prototype.addTransceiver;\n  if (origAddTransceiver) {\n    window.RTCPeerConnection.prototype.addTransceiver =\n      function addTransceiver() {\n        this.setParametersPromises = [];\n        const initParameters = arguments[1];\n        const shouldPerformCheck = initParameters &&\n                                  'sendEncodings' in initParameters;\n        if (shouldPerformCheck) {\n          // If sendEncodings params are provided, validate grammar\n          initParameters.sendEncodings.forEach((encodingParam) => {\n            if ('rid' in encodingParam) {\n              const ridRegex = /^[a-z0-9]{0,16}$/i;\n              if (!ridRegex.test(encodingParam.rid)) {\n                throw new TypeError('Invalid RID value provided.');\n              }\n            }\n            if ('scaleResolutionDownBy' in encodingParam) {\n              if (!(parseFloat(encodingParam.scaleResolutionDownBy) >= 1.0)) {\n                throw new RangeError('scale_resolution_down_by must be >= 1.0');\n              }\n            }\n            if ('maxFramerate' in encodingParam) {\n              if (!(parseFloat(encodingParam.maxFramerate) >= 0)) {\n                throw new RangeError('max_framerate must be >= 0.0');\n              }\n            }\n          });\n        }\n        const transceiver = origAddTransceiver.apply(this, arguments);\n        if (shouldPerformCheck) {\n          // Check if the init options were applied. If not we do this in an\n          // asynchronous way and save the promise reference in a global object.\n          // This is an ugly hack, but at the same time is way more robust than\n          // checking the sender parameters before and after the createOffer\n          // Also note that after the createoffer we are not 100% sure that\n          // the params were asynchronously applied so we might miss the\n          // opportunity to recreate offer.\n          const {sender} = transceiver;\n          const params = sender.getParameters();\n          if (!('encodings' in params) ||\n              // Avoid being fooled by patched getParameters() below.\n              (params.encodings.length === 1 &&\n               Object.keys(params.encodings[0]).length === 0)) {\n            params.encodings = initParameters.sendEncodings;\n            sender.sendEncodings = initParameters.sendEncodings;\n            this.setParametersPromises.push(sender.setParameters(params)\n              .then(() => {\n                delete sender.sendEncodings;\n              }).catch(() => {\n                delete sender.sendEncodings;\n              })\n            );\n          }\n        }\n        return transceiver;\n      };\n  }\n}\n\nexport function shimGetParameters(window) {\n  if (!(typeof window === 'object' && window.RTCRtpSender)) {\n    return;\n  }\n  const origGetParameters = window.RTCRtpSender.prototype.getParameters;\n  if (origGetParameters) {\n    window.RTCRtpSender.prototype.getParameters =\n      function getParameters() {\n        const params = origGetParameters.apply(this, arguments);\n        if (!('encodings' in params)) {\n          params.encodings = [].concat(this.sendEncodings || [{}]);\n        }\n        return params;\n      };\n  }\n}\n\nexport function shimCreateOffer(window) {\n  // https://github.com/webrtcHacks/adapter/issues/998#issuecomment-516921647\n  // Firefox ignores the init sendEncodings options passed to addTransceiver\n  // https://bugzilla.mozilla.org/show_bug.cgi?id=1396918\n  if (!(typeof window === 'object' && window.RTCPeerConnection)) {\n    return;\n  }\n  const origCreateOffer = window.RTCPeerConnection.prototype.createOffer;\n  window.RTCPeerConnection.prototype.createOffer = function createOffer() {\n    if (this.setParametersPromises && this.setParametersPromises.length) {\n      return Promise.all(this.setParametersPromises)\n      .then(() => {\n        return origCreateOffer.apply(this, arguments);\n      })\n      .finally(() => {\n        this.setParametersPromises = [];\n      });\n    }\n    return origCreateOffer.apply(this, arguments);\n  };\n}\n\nexport function shimCreateAnswer(window) {\n  // https://github.com/webrtcHacks/adapter/issues/998#issuecomment-516921647\n  // Firefox ignores the init sendEncodings options passed to addTransceiver\n  // https://bugzilla.mozilla.org/show_bug.cgi?id=1396918\n  if (!(typeof window === 'object' && window.RTCPeerConnection)) {\n    return;\n  }\n  const origCreateAnswer = window.RTCPeerConnection.prototype.createAnswer;\n  window.RTCPeerConnection.prototype.createAnswer = function createAnswer() {\n    if (this.setParametersPromises && this.setParametersPromises.length) {\n      return Promise.all(this.setParametersPromises)\n      .then(() => {\n        return origCreateAnswer.apply(this, arguments);\n      })\n      .finally(() => {\n        this.setParametersPromises = [];\n      });\n    }\n    return origCreateAnswer.apply(this, arguments);\n  };\n}\n","/*\n *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.\n *\n *  Use of this source code is governed by a BSD-style license\n *  that can be found in the LICENSE file in the root of the source\n *  tree.\n */\n'use strict';\nimport * as utils from '../utils';\n\nexport function shimLocalStreamsAPI(window) {\n  if (typeof window !== 'object' || !window.RTCPeerConnection) {\n    return;\n  }\n  if (!('getLocalStreams' in window.RTCPeerConnection.prototype)) {\n    window.RTCPeerConnection.prototype.getLocalStreams =\n      function getLocalStreams() {\n        if (!this._localStreams) {\n          this._localStreams = [];\n        }\n        return this._localStreams;\n      };\n  }\n  if (!('addStream' in window.RTCPeerConnection.prototype)) {\n    const _addTrack = window.RTCPeerConnection.prototype.addTrack;\n    window.RTCPeerConnection.prototype.addStream = function addStream(stream) {\n      if (!this._localStreams) {\n        this._localStreams = [];\n      }\n      if (!this._localStreams.includes(stream)) {\n        this._localStreams.push(stream);\n      }\n      // Try to emulate Chrome's behaviour of adding in audio-video order.\n      // Safari orders by track id.\n      stream.getAudioTracks().forEach(track => _addTrack.call(this, track,\n        stream));\n      stream.getVideoTracks().forEach(track => _addTrack.call(this, track,\n        stream));\n    };\n\n    window.RTCPeerConnection.prototype.addTrack =\n      function addTrack(track, ...streams) {\n        if (streams) {\n          streams.forEach((stream) => {\n            if (!this._localStreams) {\n              this._localStreams = [stream];\n            } else if (!this._localStreams.includes(stream)) {\n              this._localStreams.push(stream);\n            }\n          });\n        }\n        return _addTrack.apply(this, arguments);\n      };\n  }\n  if (!('removeStream' in window.RTCPeerConnection.prototype)) {\n    window.RTCPeerConnection.prototype.removeStream =\n      function removeStream(stream) {\n        if (!this._localStreams) {\n          this._localStreams = [];\n        }\n        const index = this._localStreams.indexOf(stream);\n        if (index === -1) {\n          return;\n        }\n        this._localStreams.splice(index, 1);\n        const tracks = stream.getTracks();\n        this.getSenders().forEach(sender => {\n          if (tracks.includes(sender.track)) {\n            this.removeTrack(sender);\n          }\n        });\n      };\n  }\n}\n\nexport function shimRemoteStreamsAPI(window) {\n  if (typeof window !== 'object' || !window.RTCPeerConnection) {\n    return;\n  }\n  if (!('getRemoteStreams' in window.RTCPeerConnection.prototype)) {\n    window.RTCPeerConnection.prototype.getRemoteStreams =\n      function getRemoteStreams() {\n        return this._remoteStreams ? this._remoteStreams : [];\n      };\n  }\n  if (!('onaddstream' in window.RTCPeerConnection.prototype)) {\n    Object.defineProperty(window.RTCPeerConnection.prototype, 'onaddstream', {\n      get() {\n        return this._onaddstream;\n      },\n      set(f) {\n        if (this._onaddstream) {\n          this.removeEventListener('addstream', this._onaddstream);\n          this.removeEventListener('track', this._onaddstreampoly);\n        }\n        this.addEventListener('addstream', this._onaddstream = f);\n        this.addEventListener('track', this._onaddstreampoly = (e) => {\n          e.streams.forEach(stream => {\n            if (!this._remoteStreams) {\n              this._remoteStreams = [];\n            }\n            if (this._remoteStreams.includes(stream)) {\n              return;\n            }\n            this._remoteStreams.push(stream);\n            const event = new Event('addstream');\n            event.stream = stream;\n            this.dispatchEvent(event);\n          });\n        });\n      }\n    });\n    const origSetRemoteDescription =\n      window.RTCPeerConnection.prototype.setRemoteDescription;\n    window.RTCPeerConnection.prototype.setRemoteDescription =\n      function setRemoteDescription() {\n        const pc = this;\n        if (!this._onaddstreampoly) {\n          this.addEventListener('track', this._onaddstreampoly = function(e) {\n            e.streams.forEach(stream => {\n              if (!pc._remoteStreams) {\n                pc._remoteStreams = [];\n              }\n              if (pc._remoteStreams.indexOf(stream) >= 0) {\n                return;\n              }\n              pc._remoteStreams.push(stream);\n              const event = new Event('addstream');\n              event.stream = stream;\n              pc.dispatchEvent(event);\n            });\n          });\n        }\n        return origSetRemoteDescription.apply(pc, arguments);\n      };\n  }\n}\n\nexport function shimCallbacksAPI(window) {\n  if (typeof window !== 'object' || !window.RTCPeerConnection) {\n    return;\n  }\n  const prototype = window.RTCPeerConnection.prototype;\n  const origCreateOffer = prototype.createOffer;\n  const origCreateAnswer = prototype.createAnswer;\n  const setLocalDescription = prototype.setLocalDescription;\n  const setRemoteDescription = prototype.setRemoteDescription;\n  const addIceCandidate = prototype.addIceCandidate;\n\n  prototype.createOffer =\n    function createOffer(successCallback, failureCallback) {\n      const options = (arguments.length >= 2) ? arguments[2] : arguments[0];\n      const promise = origCreateOffer.apply(this, [options]);\n      if (!failureCallback) {\n        return promise;\n      }\n      promise.then(successCallback, failureCallback);\n      return Promise.resolve();\n    };\n\n  prototype.createAnswer =\n    function createAnswer(successCallback, failureCallback) {\n      const options = (arguments.length >= 2) ? arguments[2] : arguments[0];\n      const promise = origCreateAnswer.apply(this, [options]);\n      if (!failureCallback) {\n        return promise;\n      }\n      promise.then(successCallback, failureCallback);\n      return Promise.resolve();\n    };\n\n  let withCallback = function(description, successCallback, failureCallback) {\n    const promise = setLocalDescription.apply(this, [description]);\n    if (!failureCallback) {\n      return promise;\n    }\n    promise.then(successCallback, failureCallback);\n    return Promise.resolve();\n  };\n  prototype.setLocalDescription = withCallback;\n\n  withCallback = function(description, successCallback, failureCallback) {\n    const promise = setRemoteDescription.apply(this, [description]);\n    if (!failureCallback) {\n      return promise;\n    }\n    promise.then(successCallback, failureCallback);\n    return Promise.resolve();\n  };\n  prototype.setRemoteDescription = withCallback;\n\n  withCallback = function(candidate, successCallback, failureCallback) {\n    const promise = addIceCandidate.apply(this, [candidate]);\n    if (!failureCallback) {\n      return promise;\n    }\n    promise.then(successCallback, failureCallback);\n    return Promise.resolve();\n  };\n  prototype.addIceCandidate = withCallback;\n}\n\nexport function shimGetUserMedia(window) {\n  const navigator = window && window.navigator;\n\n  if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {\n    // shim not needed in Safari 12.1\n    const mediaDevices = navigator.mediaDevices;\n    const _getUserMedia = mediaDevices.getUserMedia.bind(mediaDevices);\n    navigator.mediaDevices.getUserMedia = (constraints) => {\n      return _getUserMedia(shimConstraints(constraints));\n    };\n  }\n\n  if (!navigator.getUserMedia && navigator.mediaDevices &&\n    navigator.mediaDevices.getUserMedia) {\n    navigator.getUserMedia = function getUserMedia(constraints, cb, errcb) {\n      navigator.mediaDevices.getUserMedia(constraints)\n      .then(cb, errcb);\n    }.bind(navigator);\n  }\n}\n\nexport function shimConstraints(constraints) {\n  if (constraints && constraints.video !== undefined) {\n    return Object.assign({},\n      constraints,\n      {video: utils.compactObject(constraints.video)}\n    );\n  }\n\n  return constraints;\n}\n\nexport function shimRTCIceServerUrls(window) {\n  if (!window.RTCPeerConnection) {\n    return;\n  }\n  // migrate from non-spec RTCIceServer.url to RTCIceServer.urls\n  const OrigPeerConnection = window.RTCPeerConnection;\n  window.RTCPeerConnection =\n    function RTCPeerConnection(pcConfig, pcConstraints) {\n      if (pcConfig && pcConfig.iceServers) {\n        const newIceServers = [];\n        for (let i = 0; i < pcConfig.iceServers.length; i++) {\n          let server = pcConfig.iceServers[i];\n          if (!server.hasOwnProperty('urls') &&\n              server.hasOwnProperty('url')) {\n            utils.deprecated('RTCIceServer.url', 'RTCIceServer.urls');\n            server = JSON.parse(JSON.stringify(server));\n            server.urls = server.url;\n            delete server.url;\n            newIceServers.push(server);\n          } else {\n            newIceServers.push(pcConfig.iceServers[i]);\n          }\n        }\n        pcConfig.iceServers = newIceServers;\n      }\n      return new OrigPeerConnection(pcConfig, pcConstraints);\n    };\n  window.RTCPeerConnection.prototype = OrigPeerConnection.prototype;\n  // wrap static methods. Currently just generateCertificate.\n  if ('generateCertificate' in OrigPeerConnection) {\n    Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', {\n      get() {\n        return OrigPeerConnection.generateCertificate;\n      }\n    });\n  }\n}\n\nexport function shimTrackEventTransceiver(window) {\n  // Add event.transceiver member over deprecated event.receiver\n  if (typeof window === 'object' && window.RTCTrackEvent &&\n      'receiver' in window.RTCTrackEvent.prototype &&\n      !('transceiver' in window.RTCTrackEvent.prototype)) {\n    Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', {\n      get() {\n        return {receiver: this.receiver};\n      }\n    });\n  }\n}\n\nexport function shimCreateOfferLegacy(window) {\n  const origCreateOffer = window.RTCPeerConnection.prototype.createOffer;\n  window.RTCPeerConnection.prototype.createOffer =\n    function createOffer(offerOptions) {\n      if (offerOptions) {\n        if (typeof offerOptions.offerToReceiveAudio !== 'undefined') {\n          // support bit values\n          offerOptions.offerToReceiveAudio =\n            !!offerOptions.offerToReceiveAudio;\n        }\n        const audioTransceiver = this.getTransceivers().find(transceiver =>\n          transceiver.receiver.track.kind === 'audio');\n        if (offerOptions.offerToReceiveAudio === false && audioTransceiver) {\n          if (audioTransceiver.direction === 'sendrecv') {\n            if (audioTransceiver.setDirection) {\n              audioTransceiver.setDirection('sendonly');\n            } else {\n              audioTransceiver.direction = 'sendonly';\n            }\n          } else if (audioTransceiver.direction === 'recvonly') {\n            if (audioTransceiver.setDirection) {\n              audioTransceiver.setDirection('inactive');\n            } else {\n              audioTransceiver.direction = 'inactive';\n            }\n          }\n        } else if (offerOptions.offerToReceiveAudio === true &&\n            !audioTransceiver) {\n          this.addTransceiver('audio', {direction: 'recvonly'});\n        }\n\n        if (typeof offerOptions.offerToReceiveVideo !== 'undefined') {\n          // support bit values\n          offerOptions.offerToReceiveVideo =\n            !!offerOptions.offerToReceiveVideo;\n        }\n        const videoTransceiver = this.getTransceivers().find(transceiver =>\n          transceiver.receiver.track.kind === 'video');\n        if (offerOptions.offerToReceiveVideo === false && videoTransceiver) {\n          if (videoTransceiver.direction === 'sendrecv') {\n            if (videoTransceiver.setDirection) {\n              videoTransceiver.setDirection('sendonly');\n            } else {\n              videoTransceiver.direction = 'sendonly';\n            }\n          } else if (videoTransceiver.direction === 'recvonly') {\n            if (videoTransceiver.setDirection) {\n              videoTransceiver.setDirection('inactive');\n            } else {\n              videoTransceiver.direction = 'inactive';\n            }\n          }\n        } else if (offerOptions.offerToReceiveVideo === true &&\n            !videoTransceiver) {\n          this.addTransceiver('video', {direction: 'recvonly'});\n        }\n      }\n      return origCreateOffer.apply(this, arguments);\n    };\n}\n\nexport function shimAudioContext(window) {\n  if (typeof window !== 'object' || window.AudioContext) {\n    return;\n  }\n  window.AudioContext = window.webkitAudioContext;\n}\n\n","/*\n *  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.\n *\n *  Use of this source code is governed by a BSD-style license\n *  that can be found in the LICENSE file in the root of the source\n *  tree.\n */\n/* eslint-env node */\n'use strict';\n\nimport SDPUtils from 'sdp';\nimport * as utils from './utils';\n\nexport function shimRTCIceCandidate(window) {\n  // foundation is arbitrarily chosen as an indicator for full support for\n  // https://w3c.github.io/webrtc-pc/#rtcicecandidate-interface\n  if (!window.RTCIceCandidate || (window.RTCIceCandidate && 'foundation' in\n      window.RTCIceCandidate.prototype)) {\n    return;\n  }\n\n  const NativeRTCIceCandidate = window.RTCIceCandidate;\n  window.RTCIceCandidate = function RTCIceCandidate(args) {\n    // Remove the a= which shouldn't be part of the candidate string.\n    if (typeof args === 'object' && args.candidate &&\n        args.candidate.indexOf('a=') === 0) {\n      args = JSON.parse(JSON.stringify(args));\n      args.candidate = args.candidate.substr(2);\n    }\n\n    if (args.candidate && args.candidate.length) {\n      // Augment the native candidate with the parsed fields.\n      const nativeCandidate = new NativeRTCIceCandidate(args);\n      const parsedCandidate = SDPUtils.parseCandidate(args.candidate);\n      const augmentedCandidate = Object.assign(nativeCandidate,\n          parsedCandidate);\n\n      // Add a serializer that does not serialize the extra attributes.\n      augmentedCandidate.toJSON = function toJSON() {\n        return {\n          candidate: augmentedCandidate.candidate,\n          sdpMid: augmentedCandidate.sdpMid,\n          sdpMLineIndex: augmentedCandidate.sdpMLineIndex,\n          usernameFragment: augmentedCandidate.usernameFragment,\n        };\n      };\n      return augmentedCandidate;\n    }\n    return new NativeRTCIceCandidate(args);\n  };\n  window.RTCIceCandidate.prototype = NativeRTCIceCandidate.prototype;\n\n  // Hook up the augmented candidate in onicecandidate and\n  // addEventListener('icecandidate', ...)\n  utils.wrapPeerConnectionEvent(window, 'icecandidate', e => {\n    if (e.candidate) {\n      Object.defineProperty(e, 'candidate', {\n        value: new window.RTCIceCandidate(e.candidate),\n        writable: 'false'\n      });\n    }\n    return e;\n  });\n}\n\nexport function shimMaxMessageSize(window, browserDetails) {\n  if (!window.RTCPeerConnection) {\n    return;\n  }\n\n  if (!('sctp' in window.RTCPeerConnection.prototype)) {\n    Object.defineProperty(window.RTCPeerConnection.prototype, 'sctp', {\n      get() {\n        return typeof this._sctp === 'undefined' ? null : this._sctp;\n      }\n    });\n  }\n\n  const sctpInDescription = function(description) {\n    if (!description || !description.sdp) {\n      return false;\n    }\n    const sections = SDPUtils.splitSections(description.sdp);\n    sections.shift();\n    return sections.some(mediaSection => {\n      const mLine = SDPUtils.parseMLine(mediaSection);\n      return mLine && mLine.kind === 'application'\n          && mLine.protocol.indexOf('SCTP') !== -1;\n    });\n  };\n\n  const getRemoteFirefoxVersion = function(description) {\n    // TODO: Is there a better solution for detecting Firefox?\n    const match = description.sdp.match(/mozilla...THIS_IS_SDPARTA-(\\d+)/);\n    if (match === null || match.length < 2) {\n      return -1;\n    }\n    const version = parseInt(match[1], 10);\n    // Test for NaN (yes, this is ugly)\n    return version !== version ? -1 : version;\n  };\n\n  const getCanSendMaxMessageSize = function(remoteIsFirefox) {\n    // Every implementation we know can send at least 64 KiB.\n    // Note: Although Chrome is technically able to send up to 256 KiB, the\n    //       data does not reach the other peer reliably.\n    //       See: https://bugs.chromium.org/p/webrtc/issues/detail?id=8419\n    let canSendMaxMessageSize = 65536;\n    if (browserDetails.browser === 'firefox') {\n      if (browserDetails.version < 57) {\n        if (remoteIsFirefox === -1) {\n          // FF < 57 will send in 16 KiB chunks using the deprecated PPID\n          // fragmentation.\n          canSendMaxMessageSize = 16384;\n        } else {\n          // However, other FF (and RAWRTC) can reassemble PPID-fragmented\n          // messages. Thus, supporting ~2 GiB when sending.\n          canSendMaxMessageSize = 2147483637;\n        }\n      } else if (browserDetails.version < 60) {\n        // Currently, all FF >= 57 will reset the remote maximum message size\n        // to the default value when a data channel is created at a later\n        // stage. :(\n        // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831\n        canSendMaxMessageSize =\n          browserDetails.version === 57 ? 65535 : 65536;\n      } else {\n        // FF >= 60 supports sending ~2 GiB\n        canSendMaxMessageSize = 2147483637;\n      }\n    }\n    return canSendMaxMessageSize;\n  };\n\n  const getMaxMessageSize = function(description, remoteIsFirefox) {\n    // Note: 65536 bytes is the default value from the SDP spec. Also,\n    //       every implementation we know supports receiving 65536 bytes.\n    let maxMessageSize = 65536;\n\n    // FF 57 has a slightly incorrect default remote max message size, so\n    // we need to adjust it here to avoid a failure when sending.\n    // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1425697\n    if (browserDetails.browser === 'firefox'\n         && browserDetails.version === 57) {\n      maxMessageSize = 65535;\n    }\n\n    const match = SDPUtils.matchPrefix(description.sdp,\n      'a=max-message-size:');\n    if (match.length > 0) {\n      maxMessageSize = parseInt(match[0].substr(19), 10);\n    } else if (browserDetails.browser === 'firefox' &&\n                remoteIsFirefox !== -1) {\n      // If the maximum message size is not present in the remote SDP and\n      // both local and remote are Firefox, the remote peer can receive\n      // ~2 GiB.\n      maxMessageSize = 2147483637;\n    }\n    return maxMessageSize;\n  };\n\n  const origSetRemoteDescription =\n      window.RTCPeerConnection.prototype.setRemoteDescription;\n  window.RTCPeerConnection.prototype.setRemoteDescription =\n    function setRemoteDescription() {\n      this._sctp = null;\n      // Chrome decided to not expose .sctp in plan-b mode.\n      // As usual, adapter.js has to do an 'ugly worakaround'\n      // to cover up the mess.\n      if (browserDetails.browser === 'chrome' && browserDetails.version >= 76) {\n        const {sdpSemantics} = this.getConfiguration();\n        if (sdpSemantics === 'plan-b') {\n          Object.defineProperty(this, 'sctp', {\n            get() {\n              return typeof this._sctp === 'undefined' ? null : this._sctp;\n            },\n            enumerable: true,\n            configurable: true,\n          });\n        }\n      }\n\n      if (sctpInDescription(arguments[0])) {\n        // Check if the remote is FF.\n        const isFirefox = getRemoteFirefoxVersion(arguments[0]);\n\n        // Get the maximum message size the local peer is capable of sending\n        const canSendMMS = getCanSendMaxMessageSize(isFirefox);\n\n        // Get the maximum message size of the remote peer.\n        const remoteMMS = getMaxMessageSize(arguments[0], isFirefox);\n\n        // Determine final maximum message size\n        let maxMessageSize;\n        if (canSendMMS === 0 && remoteMMS === 0) {\n          maxMessageSize = Number.POSITIVE_INFINITY;\n        } else if (canSendMMS === 0 || remoteMMS === 0) {\n          maxMessageSize = Math.max(canSendMMS, remoteMMS);\n        } else {\n          maxMessageSize = Math.min(canSendMMS, remoteMMS);\n        }\n\n        // Create a dummy RTCSctpTransport object and the 'maxMessageSize'\n        // attribute.\n        const sctp = {};\n        Object.defineProperty(sctp, 'maxMessageSize', {\n          get() {\n            return maxMessageSize;\n          }\n        });\n        this._sctp = sctp;\n      }\n\n      return origSetRemoteDescription.apply(this, arguments);\n    };\n}\n\nexport function shimSendThrowTypeError(window) {\n  if (!(window.RTCPeerConnection &&\n      'createDataChannel' in window.RTCPeerConnection.prototype)) {\n    return;\n  }\n\n  // Note: Although Firefox >= 57 has a native implementation, the maximum\n  //       message size can be reset for all data channels at a later stage.\n  //       See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831\n\n  function wrapDcSend(dc, pc) {\n    const origDataChannelSend = dc.send;\n    dc.send = function send() {\n      const data = arguments[0];\n      const length = data.length || data.size || data.byteLength;\n      if (dc.readyState === 'open' &&\n          pc.sctp && length > pc.sctp.maxMessageSize) {\n        throw new TypeError('Message too large (can send a maximum of ' +\n          pc.sctp.maxMessageSize + ' bytes)');\n      }\n      return origDataChannelSend.apply(dc, arguments);\n    };\n  }\n  const origCreateDataChannel =\n    window.RTCPeerConnection.prototype.createDataChannel;\n  window.RTCPeerConnection.prototype.createDataChannel =\n    function createDataChannel() {\n      const dataChannel = origCreateDataChannel.apply(this, arguments);\n      wrapDcSend(dataChannel, this);\n      return dataChannel;\n    };\n  utils.wrapPeerConnectionEvent(window, 'datachannel', e => {\n    wrapDcSend(e.channel, e.target);\n    return e;\n  });\n}\n\n\n/* shims RTCConnectionState by pretending it is the same as iceConnectionState.\n * See https://bugs.chromium.org/p/webrtc/issues/detail?id=6145#c12\n * for why this is a valid hack in Chrome. In Firefox it is slightly incorrect\n * since DTLS failures would be hidden. See\n * https://bugzilla.mozilla.org/show_bug.cgi?id=1265827\n * for the Firefox tracking bug.\n */\nexport function shimConnectionState(window) {\n  if (!window.RTCPeerConnection ||\n      'connectionState' in window.RTCPeerConnection.prototype) {\n    return;\n  }\n  const proto = window.RTCPeerConnection.prototype;\n  Object.defineProperty(proto, 'connectionState', {\n    get() {\n      return {\n        completed: 'connected',\n        checking: 'connecting'\n      }[this.iceConnectionState] || this.iceConnectionState;\n    },\n    enumerable: true,\n    configurable: true\n  });\n  Object.defineProperty(proto, 'onconnectionstatechange', {\n    get() {\n      return this._onconnectionstatechange || null;\n    },\n    set(cb) {\n      if (this._onconnectionstatechange) {\n        this.removeEventListener('connectionstatechange',\n            this._onconnectionstatechange);\n        delete this._onconnectionstatechange;\n      }\n      if (cb) {\n        this.addEventListener('connectionstatechange',\n            this._onconnectionstatechange = cb);\n      }\n    },\n    enumerable: true,\n    configurable: true\n  });\n\n  ['setLocalDescription', 'setRemoteDescription'].forEach((method) => {\n    const origMethod = proto[method];\n    proto[method] = function() {\n      if (!this._connectionstatechangepoly) {\n        this._connectionstatechangepoly = e => {\n          const pc = e.target;\n          if (pc._lastConnectionState !== pc.connectionState) {\n            pc._lastConnectionState = pc.connectionState;\n            const newEvent = new Event('connectionstatechange', e);\n            pc.dispatchEvent(newEvent);\n          }\n          return e;\n        };\n        this.addEventListener('iceconnectionstatechange',\n          this._connectionstatechangepoly);\n      }\n      return origMethod.apply(this, arguments);\n    };\n  });\n}\n\nexport function removeExtmapAllowMixed(window, browserDetails) {\n  /* remove a=extmap-allow-mixed for webrtc.org < M71 */\n  if (!window.RTCPeerConnection) {\n    return;\n  }\n  if (browserDetails.browser === 'chrome' && browserDetails.version >= 71) {\n    return;\n  }\n  if (browserDetails.browser === 'safari' && browserDetails.version >= 605) {\n    return;\n  }\n  const nativeSRD = window.RTCPeerConnection.prototype.setRemoteDescription;\n  window.RTCPeerConnection.prototype.setRemoteDescription =\n  function setRemoteDescription(desc) {\n    if (desc && desc.sdp && desc.sdp.indexOf('\\na=extmap-allow-mixed') !== -1) {\n      const sdp = desc.sdp.split('\\n').filter((line) => {\n        return line.trim() !== 'a=extmap-allow-mixed';\n      }).join('\\n');\n      // Safari enforces read-only-ness of RTCSessionDescription fields.\n      if (window.RTCSessionDescription &&\n          desc instanceof window.RTCSessionDescription) {\n        arguments[0] = new window.RTCSessionDescription({\n          type: desc.type,\n          sdp,\n        });\n      } else {\n        desc.sdp = sdp;\n      }\n    }\n    return nativeSRD.apply(this, arguments);\n  };\n}\n\nexport function shimAddIceCandidateNullOrEmpty(window, browserDetails) {\n  // Support for addIceCandidate(null or undefined)\n  // as well as addIceCandidate({candidate: \"\", ...})\n  // https://bugs.chromium.org/p/chromium/issues/detail?id=978582\n  // Note: must be called before other polyfills which change the signature.\n  if (!(window.RTCPeerConnection && window.RTCPeerConnection.prototype)) {\n    return;\n  }\n  const nativeAddIceCandidate =\n      window.RTCPeerConnection.prototype.addIceCandidate;\n  if (!nativeAddIceCandidate || nativeAddIceCandidate.length === 0) {\n    return;\n  }\n  window.RTCPeerConnection.prototype.addIceCandidate =\n    function addIceCandidate() {\n      if (!arguments[0]) {\n        if (arguments[1]) {\n          arguments[1].apply(null);\n        }\n        return Promise.resolve();\n      }\n      // Firefox 68+ emits and processes {candidate: \"\", ...}, ignore\n      // in older versions.\n      // Native support for ignoring exists for Chrome M77+.\n      // Safari ignores as well, exact version unknown but works in the same\n      // version that also ignores addIceCandidate(null).\n      if (((browserDetails.browser === 'chrome' && browserDetails.version < 78)\n           || (browserDetails.browser === 'firefox'\n               && browserDetails.version < 68)\n           || (browserDetails.browser === 'safari'))\n          && arguments[0] && arguments[0].candidate === '') {\n        return Promise.resolve();\n      }\n      return nativeAddIceCandidate.apply(this, arguments);\n    };\n}\n\n// Note: Make sure to call this ahead of APIs that modify\n// setLocalDescription.length\nexport function shimParameterlessSetLocalDescription(window, browserDetails) {\n  if (!(window.RTCPeerConnection && window.RTCPeerConnection.prototype)) {\n    return;\n  }\n  const nativeSetLocalDescription =\n      window.RTCPeerConnection.prototype.setLocalDescription;\n  if (!nativeSetLocalDescription || nativeSetLocalDescription.length === 0) {\n    return;\n  }\n  window.RTCPeerConnection.prototype.setLocalDescription =\n    function setLocalDescription() {\n      let desc = arguments[0] || {};\n      if (typeof desc !== 'object' || (desc.type && desc.sdp)) {\n        return nativeSetLocalDescription.apply(this, arguments);\n      }\n      // The remaining steps should technically happen when SLD comes off the\n      // RTCPeerConnection's operations chain (not ahead of going on it), but\n      // this is too difficult to shim. Instead, this shim only covers the\n      // common case where the operations chain is empty. This is imperfect, but\n      // should cover many cases. Rationale: Even if we can't reduce the glare\n      // window to zero on imperfect implementations, there's value in tapping\n      // into the perfect negotiation pattern that several browsers support.\n      desc = {type: desc.type, sdp: desc.sdp};\n      if (!desc.type) {\n        switch (this.signalingState) {\n          case 'stable':\n          case 'have-local-offer':\n          case 'have-remote-pranswer':\n            desc.type = 'offer';\n            break;\n          default:\n            desc.type = 'answer';\n            break;\n        }\n      }\n      if (desc.sdp || (desc.type !== 'offer' && desc.type !== 'answer')) {\n        return nativeSetLocalDescription.apply(this, [desc]);\n      }\n      const func = desc.type === 'offer' ? this.createOffer : this.createAnswer;\n      return func.apply(this)\n        .then(d => nativeSetLocalDescription.apply(this, [d]));\n    };\n}\n","/*\n *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.\n *\n *  Use of this source code is governed by a BSD-style license\n *  that can be found in the LICENSE file in the root of the source\n *  tree.\n */\n/* eslint-env node */\n\n'use strict';\n\nimport {adapterFactory} from './adapter_factory.js';\n\nconst adapter =\n  adapterFactory({window: typeof window === 'undefined' ? undefined : window});\nexport default adapter;\n","/*\n *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.\n *\n *  Use of this source code is governed by a BSD-style license\n *  that can be found in the LICENSE file in the root of the source\n *  tree.\n */\nimport * as utils from './utils';\n\n  // Browser shims.\nimport * as chromeShim from './chrome/chrome_shim';\nimport * as firefoxShim from './firefox/firefox_shim';\nimport * as safariShim from './safari/safari_shim';\nimport * as commonShim from './common_shim';\nimport * as sdp from 'sdp';\n\n// Shimming starts here.\nexport function adapterFactory({window} = {}, options = {\n  shimChrome: true,\n  shimFirefox: true,\n  shimSafari: true,\n}) {\n  // Utils.\n  const logging = utils.log;\n  const browserDetails = utils.detectBrowser(window);\n\n  const adapter = {\n    browserDetails,\n    commonShim,\n    extractVersion: utils.extractVersion,\n    disableLog: utils.disableLog,\n    disableWarnings: utils.disableWarnings,\n    // Expose sdp as a convenience. For production apps include directly.\n    sdp,\n  };\n\n  // Shim browser if found.\n  switch (browserDetails.browser) {\n    case 'chrome':\n      if (!chromeShim || !chromeShim.shimPeerConnection ||\n          !options.shimChrome) {\n        logging('Chrome shim is not included in this adapter release.');\n        return adapter;\n      }\n      if (browserDetails.version === null) {\n        logging('Chrome shim can not determine version, not shimming.');\n        return adapter;\n      }\n      logging('adapter.js shimming chrome.');\n      // Export to the adapter global object visible in the browser.\n      adapter.browserShim = chromeShim;\n\n      // Must be called before shimPeerConnection.\n      commonShim.shimAddIceCandidateNullOrEmpty(window, browserDetails);\n      commonShim.shimParameterlessSetLocalDescription(window, browserDetails);\n\n      chromeShim.shimGetUserMedia(window, browserDetails);\n      chromeShim.shimMediaStream(window, browserDetails);\n      chromeShim.shimPeerConnection(window, browserDetails);\n      chromeShim.shimOnTrack(window, browserDetails);\n      chromeShim.shimAddTrackRemoveTrack(window, browserDetails);\n      chromeShim.shimGetSendersWithDtmf(window, browserDetails);\n      chromeShim.shimGetStats(window, browserDetails);\n      chromeShim.shimSenderReceiverGetStats(window, browserDetails);\n      chromeShim.fixNegotiationNeeded(window, browserDetails);\n\n      commonShim.shimRTCIceCandidate(window, browserDetails);\n      commonShim.shimConnectionState(window, browserDetails);\n      commonShim.shimMaxMessageSize(window, browserDetails);\n      commonShim.shimSendThrowTypeError(window, browserDetails);\n      commonShim.removeExtmapAllowMixed(window, browserDetails);\n      break;\n    case 'firefox':\n      if (!firefoxShim || !firefoxShim.shimPeerConnection ||\n          !options.shimFirefox) {\n        logging('Firefox shim is not included in this adapter release.');\n        return adapter;\n      }\n      logging('adapter.js shimming firefox.');\n      // Export to the adapter global object visible in the browser.\n      adapter.browserShim = firefoxShim;\n\n      // Must be called before shimPeerConnection.\n      commonShim.shimAddIceCandidateNullOrEmpty(window, browserDetails);\n      commonShim.shimParameterlessSetLocalDescription(window, browserDetails);\n\n      firefoxShim.shimGetUserMedia(window, browserDetails);\n      firefoxShim.shimPeerConnection(window, browserDetails);\n      firefoxShim.shimOnTrack(window, browserDetails);\n      firefoxShim.shimRemoveStream(window, browserDetails);\n      firefoxShim.shimSenderGetStats(window, browserDetails);\n      firefoxShim.shimReceiverGetStats(window, browserDetails);\n      firefoxShim.shimRTCDataChannel(window, browserDetails);\n      firefoxShim.shimAddTransceiver(window, browserDetails);\n      firefoxShim.shimGetParameters(window, browserDetails);\n      firefoxShim.shimCreateOffer(window, browserDetails);\n      firefoxShim.shimCreateAnswer(window, browserDetails);\n\n      commonShim.shimRTCIceCandidate(window, browserDetails);\n      commonShim.shimConnectionState(window, browserDetails);\n      commonShim.shimMaxMessageSize(window, browserDetails);\n      commonShim.shimSendThrowTypeError(window, browserDetails);\n      break;\n    case 'safari':\n      if (!safariShim || !options.shimSafari) {\n        logging('Safari shim is not included in this adapter release.');\n        return adapter;\n      }\n      logging('adapter.js shimming safari.');\n      // Export to the adapter global object visible in the browser.\n      adapter.browserShim = safariShim;\n\n      // Must be called before shimCallbackAPI.\n      commonShim.shimAddIceCandidateNullOrEmpty(window, browserDetails);\n      commonShim.shimParameterlessSetLocalDescription(window, browserDetails);\n\n      safariShim.shimRTCIceServerUrls(window, browserDetails);\n      safariShim.shimCreateOfferLegacy(window, browserDetails);\n      safariShim.shimCallbacksAPI(window, browserDetails);\n      safariShim.shimLocalStreamsAPI(window, browserDetails);\n      safariShim.shimRemoteStreamsAPI(window, browserDetails);\n      safariShim.shimTrackEventTransceiver(window, browserDetails);\n      safariShim.shimGetUserMedia(window, browserDetails);\n      safariShim.shimAudioContext(window, browserDetails);\n\n      commonShim.shimRTCIceCandidate(window, browserDetails);\n      commonShim.shimMaxMessageSize(window, browserDetails);\n      commonShim.shimSendThrowTypeError(window, browserDetails);\n      commonShim.removeExtmapAllowMixed(window, browserDetails);\n      break;\n    default:\n      logging('Unsupported browser!');\n      break;\n  }\n\n  return adapter;\n}\n","'use strict';\n\nmodule.exports = function () {\n  throw new Error(\n    'ws does not work in the browser. Browser clients must use the native ' +\n      'WebSocket object'\n  );\n};\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\tid: moduleId,\n\t\tloaded: false,\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n\t// Flag the module as loaded\n\tmodule.loaded = true;\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","__webpack_require__.amdO = {};","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.g = (function() {\n\tif (typeof globalThis === 'object') return globalThis;\n\ttry {\n\t\treturn this || new Function('return this')();\n\t} catch (e) {\n\t\tif (typeof window === 'object') return window;\n\t}\n})();","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","__webpack_require__.nmd = (module) => {\n\tmodule.paths = [];\n\tif (!module.children) module.children = [];\n\treturn module;\n};","// startup\n// Load entry module and return exports\n// This entry module used 'module' so it can't be inlined\nvar __webpack_exports__ = __webpack_require__(449);\n"],"names":["root","factory","exports","module","define","amd","self","Logger","LogCollector","logStorage","options","this","stringifyObjects","storeInterval","maxEntryLength","Object","keys","levels","forEach","logLevel","_log","apply","arguments","bind","storeLogsIntervalID","queue","totalLen","outputCache","prototype","stringify","someObject","JSON","error","formatLogMessage","msg","i","len","length","arg","ERROR","timestamp","prevMessage","prevMessageText","text","count","push","_flush","start","_reschedulePublishInterval","window","clearTimeout","setTimeout","flush","force","reschedule","isReady","cachedQueue","storeLogs","stop","consoleTransport","console","globalTransports","addGlobalTransport","transport","indexOf","removeGlobalTransport","transportIdx","splice","globalOptions","getCallerInfo","callerInfo","methodName","fileLocation","line","column","Error","stack","split","m","match","substr","log","logger","level","args","Array","slice","call","disableCallerInfo","transports","concat","t","l","logPrefixes","Date","toISOString","id","fullLogParts","methods","setGlobalOptions","setLevel","TRACE","DEBUG","INFO","LOG","WARN","idLoggers","loggers","curLevel","getLogger","getUntrackedLogger","setLogLevelById","setLogLevel","transform","transformUtils","parseSsrcs","writeSsrcs","getSsrcAttribute","mLine","ssrc","attributeName","ssrcs","filter","ssrcInfo","attribute","map","value","Simulcast","numOfLayers","ssrcCache","processVideo","session","action","isArray","media","type","validateDescription","desc","sdp","clearSsrcCache","setSsrcCache","_parseSimLayers","simGroup","ssrcGroups","find","group","semantics","ssrcStr","parseInt","_buildNewToOldSsrcMap","newSsrcList","oldSsrcList","ssrcMap","newSsrc","oldSsrc","_fillInSourceDataFromCache","newSimSsrcs","newMsid","newCname","ssrcsToReplace","ssrcsToAdd","values","join","_generateSourceData","primarySsrc","addAssociatedStream","primarySsrcCname","primarySsrcMsid","usesUnifiedPlan","msid","simSsrcs","simSsrc","Math","floor","random","_restoreSimulcast","numSsrcs","index","array","numGroups","fidGroup","mungeRemoteDescription","enableConferenceFlag","parse","explodeRemoteSimulcast","sources","order","j","simulcastSsrcs","parts","cname","relatedGroup","relatedSsrcs","relatedSSRC","simulcastGroup","info","nuke","implodeRemoteSimulcast","invalid","some","assertGoogConference","xGoogleFlag","undefined","removeGoogConference","RTCSessionDescription","write","mungeLocalDescription","direction","source","grammar","v","name","reg","o","names","format","s","u","e","p","z","r","c","b","a","rate","address","subtype","config","sessionConfig","str","raddr","tcptype","generation","maxMessageSize","RegExp","dir2","key","obj","parser","writer","parseFmtpConfig","parseParams","parsePayloads","parseRemoteCandidates","parseImageAttributes","parseSimulcastStreamList","toIntIfInt","String","Number","parseReg","location","content","needsBlank","keyLocation","rawName","attachProperties","validLine","test","rtp","fmtp","paramReducer","acc","expr","reduce","candidates","component","ip","port","item","substring","stream","scid","paused","formatRegExp","formatStr","replace","x","makeLine","Function","n","defaultOuterOrder","defaultInnerOrder","opts","version","payloads","outerOrder","innerOrder","el","freeze","object","oc","MIME_TYPE","HTML","isHTML","XML_APPLICATION","XML_TEXT","XML_XHTML_APPLICATION","XML_SVG_IMAGE","NAMESPACE","uri","SVG","XML","XMLNS","conventions","dom","entities","sax","DOMImplementation","ParseError","XMLReader","DOMParser","locator","DOMHandler","cdata","position","node","lineNumber","columnNumber","_locator","systemId","_toString","chars","java","lang","appendElement","hander","currentElement","appendChild","doc","parseFromString","mimeType","domBuilder","errorHandler","defaultNSMap","xmlns","entityMap","HTML_ENTITIES","XML_ENTITIES","setDocumentLocator","errorImpl","isCallback","build","fn","buildErrorHandler","xml","startDocument","createDocument","documentURI","startElement","namespaceURI","localName","qName","attrs","createElementNS","getURI","getValue","attr","getQName","createAttributeNS","getLocator","nodeValue","setAttributeNode","endElement","current","tagName","parentNode","startPrefixMapping","prefix","endPrefixMapping","processingInstruction","target","data","ins","createProcessingInstruction","ignorableWhitespace","ch","characters","charNode","createCDATASection","createTextNode","skippedEntity","endDocument","normalize","comment","comm","createComment","startCDATA","endCDATA","startDTD","publicId","impl","implementation","createDocumentType","dt","doctype","warning","warn","fatalError","XMLSerializer","notEmptyString","input","orderedSetReducer","element","hasOwnProperty","toOrderedSet","list","splitOnASCIIWhitespace","copy","src","dest","_extends","Class","Super","pt","constructor","NodeType","ELEMENT_NODE","ATTRIBUTE_NODE","TEXT_NODE","CDATA_SECTION_NODE","ENTITY_REFERENCE_NODE","ENTITY_NODE","PROCESSING_INSTRUCTION_NODE","COMMENT_NODE","DOCUMENT_NODE","DOCUMENT_TYPE_NODE","DOCUMENT_FRAGMENT_NODE","NOTATION_NODE","ExceptionCode","ExceptionMessage","HIERARCHY_REQUEST_ERR","INDEX_SIZE_ERR","DOMSTRING_SIZE_ERR","NOT_FOUND_ERR","WRONG_DOCUMENT_ERR","INVALID_CHARACTER_ERR","NO_DATA_ALLOWED_ERR","NO_MODIFICATION_ALLOWED_ERR","INUSE_ATTRIBUTE_ERR","NOT_SUPPORTED_ERR","DOMException","code","message","captureStackTrace","NodeList","LiveNodeList","refresh","_node","_refresh","_updateLiveList","inc","_inc","ownerDocument","ls","__set__","NamedNodeMap","_findNodeIndex","_addNamedNode","newAttr","oldAttr","ownerElement","_onRemoveAttribute","_nsMap","_onAddAttribute","_removeNamedNode","lastIndex","Node","_xmlEncoder","charCodeAt","_visitNode","callback","firstChild","nextSibling","Document","remove","_onUpdateChild","newChild","cs","childNodes","child","_removeChild","previous","previousSibling","next","lastChild","_insertBefore","nextChild","cp","removeChild","nodeType","newFirst","newLast","pre","Element","Attr","CharacterData","Text","Comment","CDATASection","DocumentType","Notation","Entity","EntityReference","DocumentFragment","ProcessingInstruction","nodeSerializeToString","isHtml","nodeFilter","buf","refNode","documentElement","lookupPrefix","visibleNamespaces","namespace","serializeToString","needNamespaceDefine","ns","addSerializedAttribute","qualifiedName","attributes","nodeName","prefixedNodeName","defaultNS","ai","nsi","pubid","sysid","sub","internalSubset","importNode","deep","node2","cloneNode","attrs2","_ownerElement","INVALID_STATE_ERR","SYNTAX_ERR","INVALID_MODIFICATION_ERR","NAMESPACE_ERR","INVALID_ACCESS_ERR","toString","getNamedItem","setNamedItem","setNamedItemNS","getNamedItemNS","removeNamedItem","removeNamedItemNS","hasFeature","feature","insertBefore","refChild","replaceChild","oldChild","hasChildNodes","appendData","isSupported","hasAttributes","lookupNamespaceURI","isDefaultNamespace","importedNode","getElementById","rtv","getAttribute","getElementsByClassName","classNames","classNamesSet","base","nodeClassNames","matches","nodeClassNamesSet","every","createElement","createDocumentFragment","createAttribute","specified","createEntityReference","pl","hasAttribute","getAttributeNode","setAttribute","removeAttribute","removeAttributeNode","_appendSingleChild","setAttributeNodeNS","removeAttributeNS","old","getAttributeNodeNS","hasAttributeNS","getAttributeNS","setAttributeNS","getElementsByTagName","getElementsByTagNameNS","substringData","offset","insertData","replaceData","deleteData","splitText","newText","newNode","defineProperty","getTextContent","get","$$length","set","amp","apos","gt","lt","quot","Agrave","Aacute","Acirc","Atilde","Auml","Aring","AElig","Ccedil","Egrave","Eacute","Ecirc","Euml","Igrave","Iacute","Icirc","Iuml","ETH","Ntilde","Ograve","Oacute","Ocirc","Otilde","Ouml","Oslash","Ugrave","Uacute","Ucirc","Uuml","Yacute","THORN","szlig","agrave","aacute","acirc","atilde","auml","aring","aelig","ccedil","egrave","eacute","ecirc","euml","igrave","iacute","icirc","iuml","eth","ntilde","ograve","oacute","ocirc","otilde","ouml","oslash","ugrave","uacute","ucirc","uuml","yacute","thorn","yuml","nbsp","iexcl","cent","pound","curren","yen","brvbar","sect","uml","ordf","laquo","not","shy","macr","deg","plusmn","sup2","sup3","acute","micro","para","middot","cedil","sup1","ordm","raquo","frac14","frac12","frac34","iquest","times","divide","forall","part","exist","empty","nabla","isin","notin","ni","prod","sum","minus","lowast","radic","prop","infin","ang","and","or","cap","cup","there4","sim","cong","asymp","ne","equiv","le","ge","sup","nsub","sube","supe","oplus","otimes","perp","sdot","Alpha","Beta","Gamma","Delta","Epsilon","Zeta","Eta","Theta","Iota","Kappa","Lambda","Mu","Nu","Xi","Omicron","Pi","Rho","Sigma","Tau","Upsilon","Phi","Chi","Psi","Omega","alpha","beta","gamma","delta","epsilon","zeta","eta","theta","iota","kappa","lambda","mu","nu","xi","omicron","pi","rho","sigmaf","sigma","tau","upsilon","phi","chi","psi","omega","thetasym","upsih","piv","OElig","oelig","Scaron","scaron","Yuml","fnof","circ","tilde","ensp","emsp","thinsp","zwnj","zwj","lrm","rlm","ndash","mdash","lsquo","rsquo","sbquo","ldquo","rdquo","bdquo","dagger","Dagger","bull","hellip","permil","prime","Prime","lsaquo","rsaquo","oline","euro","trade","larr","uarr","rarr","darr","harr","crarr","lceil","rceil","lfloor","rfloor","loz","spades","clubs","hearts","diams","nameStartChar","nameChar","tagNamePattern","copyLocator","f","parseElementStartPart","currentNSMap","entityReplacer","addAttribute","qname","startIndex","attributeNames","addValue","attrName","charAt","setTagName","closed","localNSMap","nsp","nsPrefix","_copy","parseHtmlSpecialContent","elStartEnd","elEndStart","fixSelfClosed","closeMap","pos","lastIndexOf","parseDCC","end","matchs","exec","lastMatch","endDTD","parseInstruction","ElementAttributes","defaultNSMapCopy","k","surrogate1","surrogate2","fromCharCode","fixedFromCharCode","appendText","xt","lineEnd","linePattern","lineStart","parseStack","tagStart","pop","endMatch","toLowerCase","locator2","max","getLocalName","getTokenAuthUrl","urlPattern","roomName","roleUpgrade","EventEmitterForwarder","addListener","emit","forward","srcEvent","handlers","oldOnErrorHandler","onerror","oldOnUnhandledRejection","onunhandledrejection","handler","event","reason","GlobalOnErrorHandler","addHandler","callErrorHandler","errHandler","callUnhandledRejectionHandler","randomInt","min","randomElement","arr","RandomUtil","randomHexDigit","randomHexString","ret","randomAlphanumStr","result","currentExecutingScript","require","ScriptUtil","loadScript","async","prepend","relativeURL","loadCallback","errorCallback","d","document","script","referenceNode","scriptEl","scriptSrc","baseScriptSrc","onload","integerHash","string","char","hash","pow","abs","generateUsername","RTCEvents","CREATE_ANSWER_FAILED","CREATE_OFFER_FAILED","DATA_CHANNEL_OPEN","ENDPOINT_CONN_STATUS_CHANGED","DOMINANT_SPEAKER_CHANGED","LASTN_ENDPOINT_CHANGED","FORWARDED_SOURCES_CHANGED","PERMISSIONS_CHANGED","SENDER_VIDEO_CONSTRAINTS_CHANGED","LASTN_VALUE_CHANGED","LOCAL_TRACK_SSRC_UPDATED","LOCAL_TRACK_MAX_ENABLED_RESOLUTION_CHANGED","TRACK_ATTACHED","REMOTE_TRACK_ADDED","REMOTE_TRACK_MUTE","REMOTE_TRACK_REMOVED","REMOTE_TRACK_UNMUTE","SET_LOCAL_DESCRIPTION_FAILED","SET_REMOTE_DESCRIPTION_FAILED","AUDIO_OUTPUT_DEVICE_CHANGED","DEVICE_LIST_CHANGED","DEVICE_LIST_WILL_CHANGE","DEVICE_LIST_AVAILABLE","ENDPOINT_MESSAGE_RECEIVED","ENDPOINT_STATS_RECEIVED","LOCAL_UFRAG_CHANGED","REMOTE_UFRAG_CHANGED","Resolutions","width","height","VideoType","AuthenticationEvents","IDENTITY_UPDATED","XMPPEvents","byteLength","b64","lens","getLens","validLen","placeHoldersLen","toByteArray","tmp","Arr","_byteLength","curByte","revLookup","fromByteArray","uint8","extraBytes","maxChunkLength","len2","encodeChunk","lookup","Uint8Array","num","output","enumerable","Symbol","toStringTag","__esModule","create","default","getFirstMatch","getSecondMatch","matchAndReturnConst","getWindowsVersionName","getMacOSVersionName","getAndroidVersionName","getVersionPrecision","compareVersions","reverse","getBrowserAlias","BROWSER_ALIASES_MAP","getBrowserTypeByAlias","BROWSER_MAP","ENGINE_MAP","OS_MAP","PLATFORMS_MAP","Bada","BlackBerry","Chrome","Chromium","Epiphany","Firefox","Focus","Generic","Googlebot","Maxthon","Opera","PhantomJS","Puffin","QupZilla","QQ","QQLite","Safari","Sailfish","SeaMonkey","Sleipnir","Swing","Tizen","Vivaldi","WeChat","Roku","amazon_silk","android","bada","blackberry","chrome","chromium","epiphany","firefox","focus","generic","googlebot","google_search","ie","k_meleon","maxthon","edge","mz","naver","opera","opera_coast","phantomjs","puffin","qupzilla","qq","qqlite","safari","sailfish","samsung_internet","seamonkey","sleipnir","swing","tizen","uc","vivaldi","webos","wechat","yandex","tablet","mobile","desktop","tv","WindowsPhone","Windows","MacOS","iOS","Android","WebOS","Linux","ChromeOS","PlayStation4","EdgeHTML","Blink","Trident","Presto","Gecko","WebKit","configurable","writable","getParser","getResult","_ua","parsedResult","getUA","parseBrowser","browser","describe","getBrowser","getBrowserName","getBrowserVersion","getOS","os","parseOS","getOSName","getOSVersion","getPlatform","platform","parsePlatform","getPlatformType","getEngine","engine","parseEngine","getEngineName","assign","satisfies","isOS","isPlatform","isBrowser","compareVersion","isEngine","is","search","versionName","vendor","model","scriptReadyRegex","fullPageUrl","href","pageUrl","scripts","supportsScriptReadyState","isNotOpera","hasNativeCurrentScriptAccessor","stackTraceLimit","Infinity","hasStackBeforeThrowing","hasStackAfterThrowing","getScriptUrlFromStack","skipStackDepth","url","ignoreMessage","round","_nearestExecutingScript","eligibleScripts","readyState","err","getScriptFromUrl","getSoleInlineScript","currentScript","thrownErr","near","far","origin","ReflectOwnKeys","R","Reflect","ReflectApply","receiver","ownKeys","getOwnPropertySymbols","getOwnPropertyNames","NumberIsNaN","isNaN","EventEmitter","init","once","emitter","Promise","resolve","reject","errorListener","removeListener","resolver","eventTargetAgnosticAddListener","flags","on","addErrorHandlerIfEventEmitter","_events","_eventsCount","_maxListeners","defaultMaxListeners","checkListener","listener","TypeError","_getMaxListeners","that","_addListener","events","existing","newListener","unshift","warned","w","onceWrapper","fired","wrapFn","_onceWrap","state","wrapped","_listeners","unwrap","evlistener","unwrapListeners","arrayClone","listenerCount","addEventListener","wrapListener","removeEventListener","RangeError","getPrototypeOf","setMaxListeners","getMaxListeners","doError","er","context","listeners","prependListener","prependOnceListener","originalListener","shift","spliceOne","off","removeAllListeners","rawListeners","eventNames","global","noGlobal","getProto","flat","class2type","hasOwn","fnToString","ObjectFunctionString","support","isFunction","isWindow","preservedScriptAttributes","nonce","noModule","DOMEval","val","head","toType","jQuery","selector","isArrayLike","jquery","toArray","pushStack","elems","merge","prevObject","each","elem","first","eq","last","even","grep","_elem","odd","sort","extend","copyIsArray","clone","isPlainObject","expando","noop","proto","Ctor","isEmptyObject","globalEval","makeArray","results","inArray","second","invert","callbackExpect","guid","iterator","_i","Sizzle","Expr","getText","isXML","tokenize","compile","select","outermostContext","sortInput","hasDuplicate","setDocument","docElem","documentIsHTML","rbuggyQSA","rbuggyMatches","contains","preferredDoc","dirruns","done","classCache","createCache","tokenCache","compilerCache","nonnativeSelectorCache","sortOrder","pushNative","booleans","whitespace","identifier","pseudos","rwhitespace","rtrim","rcomma","rcombinators","rdescend","rpseudo","ridentifier","matchExpr","rhtml","rinputs","rheader","rnative","rquickExpr","rsibling","runescape","funescape","escape","nonHex","high","rcssescape","fcssescape","asCodePoint","unloadHandler","inDisabledFieldset","addCombinator","disabled","dir","els","seed","nid","groups","newSelector","newContext","qsa","testContext","scope","toSelector","querySelectorAll","qsaError","cache","cacheLength","markFunction","assert","addHandle","attrHandle","siblingCheck","cur","diff","sourceIndex","createInputPseudo","createButtonPseudo","createDisabledPseudo","isDisabled","createPositionalPseudo","argument","matchIndexes","hasCompare","subWindow","defaultView","top","attachEvent","className","getById","getElementsByName","attrId","tag","innerHTML","matchesSelector","webkitMatchesSelector","mozMatchesSelector","oMatchesSelector","msMatchesSelector","disconnectedMatch","compareDocumentPosition","adown","bup","compare","sortDetached","aup","ap","bp","elements","sel","uniqueSort","duplicates","detectDuplicates","sortStable","textContent","selectors","createPseudo","relative","preFilter","excess","unquoted","nodeNameSelector","pattern","operator","check","what","_argument","simple","ofType","_context","uniqueCache","outerCache","nodeIndex","parent","useCache","uniqueID","pseudo","setFilters","idx","matched","matcher","unmatched","elemLang","activeElement","hasFocus","tabIndex","checked","selected","selectedIndex","_matchIndexes","radio","checkbox","file","password","image","submit","reset","tokens","combinator","skip","checkNonElements","doneName","oldCache","newCache","elementMatcher","matchers","condense","newUnmatched","mapped","setMatcher","postFilter","postFinder","postSelector","temp","preMap","postMap","preexisting","contexts","multipleContexts","matcherIn","matcherOut","matcherFromTokens","checkContext","leadingRelative","implicitRelative","matchContext","matchAnyContext","filters","parseOnly","soFar","preFilters","cached","setMatchers","elementMatchers","bySet","byElement","superMatcher","outermost","matchedCount","setMatched","contextBackup","dirrunsUnique","matcherFromGroupMatchers","token","compiled","_name","defaultValue","unique","isXMLDoc","escapeSelector","until","truncate","siblings","rneedsContext","needsContext","rsingleTag","winnow","qualifier","rootjQuery","parseHTML","ready","rparentsprev","guaranteedUnique","children","contents","prev","sibling","has","targets","closest","prevAll","add","addBack","parents","parentsUntil","nextAll","nextUntil","prevUntil","contentDocument","rnothtmlwhite","Identity","Thrower","ex","adoptValue","noValue","method","promise","fail","then","Callbacks","_","flag","createOptions","firing","memory","locked","firingIndex","fire","stopOnFalse","disable","lock","fireWith","Deferred","func","tuples","always","deferred","pipe","fns","newDefer","tuple","returned","progress","notify","onFulfilled","onRejected","onProgress","maxDepth","depth","special","mightThrow","notifyWith","resolveWith","process","exceptionHook","stackTrace","rejectWith","getStackHook","stateString","when","singleValue","remaining","resolveContexts","resolveValues","primary","updateFunc","rerrorNames","readyException","readyList","completed","catch","readyWait","wait","doScroll","access","chainable","emptyGet","raw","bulk","_key","rmsPrefix","rdashAlpha","fcamelCase","_all","letter","toUpperCase","camelCase","acceptData","owner","Data","uid","hasData","dataPriv","dataUser","rbrace","rmultiDash","dataAttr","getData","removeData","_data","_removeData","dequeue","startLength","hooks","_queueHooks","setter","clearQueue","defer","pnum","rcssNum","cssExpand","isAttached","composed","getRootNode","isHiddenWithinTree","style","display","css","defaultDisplayMap","getDefaultDisplay","body","showHide","show","hide","toggle","div","rcheckableType","rtagName","rscriptType","checkClone","noCloneChecked","option","wrapMap","thead","col","tr","td","_default","getAll","setGlobalEval","refElements","tbody","tfoot","colgroup","caption","th","optgroup","buildFragment","selection","ignored","wrap","attached","fragment","nodes","htmlPrefilter","rtypenamespace","returnTrue","returnFalse","expectSync","safeActiveElement","types","one","origFn","leverageNative","notAsync","saved","isTrigger","delegateType","stopPropagation","stopImmediatePropagation","preventDefault","trigger","Event","handleObjIn","eventHandle","handleObj","namespaces","origType","elemData","handle","triggered","dispatch","bindType","delegateCount","setup","mappedTypes","origCount","teardown","removeEvent","nativeEvent","handlerQueue","fix","delegateTarget","preDispatch","isPropagationStopped","currentTarget","isImmediatePropagationStopped","rnamespace","postDispatch","matchedHandlers","matchedSelectors","button","addProp","hook","originalEvent","load","noBubble","click","beforeunload","returnValue","props","isDefaultPrevented","defaultPrevented","relatedTarget","timeStamp","now","isSimulated","altKey","bubbles","cancelable","changedTouches","ctrlKey","detail","eventPhase","metaKey","pageX","pageY","shiftKey","view","charCode","keyCode","buttons","clientX","clientY","offsetX","offsetY","pointerId","pointerType","screenX","screenY","targetTouches","toElement","touches","which","blur","mouseenter","mouseleave","pointerenter","pointerleave","orig","related","rnoInnerhtml","rchecked","rcleanScript","manipulationTarget","disableScript","restoreScript","cloneCopyEvent","udataOld","udataCur","fixInput","domManip","collection","hasScripts","iNoClone","valueIsFunction","html","_evalUrl","keepData","cleanData","dataAndEvents","deepDataAndEvents","srcElements","destElements","inPage","detach","append","before","after","replaceWith","appendTo","prependTo","insertAfter","replaceAll","original","insert","rnumnonpx","getStyles","opener","getComputedStyle","swap","rboxStyle","curCSS","computed","minWidth","maxWidth","getPropertyValue","pixelBoxStyles","addGetHookIf","conditionFn","hookFn","computeStyleTests","container","cssText","divStyle","pixelPositionVal","reliableMarginLeftVal","roundPixelMeasures","marginLeft","right","pixelBoxStylesVal","boxSizingReliableVal","scrollboxSizeVal","offsetWidth","measure","parseFloat","reliableTrDimensionsVal","backgroundClip","clearCloneStyle","boxSizingReliable","pixelPosition","reliableMarginLeft","scrollboxSize","reliableTrDimensions","table","trChild","trStyle","borderTopWidth","borderBottomWidth","offsetHeight","cssPrefixes","emptyStyle","vendorProps","finalPropName","cssProps","capName","vendorPropName","rdisplayswap","rcustomProp","cssShow","visibility","cssNormalTransform","letterSpacing","fontWeight","setPositiveNumber","subtract","boxModelAdjustment","dimension","box","isBorderBox","styles","computedVal","extra","ceil","getWidthOrHeight","valueIsBorderBox","offsetProp","getClientRects","cssHooks","opacity","cssNumber","origName","isCustomProp","valueParts","tween","adjusted","scale","maxIterations","currentValue","initial","unit","initialInUnit","adjustCSS","setProperty","isFinite","getBoundingClientRect","scrollboxSizeBuggy","left","margin","padding","border","suffix","expand","expanded","delay","time","fx","speeds","timeout","opt","checkOn","optSelected","radioValue","boolHook","removeAttr","nType","attrHooks","bool","attrNames","getter","lowercaseName","rfocusable","rclickable","stripAndCollapse","getClass","classesToArray","removeProp","propFix","propHooks","tabindex","addClass","classes","curValue","clazz","finalValue","removeClass","toggleClass","stateVal","isValidValue","hasClass","rreturn","valHooks","optionSet","focusin","rfocusMorph","stopPropagationCallback","onlyHandlers","bubbleType","ontype","lastElement","eventPath","parentWindow","simulate","triggerHandler","attaches","parseXML","parserErrorElem","rbracket","rCRLF","rsubmitterTypes","rsubmittable","buildParams","traditional","param","valueOrFunction","encodeURIComponent","serialize","serializeArray","wrapAll","firstElementChild","wrapInner","htmlIsFunction","hidden","visible","createHTMLDocument","keepScripts","parsed","setOffset","curPosition","curLeft","curCSSTop","curTop","curOffset","curCSSLeft","curElem","using","rect","win","pageYOffset","pageXOffset","offsetParent","parentOffset","scrollLeft","scrollTop","scrollTo","Height","Width","defaultExtra","funcName","unbind","delegate","undelegate","hover","fnOver","fnOut","proxy","holdReady","hold","parseJSON","isNumeric","trim","_jQuery","_$","$","noConflict","WINDOW","JS_MD5_NO_WINDOW","WEB_WORKER","NODE_JS","JS_MD5_NO_NODE_JS","versions","g","COMMON_JS","JS_MD5_NO_COMMON_JS","AMD","ARRAY_BUFFER","JS_MD5_NO_ARRAY_BUFFER","ArrayBuffer","HEX_CHARS","EXTRA","SHIFT","OUTPUT_TYPES","BASE64_ENCODE_CHAR","blocks","buffer8","buffer","Uint32Array","JS_MD5_NO_ARRAY_BUFFER_IS_VIEW","isView","createOutputMethod","outputType","Md5","update","createMethod","nodeWrap","crypto","eval","Buffer","nodeMethod","createHash","digest","sharedMemory","h0","h1","h2","h3","bytes","hBytes","finalized","hashed","notString","lastByteIndex","finalize","bc","da","hex","arrayBuffer","base64","v1","v2","v3","base64Str","md5","HASH_UNDEFINED","MAX_SAFE_INTEGER","argsTag","boolTag","dateTag","funcTag","genTag","mapTag","numberTag","objectTag","promiseTag","regexpTag","setTag","stringTag","symbolTag","weakMapTag","arrayBufferTag","dataViewTag","float32Tag","float64Tag","int8Tag","int16Tag","int32Tag","uint8Tag","uint8ClampedTag","uint16Tag","uint32Tag","reFlags","reIsHostCtor","reIsUint","cloneableTags","freeGlobal","freeSelf","freeExports","freeModule","moduleExports","addMapEntry","pair","addSetEntry","arrayReduce","iteratee","accumulator","initAccum","isHostObject","mapToArray","size","overArg","setToArray","arrayProto","funcProto","objectProto","coreJsData","maskSrcKey","IE_PROTO","funcToString","objectToString","reIsNative","getPrototype","objectCreate","propertyIsEnumerable","nativeGetSymbols","nativeIsBuffer","isBuffer","nativeKeys","DataView","getNative","Map","Set","WeakMap","nativeCreate","dataViewCtorString","toSource","mapCtorString","promiseCtorString","setCtorString","weakMapCtorString","symbolProto","symbolValueOf","valueOf","Hash","entries","clear","entry","ListCache","MapCache","Stack","__data__","assignValue","objValue","assocIndexOf","baseClone","isDeep","isFull","customizer","isObject","isArr","initCloneArray","copyArray","getTag","isFunc","cloneBuffer","isPrototype","initCloneObject","copyObject","getSymbols","copySymbols","baseAssign","cloneFunc","symbol","cloneArrayBuffer","dataView","byteOffset","cloneDataView","typedArray","cloneTypedArray","cloneMap","regexp","cloneRegExp","cloneSet","initCloneByTag","stacked","keysFunc","symbolsFunc","arrayPush","baseGetAllKeys","getAllKeys","arrayEach","subValue","newValue","getMapData","baseIsNative","pairs","LARGE_ARRAY_SIZE","isIndex","other","ctorString","isLength","inherited","isObjectLike","isArrayLikeObject","isArguments","baseTimes","skipIndexes","arrayLikeKeys","baseKeys","reTrim","reIsBadHex","reIsBinary","reIsOctal","freeParseInt","nativeMax","nativeMin","toNumber","isSymbol","isBinary","lastArgs","lastThis","maxWait","timerId","lastCallTime","lastInvokeTime","leading","maxing","trailing","invokeFunc","thisArg","leadingEdge","timerExpired","shouldInvoke","timeSinceLastCall","trailingEdge","remainingWait","debounced","isInvoking","cancel","arrayTag","errorTag","typedArrayTags","freeProcess","nodeUtil","binding","nodeIsTypedArray","isTypedArray","arraySome","predicate","nativeObjectToString","symToStringTag","SetCache","baseGetTag","isOwn","unmasked","getRawTag","baseIsArguments","baseIsEqual","bitmask","equalFunc","objIsArr","othIsArr","objTag","othTag","objIsObj","othIsObj","isSameTag","equalArrays","convert","isPartial","equalByTag","objIsWrapped","othIsWrapped","objUnwrapped","othUnwrapped","objProps","objLength","skipCtor","othValue","compared","objCtor","othCtor","equalObjects","baseIsEqualDeep","arrLength","othLength","seen","arrValue","othIndex","isMasked","resIndex","arrayFilter","baseUnary","isArg","isBuff","isType","clksrcExt","mediaClockValue","rateNumerator","rateDenominator","SDPUtils","localCName","generateIdentifier","splitLines","blob","splitSections","getDescription","sections","getMediaSections","matchPrefix","parseCandidate","candidate","foundation","protocol","priority","relatedAddress","relatedPort","tcpType","ufrag","usernameFragment","writeCandidate","parseIceOptions","parseRtpMap","payloadType","clockRate","channels","numChannels","writeRtpMap","codec","preferredPayloadType","parseExtmap","writeExtmap","headerExtension","preferredId","parseFmtp","kv","writeFmtp","parameters","params","parseRtcpFb","parameter","writeRtcpFb","lines","rtcpFeedback","fb","parseSsrcMedia","sp","colon","parseSsrcGroup","getMid","mediaSection","mid","parseFingerprint","algorithm","getDtlsParameters","sessionpart","role","fingerprints","writeDtlsParameters","setupType","fp","parseCryptoLine","cryptoSuite","keyParams","sessionParams","writeCryptoLine","writeCryptoKeyParams","parseCryptoKeyParams","keyMethod","keySalt","lifeTime","mkiValue","mkiLength","getCryptoParameters","getIceParameters","pwd","writeIceParameters","iceLite","parseRtpParameters","description","codecs","headerExtensions","fecMechanisms","rtcp","mline","rtpmapline","fmtps","writeRtpDescription","kind","caps","maxptime","extension","parseRtpEncodingParameters","encodingParameters","hasRed","hasUlpfec","secondarySsrc","flows","apt","encParam","codecPayloadType","rtx","fec","mechanism","bandwidth","maxBitrate","parseRtcpParameters","rtcpParameters","remoteSsrc","rsize","reducedSize","compound","mux","writeRtcpParameters","parseMsid","spec","track","planB","msidParts","parseSctpDescription","parseMLine","maxSizeLine","sctpPort","fmt","sctpMapLines","writeSctpDescription","sctp","generateSessionId","writeSessionBoilerplate","sessId","sessVer","sessUser","sessionId","getDirection","getKind","isRejected","parseOLine","username","sessionVersion","netType","addressType","isValidSDP","JitsiConferenceErrors","AUTHENTICATION_REQUIRED","CHAT_ERROR","SETTINGS_ERROR","CONFERENCE_DESTROYED","CONFERENCE_MAX_USERS","CONNECTION_ERROR","CONFERENCE_RESTARTED","NOT_ALLOWED_ERROR","MEMBERS_ONLY_ERROR","CONFERENCE_ACCESS_DENIED","FOCUS_DISCONNECTED","FOCUS_LEFT","GRACEFUL_SHUTDOWN","ICE_FAILED","INCOMPATIBLE_SERVER_VERSIONS","OFFER_ANSWER_FAILED","PASSWORD_NOT_SUPPORTED","PASSWORD_REQUIRED","RESERVATION_ERROR","VIDEOBRIDGE_NOT_AVAILABLE","JitsiConferenceEvents","AUDIO_INPUT_STATE_CHANGE","AUDIO_UNMUTE_PERMISSIONS_CHANGED","AUTH_STATUS_CHANGED","BEFORE_STATISTICS_DISPOSED","CONFERENCE_ERROR","CONFERENCE_FAILED","CONFERENCE_JOIN_IN_PROGRESS","CONFERENCE_JOINED","CONFERENCE_LEFT","CONFERENCE_UNIQUE_ID_SET","CONNECTION_ESTABLISHED","CONNECTION_INTERRUPTED","CONNECTION_RESTORED","DATA_CHANNEL_OPENED","DISPLAY_NAME_CHANGED","CONFERENCE_CREATED_TIMESTAMP","DTMF_SUPPORT_CHANGED","JVB121_STATUS","KICKED","PARTICIPANT_KICKED","LAST_N_ENDPOINTS_CHANGED","LOCK_STATE_CHANGED","SERVER_REGION_CHANGED","_MEDIA_SESSION_STARTED","_MEDIA_SESSION_ACTIVE_CHANGED","MEMBERS_ONLY_CHANGED","MESSAGE_RECEIVED","NO_AUDIO_INPUT","NOISY_MIC","NON_PARTICIPANT_MESSAGE_RECEIVED","PRIVATE_MESSAGE_RECEIVED","PARTICIPANT_CONN_STATUS_CHANGED","PARTCIPANT_FEATURES_CHANGED","PARTICIPANT_PROPERTY_CHANGED","P2P_STATUS","PHONE_NUMBER_CHANGED","PROPERTIES_CHANGED","RECORDER_STATE_CHANGED","VIDEO_SIP_GW_AVAILABILITY_CHANGED","VIDEO_SIP_GW_SESSION_STATE_CHANGED","START_MUTED_POLICY_CHANGED","STARTED_MUTED","SUBJECT_CHANGED","SUSPEND_DETECTED","TALK_WHILE_MUTED","TRACK_ADDED","TRACK_AUDIO_LEVEL_CHANGED","TRACK_MUTE_CHANGED","TRACK_REMOVED","TRACK_UNMUTE_REJECTED","TRANSCRIPTION_STATUS_CHANGED","USER_JOINED","USER_LEFT","USER_ROLE_CHANGED","USER_STATUS_CHANGED","VIDEO_UNMUTE_PERMISSIONS_CHANGED","BOT_TYPE_CHANGED","LOBBY_USER_JOINED","LOBBY_USER_UPDATED","LOBBY_USER_LEFT","AV_MODERATION_APPROVED","AV_MODERATION_REJECTED","AV_MODERATION_CHANGED","AV_MODERATION_PARTICIPANT_APPROVED","AV_MODERATION_PARTICIPANT_REJECTED","FACIAL_EXPRESSION_ADDED","BREAKOUT_ROOMS_MOVE_TO_ROOM","BREAKOUT_ROOMS_UPDATED","CALLSTATS_SCRIPT_URL","JitsiTrackErrors","CONSTRAINT_FAILED","ELECTRON_DESKTOP_PICKER_ERROR","ELECTRON_DESKTOP_PICKER_NOT_FOUND","GENERAL","NOT_FOUND","PERMISSION_DENIED","SCREENSHARING_GENERIC_ERROR","SCREENSHARING_USER_CANCELED","TIMEOUT","TRACK_IS_DISPOSED","TRACK_NO_STREAM_FOUND","UNSUPPORTED_RESOLUTION","TRACK_ERROR_TO_MESSAGE_MAP","JitsiTrackError","devices","gum","constraints","constraintName","constraint","video","failedConstraintName","mandatory","minHeight","getResolutionFromFailedConstraint","AnalyticsEvents","TYPE_OPERATIONAL","TYPE_PAGE","TYPE_TRACK","TYPE_UI","ACTION_JINGLE_RESTART","ACTION_JINGLE_SA_TIMEOUT","ACTION_JINGLE_SI_RECEIVED","ACTION_JINGLE_SI_TIMEOUT","ACTION_JINGLE_TERMINATE","ACTION_JINGLE_TR_RECEIVED","ACTION_JINGLE_TR_SUCCESS","ACTION_P2P_DECLINED","ACTION_P2P_ESTABLISHED","ACTION_P2P_FAILED","ACTION_P2P_SWITCH_TO_JVB","AVAILABLE_DEVICE","CONNECTION_DISCONNECTED","FEEDBACK","ICE_DURATION","ICE_ESTABLISHMENT_DURATION_DIFF","ICE_STATE_CHANGED","NO_BYTES_SENT","TRACK_UNMUTED","createConferenceEvent","createConnectionStageReachedEvent","stage","actionSubject","createGetUserMediaEvent","createJingleEvent","createP2PEvent","createRemotelyMutedEvent","mediaType","createRtpStatsEvent","Events","AUDIO_LEVEL","BEFORE_DISPOSED","BYTE_SENT_STATS","CONNECTION_STATS","LONG_TASKS_STATS","CHROME","OPERA","FIREFOX","INTERNET_EXPLORER","SAFARI","NWJS","ELECTRON","REACT_NATIVE","UNKNOWN","bowserNameToJitsiName","_detectElectron","userAgent","navigator","JitsiMeetElectron","_detectNWJS","_detectReactNative","product","DummyLocalStorage","_storage","getItem","keyName","setItem","keyValue","removeItem","jitsiLocalStorage","super","localStorage","_localStorageDisabled","ignore","isLocalStorageDisabled","dontEmitChangedEvent","localStorageContent","browserInfo","_bowser","Bowser","detectedBrowserInfo","bowser","detectors","_detectChromiumBased","_detect","_version","getName","isChrome","isOpera","isFirefox","isIExplorer","isSafari","isNWJS","isElectron","isReactNative","getVersion","_checkCondition","checkTree","isVersionGreaterThan","isVersionLessThan","isVersionEqualTo","doesVideoMuteByStreamRemove","isChromiumBased","isWebKitBased","isIosBrowser","maxTouchPoints","Boolean","mediaDevices","getUserMedia","RTCRtpTransceiver","isTwa","matchMedia","_getSafariVersion","_getChromiumBasedVersion","isSupportedAndroidBrowser","isSupportedIOSBrowser","_getIOSVersion","isUserInteractionRequiredForUnmute","supportsVideoMuteOnConnInterrupted","supportsBandwidthStatistics","supportsCodecPreferences","RTCRtpReceiver","getCapabilities","supportsDeviceChangeEvent","ondevicechange","supportsLocalCandidateRttStatistics","supportsPerformanceObserver","PerformanceObserver","supportedEntryTypes","supportsReceiverStats","supportsRTTStatistics","supportsVP9","usesSdpMungingForSimulcast","usesAdapter","usesRidsForSimulcast","supportsGetDisplayMedia","getDisplayMedia","supportsEncodedTransform","RTCRtpScriptTransform","supportsInsertableStreams","RTCRtpSender","createEncodedStreams","ReadableStream","postMessage","supportsAudioRed","supportsUnifiedPlan","supportsVADDetection","supportsRTX","ua","disposed","analyticsHandlers","permanentProperties","conferenceName","addPermanentProperties","dispose","setAnalyticsHandlers","_setUserProperties","_sendEvent","setUserProperties","properties","setConferenceName","sendEvent","eventName","_verifyRequiredFields","objectType","containerType","containerId","objectId","_maybeCacheEvent","wrtcFuncNames","reportType","_fabrics","CallStats","backend","backendInitialized","atLeastOneFabric","defaultInstance","callStatsInstance","fabrics","hasFabric","debug","_addNewFabric","_emptyReportQueue","csInstance","defaultConfID","confID","defaultPC","peerconnection","report","reportsQueue","errorData","_reportError","pc","eventData","sendFabricEvent","associateMstWithUserID","callStatsId","usageLabel","_error","reportError","theBackend","tryCatchMethods","originalMethod","theArguments","debugMethods","originalReportError","exception","CallStatsBackend","callstats","_traceAndCatchBackendCalls","userID","aliasName","userName","callStatsID","callStatsSecret","configParams","applicationName","applicationVersion","siteID","initialize","_initCallback","getWiFiStatsMethod","attachWifiStatsHandler","addresses","devicesData","_reportEvent","conferenceID","overall","sendUserFeedback","status","mute","tpc","remoteUserID","fabricAttributes","remoteEndpointType","isP2P","endpointType","peer","server","addNewFabric","fabricUsage","multiplex","_addNewFabricCallback","success","associateStreamWithVideoTag","isLocal","streamEndpointId","sendDominantSpeakerEvent","sendTerminateEvent","fabricEvent","fabricTerminated","delete","sendIceConnectionFailedEvent","sendCreateOfferFailed","sendCreateAnswerFailed","sendResumeOrHoldEvent","isResume","sendScreenSharingEvent","sendSetLocalDescFailed","sendSetRemoteDescFailed","sendAddIceCandidateFailed","AudioContext","webkitAudioContext","LocalStatsCollector","interval","intervalId","intervalMilis","audioLevel","safeCounterIncrement","number","nextValue","calculateAverage","valueArray","filterPositiveValues","suspend","isLocalStatsSupported","resume","analyser","createAnalyser","smoothingTimeConstant","fftSize","createMediaStreamSource","connect","setInterval","frequencyBinCount","getByteTimeDomainData","samples","maxVolume","toFixed","timeDomainDataToAudioLevel","newLevel","lastLevel","animateLevel","clearInterval","RunningAverage","average","addNext","getAverage","PerformanceObserverStats","statsInterval","eventEmitter","longTasks","maxDuration","performanceStatsInterval","stats","getLongTasksStats","avgRatePerMinute","maxDurationMs","startObserver","longTaskEventHandler","getEntries","task","duration","observer","observe","buffered","startTime","longTasksIntervalId","_lastTimeStamp","StatisticsEvents","stopObserver","disconnect","MediaType","calculatePacketLoss","lostPackets","totalPackets","SsrcStats","loss","bitrate","download","upload","resolution","framerate","ConferenceStats","packetLoss","StatsCollector","audioLevelsInterval","baselineAudioLevelsReport","currentAudioLevelsReport","currentStatsReport","previousStatsReport","audioLevelReportHistory","audioLevelsIntervalId","conferenceStats","audioLevelsIntervalMilis","speakerList","statsIntervalId","statsIntervalMilis","ssrc2stats","setLoss","setResolution","addBitrate","resetBitrate","setFramerate","setCodec","setSpeakerList","startAudioLevelStats","audioLevels","getAudioLevels","getStats","processAudioLevelReport","processStats","processStatsReport","_processAndEmitReport","bitrateDownload","bitrateUpload","resolutions","framerates","audioCodec","videoCodec","audioBitrateDownload","audioBitrateUpload","videoBitrateDownload","videoBitrateUpload","ssrcStats","isDownloadStream","packetsTotal","packetsLost","getTrackBySSRC","isAudioTrack","participantId","getParticipantId","userResolutions","userFramerates","codecDesc","userCodecs","audio","total","avgAudioLevels","localAvgAudioLevels","avgAudioLevel","getNonNegativeValue","_calculateBitrate","fieldName","bytesNow","bytesBefore","bytesProcessed","timeMs","bitrateKbps","byteSentStats","nominated","availableIncomingBitrate","availableOutgoingBitrate","remoteUsedCandidate","remoteCandidateId","localUsedCandidate","localCandidateId","localip","conferenceStatsTransport","p2p","localCandidateType","candidateType","remoteCandidateType","networkType","rtt","currentRoundTripTime","packetsNow","packetsBefore","packetsDiff","packetsLostNow","packetsLostBefore","packetsLostDiff","frameHeight","frameWidth","frameRate","framesPerSecond","bytesSent","codecId","codecShortType","VIDEO","remoteSource","localVideoTracks","getLocalTracks","getLocalSSRC","framesSent","numberOfActiveStreams","getActiveSimulcastStreams","trackIdentifier","getSsrcByTrackId","AUDIO","_instances","isCallstatsLoaded","_initCallStatsBackend","isBackendInitialized","initBackend","Statistics","xmpp","rtpStatsMap","callStatsIntegrationEnabled","enableCallStats","disableThirdPartyRequests","callStatsApplicationLogsDisabled","customScriptUrl","loadCallStatsAPI","callsStatsInstances","instances","audioLevelsEnabled","disableAudioLevels","pcStatsInterval","longTasksStatsInterval","analytics","startRemoteStats","stopRemoteStats","rtpStats","RTPStats","localStats","startLocalStats","LocalStats","addAudioLevelListener","removeAudioLevelListener","addBeforeDisposedListener","removeBeforeDisposedListener","addConnectionStatsListener","removeConnectionStatsListener","addByteSentStatsListener","removeByteSentStatsListener","addLongTasksStatsListener","attachLongTasksStats","conference","performanceObserverStats","removeLongTasksStatsListener","from","callStats","stopCallStats","tpcId","_stopRemoteStats","stopLocalStats","startCallStats","newInstance","_getAllCallStatsInstances","csInstances","statistics","isCallstatsEnabled","sendConnectionResumeOrHoldEvent","instance","sendMuteEvent","muted","roomJid","sendActiveDeviceListEvent","globalSet","userId","sendGetUserMediaFailed","formatJitsiTrackErrorForCallStats","sendLog","globalSubSet","csPerStats","sendApplicationLog","sendFeedback","rating","LOCAL_JID","reportGlobalError","sendAnalyticsAndLog","eventToLog","sendAnalytics","JitsiConferenceEventManager","xmppListeners","p2pJingleSession","jvbJingleSession","isMuted","getType","JitsiTrackEvents","setupChatRoomListeners","chatRoom","room","chatRoomForwarder","jingleSession","rtc","closeBridgeChannel","features","participant","getParticipantById","Strophe","setFeatures","offerIq","_setBridgeChannel","actor","mutedByFocusActor","setAudioMute","isMutedByFocus","mutedVideoByFocusActor","setVideoMute","isVideoMutedByFocus","_onMucJoined","isJvbConnectionInterrupted","connectionTimes","_onConferenceRestarted","connection","emuc","doLeave","roomjid","_onIceConnectionFailed","jid","resource","getStatus","setTerminator","setInitiator","setParticipantPropertyListener","onMemberKicked","onSuspendDetected","onMemberJoined","_onMemberBotTypeChanged","onMemberLeft","onDisplayNameChanged","onLocalRoleChanged","isModerator","recorderSession","logObject","getError","onUserRoleChanged","authEnabled","authIdentity","txt","myJid","ts","_status","payload","addPresenceListener","myUserId","startAudioMuted","startVideoMuted","updated","startMutedPolicy","setupRTCListeners","onRemoteTrackAdded","onRemoteTrackRemoved","dominant","lastDominantSpeaker","performance","isVideoTrack","videoType","removeXMPPListeners","setupXMPPListeners","_addConferenceXMPPListener","onIncomingCall","onCallAccepted","onTransportInfo","onCallEnded","audioMuted","videoMuted","ignoreStartMuted","createdTimestamp","actorJid","actorParticipant","getParticipants","getJid","enabled","setupStatisticsListeners","setAudioLevel","startSilent","onByteSentStatsReceived","LOCAL_TRACK_STOPPED","TRACK_AUDIO_OUTPUT_CHANGED","TRACK_VIDEOTYPE_CHANGED","NO_DATA_FROM_SOURCE","TRACK_STREAMING_STATUS_CHANGED","ParticipantConnectionStatus","ACTIVE","INACTIVE","INTERRUPTED","RESTORING","ParticipantConnectionStatusHandler","isConnectionActiveByJvb","isInLastN","isRestoringTimedout","isVideoMuted","isVideoTrackFrozen","trackTimers","connStatusFromJvb","outOfLastNTimeout","p2pRtcMuteTimeout","rtcMuteTimeout","rtcMutedTimestamp","enteredLastNTimestamp","restoringTimers","connectionStatusMap","_getVideoFrozenTimeout","isP2PActive","_onEndpointConnStatusChanged","onEndpointConnStatusChanged","_onP2PStatus","refreshConnectionStatusForAll","_onUserLeft","onUserLeft","_onTrackRtcMuted","onTrackRtcMuted","_onTrackRtcUnmuted","onTrackRtcUnmuted","_onRemoteTrackAdded","_onRemoteTrackRemoved","_onSignallingMuteChanged","onSignallingMuteChanged","_onTrackVideoTypeChanged","onTrackVideoTypeChanged","_onLastNChanged","_onLastNValueChanged","participantIds","clearRtcMutedTimestamp","endpointId","isActive","figureOutConnectionStatus","_changeConnectionStatus","newStatus","getConnectionStatus","getId","_setConnectionStatus","remoteTrack","hasAnyVideoRTCMuted","hasAnyVideoTrackWebRTCMuted","participants","inP2PMode","isRestoringTimedOut","_isRestoringTimedout","audioOnlyMode","getLastN","isConnActiveByJvb","newState","_getNewStateForP2PMode","_getNewStateForJvbMode","_clearRestoringTimer","oldConnectionStatus","connectionStatus","nowMs","maybeSendParticipantConnectionStatusEvent","startedMs","videoTracks","getTracksByMediaType","participantConnectionStatus","createParticipantConnectionStatusEvent","leavingLastN","enteringLastN","rTimer","JitsiParticipant","displayName","statsID","identity","isReplacing","isReplaced","_jid","_id","_conference","_displayName","_supportsDTMF","_tracks","_role","_hidden","_statsID","_connectionStatus","_properties","_identity","_isReplacing","_isReplaced","_features","getConference","getProperty","getTracks","jitsiTrack","isWebRTCTrackMuted","oldValue","getDisplayName","getStatsID","isHidden","isHiddenFromRecorder","user","isAudioMuted","_isMediaTypeMuted","getRole","setRole","newRole","setIsReplacing","newIsReplacing","setIsReplaced","newIsReplaced","supportsDTMF","getFeatures","newFeatures","getBotType","_botType","setBotType","newBotType","JitsiConnectionEvents","CONNECTION_FAILED","WRONG_STATE","DISPLAY_NAME_REQUIRED","JitsiConnectionErrors","CONNECTION_DROPPED_ERROR","OTHER_ERROR","SERVER_ERROR","clearRejectTimeout","_timeout","setRejectTimeout","ms","Listenable","kJitsiE2EE","E2EEcontext","sharedKey","baseUrl","ljm","querySelector","workerUrl","workerBlob","Blob","URL","createObjectURL","_worker","Worker","operation","cleanup","cleanupAll","handleReceiver","receiverStreams","readableStream","readable","writableStream","handleSender","sender","senderStreams","setKey","keyIndex","KeyHandler","e2eeCtx","E2EEContext","_enabling","_onMediaSessionStarted","_onLocalTrackAdded","_setupReceiverE2EEForTrack","_trackMuteChanged","isEnabled","_setEnabled","setLocalParticipantProperty","_restartMediaSessions","setEncryptionKey","getMediaSessions","_setupSenderE2EEForTrack","localTracks","findReceiverForTrack","findSenderForTrack","ExternallyManagedKeyHandler","keyInfo","encryptionKey","getRandomValues","rnds8","rng","msCrypto","uuid","byteToHex","rnds","OLM_MESSAGE_TYPE","OLM_MESSAGE_TYPES","kOlmData","OlmAdapterEvents","OLM_ID_KEY_READY","PARTICIPANT_E2EE_CHANNEL_READY","PARTICIPANT_KEY_UPDATED","OlmAdapter","_conf","_init","_keyIndex","_reqs","_sessionInitialization","_bootstrapOlm","_onEndpointMessageReceived","_onConferenceLeft","_onParticipantLeft","_onParticipantPropertyChanged","promises","localParticipantId","FEATURE_E2EE","_sendSessionInit","allSettled","Olm","pId","olmData","_getParticipantOlmData","uuidv4","JITSI_MEET_MUC_TYPE","olm","ciphertext","_encryptKeyInfo","_sendMessage","updateCurrentKey","clearParticipantSession","free","clearAllParticipantsSessions","_olmAccount","Account","idKeys","identity_keys","_idKey","curve25519","get_library_version","_onIdKeyReady","idKey","_onParticipantE2EEChannelReady","base64js","encrypt","_sendError","Session","create_outbound","otKey","ack","pendingSessionUuid","create_inbound","remove_one_time_keys","decrypt","json","safeJsonParse","lastKey","isEqual","isE2EEEnabled","sendMessage","generate_one_time_keys","otKeys","one_time_keys","mark_keys_as_published","ManagedKeyHandler","_conferenceJoined","_olmAdapter","_rotateKey","debounce","_rotateKeyImpl","_ratchetKey","_ratchetKeyImpl","_onParticipantKeyUpdated","_onParticipantJoined","initSessions","_generateKey","updateKey","material","keyBytes","subtle","importKey","newKey","textEncoder","TextEncoder","deriveBits","salt","encode","ratchet","E2EEncryption","e2ee","_externallyManaged","externallyManagedKey","_keyHandler","testing","disableE2EE","enableEncodedTransformSupport","setEnabled","IDENTITY_PROPERTIES","IDENTITY_PROPERTIES_FOR_COMPARE","compareIdentities","res","parseDiscoInfo","identities","category","Caps","disco","rooms","externalFeatures","_addChatRoom","_removeChatRoom","addFeature","external","_generateVersion","_updateRoomWithExternalFeatures","removeFeature","sendPresence","removeFromPresence","addOrReplaceInPresence","getFeaturesAndIdentities","_getDiscoInfo","response","_fixChatRoomPresenceMap","ver","_notifyVersionChanged","sortedIdentities","accumulatedValue","sortedFeatures","b64_sha1","generateSha","_identities","NETWORK_INFO_EVENT","_current","isOnline","updateNetworkInfo","ResumeTask","stropheConnection","_stropheConn","_resumeRetryN","_retryDelay","retryDelay","schedule","_cancelResume","_networkOnlineListener","NetworkInfo","_scheduleResume","_resumeTimeout","retry","minDelay","getJitterDelay","_resumeConnection","streamManagement","resumeToken","getResumeToken","service","oldToken","LastRequestTracker","_lastSuccess","_lastFailedMessage","startTracking","xmppConnection","originalRawInput","rawInput","rawMessage","includes","connected","getLastFailedMessage","getTimeSinceLastSuccess","getConnectionPluginDefinition","ConnectionPluginListenable","PingConnectionPlugin","ConnectionPlugin","getTimeSinceLastServerResponse","onPingThresholdExceeded","pingOptions","failedPings","_onPingThresholdExceeded","_getTimeSinceLastServerResponse","pingInterval","pingTimeout","pingThreshold","threshold","pingTimestampsToKeep","pingExecIntervals","ping","_addPingExecutionTimestamp","iq","$iq","to","sendIQ2","startInterval","remoteJid","_lastServerCheck","errmsg","stopInterval","getTime","getPingSuspendTime","pingIntervals","maxInterval","previousTS","currentInterval","XmppConnection","CONN_STATUS_CHANGED","CONN_SHARD_CHANGED","Status","enableWebsocketResume","websocketKeepAlive","websocketKeepAliveUrl","serviceUrl","shard","xmppPing","_options","_usesWebsocket","startsWith","maxRetries","_rawInputTracker","LastSuccessTracker","_resumeTask","_deferredIQs","addConnectionPlugin","_onPingErrorThresholdExceeded","_oneSuccessfulConnect","websocket","_proto","socket","isUsingWebSocket","WebSocket","OPEN","disconnecting","domain","lastResponseHeaders","pingDomain","_maybeStartWSKeepAlive","plugin","attach","sid","rid","_stropheConnectionCb","pass","targetCallback","blockCallback","_maybeEnableStreamResume","_keepAliveAndCheckShard","_processDeferredIQs","_tryResumingConnection","_wsKeepAlive","_clearDeferredIQs","closeWebsocket","_closeSocket","_onClose","enable","intervalWithJitter","fetch","responseShard","headers","timeLeft","sendIQ","send","stanza","errback","sendUnavailableBeacon","sendBeacon","_changeConnectStatus","_buildBody","pres","$pres","cnode","tree","_abortAllRequests","_doDisconnect","JitsiTranscriptionStatus","ON","OFF","AVModeration","_xmpp","_mainRoom","_moderationEnabledByType","_whitelistAudio","_whitelistVideo","_onMessage","avModerationComponentAddress","$msg","up","approve","jidToWhitelist","jidToBlacklist","removed","approved","whitelists","newWhitelists","oldList","newList","FEATURE_KEY","BREAKOUT_ROOM_ACTIONS","ADD","REMOVE","MOVE_TO_ROOM","BREAKOUT_ROOM_EVENTS","BreakoutRooms","_handleMessages","_rooms","createBreakoutRoom","subject","removeBreakoutRoom","breakoutRoomJid","sendParticipantToRoom","participantJid","getComponentAddress","breakoutRoomsComponentAddress","_setIsBreakoutRoom","isBreakoutRoom","_isBreakoutRoom","_setMainRoomJid","_mainRoomJid","getMainRoomJid","EMAIL_COMMAND","Lobby","mainRoom","maybeJoinLobbyRoom","_maybeJoinLobbyRoom","lobbyRoomJid","lobbySupported","setMembersOnly","lobbyRoom","membersOnlyEnabled","sendPrivateMessage","getLocalId","myroomjid","addMessageListener","removeMessageHandler","leave","setLobbyRoomJid","joined","email","customDomain","createRoom","disableDiscoInfo","disableFocus","enableLobby","nick","isHiddenDomain","botType","members","getBreakoutRooms","avatar","clean","isSelfPresence","invitePassword","denyAccess","kick","approveAccess","mainRoomJid","memberRoomJid","msgToSend","_callStatsUserName","_machineId","externalStorage","callStatsUserName","UsernameGenerator","generateCallStatsUserName","machineId","amDid","jitsiMeetId","_p8","generateJitsiMeetId","createExpBackoffTimer","step","Moderator","Settings","xmppService","getNextTimeout","getNextErrorTimeout","externalAuthEnabled","sipGatewayEnabled","isExternalAuthEnabled","isSipGatewayEnabled","onMucMemberLeft","setFocusUserJid","focusJid","focusUserJid","getFocusUserJid","getFocusComponent","focusComponent","hosts","createConferenceIq","machineUID","disableRtx","audioPacketDelay","startBitrate","minBitrate","rtcstatsEnabled","callstatsDisabled","parseSessionId","resultIq","parseConfigOptions","authenticationEnabled","allocateConferenceFocus","_allocateConferenceFocusSuccess","_allocateConferenceFocusError","invalidSession","reservationErr","errorCode","errorTextNode","errorMsg","anonymousdomain","waitMs","retrySec","authenticate","errorIq","getLoginUrl","urlCallback","failureCallback","_getLoginUrl","popup","urlCb","failureCb","decodeURIComponent","getPopupLoginUrl","logout","logoutUrl","packet2JSON","xmlElement","json2packet","packet","filterNodeFromPresenceJSON","MEMBERS_AFFILIATIONS","ChatRoom","XMPP","replaceParticipant","presMap","presHandlers","_removeConnListeners","inProgressEmitted","focusMucJid","noBridgeAvailable","moderator","lobby","avModeration","breakoutRooms","initPresenceMap","lastPresences","phoneNumber","phonePin","participantPropertyListener","transcriptionStatus","xns","statsId","presenceUpdateTime","onConnStatusChanged","fromJoin","billingId","presenceSyncTime","discoRoomInfo","getInfo","meetingIdValEl","setMeetingId","membersOnly","lobbyRoomField","isBreakoutField","breakoutMainRoomField","meetingId","createNonAnonymousRoom","getForm","form","formSubmit","CONNECTED","onPresence","member","statusEl","hasStatusUpdate","hasVersionUpdate","xElement","mucUserItem","isReplaceParticipant","affiliation","isFocus","hiddenDomain","fromHiddenDomain","presence","xEl","extractIdentityInformation","userInfo","tags","hiddenFromRecorderFeatureEnabled","groupInfo","_extractFeatures","_initFocus","memberOfThis","displayJids","restartByTerminateSupported","supportsRestartByTerminate","att","phone","pin","processNode","var","focusFeatures","tagHandlers","elementName","setSubject","onParticipantLeft","skipEvents","onPresenceUnavailable","destroySelect","reasonSelect","isKick","membersKeys","actorSelect","actorNick","onMessage","settingsErrorMsg","subjectText","stamp","dateParts","invite","passwordSelect","jsonMessage","parsedJson","tryParseJSONAndVerify","onPresenceError","lobbyRoomNode","lobbyRoomOldNode","setAffiliation","grantIQ","kickIQ","lockRoom","onSuccess","onError","onNotSupported","formsubmit","formToSubmit","addToPresence","matchingNodes","getFromPresence","removePresenceListener","handlerIdx","mucJid","getMemberRole","peerJid","addAudioInfoToPresence","audioMutedTagName","addVideoInfoToPresence","videoMutedTagName","getMediaPresenceInfo","mutedNode","codecTypeNode","videoTypeNode","codecType","getLastPresence","mucNick","isSIPCallingSupported","dial","rayo","hangup","getLobby","getAVModeration","getPhoneNumber","getPhonePin","getMeetingId","muteParticipant","iqToFocus","onMute","onMuteVideo","onMucLeft","doReject","MucConnectionPlugin","isRoomCreated","_sourceNameSignaling","sourceNameSignaling","_sendMultipleVideoStreams","sendMultipleVideoStreams","isMultiStreamSupportEnabled","isSourceNameSignalingEnabled","_createSourceExtension","sourceCompactJson","$build","FeatureFlags","_createSsrcGroupExtension","ssrcGroupCompactJson","_getOrCreateRtpDescription","jingle","expandSourcesFromJson","jsonMessageXml","audioRtpDescription","videoRtpDescription","ownerSources","videoSources","videoSsrcGroups","audioSources","audioSsrcGroups","H264","OPUS","ULPFEC","VP8","VP9","RECVONLY","SENDONLY","SENDRECV","ScreenObtainer","obtainStream","_createObtainStreamMethod","onFailure","JitsiMeetNW","obtainDesktopStream","jitsiError","obtainScreenOnElectron","obtainScreenFromGetDisplayMediaRN","obtainScreenFromGetDisplayMedia","_getAudioConstraints","audioQuality","stereo","autoGainControl","channelCount","echoCancellation","noiseSuppression","JitsiMeetScreenObtainer","openDesktopPicker","desktopSharingFrameRate","desktopSharingSources","streamId","streamType","screenShareAudio","audioConstraints","optionalConstraints","optional","chromeMediaSource","chromeMediaSourceId","minFrameRate","maxFrameRate","screen","maxHeight","sourceId","sourceType","cursor","errorDetails","errorName","errorStack","setDesktopSharingFrameRate","maxFps","SDPUtil","filterSpecialChars","iceparams","mediadesc","sessiondesc","findLine","parseICEUfrag","parseICEPwd","buildICEUfrag","frag","buildICEPwd","parseMID","parseMSIDAttribute","ssrcLines","msidLine","buildMLine","parseRTPMap","clockrate","parseSCTPMap","parseSCTPPort","buildRTPMap","parseCrypto","fingerprint","parseICECandidate","network","buildICECandidate","cand","hasOwnAttribute","parseSSRC","parseSourceNameLine","sourceNameLine","ssrcSdpLine","parseRTCPFB","haystack","needle","findLines","needles","candidateToJingle","candidateFromJingle","parsePrimaryVideoSsrc","videoMLine","generateSsrc","ssrcLine","parseGroupSsrcs","ssrcGroup","getMedia","getUfrag","ufragLines","preferCodec","codecName","matchingPayloadTypes","payloadTypes","payloadIndex","stripCodec","highProfile","h264Pts","removePts","stripH264HighCodec","CodecMimeType","rtxApts","rtxPts","keepPts","MediaDirection","rtcpFb","SDP","mediaI","arrayEquals","array1","array2","equals","SDPDiffer","mySDP","otherSDP","failICE","removeTcpCandidates","removeUdpCandidates","addMlineForNewLocalSource","clonedeep","mids","getMediaSsrcMap","mediaSSRCs","mediaindex","linessrc","containsSSRC","medias","toJingle","thecreator","assrcline","creator","amidline","rtpmap","afmtpline","fmtpParameters","rtcpFbToJingle","availableSsrc","ssrcParameters","sourceName","ridLines","rids","ridLine","ridInfo","extmapLines","extmap","senders","transportToJingle","sctpport","sctpmap","sctpAttrs","streams","setupLine","iceParameters","payloadtype","feedback","rtcpFbFromJingle","feedbackElementTrrInt","fromJingle","jingle2media","__","hdrExt","userSources","nonUserSources","isUserSource","sourceStr","getNewMedia","myMedias","othersMedias","newMedia","othersMediaIdx","myMedia","othersMedia","otherSsrcGroup","mySsrcGroup","modify","sdpMediaSsrcs","modified","ssrcNum","mediaSsrc","hasQueueMicrotask","queueMicrotask","hasSetImmediate","setImmediate","hasNextTick","nextTick","fallback","setImmediate$1","handlePromise","invokeCallback","isAsync","wrapAsync","asyncFn","awaitify","arity","cbArgs","applyEach","eachfn","callArgs","cb","_asyncMap","counter","_iteratee","iterCb","breakLoop","wrapper","callFn","onlyOnce","asyncEachOfLimit","generator","limit","canceled","awaiting","running","replenish","iterDone","iterateeCallback","handleError","eachOfLimit","asyncIterator","isAsyncIterable","nextElem","coll","createArrayIterator","getIterator","createES2015Iterator","okeys","createObjectIterator","createIterator","looping","eachOfLimit$2","eachOfArrayLike","iteratorCallback","eachOfGeneric","eachOf$1","map$1","eachOfSeries$1","DLL","tail","removeLink","setInitial","testFn","curr","dll","worker","concurrency","numRunning","workersList","drain","saturated","unsaturated","ev","processingScheduled","_insert","insertAtFront","rejectOnError","rej","promiseCallback","q","started","_tasks","_createCB","tasks","idle","_maybeDrain","eventMethod","handleAndRemove","isProcessing","datum","pushAsync","kill","unshiftAsync","pause","defineProperties","memo","mapLimit$1","concatLimit$1","mapResults","_createTester","testResult","testPassed","consoleFunc","resultArgs","_withoutIndex","_fn","_test","truth","eachLimit$2","eachSeries$1","filterArray","truthValues","filterGeneric","_filter","sync","innerArgs","ensureAsync","newObj","taskCb","criteria","comparator","rest","taskIndex","nextTask","AsyncQueue","_queue","_processQueueTasks","items","_stopped","finishedCallback","shutdown","JingleSessionState","PENDING","ENDED","JingleSession","localJid","mediaConstraints","pcConfig","isInitiator","usedrip","dripContainer","_signalingLayer","initiatorJid","responderJid","signalingLayer","doInitialize","addIceCandidates","getState","addSources","removeSources","terminate","failure","acceptOffer","_getInitiatorJid","MediaSessionEvents","IQ_TIMEOUT","JingleSessionPC","jingleContents","videoContents","maxFrameHeightSel","_bridgeSessionId","_cachedOldLocalSdp","_cachedNewLocalSdp","_iceCheckingStartedTimestamp","_gatheringStartedTimestamp","localRecvMaxFrameHeight","_localVideoActive","_remoteVideoActive","_gatheringReported","lasticecandidate","remoteRecvMaxFrameHeight","modificationQueue","wasConnected","establishmentDuration","_xmppListeners","onXmppStatusChanged","_removeSenderVideoConstraintsChangeListener","_assertNotEnded","isReconnect","wasstable","webrtcIceUdpDisable","webrtcIceTcpDisable","pcOptions","gatherStats","maxstats","capScreenshareBitrate","enableInsertableStreams","videoQuality","forceTurnRelay","enableUnifiedOnChrome","disableSimulcast","abtestSuspendVideo","_abtestSuspendVideoEnabled","preferH264","disableH264","preferredCodec","createPeerConnection","onicecandidate","phase","initiator","sendIceCandidate","onsignalingstatechange","signalingState","connectionState","oniceconnectionstatechange","isStable","iceConnectionState","reconnect","usesTerminateForRestart","enableIceRestart","iceStarted","onconnectionstatechange","icestate","onnegotiationneeded","remoteDescription","workFunction","oldSdp","localDescription","_renegotiate","configureSenderVideoEncodings","newSdp","notifyMySSRCUpdate","getRemoteRecvMaxFrameHeight","localSDP","ice","sdpMLineIndex","jcand","errorMesssage","sendIceCandidates","cands","sdpMid","fingerprintLine","required","newJingleErrorHandler","sendIceFailedNotification","sessionInfo","iceCandidates","rtcCandidate","RTCIceCandidate","iceCandidate","addIceCandidate","outerHTML","readSsrcInfo","ssrcElement","setSSRCOwner","setTrackSourceName","i3","ssrcInfoElement","jidOrEndpointId","generateRecvonlySsrc","getConfiguredVideoCodec","jingleOffer","setOfferAnswerCycle","sendSessionAccept","addTracks","localTrack","addTrack","all","createOffer","offerSdp","setLocalDescription","sendSessionInitiate","setAnswer","jingleAnswer","remoteSdp","_responderRenegotiate","jingleOfferAnswerIq","newRemoteSdp","_processNewJingleOfferIq","oldLocalSdp","bridgeSessionId","sendContentModify","newLocalSdp","setVideoCodecs","preferred","replaceTransport","jingleOfferElem","enableForcedReload","sendTransportAccept","originalOffer","newFingerprint","accept","responder","maxFrameHeight","sessionModify","setReceiverVideoConstraint","transportAccept","medialines","sendTransportReject","transportReject","setSenderVideoConstraint","jitsiLocalTrack","getLocalVideoTracks","getSourceName","getLocalVideoTrack","setSenderVideoConstraints","sendSessionTerminate","sessionTerminate","reasonDescription","restart","requestRestart","onTerminated","reasonCondition","reasonText","close","_parseSsrcInfoFromSourceAdd","sourceAddElem","currentRemoteSdp","addSsrcInfo","i1","i2","addRemoteStream","_addOrRemoveRemoteStream","removeRemoteStream","removeRemoteStreamsOnLeave","finishCallback","removeSsrcInfo","getRemoteSourceInfoByParticipant","_processRemoteRemoveSource","newLocalSDP","isAdd","logPrefix","errMsg","addOrRemoveSsrcInfo","_parseSsrcInfoFromSourceRemove","_processRemoteAddSource","findIndex","desiredDirection","getDesiredMediaDirection","optionalRemoteSdp","_initiatorRenegotiate","setRemoteDescription","createAnswer","answer","offer","replaceTrack","oldTrack","newTrack","clearRecvonlySsrc","shouldRenegotiate","sourceRemoveElem","_verifyNoSSRCChanged","operationName","oldSDP","currentLocalSDP","sdpDiff","addedMedia","removedMedia","addTrackAsUnmute","_addRemoveTrackAsMuteUnmute","removeTrackAsMute","isMute","oldLocalSDP","removeTrackMute","addTrackUnmute","setMediaTransferActive","audioActive","videoActive","logAudioStr","logVideoStr","isSessionActive","audioActiveChanged","setAudioTransferActive","pcVideoActiveChanged","setVideoTransferActive","modifyContents","newVideoSenders","parseVideoSenders","newMaxFrameHeight","parseMaxFrameHeight","_modifyRemoteVideoActive","remoteVideoSenders","isRemoteVideoActive","newSDP","getSignaledSourceInfo","sdpDiffer","mediaIndex","signaledSsrcs","removedAnySSRCs","ctx","sourceInfo","request","errResponse","errorElSel","errorReasonSel","errorMsgSel","getIceConnectionState","getConnectionState","abTesting","enableSuspendVideoTest","_parseIceCandidates","parseCandidates","candidateAttrs","JingleConnectionPlugin","iceConfig","sessions","jvbIceConfig","jvb","p2pIceConfig","offerToReceiveAudio","offerToReceiveVideo","onJingle","fromJid","sess","jsonMessages","audioVideoSsrcs","logMessage","endpoint","startMuted","iceUfrag","icePwd","dtlsFingerprint","successTime","newP2PJingleSession","me","getStunAndTurnCredentials","v2Res","onReceiveStunAndTurnCredentials","v1Res","iceservers","dict","urls","credential","useTurnUdp","iceServers","getLog","updateLog","StropheLogger","logIncoming","rawOutput","logOutgoing","RAYO_XMLNS","RayoConnectionPlugin","onRayo","roomPass","req","callResource","lastErrorStatus","resetLastErrorStatusRegExpr","lastErrorStatusRegExpr","FAILURE_REGEX","DEFAULT_STUN_SERVERS","FEATURE_JIGASI","disconnectInProgress","authenticatedUser","trace","errStatusCapture","createConnection","bosh","deploymentInfo","details","shard_changed","suspend_time","time_since_last_success","_initStrophePlugins","initFeaturesList","disableBeforeUnloadHandlers","enableOpusRed","enableRemb","enableTcc","enableLipSync","getConnection","connectionHandler","credentials","statusStr","_maybeSendDeploymentInfoStat","_sysMessageHandler","deleteHandler","sendDiscoInfo","_resetState","sendDeploymentInfo","_processDiscoInfoIdentities","anonymousConnectionFailed","connectionFailed","lastErrorMsg","wasIntentionalDisconnect","_getConnectionFailedReasonDetails","lastFailedRawMessage","_parseConnectionFailedMessage","speakerStatsComponentAddress","conferenceDurationComponentAddress","processLobbyFeatures","fr","endsWith","region","_onPrivateMessage","_connect","_addSysHandler","_onSystemMessage","foundIceServers","attaching","configDomain","hostname","onCreateResource","getRoomJid","mucNickname","muc","getJingleLog","getXmppLog","getSessions","disconnectListener","_cleanupXmppConnection","evType","p2pStunServers","stunServers","iceTransportPolicy","headersArr","header","sendFacialExpressionEvent","expression","facialExpression","jsonString","users","created_timestamp","acceptedStatuses","aprops","authenticateAndUpgradeRole","rejectPromise","onLoginSuccessful","roomPassword","authenticationError","connectionError","CodecSelection","disabledCodec","_getCodecMimeType","jvbCodec","p2pCodec","jvbPreferredCodec","_isCodecSupported","p2pPreferredCodec","_selectPreferredCodec","mediaSession","currentCodec","selectedCodec","enforcePreferredCodec","remoteParticipants","remote","peerMediaInfo","getPeerMediaInfo","peerCodec","getPreferredCodec","BridgeChannel","wsUrl","_channel","_eventEmitter","_mode","_areRetriesEnabled","_closedFromClient","datachannel","createDataChannel","_handleChannel","_wsUrl","_initWebSocket","ws","_startConnectionRetries","timeoutS","reload","isOpen","_retryTimeout","_stopConnectionRetries","_retryWebSocketConnection","closeEvent","createBridgeChannelClosedEvent","mode","sendEndpointStatsMessage","_send","colibriClass","msgPayload","sendSetLastNMessage","lastN","sendSelectedEndpointsMessage","endpointIds","selectedEndpoints","sendReceiverVideoConstraintMessage","maxFrameHeightPixels","sendNewReceiverVideoConstraintsMessage","sendVideoTypeMessage","sendSourceVideoTypeMessage","channel","onopen","onmessage","dominantSpeakerEndpoint","previousSpeakers","active","lastNEndpoints","forwardedSources","videoConstraints","onclose","jsonObject","DEFAULT_CONSTRAINTS","ideal","audioOutputDeviceId","audioOutputChanged","disableAP","disableAEC","disableNS","disableAGC","featureDetectionAudioEl","isAudioOutputDeviceChangeAvailable","setSinkId","availableDevicesPollTimer","availableDevices","emptyFuncton","updateGrantedPermissions","um","audioTracksReceived","getAudioTracks","videoTracksReceived","getVideoTracks","grantedPermissions","sendDeviceListToAnalytics","deviceList","audioInputDeviceCount","audioOutputDeviceCount","videoInputDeviceCount","videoOutputDeviceCount","device","deviceId","groupId","label","updateKnownDevices","pds","newDevices","mediaDeviceInfoToJSON","facing","compareAvailableMediaDevices","rtcUtils","origAttachMediaStream","RTCPeerConnectionType","RTCPeerConnection","attachMediaStream","getStreamID","getTrackID","srcObject","isDeviceChangeAvailable","getAudioOutputDevice","pcConstraints","googScreencastMinBitrate","googCpuOveruseDetection","screenObtainer","isDeviceListAvailable","enumerateDevices","ds","_getUserMedia","umDevices","gumTimeout","timeoutExpired","_getDesktopMedia","_getMissingTracks","requestedDevices","missingDevices","audioDeviceRequested","videoDeviceRequested","obtainAudioAndVideoPermissions","otherOptions","mediaStreamsMetaData","maybeRequestDesktopDevice","desktopSharingSourceDevice","matchingDevice","maybeRequestCaptureDevices","requestedCaptureDevices","cameraDeviceId","facingMode","CameraFacingMode","micDeviceId","getConstraints","desktopStream","desktopAudioTracks","desktopAudioStream","MediaStream","desktopVideoTracks","desktopVideoStream","avStream","audioTracks","audioStream","effects","videoStream","stopMediaStream","deviceType","mediaStream","release","isDesktopSharingEnabled","setAudioOutputDevice","getCurrentlyAvailableMediaDevices","arePermissionsGrantedForAvailableDevices","getEventDataForActiveDevice","deviceData","setSuspendVideo","googSuspendBelowMinBitrate","trackHandler2Prop","JitsiTrack","streamInactiveHandler","trackMediaType","containers","_streamInactiveHandler","_setStream","_addMediaStreamInactiveHandler","onended","oninactive","_setHandler","_unregisterHandlers","videoTrack","getVideoType","isLocalAudioTrack","getOriginalStream","getStreamId","getTrack","getTrackLabel","getTrackId","getUsageLabel","_maybeFireTrackAttached","_onTrackAttach","RTCUtils","_attachTTFMTracker","_onTrackDetach","isScreenSharing","newAudioLevel","getMSID","trackId","setAudioOutput","JitsiLocalTrack","rtcId","_setEffectInProgress","effect","_startStreamEffect","displaySurface","getSettings","metadata","maxEnabledResolution","_constraints","_prevSetMuted","_facingMode","_trackEnded","_hasSentData","_testDataSent","_realDeviceId","_sourceName","_trackMutedTS","_onDeviceListWillChange","oldRealDeviceId","_setRealDeviceIdFromDeviceList","_onAudioOutputDeviceChanged","_initNoDataFromSourceHandlers","_addStreamToConferenceAsUnmute","_addLocalTrackAsUnmute","_fireNoDataFromSourceEvent","isReceivingData","createNoDataFromSourceEvent","_isNoDataFromSourceEventsEnabled","_queueSetMuted","setMuted","_setMuted","_removeStreamFromConferenceAsMute","successCallback","_removeLocalTrackAsMute","_sendMuteStatus","_setTrackMuteStatus","logMuteInfo","_streamEffect","_stopStreamEffect","stopStream","streamOptions","getDeviceId","getCameraFacingMode","streamsInfo","PRESENTER","streamInfo","cont","_sendBridgeVideoTypeMessage","storedMSID","_originalStream","startEffect","stopEffect","_switchCamera","_switchStreamEffect","setEffect","removeTrack","trackSettings","getDuration","isEnded","_stopStreamInProgress","_effectEnabled","setConference","setSourceName","unmute","found","PLAN_B_MIDS","findSimGroup","grp","findFidGroup","addSimGroupSources","sourceGroups","sourceList","findSourcebyId","relatedFidGroup","relatedSsrc","addSourcesToMline","otherSsrc","simGroup2","checkIfMlineForSsrcExists","mlines","Interop","toPlanB","sessionMedia","bLine","bundle","msidSemantic","semantic","resStr","toUnifiedPlan","currentDesc","iceRestart","newDesc","oldDesc","newMLine","oldMLine","checkForIceRestart","newIceUfrag","newIcePwd","newMline","mLineForData","ssrc2group","createSourceGroupMap","bundleOnly","existingMline","resultSdp","SignalingEvents","PEER_MUTED_CHANGED","PEER_VIDEO_TYPE_CHANGED","getSourceNameForJitsiTrack","trackIdx","getMediaTypeFromSourceName","firstLetterOfMediaTypeIdx","firstLetterOfMediaType","SignalingLayer","getSSRCOwner","getPeerSourceInfo","getTrackSourceName","parsePrimarySSRC","parseSecondarySSRC","_getSSRCCount","MLineWrap","getSSRCAttrValue","ssrcNumber","ssrcObj","removeSSRC","addSSRCAttribute","findGroup","findGroups","findGroupByPrimarySSRC","primarySSRC","findSSRCByMSID","getSSRCCount","containsAnySSRCGroups","getPrimaryVideoSsrc","fecGroup","getRtxSSRC","getSSRCs","getPrimaryVideoSSRCs","videoSSRCs","ssrcGroupInfo","dumpSSRCGroups","removeGroupsWithSSRC","removeGroupsBySemantics","replaceSSRC","oldSSRC","newSSRC","addSSRCGroup","SdpTransformWrap","rawSDP","parsedSDP","selectMedia","selectedMLines","toRawSDP","LocalSdpMunger","localEndpointId","_addMutedLocalVideoTracksToSDP","transformer","localVideos","isCamera","isInPeerConnection","isMediaStreamInPc","requiredSSRCs","isSimulcastOn","simulcast","sdpConsistency","cachedPrimarySsrc","primaryCname","rtxModifier","modifyRtxSsrcs2","_generateMsidAttribute","pcId","_transformMediaIdentifiers","sourceToMsidMap","streamAndTrackIDs","mediaDirection","generatedMsid","maybeAddMutedLocalVideoTracksToSDP","transformStreamIdentifiers","sessionDesc","audioMLine","_injectSourceNames","updateAssociatedRtxStream","primarySsrcInfo","rtxSsrc","previousRtxSSRC","RtxModifier","correspondingRtxSsrcs","ssrcMapping","modifyRtxSsrcs","sdpStr","sdpTransformer","videoMLines","primaryVideoSsrcs","correspondingRtxSsrc","stripRtx","fidGroups","SdpConsistency","clearVideoSsrcCache","injectRecvOnly","setPrimarySsrc","hasPrimarySsrcCached","makeVideoPrimarySsrcsConsistent","newPrimarySsrc","SdpSimulcast","_ssrcCache","_fillSsrcsFromCache","cachedSsrcs","newSsrcs","_getSsrcAttribute","_generateNewSsrcsForSimulcast","addAssociatedAttributes","_generateSsrc","mungedSsrcs","mungedSsrcGroups","TrackStreamingStatus","TrackStreamingStatusImpl","isInForwardedSources","restoringTimer","streamingStatusMap","trackTimer","outOfForwardedSourcesTimeout","figureOutStreamingStatus","_onForwardedSourcesChanged","onForwardedSourcesChanged","maybeSendTrackStreamingStatusEvent","_changeStreamingStatus","getTrackStreamingStatus","_setTrackStreamingStatus","isVideoRTCMuted","oldStreamingStatus","streamingStatus","trackStreamingStatus","createTrackStreamingStatusEvent","leavingForwardedSources","enteringForwardedSources","_clearEnteredForwardedSourcesTimestamp","_setEnteredForwardedSourcesTimestamp","enteredForwardedSourcesTimestamp","_getEnteredForwardedSourcesTimestamp","_isCurrentTrack","ttfmTrackerAudioAttached","ttfmTrackerVideoAttached","containerEvents","JitsiRemoteTrack","ownerEndpointId","_trackStreamingStatus","_trackStreamingStatusImpl","_enteredForwardedSourcesTimestamp","_addEventListener","_removeEventListener","hasBeenMuted","_bindTrackHandlers","_containerHandlers","_containerEventHandler","_onTrackMute","_onTrackUnmute","_initTrackStreamingStatus","_disposeTrackStreamingStatus","setMute","getSSRC","_setVideoType","_playCallback","getConnectionTimes","gumStart","gumEnd","gumDuration","ttfm","_getStatus","_p2pConnStatusRtcMuteTimeout","_peerConnStatusRtcMuteTimeout","_peerConnStatusOutOfLastNTimeout","HD_BITRATE","SIM_LAYER_RIDS","TPCUtils","bitrateSettings","maxBitratesVideo","standardBitrates","low","standard","videoBitrates","encodingBitrates","localStreamEncodingsConfig","scaleResolutionDownBy","_getStreamEncodings","ensureCorrectOrderOfSsrcs","parsedSdp","reorderedSsrcs","findTransceiver","getTransceivers","insertUnifiedPlanSimulcastReceive","simulcast_03","simulcastLine","transceiverInit","sendEncodings","addTransceiver","calculateEncodingsActiveState","localVideoTrack","newHeight","encoding","isSharingLowFpsScreen","calculateEncodingsBitrates","desktopShareBitrate","desktopBitrate","presenterEnabled","transceiver","currentDirection","trackIndex","setEncodings","getParameters","encodings","setParameters","transceivers","updateEncodingsResolution","TraceablePeerConnection","audioTransferActive","_dtmfSender","_dtmfTonesQueue","videoTransferActive","remoteTracks","_addedStreams","localSSRCs","localUfrag","remoteUfrag","_dtlsTransport","_peerVideoTypeChanged","_peerMutedChanged","safeConstraints","rtcStatsSFUP2P","tpcUtils","statsinterval","_capScreenshareBitrate","_usesUnifiedPlan","_usesTransceiverCodecPreferences","interop","localSdpMunger","getLocalEndpointId","_senderVideoMaxHeight","_senderMaxHeights","onTrack","evt","_remoteTrackAdded","_remoteTrackRemoved","onaddstream","_remoteStreamAdded","onremovestream","_remoteStreamRemoved","ondatachannel","_processStat","stat","statValue","endTime","dumpSDP","isAddOperation","hasLocalSource","hasAnyTracksOfType","mediaTransferActive","_getReceiversByEndpointIds","endpoints","receivers","getRemoteTracks","remoteTrackIds","getReceivers","audioReceivers","getSynchronizationSources","tracks","endpointTracksByMediaType","primarySsrcs","fidLines","getTargetVideoBitrates","findTrackById","RTC","isUserStreamById","onaddtrack","onremovetrack","streamAudioTracks","audioTrack","streamVideoTracks","remoteSDP","mediaLines","mls","trackSsrc","_createRemoteTrack","remoteTracksMap","userTracksByMediaType","existingTrack","isUserStream","toBeRemoved","_removeRemoteTrack","removeRemoteTracks","removedTracks","remoteTracksByMedia","_extractSSRCMap","groupsMap","groupSSRCs","_getSSRC","_injectSsrcGroupForUnifiedSimulcast","getters","audioMedia","changed","videoMedia","enforceSendRecv","_adjustRemoteMediaDirection","_isSharingScreen","_mungeCodecOrder","codecPreference","bitrates","hdBitrate","webrtcStream","_addStream","generateNewStreamSSRCInfo","rtxSsrcMapping","promiseChain","_assertTrackBelongs","webRtcStream","addStream","_removeStream","removeStream","doesBelong","defaultCodec","lowFps","findSenderByKind","getSenders","negotiationNeeded","mediaActive","_ensureSimulcastGroupIsLast","localSdp","videoStartIndex","simStartIndex","otherStartIndex","simEndIndex","simStr","otherEndIndex","sdpHead","simStrTrimmed","sdpTail","_adjustLocalMediaDirection","modifiedDirection","desiredAudioDirection","desiredVideoDirection","hasRemoteSource","_mungeOpus","opusMaxAverageBitrate","mLines","fmtpOpus","fmtpConfig","sdpChanged","maxaveragebitrate","mungedConfig","_initializeDtlsTransport","onstatechange","currentDescription","firstSsrcs","newSsrcLines","filteredLines","ssrcId","cnameLine","replaceDefaultUnifiedPlanMsid","normalizePlanB","videoSender","preference","degradationPreference","encodingsEnabledState","maxBitrates","scaleFactor","layer","sendTones","tones","interToneGap","rtpSender","dtmf","localAudioTrack","createDTMFSender","ontonechange","_onToneChange","toneBuffer","insertDTMF","tone","peerTracks","_removePeerConnection","_createOfferOrAnswer","isOffer","logName","handleSuccess","resolveFn","rejectFn","_processLocalSSRCsMap","handleFailure","eventType","capabilities","setCodecPreferences","oaPromise","_extractPrimarySSRC","sourceIdentifier","newSSRCNum","oldSSRCNum","activeStreams","currNumSsrcs","ConnectionQualityEvents","peerConnectionIdCounter","rtcTrackIdCounter","_createLocalTracks","mediaStreamMetaData","metaData","peerConnections","_lastN","_lastNEndpoints","_forwardedSources","_maxFrameHeight","_selectedEndpoints","_lastNChangeListener","_forwardedSourcesChangeListener","_onDeviceListChanged","_updateAudioOutputForAudioTracks","_videoType","BridgeVideoType","destroy","_channelOpenListener","tracksInfo","initializeBridgeChannel","logError","msgType","_receiverVideoConstraints","oldLastNEndpoints","leavingLastNEndpoints","enteringLastNEndpoints","oldForwardedSources","setNewReceiverVideoConstraints","setVideoType","sendSourceVideoType","selectEndpoints","ids","signaling","encodedInsertableStreams","sdpSemantics","bundlePolicy","newConnection","traceablePeerConnection","addLocalTrack","getForwardedSources","localVideo","getLocalAudioTrack","localAudio","pcRemoteTracks","mutePromises","removeLocalTrack","elSelector","sendChannelMessage","setLastN","remoteAudioTracks","LOCAL_STATS_UPDATED","REMOTE_STATS_UPDATED","kSimulcastFormats","layers","targetRN","ConnectionQuality","_localStats","connectionQuality","jvbRTT","_lastConnectionQualityUpdate","_remoteStats","_timeIceConnected","_timeVideoUnmuted","ConferenceEvents","_updateLocalConnectionQuality","_broadcastLocalStats","ICE_CONNECTION_STATE_CHANGED","_updateRemoteStats","_updateLocalStats","_maybeUpdateUnmuteTime","serverRegion","bridgeCount","_calculateConnectionQuality","resolutionName","quality","DESKTOP","activeTPC","getActivePeerConnection","videoQualitySettings","millisSinceStart","simulcastFormat","targetHeight","rampUp","getTarget","maxIncreasePerSecond","prevConnectionQuality","diffSeconds","updateLocalConnectionQuality","isConnectionInterrupted","IceFailedHandling","_actOnIceFailed","explicitlyDisabled","useTerminateForRestart","jvbConnection","jvbConnIceState","_canceled","_iceFailedTimeout","DetectionEvents","DETECTOR_STATE_CHANGE","VAD_NOISY_DEVICE","VAD_REPORT_PUBLISHED","VAD_SCORE_PUBLISHED","VAD_TALK_WHILE_MUTED","NoAudioSignalDetection","_timeoutTrigger","_hasAudioInput","_audioLevel","_trackAdded","_clearTriggerTimeout","_handleAudioInputStateChange","_handleNoAudioInputDetection","_eventFired","_audioTrack","P2PDominantSpeakerDetection","myUserID","createAudioContext","AudioContextImpl","TrackVADEmitter","procNodeSampleRate","vadProcessor","_procNodeSampleRate","_vadProcessor","_localTrack","_bufferResidue","Float32Array","_audioContext","sampleRate","getRequiredPCMFrequency","_vadSampleSize","getSampleLength","_onAudioProcess","_initializeAudioContext","_audioSource","_audioProcessingNode","createScriptProcessor","audioEvent","inData","inputBuffer","getChannelData","completeInData","sampleTimestamp","pcmSample","vadScore","calculateAudioFrameVAD","score","pcmData","_connectAudioGraph","onaudioprocess","destination","_disconnectAudioGraph","_cleanupResources","getDeviceLabel","_destroyed","VADAudioAnalyser","createVADProcessor","_createVADProcessor","_vadEmitter","_isVADEmitterRunning","_detectionServices","_vadInitTracker","_processVADScore","_trackRemoved","addVADDetectionService","vadService","detector","_stopVADEmitter","_startVADEmitter","processVADScore","_changeDetectorsMuteState","changeMuteState","vadEmitter","VADNoiseDetection","_processing","_scoreArray","_audioLvlArray","_active","_calculateNoisyScore","scoreAvg","audioLevelAvg","_setActiveState","_recordValues","avgAudioLvl","_processTimeout","posAudioLevels","VADTalkMutedDetection","_calculateVADScore","E2ePingEvents","E2E_RTT_CHANGED","E2E_PING_REQUEST","E2E_PING_RESPONSE","ParticipantWrapper","e2eping","requests","lastRequestId","clearIntervals","sendRequest","handleResponse","maybeSendAnalytics","isDataChannelOpen","pingIntervalMs","analyticsInterval","analyticsIntervalMs","requestId","requestMessage","timeSent","createE2eRttEvent","E2ePing","participantJoined","participantLeft","messageReceived","dataChannelOpened","participantWrapper","handleRequest","Jvb121EventGenerator","_jvb121","evaluateStatus","oldStatus","getParticipantCount","ReceiverVideoConstraints","_defaultConstraints","defaultConstraints","onStageEndpoints","updateLastN","updateReceiveResolution","updateReceiverVideoConstraints","updateSelectedEndpoints","ReceiveVideoController","_rtc","startLastN","channelLastN","useNewBandwidthAllocationStrategy","remoteEndpointIds","oldConstraints","newConstraints","setPreferredReceiveMaxFrameHeight","setReceiverConstraints","isEndpointsFormat","isSourcesFormat","p2pSession","SendVideoController","_preferredSendMaxFrameHeight","_sourceSenderConstraints","_configureConstraintsForLocalSources","_onSenderConstraintsReceived","_propagateSendMaxFrameHeight","getActiveMediaSession","_senderVideoConstraints","idealHeight","sendMaxFrameHeight","_selectSendMaxFrameHeight","activeMediaSession","setPreferredSendMaxFrameHeight","getFocusRecordingUpdate","jibriStatus","recordingMode","sessionID","getHiddenDomainUpdate","liveStreamViewURLContainer","liveStreamViewURL","modeContainer","sessionIDContainer","getSessionIdFromIq","jibri","getSessionId","sessionIdContainer","isFromFocus","JibriSession","_connection","_setSessionID","setStatus","getID","_sessionID","getInitiator","_initiator","getLiveStreamViewURL","_liveStreamViewURL","getTerminator","_terminator","getMode","setError","setLiveStreamViewURL","appData","broadcastId","_createIQ","recordingXMLUtils","_setErrorFromIq","AudioOutputProblemDetector","_localAudioLevelCache","_reportedParticipants","_audioProblemCandidates","_numberOfRemoteAudioLevelsReceived","_onLocalAudioLevelsReport","_onRemoteAudioLevelReceived","_clearUserData","numberOfReports","localAudioLevels","remoteAudioLevels","localAudioLevelsString","createAudioOutputProblemEvent","AverageStatReport","calculate","appendReport","ConnectionAvgStats","avgRtpStatsReporter","_n","_sampleIdx","_avgRTT","_avgRemoteRTTMap","_avgRtpStatsReporter","_avgEnd2EndRTT","_onConnectionStats","_calculateAvgStats","_onRemoteStatsUpdated","_processRemoteStats","batchReport","jvbEnd2EndRTT","jvbStatsMonitor","avgRemoteRTT","_calculateAvgRemoteRTT","avgLocalRTT","_resetAvgStats","remoteAvg","avg","validData","rttAvg","AvgRTPStatsReporter","_avgAudioBitrateUp","_avgAudioBitrateDown","_avgVideoBitrateUp","_avgVideoBitrateDown","_avgBandwidthUp","_avgBandwidthDown","_avgPacketLossTotal","_avgPacketLossUp","_avgPacketLossDown","_avgRemoteFPS","_avgRemoteScreenFPS","_avgLocalFPS","_avgLocalScreenFPS","_avgRemoteCameraPixels","_avgRemoteScreenPixels","_avgLocalCameraPixels","_avgLocalScreenPixels","_avgCQ","_cachedTransportStats","_onLocalStatsUpdated","_maybeSendTransportAnalyticsEvent","_onP2PStatusChanged","p2pStatsMonitor","_onJvb121StatusChanged","_resetAvgJvbStats","confSize","_calculateAvgVideoFps","_calculateAvgVideoPixels","peerResolutions","peerPixelsSum","peerCount","myID","peerID","videosResolution","peerAvgPixels","_calculatePeerAvgVideoPixels","videos","peerSsrcCount","peerSsrcPixels","peerFpsSum","videosFps","peerAvgFPS","_calculatePeerAvgVideoFps","peerSsrcFps","transportStats","isLocalStats","_userId","setDisplayName","_isLocalStats","setDominantSpeaker","totalDominantSpeakerTime","_dominantSpeakerStart","_hasLeft","_facialExpressions","happy","neutral","surprised","angry","fearful","disgusted","sad","getUserId","newName","isDominantSpeaker","isNowDominantSpeaker","timeElapsed","getTotalDominantSpeakerTime","hasLeft","markAsHasLeft","getFacialExpressions","setFacialExpressions","facialExpressions","addFacialExpression","FacialExpressions","SpeakerStatsCollector","dominantSpeakerId","SpeakerStats","_onDominantSpeaker","_onUserJoin","_onUserLeave","_onDisplayNameChange","_onFacialExpressionAdd","_updateStats","oldDominantSpeaker","newDominantSpeaker","savedUser","newStats","speakerStatsToUpdate","newParticipant","RecordingResult","wordArray","TrackRecorder","recorder","AUDIO_WEBM","AUDIO_OGG","startRecorder","trackRecorder","stopRecorder","determineCorrectFileType","MediaRecorder","isTypeSupported","AudioRecorder","jitsiConference","recorders","fileType","isRecording","instantiateTrackRecorder","updateNames","originalStream","ondataavailable","dataEvent","recorderToRemove","revokeObjectURL","getRecordingResults","getFileType","Word","word","begin","getWord","getBeginTime","getEndTime","SphinxService","recordingResult","verify","formatResponse","audioBlob","sphinxURL","toReturn","getURL","audioFileBlob","XMLHttpRequest","onreadystatechange","DONE","responseText","open","setRequestHeader","audioRecorder","objects","filler","BEFORE_STATE","RECORDING_STATE","TRANSCRIBING_STATE","FINISHED_STATE","Transcriber","transcriptionService","transcription","lineLength","blobCallBack","transcriber","getUTCMilliseconds","wordObject","maybeMerge","hasPopulatedArrays","twoDimensionalArray","callBack","arrays","potentialWords","pushWordToSortedArray","lowestWordArray","wordToAdd","updateTranscription","foundSmaller","wordToCompare","getTranscription","ComponentsVersions","addCommandListener","processVersions","VideoSIPGWStatusConstants","VideoSIPGWStateConstants","VideoSIPGWErrorConstants","mucResource","getComponentVersion","componentName","STATUS_AVAILABLE","STATUS_UNDEFINED","STATUS_BUSY","STATE_ON","STATE_OFF","STATE_PENDING","STATE_RETRYING","STATE_FAILED","ERROR_NO_CONNECTION","ERROR_SESSION_EXISTS","STATE_CHANGED","JitsiVideoSIPGWSession","sipAddress","VideoSIPGWConstants","_sendJibriIQ","setState","failureReason","oldState","addStateListener","removeStateListener","sipaddress","displayname","nodeTree","VideoSIPGW","sessionStateChangeListener","sessionStateChanged","handleJibriSIPState","Constants","failure_reason","createVideoSIPGWSession","SOURCE_INFO_PRESENCE_ELEMENT","SignalingLayerImpl","ssrcOwners","_localSourceState","_remoteSourceState","_sourceNames","_addLocalSourceInfoToPresence","_doesEndpointSendNewSourceInfo","setChatRoom","oldChatRoom","_audioMuteHandler","_videoMuteHandler","_videoTypeHandler","_sourceInfoHandler","_memberLeftHandler","_bindChatRoomEventHandlers","emitAudioMutedEvent","emitVideoMutedEvent","emitVideoTypeEvent","sourceInfoJSON","emitEventsFromHere","endpointSourceState","newMutedState","oldSourceState","newVideoType","newSourceNames","_findEndpointSourceInfoForMediaType","remoteSourceState","legacyGetPeerMediaInfo","lastPresence","mediaInfo","endpointMediaSource","existingOwner","setTrackMuteStatus","setTrackVideoType","existingName","JitsiConference","eventManager","componentsVersions","dtmfManager","somebodySupportsDTMF","wasStopped","avgRtpStatsN","_audioOutputProblemDetector","speakerStatsCollector","deferredStartP2PTask","backToP2PDelay","isP2PConnectionInterrupted","videoSIPGWHandler","recordingManager","_sessions","_chatRoom","getSession","_handleFocusPresence","_handleJibriPresence","startRecording","_addSession","_emitSessionUpdate","stopRecording","_createSession","_conferenceJoinAnalyticsEventSent","isE2EESupported","_e2eEncryption","_audioSenderLimitReached","_videoSenderLimitReached","JitsiConnection","appID","errType","errorType","errorMessage","createConnectionFailedEvent","ANALYTICS_CONNECTION_DISCONNECTED","JitsiMediaDevicesEvents","resourceCreator","isAuthenticatedUser","re","codecSettings","codecSelection","_statsCurrentId","statisticsId","_onIceConnectionInterrupted","_onIceConnectionRestored","_onIceConnectionEstablished","_updateProperties","_sendConferenceJoinAnalyticsEvent","_removeLocalSourceOnReject","_updateRoomPresence","_registerRtcListeners","receiveVideoController","sendVideoController","callStatsThreshold","statisticsDisplayName","callStatsCustomScriptUrl","callStatsConfigParams","enableTalkWhileMuted","_audioAnalyser","vadTalkMutedDetection","enableNoisyMicDetection","vadNoiseDetection","enableNoAudioDetection","_noAudioSignalDetection","hasAudioSignal","jvb121Status","p2pDominantSpeakerDetection","userRegion","transcriptionLanguage","_maybeSetSITimeout","isJoined","isP2PEnabled","isP2PTestModeEnabled","p2pTestMode","onLocalTrackRemoved","_sendConferenceLeftAnalyticsEvent","_delayedIceFailed","_maybeClearDeferredStartP2P","_maybeClearSITimeout","leaveError","localtrack","_desktopSharingFrameRate","isAuthEnabled","isLoggedIn","getAuthLogin","getExternalAuthUrl","urlForPopup","getPerformanceStats","longTasksStats","eventId","command","removeCommandListener","sendTextMessage","sendPrivateTextMessage","sendCommand","sendCommandOnce","removeCommand","nickKey","getTranscriber","localAudioTracks","getTranscriptionStatus","addTrackPromises","_setupNewTrack","_fireMuteChangeEvent","_fireAudioLevelChangeEvent","activeTpc","actorId","_getInitialLocalTracks","trackType","isStartAudioMuted","isStartVideoMuted","muteHandler","audioLevelHandler","oldVideoType","oldTrackBelongsToConference","_doReplaceTrack","replaceTrackPromises","_setNewVideoType","videoTypeChanged","videoTypeTagName","trackVideoType","legacyTypeChanged","presenceChanged","audioMuteChanged","videoMuteChanged","addAsUnmutePromises","removeAsMutePromises","unlock","selectParticipant","selectParticipants","isInteger","isVideoActive","countHidden","grantOwner","revokeOwner","isMyself","isMembersOnly","kickParticipant","_sessionInitiateTimeout","muteMediaType","fullJid","_updateFeatures","_maybeStartOrStopP2P","updateDTMFSupport","botParticipant","mediaSessions","tracksToBeRemoved","kickedParticipantId","kickedParticipant","transportInfo","removedTrack","_onIncomingCallP2P","rejectReason","_shouldBeInP2PMode","_rejectIncomingCall","_acceptP2PIncomingCall","_acceptJvbIncomingCall","_suspendMediaTransferForJvbConnection","webSocket","stopOptions","forceJvb121","p2pFailed","_stopP2PSession","isDTMFSupported","peerConnection","startTranscriber","stopTranscriber","getMeetingUniqueId","setStartMutedPolicy","policy","getStartMutedPolicy","removeLocalParticipantProperty","getLocalParticipantProperty","property","overallFeedback","detailedFeedback","getSsrcByTrack","remoteUserId","_fireIncompatibleVersionsEvent","sendEndpointMessage","broadcastEndpointMessage","sendThroughVideobridge","messageType","messageToSend","remoteID","_addRemoteJVBTracks","_addRemoteTracks","_addRemoteP2PTracks","p2pEstablishmentDuration","jvbEstablishmentDuration","forceJVB121Ratio","establishmentDurationDiff","_setP2PStatus","_removeRemoteJVBTracks","audioLimitReached","videoLimitReached","_removeRemoteTracks","_removeRemoteP2PTracks","sessionNickname","_resumeMediaTransferForJvbConnection","_startP2PSession","userLeftEvent","peers","shouldBeInP2P","myId","peersId","hasBotPeer","wasP2PEstablished","muteStatusChanged","audioMuteStatusChanged","videoMuteStatusChanged","getP2PConnectionState","startP2PSession","stopP2PSession","getSpeakerStats","sendFacialExpression","perf","toggleE2EE","setMediaEncryptionKey","isLobbySupported","disableLobby","joinLobby","myLobbyUserId","sendLobbyMessage","addLobbyMessageListener","removeLobbyMessageHandler","lobbyDenyAccess","lobbyApproveAccess","isAVModerationSupported","enableAVModeration","disableAVModeration","avModerationApprove","avModerationReject","setToken","initJitsiConference","getLogs","PERMISSION_PROMPT_IS_SHOWN","SLOW_GET_USER_MEDIA","AUDIO_PERMISSION_NAME","VIDEO_PERMISSION_NAME","_permissions","_logOutputDevice","permissions","_handlePermissionsChange","_permissionsApiSupported","query","_parsePermissionState","onchange","supported","permissionStatus","deviceID","isDevicePermissionGranted","isMultipleAudioInputSupported","emitEvent","stopActiveDevices","ACTIONS","ProxyConnectionPC","receiveAudio","receiveVideo","_peerConnection","_onError","_onRemoteStream","_onSendMessage","getPeerJid","processMessage","$jingle","ACCEPT","_onSessionAccept","INITIATE","_onSessionInitiate","TERMINATE","_onSessionTerminate","TRANSPORT_INFO","_onTransportInfo","_createPeerConnection","connectionStub","pcConfigStub","roomStub","jitsiRemoteTrack","onRemoteStream","onSendMessage","PRECALL_TEST_RESULTS","_initialized","api","_loadScript","appId","appSecret","disablePrecalltest","_initialize","execute","makePrecallTest","AudioMixer","_started","_streamsToMix","_streamMSSArray","addMediaStream","_mixedMSD","createMediaStreamDestination","streamMSS","getAnalyticsAttributesFromOptions","video_requested","JitsiMeetJS","ProxyConnectionService","jitsiConnection","_onFatalError","_convertStringToXML","UNAVAILABLE","_selfCloseConnection","xmlDom","isVideo","convertVideoToDesktop","jitsiLocalTracks","createLocalTracks","stringifiedIq","onConnectionClosed","constants","recording","BUSY","RESOURCE_CONSTRAINT","UNEXPECTED_REQUEST","SERVICE_UNAVAILABLE","FILE","STREAM","sipVideoGW","detection","errors","errorTypes","logLevels","JitsiMediaDevices","enableAnalyticsLogging","enableWindowOnErrorHandler","getGlobalOnErrorHandler","isWebRtcSupported","addGlobalLogTransport","globalTransport","removeGlobalLogTransport","setGlobalLogOptions","oldfirePermissionPromptIsShownEvent","promiseFulfilled","firePermissionPromptIsShownEvent","fireSlowPromiseEvent","restOptions","mStream","currentlyAvailableMediaDevices","setVideoTrackContentHints","createTrackVADEmitter","localAudioDeviceId","createAudioMixer","getActiveAudioDevice","audioDevices","devicePromiseArray","micDevice","devicePromise","outcomeArray","successfulPromises","rejectedPromises","rejectReasons","deviceLabel","isCollectingLocalStats","lineno","colno","setNetworkInfo","hint","contentHint","precallTest","util","AuthUtil","global$1","WebSocketImplementation","getWebSocketImplementation","DOMParserImplementation","getDOMParserImplementation","getDummyXMLDOMDocument","documentMode","docStrings","ActiveXObject","_getIEXmlDom","safe_add$1","y","lsw","str2binl","bin","md5_cmn","cnt","md5_ff","md5_gg","md5_hh","md5_ii","core_md5","olda","oldb","oldc","oldd","MD5","hexdigest","binarray","hex_tab","binl2hex","binl2str","SASLMechanism","isClientFirst","mechname","onStart","onChallenge","challenge","clientChallenge","utils","out","cookies","cookieName","expires","path","cookieObj","isObj","cookieValue","unescape","cookie","core_sha1","olde","rol","safe_add","sha1_ft","sha1_kt","core_hmac_sha1","bkey","str2binb","ipad","opad","binb2b64","triplet","binb2str","SHA1","b64_hmac_sha1","str_hmac_sha1","str_sha1","abab","atob","accumulatedBits","chr","btoa","groupsOfSix","Builder","VERSION","NS","HTTPBIND","BOSH","CLIENT","AUTH","ROSTER","PROFILE","DISCO_INFO","DISCO_ITEMS","MUC","SASL","FRAMING","BIND","SESSION","STANZAS","XHTML_IM","XHTML","validTag","validAttribute","validCSS","CONNECTING","CONNFAIL","AUTHENTICATING","AUTHFAIL","DISCONNECTED","DISCONNECTING","ATTACHED","REDIRECT","CONNTIMEOUT","BINDREQUIRED","ATTACHFAIL","ErrorCondition","BAD_FORMAT","CONFLICT","MISSING_JID_NODE","NO_AUTH_MECH","UNKNOWN_REASON","LogLevel","FATAL","ElementType","NORMAL","TEXT","CDATA","FRAGMENT","SECONDARY_TIMEOUT","addNamespace","forEachChild","elemName","childNode","isTagEqual","_xmlGenerator","xmlGenerator","xmlTextNode","xmlescape","xmlunescape","xmlHtmlNode","loadXML","copyElement","createHtml","cssAttrs","cssName","cssValue","escapeNode","unescapeNode","getNodeFromJid","getDomainFromJid","bare","getBareJidFromJid","getResourceFromJid","_handleError","fatal","sourceURL","fileName","_console","_requestId","_connectionPlugins","ptype","moreattrs","impNode","xmlGen","newElem","h","xhtml","matchBare","matchBareFromJid","Handler","getNamespace","elNamespace","ignoreNamespaceFragment","namespaceMatch","nsMatch","isMatch","elem_type","run","TimedHandler","period","lastCalled","Connection","setProtocol","_sasl_data","do_bind","do_session","mechanisms","timedHandlers","removeTimeds","removeHandlers","addTimeds","addHandlers","protocolErrorHandlers","_idleTimeout","_disconnectTimeout","authenticated","do_authentication","restored","_uniqueId","_sasl_success_handler","_sasl_failure_handler","_sasl_challenge_handler","_onIdle","registerSASLMechanisms","F","WorkerWebsocket","Websocket","Bosh","_reset","_requests","getUniqueId","addProtocolErrorHandler","status_code","route","authcid","disconnection_timeout","authzid","connect_callback","wind","_attach","restore","_sessionCachingSupported","_restore","sessionStorage","xmlInput","xmlOutput","nextValidRid","_queueData","timeoutHandler","deleteTimedHandler","addTimedHandler","iqtype","_sendRestart","thand","handRef","hand","SASLAnonymous","SASLExternal","SASLOAuthBearer","SASLXOAuth2","SASLPlain","SASLSHA1","registerSASLMechanism","Mechanism","_addSysTimedHandler","_onDisconnectTimeout","_disconnect","condition","statusChanged","_dataRecv","_reqToData","strip","_emptyQueue","cond","conflict","UNKOWN_REASON","_connect_cb","_callback","bodyWrap","hasFeatures","_no_auth_received","sortMechanismsByPriority","higher","_attemptSASLAuth","_attemptLegacyAuth","mechanism_found","_sasl_success_cb","_sasl_failure_cb","_sasl_challenge_cb","_sasl_mechanism","request_auth_exchange","_onLegacyAuthIQResult","_auth2_cb","serverSignature","attribMatch","streamfeature_handlers","_onStreamFeaturesAfterSASL","explicitResourceBinding","_onResourceBindResultIQ","jidNode","_establishSession","_onSessionResultIQ","auth_str","iter","Hi","U","U_old","authMessage","cnonce","clientKey","serverKey","clientSignature","test_cnonce","core","Request","sends","xmlData","origFunc","date","NaN","abort","dead","age","timeDead","xhr","_newXHR","getResponse","responseXML","overrideMimeType","_conn","inactivity","keepalive","_cacheSession","_onRequestStateChange","_throttledRequestHandler","typ","_sendTerminate","_callProtocolErrorHandlers","reqStatus","_getRequestStatus","err_callback","HTTP","_hitError","time_elapsed","static","def","getAllResponseHeaders","valid_request","too_many_retries","_removeRequest","reqIs0","_restartRequest","_processRequest","primary_timeout","secondary_timeout","server_error","content_type","contentType","withCredentials","e2","sendFunc","customHeaders","backoff","new_service","host","pathname","_buildStream","_checkStreamError","connectstatus","errorString","_onOpen","_onInitialMessage","_handleStreamStart","streamStart","parsedMessage","see_uri","_replaceMessageHandler","_streamWrap","CLOSED","closeString","rawStanza","startString","lmap","SharedWorker","_messageHandler","_onWorkerMessage","_attachCallback","method_name","strophe_js","_items","conn","_onDiscoInfo","_onDiscoItems","addIdentity","var_name","addItem","call_back","_buildIQResult","query_attrs","iqresult","logging","autoSendCountOnEveryIncomingStanza","requestResponseInterval","_c","_NS","_isStreamManagementEnabled","_serverProcesssedStanzasCounter","_clientProcessedStanzasCounter","_clientSentStanzasCounter","_originalXMLOutput","_requestHandler","_incomingHandler","_requestResponseIntervalCount","_isSupported","_unacknowledgedStanzas","_acknowledgedStanzaListeners","addAcknowledgedStanzaListener","_resumeToken","_resuming","_originalConnect","_connectArgs","requestAcknowledgement","getOutgoingCounter","getIncomingCounter","_interceptConnectArgs","_originalOnStreamFeaturesAfterSASL","_originalDoDisconnect","_interceptDoDisconnect","_originalDisconnect","_interceptDisconnect","_resumeState","_storedJid","previd","_handleServerRequestHandler","_ackHandler","_handleServerAck","_incomingStanzaHandler","_enabledHandler","_handleEnabled","_resumeFailedHandler","_handleResumeFailed","_resumedHandler","_handleResumed","_increaseSentStanzasCounter","handledCount","_handleAcknowledgedStanzas","_increaseReceivedStanzasCounter","_answerProcessedStanzas","reportedHandledCount","lastKnownHandledCount","_throwError","logDisabled_","deprecationWarnings_","extractVersion","uastring","wrapPeerConnectionEvent","eventNameToWrap","nativeAddEventListener","nativeEventName","wrappedCallback","modifiedEvent","handleEvent","_eventMap","nativeRemoveEventListener","unwrappedCb","disableLog","disableWarnings","deprecated","oldMethod","newMethod","compactObject","walkStats","resultSet","filterStats","outbound","streamStatsType","filteredResult","trackStats","trackStat","shimGetUserMedia","browserDetails","constraintsToChrome_","cc","exact","oldname_","mix","advanced","shimConstraints_","remap","face","getSupportedFacingModeLies","getSupportedConstraints","dev","shimError_","PermissionDeniedError","PermissionDismissedError","InvalidStateError","DevicesNotFoundError","ConstraintNotSatisfiedError","TrackStartError","MediaDeviceFailedDueToShutdown","MediaDeviceKillSwitchOn","TabCaptureError","ScreenCaptureError","DeviceCaptureError","webkitGetUserMedia","origGetUserMedia","shimGetDisplayMedia","getSourceId","widthSpecified","heightSpecified","frameRateSpecified","shimMediaStream","webkitMediaStream","shimOnTrack","_ontrack","origSetRemoteDescription","_ontrackpoly","te","dispatchEvent","shimGetSendersWithDtmf","shimSenderWithDtmf","_dtmf","_pc","_senders","origAddTrack","origRemoveTrack","origAddStream","origRemoveStream","origGetSenders","shimGetStats","origGetStats","onSucc","onErr","fixChromeStats_","standardReport","standardStats","localcandidate","remotecandidate","makeMapStats","successCallbackWrapper_","shimSenderReceiverGetStats","origGetReceivers","srcElement","MediaStreamTrack","shimAddTrackRemoveTrackWithNative","getLocalStreams","_shimmedLocalStreams","existingSenders","newSenders","newSender","shimAddTrackRemoveTrack","origGetLocalStreams","nativeStreams","_reverseStreams","_streams","newStream","replaceInternalStreamId","internalId","externalStream","internalStream","replaceExternalStreamId","alreadyExists","oldStream","nativeMethod","methodObj","origSetLocalDescription","origLocalDescription","getOwnPropertyDescriptor","streamid","shimPeerConnection","webkitRTCPeerConnection","fixNegotiationNeeded","getConfiguration","nativeGetUserMedia","nativeGetSettings","applyConstraints","nativeApplyConstraints","preferredMediaSource","mediaSource","RTCTrackEvent","mozRTCPeerConnection","modernStatsTypes","inboundrtp","outboundrtp","candidatepair","nativeGetStats","shimSenderGetStats","shimReceiverGetStats","shimRemoveStream","shimRTCDataChannel","DataChannel","RTCDataChannel","shimAddTransceiver","origAddTransceiver","setParametersPromises","initParameters","shouldPerformCheck","encodingParam","maxFramerate","shimGetParameters","origGetParameters","shimCreateOffer","origCreateOffer","finally","shimCreateAnswer","origCreateAnswer","shimLocalStreamsAPI","_localStreams","_addTrack","shimRemoteStreamsAPI","getRemoteStreams","_remoteStreams","_onaddstream","_onaddstreampoly","shimCallbacksAPI","withCallback","shimConstraints","errcb","shimRTCIceServerUrls","OrigPeerConnection","newIceServers","generateCertificate","shimTrackEventTransceiver","shimCreateOfferLegacy","offerOptions","audioTransceiver","setDirection","videoTransceiver","shimAudioContext","shimRTCIceCandidate","NativeRTCIceCandidate","nativeCandidate","parsedCandidate","augmentedCandidate","toJSON","shimMaxMessageSize","_sctp","sctpInDescription","getRemoteFirefoxVersion","getCanSendMaxMessageSize","remoteIsFirefox","canSendMaxMessageSize","getMaxMessageSize","canSendMMS","remoteMMS","POSITIVE_INFINITY","shimSendThrowTypeError","wrapDcSend","dc","origDataChannelSend","origCreateDataChannel","dataChannel","shimConnectionState","checking","_onconnectionstatechange","origMethod","_connectionstatechangepoly","_lastConnectionState","newEvent","removeExtmapAllowMixed","nativeSRD","shimAddIceCandidateNullOrEmpty","nativeAddIceCandidate","shimParameterlessSetLocalDescription","nativeSetLocalDescription","adapter","shimChrome","shimFirefox","shimSafari","mozGetUserMedia","isSecureContext","RTCIceGatherer","commonShim","browserShim","adapterFactory","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","loaded","__webpack_modules__","amdO","definition","globalThis","nmd","paths","__webpack_exports__"],"sourceRoot":""}