{"version":3,"mappings":"02BAAe,MAAMA,EAAS,CAC1B,YAAYC,EAAOC,EAAM,CAAE,sBAAAC,EAAuB,mBAAAC,CAAoB,EAAG,GAAI,CACzE,KAAK,MAAQH,EACb,KAAK,KAAOC,EACZ,KAAK,sBAAwBC,GAA6F,GAC1H,KAAK,mBAAqBC,GAAoF,GAC9G,KAAK,YAAc,GACdF,EAAK,KACNA,EAAK,GAAK,YAAY,KAAK,OAAM,EAAG,SAAQ,EAAG,MAAM,EAAG,CAAC,CAAC,IAE9D,KAAK,aAAe,CAAC,CAAC,UAAU,UAAU,MAAM,WAAW,EAC3D,KAAK,qBAAuBG,GAASC,GAAiBD,EAAO,IAAI,EACjE,KAAK,wBAA0BA,GAASE,GAAiBF,EAAO,IAAI,EACpE,KAAK,aAAe,KAAK,eAAe,KAAK,IAAI,EACjDJ,EAAM,aAAa,OAAQ,UAAU,EACrCA,EAAM,aAAa,gBAAiBC,EAAK,EAAE,EAC3CD,EAAM,aAAa,gBAAiB,OAAO,EAC3CA,EAAM,aAAa,oBAAqB,MAAM,EAC9CA,EAAM,aAAa,gBAAiB,SAAS,CAChD,CACD,SAAU,CACN,KAAK,eAAc,EACnB,KAAK,KAAI,EACT,KAAK,MAAM,gBAAgB,MAAM,EACjC,KAAK,MAAM,gBAAgB,eAAe,EAC1C,KAAK,MAAM,gBAAgB,eAAe,EAC1C,KAAK,MAAM,gBAAgB,mBAAmB,EAC9C,KAAK,MAAM,gBAAgB,eAAe,CAC7C,CACD,OAAQ,CACJ,KAAK,MAAM,aAAa,gBAAiB,MAAM,EAC/C,KAAK,MAAM,iBAAiB,mBAAoB,KAAK,uBAAuB,EAC5E,KAAK,MAAM,iBAAiB,iBAAkB,KAAK,uBAAuB,EAC1E,KAAK,MAAM,iBAAiB,QAAS,KAAK,YAAY,EACtD,KAAK,MAAM,iBAAiB,UAAW,KAAK,oBAAoB,EAChE,KAAK,KAAK,iBAAiB,QAASO,EAAiB,EACrD,KAAK,sBAAqB,CAC7B,CACD,MAAO,CACH,KAAK,eAAc,EACnB,KAAK,MAAM,aAAa,gBAAiB,OAAO,EAChD,KAAK,MAAM,oBAAoB,mBAAoB,KAAK,uBAAuB,EAC/E,KAAK,MAAM,oBAAoB,iBAAkB,KAAK,uBAAuB,EAC7E,KAAK,MAAM,oBAAoB,QAAS,KAAK,YAAY,EACzD,KAAK,MAAM,oBAAoB,UAAW,KAAK,oBAAoB,EACnE,KAAK,KAAK,oBAAoB,QAASA,EAAiB,CAC3D,CACD,uBAAwB,CACpB,IAAIC,EACA,KAAK,sBACJA,EAAK,MAAM,KAAK,KAAK,KAAK,iBAAiB,6CAA6C,CAAC,EACrF,OAAOC,EAAO,EAAE,CAAC,KAAO,MAAQD,IAAO,QAAkBA,EAAG,aAAa,+BAAgC,MAAM,EAE3H,CACD,SAASE,EAAY,EAAG,CACpB,MAAMC,EAAU,MAAM,KAAK,KAAK,KAAK,iBAAiB,wBAAwB,CAAC,EAAE,OAAOF,EAAO,EAAE,CAAC,EAC5FG,EAAM,MAAM,KAAK,KAAK,KAAK,iBAAiB,iBAAiB,CAAC,EAAE,OAAOH,EAAO,EAC9EI,EAAaD,EAAI,QAAQD,CAAO,EACtC,GAAKE,IAAeD,EAAI,OAAS,GAAKF,IAAc,GAAOG,IAAe,GAAKH,IAAc,GAAK,CAC9F,KAAK,eAAc,EACnB,KAAK,MAAM,QACX,MACH,CACD,IAAII,EAAcJ,IAAc,EAAI,EAAIE,EAAI,OAAS,EACrD,GAAID,GAAWE,GAAc,EAAG,CAC5B,MAAME,EAAWF,EAAaH,EAC1BK,GAAY,GAAKA,EAAWH,EAAI,SAChCE,EAAcC,EACrB,CACD,MAAMC,EAASJ,EAAIE,CAAW,EAC9B,GAAKE,EAEL,UAAWC,KAAML,EACbK,EAAG,gBAAgB,8BAA8B,EAC7CD,IAAWC,GACX,KAAK,MAAM,aAAa,wBAAyBD,EAAO,EAAE,EAC1DA,EAAO,aAAa,gBAAiB,MAAM,EAC3CE,GAAS,KAAK,KAAMF,CAAM,GAG1BC,EAAG,gBAAgB,eAAe,CAG7C,CACD,gBAAiB,CACb,KAAK,MAAM,gBAAgB,uBAAuB,EAClD,UAAWA,KAAM,KAAK,KAAK,iBAAiB,wBAAwB,EAChEA,EAAG,gBAAgB,eAAe,EAEtC,KAAK,sBAAqB,CAC7B,CACL,CACA,SAASZ,GAAiBD,EAAOe,EAAU,CACvC,GAAI,EAAAf,EAAM,UAAYA,EAAM,SAAWA,EAAM,SAEzC,GAACe,EAAS,cAAgBf,EAAM,UAEhC,CAAAe,EAAS,YAEb,OAAQf,EAAM,IAAG,CACb,IAAK,QACGgB,GAAOD,EAAS,MAAOA,EAAS,IAAI,GACpCf,EAAM,eAAc,EAExB,MACJ,IAAK,MACGe,EAAS,uBAAyBC,GAAOD,EAAS,MAAOA,EAAS,IAAI,GACtEf,EAAM,eAAc,EAExB,MACJ,IAAK,SACDe,EAAS,eAAc,EACvB,MACJ,IAAK,YACDA,EAAS,SAAS,CAAC,EACnBf,EAAM,eAAc,EACpB,MACJ,IAAK,UACDe,EAAS,SAAS,EAAE,EACpBf,EAAM,eAAc,EACpB,MACJ,IAAK,IACGe,EAAS,cAAgBf,EAAM,UAC/Be,EAAS,SAAS,CAAC,EACnBf,EAAM,eAAc,GAExB,MACJ,IAAK,IACGe,EAAS,cAAgBf,EAAM,UAC/Be,EAAS,SAAS,EAAE,EACpBf,EAAM,eAAc,GAExB,MACJ,QACI,GAAIA,EAAM,QACN,MACJe,EAAS,eAAc,CAC9B,CACL,CACA,SAASZ,GAAkBH,EAAO,CAC9B,GAAI,EAAEA,EAAM,kBAAkB,SAC1B,OACJ,MAAMY,EAASZ,EAAM,OAAO,QAAQ,iBAAiB,EAChDY,GAEDA,EAAO,aAAa,eAAe,IAAM,QAE7CK,GAAgBL,CAAM,CAC1B,CACA,SAASI,GAAOpB,EAAOC,EAAM,CACzB,MAAMe,EAASf,EAAK,cAAc,+DAA+D,EACjG,OAAKe,GAEDA,EAAO,aAAa,eAAe,IAAM,QAE7CA,EAAO,MAAK,EACL,IAJI,EAKf,CACA,SAASK,GAAgBL,EAAQ,CAC7BA,EAAO,cAAc,IAAI,YAAY,kBAAmB,CAAE,QAAS,EAAM,EAAC,CAC9E,CACA,SAASP,GAAQQ,EAAI,CACjB,MAAQ,CAACA,EAAG,QACR,EAAEA,aAAc,kBAAoBA,EAAG,OAAS,YAC/CA,EAAG,YAAc,GAAKA,EAAG,aAAe,EACjD,CACA,SAASX,GAAiBF,EAAOe,EAAU,CACvCA,EAAS,YAAcf,EAAM,OAAS,mBACzB,SAAS,eAAee,EAAS,MAAM,aAAa,eAAe,GAAK,EAAE,GAGvFA,EAAS,eAAc,CAC3B,CACA,SAASD,GAASI,EAAWN,EAAQ,CAC5BO,GAAWD,EAAWN,CAAM,IAC7BM,EAAU,UAAYN,EAAO,UAErC,CACA,SAASO,GAAWD,EAAWE,EAAS,CACpC,MAAMC,EAAYH,EAAU,UACtBI,EAAkBD,EAAYH,EAAU,aACxCK,EAAMH,EAAQ,UACdI,EAASD,EAAMH,EAAQ,aAC7B,OAAOG,GAAOF,GAAaG,GAAUF,CACzC,CCtLA,MAAMG,GAAW,WACjB,SAASC,GAAMC,EAAMC,EAAKC,EAAQ,CAAE,UAAAC,EAAW,cAAAC,EAAe,kBAAAC,GAAsB,CAChF,UAAW,GACX,cAAe,EACf,kBAAmB,IACvB,EAAG,CACC,IAAIC,EAAWN,EAAK,YAAYC,EAAKC,EAAS,CAAC,EAG/C,GAFII,IAAa,IAEbA,EAAWF,EACX,OACJ,GAAID,EAAW,CACX,GAAIE,GAAqB,KAAM,CAC3B,GAAIA,IAAsBC,EACtB,OACJA,EAAWD,EAAoBJ,EAAI,MACtC,CAQD,GAPqBD,EAAKM,EAAW,CAAC,IACjB,KAAOJ,GAAUI,EAAWL,EAAI,OAAS,GAEzCD,EAAK,YAAY;AAAA,EAAME,EAAS,CAAC,EACnCI,GAEFN,EAAK,YAAY,IAAKE,EAAS,CAAC,EAClCI,EACX,MACP,SAEsBN,EAAK,YAAY,IAAKE,EAAS,CAAC,EAClCI,EACb,OAER,MAAMC,EAAMP,EAAKM,EAAW,CAAC,EAC7B,OAAIC,GAAO,CAACT,GAAS,KAAKS,CAAG,EACzB,OAEG,CACH,KAFgBP,EAAK,UAAUM,EAAWL,EAAI,OAAQC,CAAM,EAG5D,SAAUI,EAAWL,EAAI,MACjC,CACA,CAQA,MAAMO,WAA0B,WAAY,CAC5C,CAEA,MAAMC,WAAmC,KAAM,CAC3C,aAAc,CACV,MAAM,QAAQ,CACjB,CACL,CACA,MAAMC,GAAgB,IAAI,2DAmB1B,MAAMC,GAAN,MAAMA,WAA+BH,EAAkB,CAAvD,kCAAAI,GAAA,KAAAC,GACID,GAAA,KAAAE,GAAiB,IAAI,iBAAiB,IAAMC,GAAA,KAAKF,EAAAG,IAAL,UAAoB,GAChEJ,GAAA,KAAAK,GAAkB,IAAI,eAAe,IAAMF,GAAA,KAAKF,EAAAK,IAAL,UAA2B,GAKtEN,GAAA,KAAAO,IACAP,GAAA,KAAAQ,IA0GAR,GAAA,KAAAS,GAAW,GAEXT,GAAA,KAAAU,GAAW,GA2BXV,GAAA,KAAAW,GAAoB,IAkCpBX,GAAA,KAAAY,GAAW,IAAMT,GAAA,KAAKF,EAAAY,IAAL,YACjBb,GAAA,KAAAc,GAA6BrD,GAAU,CACnC0C,GAAA,KAAKF,EAAAc,IAAL,UAAkB1D,GAAU,EACpBI,EAAM,SAAW,UACjBA,EAAM,SAAW,QAChBA,EAAM,kBAAkB,MAAQA,EAAM,OAAO,SAASJ,CAAK,IAC5D8C,GAAA,KAAKF,EAAAK,IAAL,UAChB,EACA,GAvKI,OAAO,IAAIjD,EAAO,CACd,IAAI2D,EAAQlB,GAAc,IAAIzC,CAAK,EACnC,OAAK2D,IACDA,EAAQ,IAAIjB,GACZiB,EAAM,QAAQ3D,CAAK,EACnByC,GAAc,IAAIzC,EAAO2D,CAAK,GAE3BA,CACV,CASD,QAAQ3D,EAAO,CACX4D,GAAA,KAAKV,GAAY,IAAI,QAAQlD,CAAK,GAGlC4D,GAAA,KAAKT,GAAa,SAAS,cAAc,KAAK,GAC9CU,EAAA,KAAKV,IAAW,MAAM,SAAW,WACjCU,EAAA,KAAKV,IAAW,MAAM,cAAgB,OACtCnD,EAAM,MAAM6D,EAAA,KAAKV,GAAU,EAC3BU,EAAA,KAAKV,IAAW,YAAY,IAAI,CACnC,CAKD,aAAc,CACVL,GAAA,KAAKF,EAAAG,IAAL,WACAD,GAAA,KAAKF,EAAAY,IAAL,UACH,CAED,mBAAoB,CAChBV,GAAA,KAAKF,EAAAc,IAAL,UAAkB1D,GAAU,CACxB,KAAK,MAAM,cAAgB,OAC3B,KAAK,MAAM,WAAa,OACxB,KAAK,MAAM,SAAW,SACtB,KAAK,MAAM,QAAU,QAErB,KAAK,MAAM,WAAa,SACpBA,aAAiB,qBACjB,KAAK,MAAM,WAAa,WACxB,KAAK,MAAM,SAAW,eAGtB,KAAK,MAAM,WAAa,SAExB,KAAK,MAAM,QAAU,aACrB,KAAK,MAAM,cAAgB,UAE/B,KAAK,aAAa,cAAe,MAAM,EACvC8C,GAAA,KAAKF,EAAAG,IAAL,WACAD,GAAA,KAAKF,EAAAY,IAAL,WACAK,EAAA,KAAKhB,IAAe,QAAQ7C,EAAO,CAC/B,gBAAiB,CACb,QACA,KACH,CACjB,CAAa,EACD6D,EAAA,KAAKb,IAAgB,QAAQhD,CAAK,EAClC,SAAS,iBAAiB,SAAU6D,EAAA,KAAKJ,IAA2B,CAAE,QAAS,EAAI,CAAE,EACrF,OAAO,iBAAiB,SAAUI,EAAA,KAAKJ,IAA2B,CAAE,QAAS,EAAI,CAAE,EAEnFzD,EAAM,iBAAiB,QAAS6D,EAAA,KAAKN,IAAU,CAAE,QAAS,EAAI,CAAE,CAC5E,EACK,CAED,sBAAuB,QACnB/C,EAAAqD,EAAA,KAAKV,MAAL,MAAA3C,EAAiB,SACjBqD,EAAA,KAAKhB,IAAe,aACpBgB,EAAA,KAAKb,IAAgB,aACrB,SAAS,oBAAoB,SAAUa,EAAA,KAAKJ,IAA2B,CAAE,QAAS,EAAI,CAAE,EACxF,OAAO,oBAAoB,SAAUI,EAAA,KAAKJ,IAA2B,CAAE,QAAS,EAAI,CAAE,EAEtF,MAAMzD,EAAQ6D,EAAA,KAAKjB,EAAAkB,IACf9D,IACAA,EAAM,oBAAoB,QAAS6D,EAAA,KAAKN,IAAU,CAAE,QAAS,EAAI,CAAE,EACnEd,GAAc,OAAOzC,CAAK,EAEjC,CAqFL,EAzLI6C,GAAA,YACAG,GAAA,YAKAE,GAAA,YACAC,GAAA,YARJP,EAAA,YAuGQkB,GAAM,UAAG,OACT,OAAOtD,EAAAqD,EAAA,KAAKX,MAAL,YAAA1C,EAAgB,OAC1B,EAEDkD,GAAW,SAACK,EAAI,CACZ,MAAM/D,EAAQ6D,EAAA,KAAKjB,EAAAkB,IACnB,OAAK9D,EAEE+D,EAAG/D,CAAK,EADJ,KAAK,QAEnB,EAEDoD,GAAA,YAEAC,GAAA,YAKAW,GAAa,UAAG,CAEZlB,GAAA,KAAKF,EAAAc,IAAL,UAAkB1D,GAAU,CACxB,MAAMiE,EAAa,OAAO,iBAAiBjE,CAAK,EAChD,KAAK,MAAM,OAASiE,EAAW,OAC/B,KAAK,MAAM,MAAQA,EAAW,MAE1BjE,EAAM,eAAiB,KAAK,eAC5B,KAAK,MAAM,OAAS,QAAQiE,EAAW,MAAM,MAAMjE,EAAM,aAAe,KAAK,YAAY,OACzFA,EAAM,cAAgB,KAAK,cAC3B,KAAK,MAAM,MAAQ,QAAQiE,EAAW,KAAK,MAAMjE,EAAM,YAAc,KAAK,WAAW,OAEzF,MAAMkE,EAAYlE,EAAM,wBAClBmE,EAAY,KAAK,wBACvBP,GAAA,KAAKR,GAAWS,EAAA,KAAKT,IAAWc,EAAU,KAAOC,EAAU,MAC3DP,GAAA,KAAKP,GAAWQ,EAAA,KAAKR,IAAWa,EAAU,IAAMC,EAAU,KAC1D,KAAK,MAAM,UAAY,aAAaN,EAAA,KAAKT,GAAQ,OAAOS,EAAA,KAAKR,GAAQ,MACrE,KAAK,UAAYrD,EAAM,UACvB,KAAK,WAAaA,EAAM,WACxB,KAAK,cAAc,IAAIwC,EAA4B,CAC/D,EACK,EACDc,GAAA,YAEAL,GAAoB,UAAG,CACfY,EAAA,KAAKP,MAETM,GAAA,KAAKN,GAAoB,IACzB,sBAAsB,IAAM,CACxBR,GAAA,KAAKF,EAAAoB,IAAL,WACAJ,GAAA,KAAKN,GAAoB,GACrC,CAAS,EACJ,EAEDP,GAAa,UAAG,CACZD,GAAA,KAAKF,EAAAc,IAAL,UAAkB1D,GAAU,CACxB,MAAMiE,EAAa,OAAO,iBAAiBjE,CAAK,EAChD,UAAWoE,KAAQC,GACf,KAAK,MAAMD,CAAI,EAAIH,EAAWG,CAAI,EACtCtB,GAAA,KAAKF,EAAAK,IAAL,UACZ,EACK,EAKDO,GAAW,UAAG,CACVV,GAAA,KAAKF,EAAAc,IAAL,UAAkB1D,GAAU,CACxB,KAAK,YAAcA,EAAM,MAKzB8C,GAAA,KAAKF,EAAAoB,IAAL,UACZ,EACK,EACDT,GAAA,YACAE,GAAA,YAlLJ,IAAMa,GAAN5B,GA8LA,MAAM2B,GAAmB,CAErB,YACA,cACA,cACA,kBACA,YACA,iBACA,mBACA,oBACA,kBACA,cACA,aACA,eACA,gBACA,cAEA,YACA,cACA,aACA,cACA,WACA,iBACA,aACA,aACA,YACA,gBACA,aACA,iBACA,gBACA,cACA,UACA,YACJ,EAEA,GAAI,CACA,eAAe,OAAO,oBAAqBC,EAAsB,CACrE,OACOC,EAAG,CAEN,GAAI,EAAEA,aAAa,cAAgBA,EAAE,OAAS,qBAC1C,MAAMA,CACd,6BAEA,MAAMC,GAAN,MAAMA,EAAW,CAUb,YAAYhD,EAASiD,EAAc,EAAGC,EAAYD,EAAa,CAVnE9B,GAAA,KAAAgC,IACIhC,GAAA,KAAAiC,IACAjC,GAAA,KAAAkC,IACAlC,GAAA,KAAAmC,IAQIlB,GAAA,KAAKgB,GAAgBpD,GACrBoC,GAAA,KAAKiB,GAAeJ,GACpBb,GAAA,KAAKkB,GAAaJ,EACrB,CASD,OAAO,cAAc1E,EAAO,CACxB,KAAM,CAAE,eAAA+E,EAAgB,aAAAC,CAAc,EAAGhF,EACzC,OAAO,IAAIwE,GAAWxE,EAAO+E,GAAkB,OAAWC,GAAgB,MAAS,CACtF,CAED,IAAI,WAAY,CACZ,OAAO,KAAK,cAAgB,KAAK,SACpC,CAED,IAAI,yBAA0B,CAC1B,OAAOnB,EAAA,KAAKe,GACf,CAED,IAAI,cAAe,CACf,OAAOf,EAAA,KAAKe,GACf,CAED,IAAI,gBAAiB,CACjB,OAAOf,EAAA,KAAKe,GACf,CACD,IAAI,aAAc,CACd,OAAOf,EAAA,KAAKgB,GACf,CACD,IAAI,WAAY,CACZ,OAAOhB,EAAA,KAAKiB,GACf,CAED,eAAeG,EAAQ,CACnBrB,GAAA,KAAKiB,GAAe/B,GAAA,KAAK6B,GAAAO,IAAL,UAAkBD,GACzC,CAED,aAAaA,EAAQ,CACjBrB,GAAA,KAAKkB,GAAahC,GAAA,KAAK6B,GAAAO,IAAL,UAAkBD,GACvC,CAKD,SAASE,EAAU,GAAO,CAClBA,EACA,KAAK,aAAa,KAAK,WAAW,EAElC,KAAK,eAAe,KAAK,SAAS,CACzC,CAED,eAAgB,CACZ,OAAOrC,GAAA,KAAK6B,GAAAS,IAAL,WAAyB,eACnC,CAED,YAAa,CACT,OAAO,IAAIZ,GAAWX,EAAA,KAAKe,IAAe,KAAK,YAAa,KAAK,SAAS,CAC7E,CAMD,uBAAwB,CACpB,OAAO9B,GAAA,KAAK6B,GAAAS,IAAL,WAAyB,uBACnC,CAMD,gBAAiB,CACb,OAAOtC,GAAA,KAAK6B,GAAAS,IAAL,WAAyB,gBACnC,CAED,UAAW,CACP,OAAOtC,GAAA,KAAK6B,GAAAS,IAAL,WAAyB,UACnC,CAKD,eAAgB,CACZ,OAAOvB,EAAA,KAAKc,GAAAU,GACf,CAuBL,EA3HIT,GAAA,YACAC,GAAA,YACAC,GAAA,YAHJH,GAAA,YAuGQU,GAAW,UAAG,CACd,OAAOf,GAAuB,IAAIT,EAAA,KAAKe,GAAa,CACvD,EACGU,GAAa,UAAG,CAChB,OAAOzB,EAAA,KAAKc,GAAAU,GACf,EACDH,GAAY,SAACD,EAAQ,CACjB,OAAO,KAAK,IAAI,EAAG,KAAK,IAAIA,EAAQpB,EAAA,KAAKe,IAAc,MAAM,MAAM,CAAC,CACvE,EACDQ,GAAiB,UAAG,CAIhB,MAAMG,EAAQ,SAAS,cACjBC,EAAW3B,EAAA,KAAKc,GAAAW,IAAc,WAAW,CAAC,EAChD,OAAIE,IACAD,EAAM,SAASC,EAAU,KAAK,WAAW,EACzCD,EAAM,OAAOC,EAAU,KAAK,SAAS,GAElCD,CACV,EA3HL,IAAME,GAANjB,GA8HA,MAAMkB,GAAS,IAAI,QACnB,MAAMC,EAAa,CACf,YAAYC,EAAU5F,EAAO,CACzB,KAAK,SAAW4F,EAChB,KAAK,MAAQ5F,EACb,KAAK,SAAW,KAChB,KAAK,KAAO,KACZ,KAAK,MAAQ,KACb,KAAK,WAAa,GAClB,KAAK,cAAgB,EACrB,KAAK,QAAU,KAAK,QAAQ,KAAK,IAAI,EACrC,KAAK,QAAU,KAAK,QAAQ,KAAK,IAAI,EACrC,KAAK,UAAY,KAAK,UAAU,KAAK,IAAI,EACzC,KAAK,SAAW,KAAK,SAAS,KAAK,IAAI,EACvC,KAAK,YAAc,KAAK,YAAY,KAAK,IAAI,EAC7C,KAAK,OAAS,KAAK,OAAO,KAAK,IAAI,EACnC,KAAK,oBAAsB,GAC3BA,EAAM,iBAAiB,QAAS,KAAK,OAAO,EAC5CA,EAAM,iBAAiB,QAAS,KAAK,OAAO,EAC5CA,EAAM,iBAAiB,UAAW,KAAK,SAAS,EAChDA,EAAM,iBAAiB,OAAQ,KAAK,MAAM,CAC7C,CACD,SAAU,CACN,KAAK,MAAM,oBAAoB,QAAS,KAAK,OAAO,EACpD,KAAK,MAAM,oBAAoB,QAAS,KAAK,OAAO,EACpD,KAAK,MAAM,oBAAoB,UAAW,KAAK,SAAS,EACxD,KAAK,MAAM,oBAAoB,OAAQ,KAAK,MAAM,CACrD,CACD,aAAc,CACN,KAAK,eACL,KAAK,cAAgB,KAAK,MAAM,cAAgB,KAAK,cAE5D,CACD,SAAS6F,EAAOC,EAAM,CAClB,IAAItF,EAAIuF,EACJ,KAAK,QAAU,SAAS,eAAiB,KAAK,UAAYA,GAAMvF,EAAK,SAAS,iBAAmB,MAAQA,IAAO,OAAS,OAASA,EAAG,cAAgB,MAAQuF,IAAO,OAAS,OAASA,EAAG,iBAG7L,KAAK,WAAU,EACf,KAAK,KAAOD,EACPA,EAAK,KACNA,EAAK,GAAK,iBAAiB,KAAK,MAAM,KAAK,OAAQ,EAAG,GAAM,EAAE,SAAQ,CAAE,IAC5E,KAAK,SAAS,OAAOA,CAAI,EACzB,KAAK,SAAW,IAAI/F,GAAS,KAAK,MAAO+F,CAAI,EAC7C,KAAK,SAAS,cAAc,IAAI,MAAM,wBAAwB,CAAC,EAC/D,KAAK,aAAaA,EAAMD,EAAM,QAAQ,EACtC,KAAK,SAAS,QACdC,EAAK,iBAAiB,kBAAmB,KAAK,QAAQ,EACtDA,EAAK,iBAAiB,YAAa,KAAK,WAAW,EACnD,KAAK,SAAS,SAAS,CAAC,EAC3B,CACD,aAAaA,EAAME,EAAU,CACzB,MAAMC,EAAY,IAAIR,GAAW,KAAK,MAAOO,CAAQ,EAAE,wBACjDE,EAAiB,CAAE,KAAMD,EAAU,KAAM,IAAKA,EAAU,IAAMA,EAAU,QACxEE,EAAkBL,EAAK,wBACvBM,EAAQ,CACV,KAAMF,EAAe,KAAOC,EAAgB,KAC5C,IAAKD,EAAe,IAAMC,EAAgB,GACtD,EACQ,GAAIC,EAAM,OAAS,GAAKA,EAAM,MAAQ,EAAG,CACrC,MAAMC,EAAe,iBAAiBP,CAAI,EAC1CA,EAAK,MAAM,KAAOO,EAAa,KAAO,QAAQA,EAAa,IAAI,MAAMD,EAAM,IAAI,MAAQ,GAAGA,EAAM,IAAI,KACpGN,EAAK,MAAM,IAAMO,EAAa,IAAM,QAAQA,EAAa,GAAG,MAAMD,EAAM,GAAG,MAAQ,GAAGA,EAAM,GAAG,IAClG,CACJ,CACD,YAAa,CACT,MAAMN,EAAO,KAAK,KAClB,MAAI,CAACA,GAAQ,CAAC,KAAK,SACR,IACX,KAAK,SAAS,cAAc,IAAI,MAAM,0BAA0B,CAAC,EACjE,KAAK,KAAO,KACZA,EAAK,oBAAoB,kBAAmB,KAAK,QAAQ,EACzDA,EAAK,oBAAoB,YAAa,KAAK,WAAW,EACtD,KAAK,SAAS,UACd,KAAK,SAAW,KAChBA,EAAK,OAAM,EACJ,GACV,CACD,SAAS,CAAE,OAAA9E,GAAU,CACjB,IAAIR,EACJ,MAAM8F,EAAOtF,EAGb,GAFI,EAAEsF,aAAgB,cAElB,CAAC,KAAK,SACN,OACJ,MAAMT,EAAQ,KAAK,MACnB,GAAI,CAACA,EACD,OACJ,MAAMU,EAAY,KAAK,MAAM,MAAM,UAAU,EAAGV,EAAM,SAAWA,EAAM,IAAI,MAAM,EAC3EW,EAAY,KAAK,MAAM,MAAM,UAAUX,EAAM,SAAWA,EAAM,KAAK,MAAM,EACzEY,EAAS,CAAE,KAAAH,EAAM,IAAKT,EAAM,IAAK,MAAO,KAAM,SAAU,IAI9D,GAHiB,CAAC,KAAK,SAAS,cAAc,IAAI,YAAY,sBAAuB,CAAE,WAAY,GAAM,OAAAY,CAAM,CAAE,CAAC,GAG9G,CAACA,EAAO,MACR,OACJ,IAAIC,GAAUlG,EAAK,KAAK,SAAS,aAAa,QAAQ,KAAO,MAAQA,IAAO,OAASA,EAAK,IACtFiG,EAAO,WACPC,EAAS,IAEb,MAAMC,GAAQ,GAAGF,EAAO,KAAK,GAAGC,CAAM,GACtC,KAAK,MAAM,MAAQH,EAAYI,GAAQH,EACvC,MAAMvE,EAASsE,EAAU,OAASI,GAAM,OACxC,KAAK,WAAU,EACf,KAAK,MAAM,MAAM,CACb,cAAe,EAC3B,CAAS,EACD,KAAK,MAAM,eAAiB1E,EAC5B,KAAK,MAAM,aAAeA,EACrBwE,EAAO,WACR,KAAK,cAAgBxE,EACrB,KAAK,MAAQ,MAEjB,KAAK,SAAS,cAAc,IAAI,YAAY,0BAA2B,CAAE,WAAY,GAAO,OAAQ,CAAE,MAAO,KAAK,KAAO,EAAE,CAAC,CAC/H,CACD,QAAS,CACL,GAAI,KAAK,oBAAqB,CAC1B,KAAK,oBAAsB,GAC3B,MACH,CACD,KAAK,WAAU,CAClB,CACD,SAAU,CACN,KAAK,WAAa,EACrB,CACD,MAAM,SAAU,CACZ,GAAI,KAAK,WAAY,CACjB,KAAK,WAAa,GAClB,MACH,CACD,MAAM4D,EAAQ,KAAK,YACnB,GAAIA,EAAO,CACP,KAAK,MAAQA,EACb,MAAMC,EAAO,MAAM,KAAK,gBAAgBD,CAAK,EAC7C,GAAI,CAAC,KAAK,MACN,OACAC,EACA,KAAK,SAASD,EAAOC,CAAI,EAGzB,KAAK,WAAU,CAEtB,MAEG,KAAK,MAAQ,KACb,KAAK,WAAU,CAEtB,CACD,WAAY,CACR,MAAM7D,EAAS,KAAK,MAAM,cAAgB,EACpCF,EAAO,KAAK,MAAM,MACpBE,GAAU,KAAK,gBACf,KAAK,cAAgBA,EAAS,GAElC,SAAW,CAAE,IAAAD,EAAK,UAAAE,CAAW,IAAI,KAAK,SAAS,KAAM,CACjD,MAAM0E,EAAQ9E,GAAMC,EAAMC,EAAKC,EAAQ,CACnC,UAAAC,EACA,cAAe,KAAK,cACpB,kBAAmB,KAAK,MAAQ,KAAK,MAAM,SAAW,IACtE,CAAa,EACD,GAAI0E,EACA,MAAO,CAAE,KAAMA,EAAM,KAAM,IAAA5E,EAAK,SAAU4E,EAAM,SAEvD,CACJ,CACD,MAAM,gBAAgBf,EAAO,CACzB,MAAMgB,EAAY,GACZC,EAAWC,GAAWF,EAAU,KAAKE,CAAM,EAEjD,OADkB,KAAK,SAAS,cAAc,IAAI,YAAY,uBAAwB,CAAE,WAAY,GAAM,OAAQ,CAAE,QAAAD,EAAS,KAAMjB,EAAM,KAAM,IAAKA,EAAM,IAAO,EAAC,GAGtJ,MAAM,QAAQ,IAAIgB,CAAS,GACjB,OAAOG,GAAKA,EAAE,OAAO,EAAE,IAAIA,GAAKA,EAAE,QAAQ,EAC/C,CAAC,EAHd,MAIP,CACD,aAAc,CACV,KAAK,oBAAsB,EAC9B,CACD,UAAU5G,EAAO,CACTA,EAAM,MAAQ,WACd,KAAK,MAAQ,KACT,KAAK,eACL,KAAK,cAAgB,KAAK,MAAM,cAAgB,KAAK,cACrDA,EAAM,yBAAwB,EAC9BA,EAAM,eAAc,GAG/B,CACL,CACA,MAAM6G,WAA4B,WAAY,CAC1C,IAAI,MAAO,CACP,MAAMC,EAAW,KAAK,aAAa,MAAM,EACnCC,EAAOD,EAAWA,EAAS,MAAM,GAAG,EAAI,GACxCE,EAAgB,KAAK,aAAa,WAAW,EAC7ClF,EAAYkF,EAAgBA,EAAc,MAAM,GAAG,EAAI,GACvDC,EAAkBnF,EAAU,SAAW,GAAK,KAAK,aAAa,WAAW,EAC/E,OAAOiF,EAAK,IAAInF,IAAQ,CAAE,IAAAA,EAAK,UAAWqF,GAAmBnF,EAAU,SAASF,CAAG,CAAC,EAAG,CAC1F,CACD,IAAI,KAAK2E,EAAO,CACZ,KAAK,aAAa,OAAQA,CAAK,CAClC,CACD,mBAAoB,CAChB,MAAM3G,EAAQ,KAAK,cAAc,8BAA8B,EAC/D,GAAI,EAAEA,aAAiB,kBAAoBA,aAAiB,qBACxD,OACJ,MAAMsH,EAAQ,IAAI3B,GAAa,KAAM3F,CAAK,EAC1C0F,GAAO,IAAI,KAAM4B,CAAK,CACzB,CACD,sBAAuB,CACnB,MAAMA,EAAQ5B,GAAO,IAAI,IAAI,EACxB4B,IAELA,EAAM,QAAO,EACb5B,GAAO,OAAO,IAAI,EACrB,CACD,SAAU,CACN,MAAM4B,EAAQ5B,GAAO,IAAI,IAAI,EACxB4B,GAELA,EAAM,YAAW,CACpB,CACL,CAEK,OAAO,eAAe,IAAI,eAAe,IAC1C,OAAO,oBAAsBL,GAC7B,OAAO,eAAe,OAAO,gBAAiBA,EAAmB,GCtpBtD,SAASM,GAAU,CAAC,UAAAC,EAAY,EAAK,EAAI,GAAI,CAC3D,MAAMC,EAAU,CACZ,+HACH,0DACF,EAAG,KAAK,GAAG,EAEV,OAAO,IAAI,OAAOA,EAASD,EAAY,OAAY,GAAG,CACvD,CCLA,MAAME,GAAQH,GAAS,EAER,SAASI,GAAUC,EAAQ,CACzC,GAAI,OAAOA,GAAW,SACrB,MAAM,IAAI,UAAU,gCAAgC,OAAOA,CAAM,IAAI,EAMtE,OAAOA,EAAO,QAAQF,GAAO,EAAE,CAChC,CCXA,MAAMG,GAAY,IAAI,KAAK,UAEZ,SAASC,GAAaF,EAAQ,CAAC,qBAAAG,EAAuB,EAAK,EAAI,GAAI,CASjF,GARIH,IAAW,KAIVG,IACJH,EAASD,GAAUC,CAAM,GAGtBA,IAAW,IACd,MAAO,GAGR,IAAII,EAAS,EAEb,UAAWC,KAAKJ,GAAU,QAAQD,CAAM,EACvCI,IAGD,OAAOA,CACR,CCxBA,MAAeE,GAAA,89sBC+DT,CACJC,uBAAwBC,GACxBC,qBAAsBC,EACxB,EAAIC,GAEEC,GAAwBC,GAAmBC,OAAO,CAACC,EAAKC,IAAM,CAClE,KAAM,CAACC,EAAMC,EAAQC,CAAM,EAAIH,EAC/BD,SAAIE,CAAI,EAAI,CACVC,SACAC,UAEKJ,CACT,EAAG,CAAE,GAMCK,GAAgB,CACpB,IAAKC,GAAa,EAAG,QAAQ,EAC7B,KAAOA,GAAa,GAAI,QAAQ,EAChC,KAAOA,GAAa,EAAG,MAAM,EAC7B,MAAQA,GAAa,EAAG,MAAM,EAC9B,MAAQA,GAAa,EAAG,KAAK,EAC7B,OAASA,GAAa,EAAG,KAAK,EAC9B,OAASA,GAAa,EAAG,MAAM,CACjC,EACMC,GAAgBC,OAAOhC,KAAK6B,EAAa,EACzCI,GAAS,GAAK,GAAK,GAEnBC,GAAwCC,GAAA,CACxC,IAACA,EAAkBF,UACjBhD,SAAS,IAAImD,KAAKD,CAAS,EAAEE,QAAQ,EAAID,KAAKE,IAAS,OAC7D,OAAOP,GAAcQ,KAAYC,MAAKvD,CAAK,GAAKgD,EAClD,EAEMtD,GAAO8D,SAASC,cAAc,IAAI,EACxC/D,GAAKgE,KAAO,UACZhE,GAAKiE,UAAY,qBAGjB,MAAMC,GAAe,GACfC,GAAW,IAAIC,qBAAkCC,GAAA,CAC7CC,UAAmBC,GAAA,CACzB,GAAIA,EAAMC,eAAgB,CAClB,MAAEC,OAAMC,SAAUH,EAAMI,mBACxB,CAAEC,YAAeC,SACnBJ,KAAOC,EAAQE,EAAY,CACvBE,QAAmBC,KAAU,QAAU,OAC7C/E,GAAKgF,MAAMF,CAAgB,EAAIF,EAAaF,EAAQR,GAAe,IACrE,CACF,EACD,CACH,CAAC,EACDC,GAASc,QAAQjF,EAAI,EAErB,MAAMkF,GAAeC,GACnB,CAAC,IAAIC,KAAKC,eAAe,EAAEC,gBAAgB,EAAEC,OAAQ,GAAGC,UAAUC,SAAS,EAC3E9C,GAAmB+C,OAAW5C,EAAE,CAAC,CAAC,EAClC,IACF,EAGM6C,GAAc,IAAIC,OAAOC,GAASC,OAAQD,GAASE,KAAK,EACxDC,GAAgB,sDAChBC,GAAiB,4BACvB,SAASC,GAAcC,EAAW,CAChC,OAAOA,EACJC,QAAQT,GAAaM,EAAc,EACnCG,QAAQJ,GAAe,OAAO,CACnC,CAGA,MAAMK,GAAc,uCACdC,GAAa,IAAIV,OACrB,mBAAmBS,GAAYP,MAAM,8BACrC,KACF,EAGMS,GAAa,IAAIX,OACrB,kEACA,IACF,EAGMY,GAAwB,mBACxBC,GAAU,IAAIb,OAClB,mBAAmBY,EAAqB,yBACxC,GACF,EAEMzE,GAAY,IAAIqD,KAAKsB,UAC3B,SAASC,GAAW1K,EAAM,CACxB,OAAOA,EACJmK,QAAQ,KAAM,OAAO,EACrBA,QAAQ,KAAM,MAAM,EACpBA,QAAQ,KAAM,MAAM,EACpBA,QAAQ,KAAM,QAAQ,EACtBA,QAAQ,KAAM,QAAQ,CAC3B,CACA,SAASQ,GAAc3K,EAAM,CAAE4K,gBAAgBC,GAAS,EAAG,CAEnD,MAAEC,wBAA2BnH,KACnC,GAAImH,EAAyBF,EAAe,CAEtCG,MAAkB,GACpBC,EAAkB,GACdC,QAAenF,GAAUoF,QAAQlL,CAAI,EAChC,UAAEkL,UAASC,WAAWF,EAC3BE,EAAQP,EACSM,KAEAA,KAGvB,OAAIF,IAEAA,EAAA,4CACAN,GAAWM,CAAe,EAC1B,WAEGN,GAAWK,CAAe,EAAIC,CACvC,CAEA,OAAON,GAAW1K,CAAI,EACnBmK,QAAQT,GAAa,iDAAiD,EACtES,QAAQE,GAAY,qDAAqD,EACzEF,QAAQG,GAAY,qDAAqD,EACzEH,QACCK,GACA,6DACF,CACJ,CAGA,MAAMY,GAAMC,GAAgB/B,GAAA,IAAIH,KAAKmC,mBAAmBhC,GAAUiC,MAAS,CAAC,EACtEC,GAAKH,GAAgB/B,GAAA,IAAIH,KAAKsC,WAAWnC,GAAUiC,MAAS,CAAC,EAE7DG,GAAsB,IAEtBC,GAAa,CACjBC,MAAO,CAAAC,GAAA,QAAa,EACpBC,YAAa,CAAAD,GAAA,QAAoB,EACjCE,IAAK,CAAAF,GAAA,QAAW,EAChBG,KAAM,CAAAH,GAAA,QAAY,CACpB,EAEA,SAASI,GAAQ,CACfC,UACAC,gBACAC,aACAC,cACAC,aACAC,WACF,EAAG,QACK,WAAEC,EAAMtG,IAAGuG,KAAGC,GAAc,EAC5BC,EAAMvB,GAAIoB,EAAKlD,MAAM,EACrBsD,GAAKpB,GAAGgB,EAAKlD,MAAM,EAEzBuD,CACM,MAAAC,EAAEA,UAAOC,OAAiB,CAAAC,EAAAC,CAAA,EAAAC,EAAA,WAC1BC,EAACH,GAAmBX,GAAA,YAAAA,QAAae,GAAS,GAC1CD,EAA0BC,KACxBC,EAAmBF,EAAW,KAEhCG,QACAC,CAEN,UACQF,gBAEF,oBAAAG,EAEF5C,4BACA4C,qBACAC,sCAEgB,iBAAAC,EAChBC,iBACAC,mBACAF,wBACAG,GACAC,OACAC,sCAEK,cAAAC,GACLC,kBACAC,IACAF,OACAG,MACEC,EAACC,SACe,EAAAnB,EAAA,UAEhBoB,KAAqB,EAAApB,EAAA,IACrBkB,IAAwB,EAAAlB,EAAAqB,GAAA,gCAAAtF,EAAA,EACxBuF,EAA0BH,EAAAI,CAAIvB,EAC9B,CAACwB,EAAuBC,EAAkB,EAAAzB,EAAA,IAC1C,CAACuB,EAAUG,MAAe1B,MAG1BsB,cAAsBC,IAAQ,mBAC9BI,GAAmBF,KAClB3C,EAAa,SAEpBsC,EAAcC,QAAMO,cAAY,iBAAmB,EAEnD,EACMC,GAAsB,KAC1BT,eAAoBU,WACtBV,EAAA,wDAC4B;AAAA,KAC1BW,EAAiB,yBACXX,UAAsB,iBAGxBA,8BACAA,MAAmC,EAErCzB,gBACAyB,WACI,CACR,YAAAY,EAEAC,WAAgBC,EACVjD,SAAekD,EACX,UAAAC,CAAEJ,IAAaK,eAAYd,mBAC7BS,YADqD/C,wDACvBqD,OAASC,OAAAlC,EAAA,MACzCa,SAAuBxJ,IACzB0J,EAAA,iBAAAoB,EAAA,IAAAD,GAAA,IAAAA,CAAA,iBACAZ,MAOIa,KACFpB,GAAYkB,IAAgB,UAAGE,GACvBD,4BACI,EAAAE,GAAA,4CAAAP,CAAA,EACIR,EAAAS,KAAA5Q,EAAAkR,GAAA,0CAAAlR,EAAA,gBAAAwK,EAAA,EAClB2G,GAAAN,GAAA,EAAAJ,CAAA,CACc,SAAA9C,EAAA,CAEZmD,MAIFX,aAKaF,qBACQY,EACf,KAAAO,EAAEN,oBAAYd,EAAUC,2BAAW1C,KAAM8D,sDAC7C1D,uDACF,EAA0Ca,EACrCjB,YACH+D,gBACAC,GAAWhE,CACb,MAAAiE,EAAA,MAAAnD,EAAA,oBAAAV,EAAA,mBACAa,CACa,KAAAjN,GACP,YAAAkP,EACIe,IAGNpD,EAAY,cAAA7M,GAAEiQ,4BAAapB,KACrBE,KAAE/O,mBAAMkP,MAAYN,EAAIqB,0EAC9B3B,IAA4BtO,EAChBwP,GAAQU,GAAQrG,CAAS7J,EACrB2O,GAAAwB,CAAA,EACFlD,EAAA,UACdmB,UACAgC,iCAAwB5N,CAAA,EACxBoM,UAKAgB,CACIS,IACJ1B,MACA1B,oCACU,GACVJ,MAAe,6CAEfI,6BAAkB,GACpB2B,EAAAe,GAAA,2CAEGA,GAAA,8BACSC,GAAA,EAAAD,GAAA,8BAGZS,MACF,MACIT,SACFf,cACF,WAAAQ,EACIO,WACFC,YACF,KAAAC,EACF,iBAAAM,CACA,EAAiB9D,EACTgE,EAAA,GAAAR,GAAA,MAAAA,EAAA,WACJS,KACApB,0DACAK,yDACAd,EACAC,qBACA1C,KAEEK,uBACJ+C,GAAuBgB,GAAEpE,CAAiB,EAAA4C,EACrC5C,0EACH+D,IAAsBtG,SAAW8G,CAAYA,EAClCvE,GAAMgE,GAAa1I,GAChC6I,GAAAxB,GAAAwB,CAAA,CACA7B,CACgB,GAAAjC,EAAAD,EAAAD,CAAA,GACF,MAAAqE,GAAAnC,IACVa,GAA4BM,EAEhCZ,CAKIF,WACA2B,CACAP,EACNW,GAAA,KACC,KAAcrE,CAEjB,MAAAxH,EAEA,QAAAsL,CAAsBQ,YAAG,GAAA1D,IAAA,UAAAnB,MAAA,GAA+C,MAAA8E,GAAA/L,GAAA,kFACjDkL,EAAA,SAIrB,GAHM,CAAAa,GAAA,CAAAC,GAAiCpB,6BAIrC3C,SAA0BG,MAAS6D,GAAA1E,GAAA,YAAAA,EAAA,cAAAoB,EAAA,GAC5BuD,EAAA3E,GAAAvH,EAAA,aAAAuH,EAAA,eASPU,MARF,IAAAgE,GAAAC,GAOuClM,KAAAsL,GAAA,YAAAA,EAAA,QAE9B,EACTa,GAAA,IAGMC,KAI6C,GADxB,QAAAC,EAAA,EAG3B9B,GAAA,KAGA,MAAM0B,EAAS1E,GAAuBN,CAChCiF,OAGFtO,iBAAwB,EAC1BqK,cAAwBoE,GAAEJ,EAAQC,cAAa,gCAAAI,EAAA,CACxC,WACT,EAGMC,+BAAoCtH,kBAC1C,QAAoB,EAClBgD,EAA0BsE,YAAgBC,GAAA,KACnC,MACT,MAAAxM,CAEAiI,IAAwB,QACtBjI,CACAgM,SACAI,UACAhF,wBAEA8E,QACAK,aACAnE,6BAGKmC,GAAAkC,GAAA,IACT,MAAAC,GAAA,oBAEMP,KAAqB,IACrBQ,SAAa,KACTC,aACCA,GACT,SAAAF,GACO,oBACT,EAEAnC,GAAgB,WAER+B,OAA4B,SAAAH,GAAA,GAC5B7E,IAEF1J,GAAgByO,YAClB,CACF,SAAAK,GACOG,oBAEP,MAAC,GACD,gBACE7I,GAA2B,CACzB8I,MAASC,EAAA,kDACVC,EAAA,EAAAD,EACAE,EAAAF,EAAA,YAAAA,EAAA,uCAEL,UAA2B,CAAAE,CACnB,EAAEjN,KAAsB4K,KACxB,CAAAlD,GAAAyE,MAAEnM,GACR,GAAA0H,KAAkC1H,IACpC,MAAAkN,GAAAzD,EAAA,IACMgD,OAEGvG,OAAyBiH,gBAExBV,OAAmB,CAGvBW,GADAV,GACAU,iBAAyB,iBAC/BT,aAGIS,EAAqB,CAGvB,IAAA/R,UACYqR,GASV,GAAAnF,EAAA,GACA6F,QAAqB,CAEvB,GAAA7F,EAAA,oBACYmF,mBACQ,KAAAnF,EAAA,eAEX,KACP8F,aACQN,cACAC,SAAaD,cACbE,sBACc,MACpB,WAAAtC,EACF,SAAAd,EAEJ,UAAAC,EACAwD,OACM,iBAAApC,CACM,GAEIiB,SAAsB,WAAAN,OAEhCqB,iBACAK,KACJ,MAAWC,UACX,UAAgBjF,KAAIqC,IAAO,EAC7B,qBAAAhN,GAAA,IACAsP,WAA+B,gBAAAO,CAAA,EAKzB1O,EACJ2O,MAAqB,KACrBnD,GAAwB,KACtBlP,SAEI,CAAAsS,GAAA,WAAAJ,GAAA,SAAAhD,GAAA,WAAAqD,EAAAhQ,GAAA,MAMM2J,CACJ2C,OACEjD,mBAA0BA,eAC1B4G,EAAUtG,GACVuG,EAA4BA,GAC9B,QAAAC,EAAA,EAAAA,EAAAC,EAAA,OAAAD,IAAA,CAEF,MAAApO,EAAAqO,EAAAD,CAAA,EACS,GAAApO,EAAA,qBACFiL,gBACTc,IAA4B1L,4BAC5BsK,QAAoCtK,EAEpC6J,SAEAzC,CACA8D,CAoBkBN,GAnBpBqD,EAAA,UACF,MAAAC,GAAA,EAKEjG,CACGkG,GACAC,SACIX,QACI,EAAAQ,EAAA,OACPI,IAAoB,QAEhB,EAAMrG,GAAA,OAAAiG,EAAA,IAAAK,KAAA,MACFC,CAEF3Q,CACE4Q,GAEQ5D,sBAAyChC,EAAA,CAC/D,MAAAsF,GAAA,EAEFR,CACU,GAAM,SACG,QAGJ,oBAAA9E,CACRuF,CACL,EACG,EAEL5D,MACQqD,CACE,GAAAa,EAAA,UAAET,mBAAMpQ,EAAIA,gBAAE8Q,EACpB,IAAMD,EAAUA,EAChB,GAAMR,IAAqB,QAC3B,MAAaU,EAAA/F,EAA0BsC,EAAA,OAEjCvL,GADEA,IAAc,QAAAgP,CAAA,EAChBhP,EAAsB,WAClBiP,WAKJX,CACK,YACLQ,OAAe,CACjB,oBAAA7F,CACF,CACF,CACIqF,GACFY,MAAKvN,CACH,OAAAwN,EAAAC,EAAA,IAAAH,IAAA,MAAAA,EAAA,OAAwBvN,KAAM2N,OACE,KAAOC,wBAEnChB,GACD,QACF,gBACH,IACFlE,GAAA,IAAAmB,EAAA,GAAA4D,CAAA,EACA,CACED,EAAKvN,mCACH,MAAA4N,EAAAtR,GAAA,CAAAA,EAAAqJ,aAAA,iBAAArJ,EAAA,iBAAAgL,oBAA0B,EAGzB,cACH,4BAAAsG,CAAA,EACA,+BAAAtB,CAAA,EACF,KACA3F,2BAAY,QAAA2F,CAAA,EAAEa,yCAAM,OAAC,2BAAAb,CAAA,CACjBa,CACF7Q,IAAiB,GACjBA,SAAkBuR,EAAA,EAAA7G,EAAA,IAElB,CAAA8G,GAAmBX,UACnB,CAAAY,KAAuC,EAAA/G,EAAA,IAC/BqG,MAA6CtN,UACpC0N,MAAyB,EAAAO,GAAA,KACpCP,WACFF,EAAKvN,IACH,gCAAAiO,EAAA,IAAAxQ,GAAA,gBAAA+C,GAAA,QAAAG,GAAA,CAAA2G,WAA0B1G,IAAA2H,GAAA3H,IAAA0H,EAAA,SAAA1H,IAAAmC,IAAAkL,EAAA,SAAArN,CAAA,GAAAsN,IAAA,MAAAA,GAAA,QAAAA,GAAA,SAAAtN,CAAA,EAGzBuN,EAAA,KAAAxN,CAAA,EAEHyN,EAAA,KAAAzN,CAAA,CACF,CACF,EACM6M,EAAaC,YAAkBH,GAAUe,CAAA,IAC7Cf,SACAgB,IAAWA,MACAC,gBACXC,EAA6BJ,EACzB,OAAAK,EAAAC,CAAA,GAAAC,EAAAN,CAAA,IAAAK,EAAA,cAAAL,CAAA,GACS,CAAAF,EAAAC,CAAA,IAAA7F,EACb2F,EAAA,GACFzF,GAA0CuF,GAAA,OAAA/H,GAAA,MAAAA,EAAc,4CAAAA,EAAA,gCAAAA,CAAA,GAC1D2I,GAAA,KACFC,KACOtD,2BAA0Be,EACjC,EAEEwC,GAAyB/O,IAAS,WAAGuH,IAAA,QAAAsC,EAAA,QAAAtC,GAAA,EAAAxB,EACnCxJ,GAAiByL,GAAA,MAAAA,EAAA,EACjBzL,GAAkBwK,IAAA,aAAAhB,GAAA,EAAA8D,EAAA,OACpBmF,GAAA,KACFC,GAAA,CACOzD,gBACAA,mBAEE0D,WACAA,EACAA,EACTC,GAAA/G,IACEyB,IAAiBuF,EAAA,EAAAnI,EAAA,IAErB,OAAAoI,GAAOC,CACP,IAAOvB,GACP,IAAOC,aAEP,SAAOG,EACP,MAAA3L,CACE,IAAM4L,CACN,MACM,YAAAmB,CAAA,aAAkDC,MACrCpN,IAAe,GAC1BgN,GAASxO,MACfuO,GAEEtO,eAAS0H,CAKT6F,CAAmB,GAEnBC,QAAcoB,CAChB,6BACF,SAAC,CAAAC,EAAA,OACYC,uBACPjB,qBAA2B,GAC3BE,kBAA2B,CACxBD,oBACR,WAAArH,GAAA,YAAAA,EAAA,eAkBgBsI,EAAAC,GAAA,CACjBnS,UACF,gBAAA2J,EAAA,YAEM0H,mBAOAe,gBAA+B,EAC/BC,KAoFUzJ,GAAAsJ,EAAA,UAEQ,cACV,yBAAEI,aAEG,kBAAM,cAAYvF,wBAAE,CAAS,WAAC,EAAG,EAExCmF,MACErB,CACA0B,GAAM,sCACGpB,mEAAWmB,MAEpBJ,EAAyBnF,YAAE,IAAU,MAAC,CAAG,IAAAyF,EAAAzF,EAGpC,CACC,YACgB,EAGV,YADUyF,CAAA,EACV,MACV,CACFjK,EAAA,CAAE+J,QAES,MAAAG,EAAA,CAAO1F,6BAAE,iBAAAvD,EAAA,QAAO,OAAAmB,EAAA,cAAC,YAAAF,EAAA,cAAG,WAAAmB,EACxB,SAAAd,EAIToH,YACO,KAAA7J,EACC,iBAAA8D,EACgB,EAehB,cAAgB,YAAAsG,EACb1F,8EAAC,uDAA0C,OAChD,wCAGE9H,OAAcyN,kBAAwB,0BACpCzN,OAAO0N,OAAOD,WAAWE,wBAA2B,GACjD7F,EACH,GAAoJ,SAAAmF,EAAAW,EAAA,MACtJ,QACA,IAAA9F,EAGF,CAAeA,WAAG,GAAiK,EAAC,EAhJhMsF,mCAGI,UAAAH,EAAA,UACN9F,KAAU,SACVC,0BAAqB,SAAAhD,IAAA,UACX,aACXyJ,GAAA,CACH,WAAArK,kBAGOsK,YAA+B,CACpB,IAAAvJ,EAAA,QACXiI,uBACA,YAAAhH,EAAA,cACM,WAAAmB,EAAE9G,WAAY,UAAAiG,EAEjB,KAAA1C,EAAEwJ,kBAAiChG,CACzC,IAIFtD,GACD,WAGC2J,EAAAW,EAAA,CAAQ,kBACNb,GACEA,WAAW,CAAaM,CACDU,6EAONd,EAAAW,EAAA,CACFjJ,sBAGM,CAGjBjB,WACY,CAAkB2J,CAC5B,CACO,IACC,IAAAJ,EAAA,UACNe,cACAC,2BAkBE,aAA2B,UACzBzK,aACAD,MACAE,GAEEiE,EACApB,cACAK,SACAd,MAEAzC,CACA8D,WACF,CACF,CAEA,EACE,IACF,CA4DsL,CAC9K0B,UAAyB,OAC/B,uBACF,UAAAqE,EAAAiB,GAAA,CAMQ,OAAA3K,EAAA,SAEJ,YAAiB,GACfC,WACAD,gDACa4K,GAAA,EAAAlB,EAAAmB,EAAA,aAEX1G,QACApB,oBAAoCtK,iBACpC2K,uBACAd,EACAC,YACA1C,gBACA8D,EACF,EAAA+F,EAAAmB,EAAA,CACF,YACApO,QACIA,IAAcyN,cAAwBlK,EAAA,gBACjCmK,CACPrH,EACSqH,GAAgC,KAAAlK,GACpCuJ,EAAA,8BAEEW,eAAOD,CAChB,OAAAjK,EACA,SAESkK,cAA4C,CACrD,EAAAT,EAAA,OACF,uCACDA,EAAAmB,EAAA,CACH,YAAEf,CAEG,GAAM,GAAAN,EAAWjF,eAAE,yBAAAnB,CAAA,UAAQ,cAAAvC,IAAA,wBAAC,QAAAA,IAAA,gBAAI,UAG1CxK,GAAA,CAEA2J,kBACD3J,EAAA,SAAAA,EAAA,UAAWgO,GAAA,0CAAgByF,WAClB,EAAS9J,GAAoB,EAAe,SACnD3J,GAAA,CAAK0T,EAAM,iBAAgCD,MACxCc,uBACClB,EAAAzN,EAAA,mBAAA6O,EAAA,sBAAA3G,EAEuDmC,WAGvCrD,EAAiC,UAAAE,EAAA4H,aAAA,EAAAC,EACtC,GAAA7H,MAAA,KAIXuG,EAAAmB,CAAAnL,GAAAG,EAAA,wBAAA0E,EAE+D,CAExD,WAEL,EAGPtE,EACU,MAAgB6J,CACT7J,8BAAiB,MAAAsE,EACjCmF,CAAW,WAAuBI,CAChC,GAAiC,MAC7B,CAGVN,CACOnF,YAC+BV,EAAA,KAAAlE,GAAA,mBAAA5H,IAAAvF,EAAAmN,EAAA,0BAAAnN,EAAA,aAAAuF,GAAA,KAAAvF,IAAA,GAQI,CANX,QAAAiS,EAE7B,CACA0G,GAAkB,QACVnX,CACJuQ,KAIJtB,EAAAI,GAAAJ,GAAA,OACAmI,EAAiB/G,IAAA,UAAAA,EACf9N,GAAiB,4BAEjByK,EAAiB,YACjB,SAAgB7F,CACRiG,IACJ,GAAAyC,EAAA,UAAEQ,mBAAQf,MAAYb,QAAWQ,eAAgB9G,KAGrDsG,KAkBU,GAAA7C,GACJG,OAAa/F,GACVyK,cAAC,KAAA8C,GAAA,YAAA8D,EAAA,CAAmC,EAAE,OAAAxK,EAAA,gBAAAyK,EAAA,OAAAC,KAC3CA,GAAA,KACFC,GAAA,GAAAD,GAAA,IAEO9G,IAAC,IAA6BgH,GAAA,yBAAAC,CAAA,EAAE,GAAAD,GAAA,KAAA1S,IAAA,QACrC,OAAAA,GAAA,wBAAAvG,GAAAuG,GAAA,cAAAvG,GAAA,IACF,GACFkF,GAAA,4BAGImM,iCAA6B,GAEzB8H,WAGiBF,GAAA,QAAA1S,IAAA,IACF0L,wCACjB,CAA4C,YAC9C,QACU,CACZ,CACF,CAGAxB,EAIAvL,GACAsJ,MACa,CACP,CACMI,OACJyC,SAGM,aAAAZ,EAAEsE,WAAM8D,YAAazL,OACnBwB,YAA2B,IAAAoK,KAAA,GACnC,EAESA,2CACF,iBAAA3H,EAAA,IAAA2H,IACL,CACEjE,QACA8D,yBAGA,EACEG,EACFrL,IACOoL,iBACR,gBAAArL,GAAA,YAAAA,EAAA,aACH0L,EACDC,GAAAD,CAAA,EACD,IAAAE,EAIEL,KACEK,EAAczH,WAAW,SAAc,UAAezE,cACxDmM,GACAD,EAAAhL,EAAA,CACApJ,gBACAA,OAGQ0E,KACFrD,UAAkB,GAAY,gBAAA6S,EAAA,CAChChL,aACA4G,SAAmB/C,2BAAI,IAAAuH,OAAiBF,EAAA,MAAAjL,EAAA,mBAAA+K,CAAA,CAAQ,CAClDlU,GAAA,2BAAAA,GACD,4BACDsJ,EAAA,WACFf,EAAA,CAEcwL,+BAAS5H,YAAiB,SAAA/C,CAAC,CAC3C,CAQA,OAAamL,EAAA,CACX5H,0EAEcpB,6BACdT,WACAC,KACA1C,oBAE4BvC,CAG9B,wBACI2C,oBAAuB,CAClB+L,MAEI,+BACUtM,cACSyL,CAG1B,YAGN,EACEO,aAAoBtI,UAEb6I,2BACT,KAAA3J,EACAoJ,kBACQxK,WAEJ0K,OACJ,QAAgBrJ,EAAA,IACF,cAAAA,EAAe2J,aAG3BL,EAAgC,QACf,KAAA3G,IAChB,CAEG,GAAAsE,EAAA,SACFoC,wBAAkBjL,EAASuL,YAAwB,WAAA3H,EAEtC,CAET,WACF,GACD,YACS,SAEVqH,iBACF,gBACF,QAAArJ,EACA/K,aAAiC,UACjCA,qBACAsJ,QAAoBzK,EAAA,eAGZoN,GAAAN,CAAA,EAAAA,GAEAlD,sBAAsBD,SAE5BY,8BAGFpJ,KAAO4S,GACP5S,cAAuC,gBACvCkJ,GACMrK,iBAAaA,CACnByK,wBAAkBsC,IAAA,WAAAb,EAAA,mBAAAa,IAAA,0BACpB,MAAAA,EACC,UAAAsG,EAAAW,EAAA,CACL,KAAA8B,GAAA/I,CAAA,EAAE0G,IAEFN,CAAA,CAAW,EAAAA,EAAA,UAAiBM,kBAEnB7H,QACA,SAAA5L,GAAA,CACA4N,GAAA5N,EAAA,aACMkO,8BAAE,qBAAAmF,EAAA,UAAiB,eAAC,SAAAA,EAAAmB,EAAA,IACrBhK,QAAY,CAChB,EACAyB,2FACK,cACP,SAAAoH,EAAAmB,EAAA,CACG,YACLuB,CAAyB,CACzBC,cACF,0BACe3C,EAAAmB,EAAA,CACG,YAClB,EAEFrB,IAAA,UACS,gBACFjF,0BAAE,IAAAmF,EAAA,UAAoC,eAAC,SAAAA,EAAAmB,EAAA,CAACf,WAE7C,CACO,EACA,IACLwC,CAAS/J,GACTkI,IAAsB,CACtB8B,OAAiB,CACThK,MACNkB,YAAsBc,EAAtBd,EAEExB,CAA8B,GACzB,QACLE,EACFlC,EACA,CAEEuM,GAAM,QAAsC,EAMlDC,CAAkB3C,WAEZ0C,CAXF,EAWwD,UAC5DhD,iBAAA,qBACO3I,IAAA,eACEuC,EACPmJ,YAAiB,CACDlW,IAChB,gBAAAoI,EACqCwB,cACjCyL,GAAA,CAAM5B,MAEV,KAAAzB,EAAsByB,IACpB,MAAA4C,CAAA,EAAAhB,EAAqB,WAEZ,WAEK/K,EAAA,yBAAOmJ,IACnB,MAAA4C,EAAA,QAAmB,GACb,EAEc5C,YACtB,MAAA4B,CAAA,aAAsBiB,GAAA,EAExBjD,iBAAA,wBAAAkD,GAAc,CAAS9C,mBACrB6C,GAAA,YAAAA,EAAA,4BAA4BA,GAAA,YAAAA,EAAA,kBAAC/E,GAE/B,CAAQnP,mBAAMkU,GAAA,YAAAA,EAAA,yBAAQ7C,GACpB6C,GAAA,YAAAA,EAAA,iCAAAA,GAAA,MAAAA,EAAA,YAAAE,GAA6BF,EAAA,UACtB,CACF,qBACC,WAAAnD,EAAA,OAEdE,MAACoD,oBACCC,SAAK5K,qBAEUoC,KACT,KAAA8C,CAAA,EAAAiE,EAAiB0B,GAAA3F,GAAA,YAAAA,EAAA,OAAAA,GAAA,YAAAA,EAAA,OAAAA,GAAA,YAAAA,EAAA,aACP9C,mBACR,SAAA1D,IAAA,UAAAnB,KAAA4C,EAAgB,oBAAA7J,GAAA,CAAC8L,sBACjB,OAAA0I,EAAAzG,CAAA,MAAAyG,EAAAzG,CAAA,EAAqB,YAAA/N,CAAA,GAEU,EAEjC6J,WACS,KACGE,GAAA0K,GAClBA,EAAA,QAAAC,EAAAC,QAAA5G,CAAA,CACA/H,CACA4O,CACQ,EAAA3N,GAAAsN,GAAAxG,CAAA,EAAE6B,aAAMiF,wBAAGZ,qBAAUhB,iBAC3B,gBACE,QAAa6B,EACXD,uBACAZ,aACAc,MAASrK,EAAA9M,EAAA,eACVoN,GAAAN,CAAA,CACH,CACA,OAAasK,SAAUC,CACzB,SAAAhE,EAAAmB,EAAA,CACA8C,WACMhB,EACkB,OAAAjD,EAAAW,EAAA,CAClBuD,sBAAgD,UAClD,CAAC,CACH,EACuB,KAAA/N,GAAA6J,EAAAmE,GAAA,CACnBD,OAAgD,WAAA9L,EACjD,cAAAD,GAKDgL,iBACF,uBAAA9K,EACF,KAAAlC,EAED8D,aAA2B,UACrBoG,QAAMrG,GAAA,MACRC,CACO,MAAAmK,EAAA,CAAEpO,MAAa4L,KACrB,MACAvC,OACkB,CAEduC,CACsB,GAAA9B,EAChBlH,OACNyL,+BACEvL,oBACQyK,wCACNA,cAAoBzD,EAAAwE,GAAA,CAClB,QAAmB,OACNvV,aACf,EACOwU,gBACT,MAAC,CACH,YAEEzK,EACE,aACF,KAAAyL,CAAC,IACHvE,EAAA,UAlBWsD,cAsBjBxD,MAAA,6BAAAyE,EAAA,cAAa,SAAAvE,EAAAW,EAAA,CAAiBP,KAC5BJ,OACO,MAAAnF,EAEIhC,IACa,QACtBgK,CACQhK,CACNkB,EAAsB,CACxB,EACD,SACDiG,GAAAwE,GAAA,CAAApE,mCACEpK,SAAA,CAAAgK,EAAA,SAAqC,qCAEvCA,SAAKA,EAAAyE,GAAA,CAAO,OAAmB,GAAsB,mBAAA3M,EAC/C,oBAAAH,EAGTxB,mBAEOyC,yCACNR,uBACAD,EACAG,OACAD,aACAlC,yBACsB9F,EAAAyF,GAAA,OACtB4O,EACE,GAAU5E,EAAA0E,GAAA,CACR,QAAgB,KAAKrO,MAAK,EAC1BkJ,SAAe,CAAAW,EAAAW,EAAA,CACV,aACLtB,OAAYW,EAAA,QACd,SAAA3P,EAAAyF,GAAA,aACF,GAGJgK,EAAA,EAAAhS,GAAA,4BAAAgS,EAAA0E,GAAA,CAAW,SAAArF,GAAwBiB,QACjCN,IAAA,CAAY6E,GAAA,GACT9D,EAEW,UAAAb,EAAA,cACW4E,gBACnB,WACgB,EAAA5E,EAAA,QACP,SAAA3P,EAAAyF,GAAA,MACL+O,CAAQ,CACV,EAAA/E,EAAA0E,GAAA,CACF,SAAArE,cACeoE,eAAK,WAClB,CACO,MAAAvE,EAAA,QACE,SAAA3P,EAAAyF,GAAA,KACe,CACnBsK,EAEE,GAAM,GAAAN,EAAYjF,6CAAE,IAAA0E,GAAA,UAAAO,EAAA,SAAK,uBAAC,UAAAE,EAAAyE,GAAA,CAAG,mBAAA3M,EAC5B,oBAAAH,EACRyI,mBAEkB,SAAAjJ,IAAA,WAAA8C,EAAA,QAAAtC,GAAA,EAAAxB,EAAwBiK,sBAC1C,GAAaJ,EAAAW,EAAA,CAA8BP,aACzB,IACR/P,EAAAyF,GAAA,OACNgC,GACAH,cACAsC,qCAMAnB,+BACD,KAEHkH,GAAK,KAAa,SAAIA,EAAAW,EAAA,CAAAP,cAAkC,IAAA/P,EAAAyF,GAAA,aAE1DgK,CAAS,QACQ,4BAAAE,EAAA,UACbkD,cACF,yCAAE9C,SAAAjB,GAEG,QAAM,KAAUwF,GACrB,GAAAvE,EAAgC,SAAQJ,EAAA,QAEzC,sBAEab,wBAERwF,OAAqB3E,EAAA8E,GAAA,CACvB,SAAA9E,EAAA,UAAEI,cAEIC,MAAM,iBAAgBnO,SAAKiO,GACjCH,QAAAZ,GAAAgB,SAAO/P,EAAEyF,GAAuB,YAGpCgK,IAASzP,EAAAyF,GAAA,MACGqK,EACDf,EAAkBgB,EAEtB,GAAM,GAAAjJ,IAAU6I,YAAA+E,GAAA,CAAA3E,SAAwB,GAAAJ,EAASgF,GAAA,eAAAjQ,EAC7C,OAGf+K,IAAA,YAAMO,EAAM,eAAoCd,uFAAiBa,YAC/DN,OAAA,OAAa,YAAgBM,gBACXxH,CAAA,IADWwH,eACX,OACdtI,cACAH,gBACAsC,oBAEc,CAIdnB,MAEFkH,OAAK,EAAMrT,EAAA,OAAQsY,EAAOnP,GAAgB1C,EAAA,EAAEsF,GAAG,8BAAA3J,GAAAqE,EAAA,CAC1C,EAWP,SACO+D,IAAA,cACC,oBACgB,MAAAlG,EAAAC,EAAAC,CAAA,KACtB6P,QAAekE,GAAA,CACbhC,OACF,SAAAhS,CAAA,CAAEkP,EAEkB6E,OAAK5U,EAAEyF,SAAsB,CAAI,MAAA7E,EAEtD,SAFYkU,IAAAhU,EAEMiU,WACjB,GAAAD,CACO,EAAAlU,CAAA,IACC+O,EAAA,SAAAqF,GAAA,MAAApU,EAAAC,EAAAC,CAAA,KACN4P,MAAU5B,aAERwF,UAAqB,CACvB,EAEA,OACQ3E,EAAA,UACN,MAAA/O,EACD,SAHDkU,IAAAhU,EAGC,GAAAA,CAAA,MAAAgU,CAAA,GAAAA,CACK,EAIRnF,EAAA,CAAAI,EACE,GACO,OACCJ,EAAA,eACNe,SAAUZ,SACDf,cAAkBgB,SAEtBvF,EAFsBuF,EAET6E,CAAsB,GAAI,UAGjD1O,EAIJY,CACe,WAEd6I,EAKFF,CACS,WAMJM,CArBW,CAuBF,CAAWA,EACajP,CAAM,EAE1C,GACO,GAAAuO,IACE9G,MACPiK,YACQlW,EAAA,SAAAA,EAAA,eAAEoC,MACRgK,EACAL,cAAqC3J,CACvC,MAAAkI,EAAA,SAAAC,EACsB,QAClB,KAAMkJ,GAEaxM,GACrB,EACE3C,gEACUC,UACZoU,EAAC7M,EAAA,QACD,IAAA6M,SACA,MACE,eAAAnY,EAAe8D,cAC+BkU,IAGjDhb,IACI,MAEHob,EAAmCpb,EAAA,QAAAgD,CAAA,EACjC8D,sCACUC,WACZsU,EAAC,mBAAAC,CAAA,SACDC,IAAkCvU,YAClCmU,EAAA,QACEA,EAAerU,8DAC+BkU,EADpBlU,cAElB,oBAEV,EACK,GAAAkN,IAEX6B,EAAA2F,GAAA,SAAahZ,GAAA,CAASoU,WAAsBpU,EAAA,eAAAuW,GAC5BrI,GACV,WAAA7E,EAAA4P,GAAA,CAAO,MAAA3O,EAAA,SAAAC,EACG2D,aACRqI,GAAA,KAAQ,kBAAA/E,IAAA,YAAAA,GAAA,2BAACtD,sBACP,IAAAyK,EAAA,YAAAtP,CAGF,eAAA7I,EAAC,aAAAC,CACD,EAACkY,EACLnb,EAAAmb,EAAA,MACDO,EAAA1b,EAAA,QAAAgD,CAAA,EAGP6S,EAAM6F,EAAA,mBAAAA,CAAA,YACYC,EAAA3b,EAAA,MAAAiD,CAAA,EACGT,EAAiB,mBAAAmZ,CAAA,SAChC5H,IAA0B6H,EAAAC,EAAAC,EAAAH,EAC5BR,EAAA,MAAAI,EACFJ,EAAA,eAAAA,EAAA,aAAAlY,EAAA4Y,EAAA,OAAAC,EAAA,OAAE7F,QAEW,EACXnJ,mCACAC,GAEEgH,YAA0B,CAC5B,QAAAvR,GAAA,cACmB+S,eACnBwG,GAA6B,GAE3B,EACM,SAAAlG,EAAAmG,GAAA,CAAEhZ,mBAAgBC,WAAa,IAAAyR,EACrC,KAAAF,EACA,SAAAyH,CACA,KAKMX,aAAwBY,EAAkB,CAChD,MAA0BpJ,GAAA,EAU1BqI,CACAA,YAKAA,OAAe,CACfA,qBACF,CACD,EAIHtF,EACEgB,MACMrU,EACFuW,kBACF,IAAAoD,EACF,IAAElG,EAEgBmG,GAAA,CAChBtP,OAEe,CACbiM,WACF,GAEAgD,SAA8B,EAC5B,GACI,MAAWM,EAAA,YAAA3H,EAAA,CACT,6BAAE1R,oBAAgBC,wDAAiBkY,MACzC,GACwBnb,EAAW,IAAA8P,EAAiB,CAC9C8L,OAKAD,OACAG,KAAkBtI,EAAA,KAGlB+H,GACJG,KAKFP,YAAiBI,KACjBJ,GAEAA,GAAemB,CAAA,GACfnB,mBAAuB,YAAvBA,eACF,QACDnX,EAAAmY,GAAA,YAAAA,EAAA,kBAAAnY,EAAA,KAAAmY,GAIHtG,KAEqBrT,CACfgY,WACF,EACF,CAAEvE,CAEa,IAEb8F,CAAW,CAAErH,EAAKF,GAAMyH,EACd5O,aACJyC,SACF2D,qBAAKvN,sBACH,iBAAA4J,EAAA,SAAA8G,EAAA,uBAAAjI,CAAA,EAAAnB,CAA0B,OAAAqI,EAAA,SAGzB,mBAAA0G,EAEH,OAAA5O,GAAA,YAAAA,EAAA,UACF,SAAAH,IAAA,QAAAA,EAAAsC,GAAA,EAEA,SAAA8G,EACMuF,aACA,MAAA9I,EAAA7Q,EAAA,aACF2Z,aAAqB,MAAAzI,EACfhD,8BAAE,KAAA8C,EAAA,UAAAA,EAAA,KAAkB,wBAAAA,CAAA,EAAC,QACf,YACX,IACK6I,IAAwBvM,EACZ,OAAA4D,EAAA,OAAAlG,EAAA,MAClBsF,GAAG0J,EAKChI,IAEJ,SACM8H,QAGF9I,qBACAgB,EACWC,GAEc9F,EAC1B0K,GAEH1K,SAAuC+E,CAAA,CACvCyI,EAEAtP,iBACAsP,CACSzL,YAAC+L,GAAAtB,EAAA,KAAAA,EAAA,OAAwB,YAAAvW,EACpC,aAAA8X,EAAA,aAAAC,EAEJ,aAAAC,CAAA,EAAEzB,EACH,GAEJuB,EAAA,oBACE,MAAAxZ,EAAAwZ,EAAAE,EAETC,EAAAjY,EAAA+X,EAAAzZ,EAAA,UAEAiY,EAAyB,aAAA0B,CACvBN,EACA5O,eACAH,QAEAoJ,MAAWkG,GADXhN,gCACW,OAAAtN,KAAA,iBACXmM,YACC,mBACD,eACE,KAEE4N,YACoC,MAElC/O,SACAA,CAIM6F,cAAiBA,4BACvB,OAAI,GAAQ,MAEwC,CAClDG,KACWgB,eACXC,CACAC,WAA6B,QACzBqI,GAAA,iHAAAC,EAAAC,EAAAjd,CAAA,SAAAgd,GAAA,MAAAA,EACS,OACbA,EAAA,eAAAE,KAAA,MAIF,IACEzJ,EAAKvN,oBACH,QAAAiX,CAAA,EAAAzQ,GAAA,EAAAc,CAA0B,MAAAV,EAGzB,SAAAC,CAAA,EAAAqQ,GACH,EACK,CAAApd,EAAAqd,CAAA,EAAAnQ,IAAAzO,EAAAya,EAAA,sBAAAza,EAAA,YACLkQ,CACS0K,gBAA6B,cAAAG,EACrC,KACH,EAEAhX,YAAiB,KACnB,EACD,GAAA8a,EAEL,EAAAC,EAEAC,MACErO,GAAe,KACTsO,GAAA1Q,EAAAD,CAAA,OAAA4Q,GAAA,CAAE9Y,aAAO8X,WAAcC,eAAcC,MAAa,MAAIzB,MACxDuB,EAAmCrO,EAAA,IAGrCsP,EAA8Bf,MAC9BzN,GAAevK,KACfuW,MAAwB0B,QAC1B,OAAAe,EAAA,UACFC,EAAArb,GAAA,QAEesb,MACE,IAAA7d,aAET8d,MAAmC,EACrBvb,EAAA,OAEnB,GADiBwb,EAAA,QAAAC,EACjBA,IAAA,IACOnB,WAAuB,SACjC,UACMW,IAAyC,cAGhCS,KACL,MAAUxG,IAAAjZ,GAAA+e,EAAA,sBAAA/e,GAAA,OAAAwf,EAAA,QACpB,GAEME,SACEzG,GAAA,UAAEuF,UAAoB,CACtBD,MACa,UAAAoB,EAEVpB,MACT,EAAAqB,EACOC,GAAA;AAAA,gDACTC,GAAAH,CAAA;AAAA,4BAE4BG,GAAgB7J,EAAA;AAAA,kBACpC6J,GAAAH,CAAA;AAAA,oBAAE3R,CAAiB,EACnB6R,GAAA,8CAAAL,CAAA,KAAAd,EAASpQ,CAAiB,YAE1B,SACJnC,0BACsB,SAAC,QAAA8M,GAAA,kBACL3T,EAAC,IAChBuZ,MACDC,CAKEC,SACNrO,IAAgB,WACdsO,cAEU,EAAAxd,CAACue,EACPhB,OAAsBO,aAEVvE,EAAA,CACZ3M,OACD,EAAAoR,EACA,OAEL,GACMD,KAAsB3P,GAAS,CAC/BsP,SAAiC,QACvB,eAMe/Y,EAAA4P,CAAA,GAAA5P,EAC3BiZ,OAAsB,GAEdnG,EAAA,QAAA1S,GAAA,QAAE/E,MAAK8E,QAAS/E,eAAW0E,cACjCsZ,kBAGEjZ,UAEa,QAAA0Z,CAEb,EAAAzZ,EACA0Z,GAAAC,GAAAC,EAAAJ,EAAA,EACF,GAAA9L,MAEiB;AAAA,oDAKsBmM,GAAanM,CAAA;AAAA;AAAA,oCAEjD6L,GAAA5H,CAAA;AAAA;AAAA;AAAA,6BAEwB0H;AAAAA,0DAAYE,GAAA7L,CAAA;AAAA;AAAA;AAAA,wBACR2L,CACnB,MAAAS,IAAArgB,GAAAggB,GAAA,YAAAA,EAAA,qBAAAhgB,GAAA,KAAAggB,EAAA,CAAA7X,GAAAmY,KAAAnY,IAAA,CAAAmY,GAAA,QAC4BR;AAAAA,oDAG/BA,GAAAS,EAAA;AAAA,+CACsBT,GAAAS,EAAA;AAAA,wBAAAF,GAAA,uBAAAG,GAAAH,EAAA;AAAA;AAAA,mBAG6B3B,EAAK,EAAA3I,IAAA,aAAO8J,IAAA,8CAAAL,CAAA,KAAAd,EAErDmB,CAEfY,WACEC,CACUpb,UAGdA,GAAA,UAAAua,GACF3E,GAAA,CAEMnF,QAAOkD,EAAA,SACN,SAAA3T,EAAA,CACA,EACF,CAEH,GACE,EACEyQ,uDACGxU,SACI,CACT,IAAAC,EACcuc,OACRxc,WACF,CACF,MAAA4E,EACAiI,MAAY,EAAEjI,WAAO4P,SAAM4K,eAAaxa,EAAA,IAAAA,CAAA,QAAGya,IACrC3H,kBAAgBlD,GACdnH,eAAezI,CACvBkV,GAAA,MAAAA,EAAW,CACHzR,qBACA,kBAAAgX,CAAA,EAEJ1I,SAEAlE,SACAC,8BACA8L,IACAC,gCACEzZ,KACE0Z,YAEN,KAAU,UACA,kBAAAW,CAAA,EAC0C,SAI3C7c,EAAA,gBAAAvC,CAAA,GAAA2E,CAAA,EAGoC,EAGpCgZ,EAAA,+CAAA0B,CAAA,EAAAC,EAAA/c,GAAA,aAAAvE,CAKD6gB,WAK4BP,GAD1BlB,EAAApf,EAAA,OAC0BsgB,WACLA,4BAAgB,UAIjC,GAAArF,EAAA,sBAAA7a,EAAA,CAId,GAEFuf,UAAyB,2CAAA2B,CAAA,EACfC,EAAA,KAAkDrC,cAAKS,EAAA,kDAAA4B,CAAA,EAAOC,EAAA,KAAA9B,EAAQ,YAEhF5Z,EAAiBua,wDAET,KACNa,YAA0BvB,EAChB7Z,wDACX,kDAAAub,CAAA,EAAA1B,EACF,sDAAA2B,CAAA,EACH3B,EACF,qDAAA4B,CAAA,EACF5B,EAAA,uDAAA6B,CAAA,EAOAH,CACQ,MAAErf,QAAKsE,qBAAK,GAAMG,OAClB,wBAAEE,cAAOya,cACf,EAAIpf,EAAa,wBACfuC,EAASoC,QAAgB,aAAeiY,EAAA,IACxC,CAEEra,GAEAyM,QAAiBkM,CAAA,CACH,YAAAuE,EACJrR,EAAA,GAAAsR,EACaN,MACpBO,GAAA3B,GAAA,WAAA0B,EACG,eACR,GAAAD,EAAA,WACFC,UAAwB,aACtBnd,EAASoC,QAAgB,MACzBnG,EAAAohB,GAAA,YAAAA,EAAU,SAAV,MAAAphB,EAAA,KAAAohB,GACErd,MACAyM,CACc,IAAA6Q,EAAAC,EACJL,EACaL,6BACpB,kBAAA1U,GAAAsT,EAAA,eAAArT,CAEL;AAAA,EACF8U,EAAO,aAAAK,EAAA,YACLvd,GAASoC,KAAW3E,EAAW,IACjCyf,EAAA,SAGclQ,OAKhB+P,GAAwBS,GAAA,aAChB,MAAAC,GAAAxhB,EAAAkhB,EAAA,sBAAAlhB,EAAA,cAAER,eAAM,iBAAMyG,oBACpB2Y,UAEA,GACQhf,uCAAY6hB,OAAejC,IAAW,SAAM,CAC9CzO,iBAA2ByO,CAAA,EACjCjB,GAAA,MAAAA,EAAA,SACFlD,GAAA,MAAAA,EAAA,CAEgBtK,4BAKhBgQ,WACE7B,GAGcnO,IAKhBiQ,OACE9B,yBAA6B,CAC/B,IAAAC,EAEgBpO,aAIlB,gCAEA,SAAa,CAAAqG,EAAA,YACX,sBACkBrG,2BAIAA,kBAIAA,iBAIAA,kBAIAA,WAIlB,SACF,aACG8N,GAELnO,MAEE,cACA,MAAenP,EACTmgB,cAEJ,MACQ,IAAAlgB,EAAE4c,QAAO,EAAI1B,EACH3L,EAAQzG,EAAwB,QAClD,GAAA9I,IAAA,WAAAuC,EAAA,SAAAA,EAAA,SAAA4d,GACD,IACDD,MACG,MAAAvb,EAEC8a,uBAE8C1f,WAAS,EACzB;AAAA,gBAC9B0f,OAEFC,kBAAwC,KAAAU,EAAA,GACxCV,QAAoBnQ,EAAU8Q,GAAAC,GAAAC,CAAA,EAAAH,GAAA,uCAC9BR,KAAgC,CAChCrd,EAAA,iBACF,MAAAie,CAAA,EAAAH,GAAA,iBACIR,mBACAC;AAAAA,EACJW,CAAsBlR,YACFA,eAClB7E,KAAoB3H,CAAA,EAClB4H,oBACG3L,EAAA,kBAAA0hB,GAAA,CACP,KAAsBnR,CACR,MAAkBmR,EAAA3d,EAAAqd,GAAA,OAAEP,sBAAOC,CAAiBD,MAAO7gB,EAAA,iCACpD8gB,CAEOvQ,MACpB,EAIIoR,YAGEX,EAAMN,QAA6BkB,YAAc,UAGvDZ,EACEa,QAAYte,GAAA,OACb,MACKxC,QACDA,EAAMwC,EACEyb,EAAAhf,EAAA,4BACL+d,GAAcmB,EACpB1B,GAAmBxd,CAAA,GACLR,EAAA8e,EAAA,gBAAA9e,EAAA,KAAA8e,EAAA/a,GAAAqd,EACJ5B,CAAA,EAAA2C,IACK5D,EAEf,OACC,aACE,YAIEY,EACA,SAAApb,GAAA,CACC,GAAAmd,EAAA,SAAyB1J,KAE/BJ,CACQ,UAAAnW,CAAA,EACS8C,EAAA,OACFmd,EAAA,kBAAAjgB,CACD,CACZqhB,CAAW,GACPlL,EAAA,OACJmL,IAAKrB,EACLsB,MAAK,oBAAI,cACL3D,OACJpE,IACK,GACElZ,SACPoX,GAAkB,CAEV,cAAAxM,EAAA,IAAE3K,UAAKhB,CACb,MAAAiiB,EADwB1e,8BAExB2e,EAAYvW,EAA0BpI,EAChC,OAAA+Z,EACI1G,EAAA,QAAEjR,qBAAO5B,YAETqd,UACN,qBAEM,SAAAc,CAAA,IAAAvW,CAAuByV,GAEnB,OAEN,eAAca,EAAAtW,EAAA,GACZpI,EACA,UAAAqT,EAAA,QAAa,CACb,SAAAsL,iBAA2BA,GAAoB,WAAAA,GAAA,kBAC/C,MAAAD,EAA2B,IAAAtW,CACpBwW,aACDT,gBACCU,UAA0B,GAG3BV,EACCS,CAAoC,SAC7CE,GAAAC,EAAAC,EAAA/Y,EAAAoU,EAAA,CACAJ,oBAAyB8E,CAAA,EACzBtiB,OAAqB,MAAAwJ,EAAAgZ,CAAU,EACjCC,EAAA,WAAA7E,EAAA4E,CAAA,EACF,gBAAAE,EAGA9U,WAAe,CACjB,CAEF,SAAA+U,IACsBpS,aACtB,SAAAoH,EACF,KAAAsG,EACA3C,sBAAgB,KACR,EAAEtb,iBAER,GACAoe,MACAZ,OACAc,GACAsC,OAC4B,CAAA7S,EAAAC,CAAA,EAAAC,EAAA,WAC9B2U,EAAAC,GAAA,mCACO,MAAAtN,GACE,GAAA3I,EACC,KAAA2H,CAEV,EAAAiE,EACAsK,KAAiB,IAAAvO,EAAA,oBAAAA,CAAA,EAAAiE,EAAA,KAAAjE,EAAAiE,EAAA,MACfuK,gBAAwBxS,MAChByS,EAAAD,EAAAE,GAAA,KAAExiB,kBAAgBT,CACxB0gB,iBACF,iBAAAjS,EACF,eAAAG,GAEFgI,mBACEqD,qBAAKyG,EACC,IACNsC,GAAY,GACZ,CAAAE,EAAAC,CAAA,EAAAlV,EAAA,IACW8U,EAElBxN,GAAA,qBAAA5G,GAAA4F,EAAA,KAAA5F,EAEuB,CAAkB,sBAAK2O,SAAU,UAAA/I,EAAA,KACjD6O,gBACAnB,CACN,EACY1M,GAAA,qBAAA3G,IAAA2F,EAAA,KAAA3F,IACS,sBAAqB,SAAE,UAAA2F,EAAA,KAC5C,eAAA3F,EACA,CACE,EAGS,KAfM,IAgBX,EACF,CAAAyU,EAAAC,CAAA,EAAArV,EAAA,IAAE+I,OAEFJ,CACEK,IACEiL,KAQKD,4BACP3N,EAAK3I,CAEPiL,KAAA,mBAAY,SAAWsL,oCAAiB,iBAAAzT,EACpC,MAAA4U,GAAA,YAAAA,EAAA,MAEV,OAAAA,GAAA,YAAAA,EAAA,MAEA,CAIE,EAEA,GAAAA,EAAkBE,EAAW3F,CAAsB,GAC5C,MAAA4F,EAAAC,CAAA,EAAAxV,EAAA,IAAEyU,QAAUD,SAAUe,GAAA,YAAAA,EAAA,QAAA3U,GAC/BsU,EAAA,CAEA,KAAyB,mBACvB3K,SACAb,oCACAsG,0CAC4B,MAAC,OAAAuF,GAAA,YAAAA,EAAA,OACZ,CAAC,CAEZ,GAAAA,EAAA3U,EAAAkU,CAAA,GAAExV,6BAAMC,qBAAiBkW,GAAA3C,GAAA9F,EAAA,KAC/B/K,GAAOnC,IAASC,CACV4U,GAAyDvK,EAAA,CACzD,GAAAA,GAAAqL,EAAA,GAAEnO,iBAAM3I,UAAI2H,QAASiE,MAC3B,OAAM/C,GAAMR,EACHV,UAGT3G,EAAY,gBAAE4K,iBAAY,QAGJuK,KAChB,aAAAY,CAAA,EACc,EAChBhV,KACAF,eACAG,wBACAC,mBACAC,oBACE,MAAC,iBACciJ,EAAC,CAEfmL,WACD,CAACH,CACL,KACkB,KAIT,MAAA1K,GACL9C,SAAMiD,EAAA,aAAA5B,EAAA,KACG,2BACSpB,CAChB7G,GACF,EAAAiI,EAAA,YACF,IAAAvH,EACF,MAAAgJ,IACkB,GAIT,KAAA4F,EAAA,YACC,CACN2F,MAASC,EAEPjV,CACF,WACF,CACF,EACO,MAAAiV,EAGWP,CACV,GAAM,QACQ,CAClBD,EACU,MAAAQ,EAED,YAEPpV,EACoBjF,GACZ6Z,EACV,2BACF,aAAC,KACH,iBACEA,WAAa5U,OAEjB,IAAoBgV,OACpBvT,SAAgByH,GAAA5J,IAAA,UACV,MAAkBA,IAAA,UAAmB,aACrCyV,iBACU,QAAAjgB,GAAA,CACVgS,KAAM,CACG,MAAA5P,CAAA,WAEPkJ,KACoBrF,EACCoU,CACvB,EACDkG,EAAA1U,EAAA,MACHc,GAAA,IACerB,cAEjB9J,GAAAvF,EAAAskB,EAAoBC,UAApB,YAAAvkB,EAAoBukB,YAApB,MAAAhf,EAAA,KAAAvF,EACA,EACMkkB,IAINxT,SAAgBd,EAAA,MACdsU,MACC,KAAcA,CAEjB,KAAOM,EACD3U,SACNa,IACMyT,UACAK,sBACFL,KAAQ3T,CACNX,aACI,eAAA4U,CACR,EAAAL,EACA,OAAaC,EAEb,CACEG,GAAU,SAERE,QAED,KAAStB,EACRlM,EAAW,EAAAyN,GAAAF,CAAA,CAAYjN,CACT,EACV,KAAsB,oBAExBJ,MAAUyB,eACPG,mBAA0BxB,SAAoB,OAAA4G,EAC7C,EAAAgG,EAGN,CACOvU,wBAEL4O,iBAEE,OAAA4F,EACOA,CAAE,YAAAjX,OAAA,CAAmB,EAAAW,EAAA,OAAA/D,EAAA,EAAC,EAAA+D,EAAA,OAAAqQ,EAAA,EACtBiG,6BAAE,GAAoB,KACtBA,wBAAE,UAAAO,GAAA,eAAAC,CAAmB,EAAAT,EAAC,OAAAC,EAGhB,CACF,YACD,QACD,EAAAM,GAAAC,EAAA,EACP,EAAAD,GAAAE,CAAA,CACJ1M,CACAV,CAA2C,CAG3CqE,CACQ,wBAAE3V,kBAAY3F,GACpB+jB,iBAAoBO,EAEtB,MAAA9a,GACS,OAAAoU,EAEb,EAAAgG,EAGEE,CACN5T,YACE,UAAAuS,EACEqB,KAA8BS,GAAAD,EAAA9a,GAAAoU,EAAA,EAChC,OAAAiG,EAGIW,CAEAC,YACE,QAAElP,eAAMqO,eAAYc,gBACd,GAAAnX,EAAA,OAAAkV,EAAA,CACa,CACf,EAAEkC,CAAWhW,IAAmBiV,sBACtCC,SAAO,CAAAjX,GAAA,UAE4B,GAAY,OAAA8J,EAAAgF,GAAA,CACjD,UAAAhF,EAAA,OACA,MAAyB,mBACjB,UAAAE,EAAA,aAAEyM,yBAAa5U,IAAkBjF,aAAOoU,KAAWgG,EACnD,SAAAgB,IAAA,QAAAhO,EAAA,OAAE8L,MAAUD,OAAcJ,WAMhCwB,mBAAO,aAAAgB,EAAA,cAAAC,CAAA,EAAAvhB,EAAA,OAAAqR,EAA0F4M,CAEhGuD,OAASvD,EAAasD,EAACE,MAAcxD,EAAgByD,OAASzD,CAE/D,CAAC,CAAI,EAAC,EAAAoD,IAAA,SAAAA,IAAA,OAAAhO,EAAA,SACR,IAAAnB,EAAA,qBACuB,GACf,SAAE2O,2BAAWxV,mBAAmBgV,qBACtCC,mBAAO,WAAAqB,EAAA,YAAAC,CAAA,EAAA5hB,EAAA,OAAA6hB,GAEPD,GAACE,EAAmBzW,CAAe,OAAAsW,EAAAC,EAAW,MAAAD,EAAC,OAAAC,CAAA,CACjD,CAEQ,IAAE3B,uBAAa3U,MAAkBrF,WAAOoU,UAAWgG,YACnD,oBAAElB,sBAAUD,cAAcJ,2BAMhCwB,qBAAO,SAAAjN,EAAAW,EAAA,CAAA3K,KAAA,IAAA0Y,IAAAzB,EAEN0B,CAAuBC,GAAchE,QAAgBiE,CAErD,EAAI,CAAC,KAAAvC,GAAAtM,EAAA,UACR,oBAC4B,cAE1BiN,wBAAOW,GAAA,SAAAA,GAAA,oBAAyDA,GAAA,QAAArH,GAAA,CAClE,KAAAsH,EAAAvB,CAAA,EACF,aACF,GAGElM,SACEN,EAAAa,EAAA,CAAW,aAAkBP,IAC3BJ,EAEW,IACM,QACb8O,CACF,EAECd,CACC,EACEe,CAAKlQ,GACD,CACJmQ,KAAehP,EAAA2F,GAAA,CACb,YAAoB,CACdmJ,EAAA,GAAEb,EAAcC,qBAAc,cACrB,oCACUA,eAChBD,eACCC,sBACT,KACHY,EAAA,GAEAd,EAEAe,SAAW/O,EAAAW,EAAA,CACA,SACN,IAAAsM,EAEG,CACRgC,WACE,CACM,EAAEX,EAAYC,uBAAkBnlB,QACtC,UACiB,MAAA6jB,EAEbra,CACQ2b,WACT,CACH,EACF,MAAAtB,EAGUpO,CAAa,WACvB,CAGNiB,EAAW,MAAAmN,EAEF,CACC,WACNlM,CACSmO,CAAS9O,IAEb,EAAM,GAAI6E,EAAGgI,sBAAE,UAAAjN,EAAA,6BAAQ,SAAAgO,IAAA,QAAAhO,EAAA,OAAC,IAAAnB,EAAG,OAEhC,EAACyN,IACD,SAAA0B,IAAA,OAAAhO,EAAA,SACO,IAAAnB,EACC,eACNkE,kBACe,QAAA/C,EAAA,SACb,MACE4N,WACF,OACAA,YACEzjB,mBAA2B,SACjB,CAAAmjB,GAAAxN,EAAA,UACX,UAAAkO,IAAA,wCAAAmB,EAAA,KAAArhB,GAAA,8BAAA0C,IAAAsP,EAAAwE,GAAA,CACH,QAAElE,OAEG,aAAM,EAAW6M,uBAAE,YAAO,EAAC,eAAG,kBAEtC,gBACG,WAAAjN,EAAA,UAGNA,cACiB,cACb8O,SAAkB9O,EAAAW,EAAA,CACpB,iBAEA,IAAQ,IAAAsM,EACNjN,CACO,WACC,CACS,CACb8O,EAAkB,CACpB,EAAE1O,SAEG,CAAAN,EAAA0E,GAAA,CAAM,SAAArN,IAAA,UAAO8V,0BAAEC,EAAA,QAAA3G,GAAA,MAAA0G,EAAQ,CAAG,WAEjC,GAGM,YACOA,2BAAE,UAAArI,EAAA,aAAwBA,EAAA,eAAAjH,CAAA,EAAC,MAAAyR,GAAA,YAAA5e,GAAA,CAC3Byc,qBAAE,OAAApF,KAAA,WAAAuH,GAAA,MAAwB,gBAAAA,GAAA,OAC1BnC,2BAAE1G,GAAA5Z,EAAA,QAAAsgB,EAAwB,CAAC,YACtB,QAEZ,GAAAtgB,EAAA,OAEN,CAAe,GACbsgB,EACGe,CACWnP,WAAS,EACjBmP,CACF,QAAYnP,CAAgBzH,EAAA,YAASjJ,GAAAvF,EAAAskB,EAAA,sBAAAtkB,EAAA,kBAAAuF,EAAA,KAAAvF,EACpB,CACjB,GAAyB,EACvB,UAAAoX,EAAAW,EAAA,CAEN,gBAAW,GAAA0G,OAAA,KAAAvH,EAAA,SAAY,SAErBA,KAAA,IACGkO,QAKa,GAAAhO,EAAA,0BACW4E,QACnB,SAAA5E,EAAAmB,EAAA,CACgB,YACP,GACL0D,CAAQ,CACV,IAAAwC,OAAA,MAAAvH,EAAA0E,GAAA,CACF,SAAArN,IAAA,UACM,aACGC,EAAA,WACA8V,EAAA,QAAA3G,GAAA,CACT8I,KACErP,EAA4B,CAAOI,WACtB,CAAY,EAAO6M,cAAE,6BAAM,MAAArI,EAAA,aAACA,EAAA,eAAAjH,CAAA,EAAG,MAAAqE,GAAA,SAAAqF,CAAA,GACpC+H,EAAA,YAAA5e,GAAAwR,GAAA,CACT,OAEQ,aACe,GACbhB,KAAM6G,OAAA,QACbzQ,KAAoB,MACpB8V,gBAA6BkC,EAAA,OACvBnC,gBAAE,OAAAtgB,EAAA,CAAA4Z,GAAA0G,EAAuC,CACnC,YACX,QAEkB,GAAAtgB,GAAA,MAAAA,EAAA,aAAAA,EAAA,YACb,CACIiY,CACD0K,EACCF,SAAwChY,EACpC,YACRwN,2DAEF,GACQ,EACR,UAAA5E,EAAAW,EAAA,CACAwM,gBAAmC,GACrCrN,UAAY,CACV9I,cAAe,CACfuP,WACW0G,mBACL,sBAAA/H,GAAAmC,CAAA,GAA6C,YAAC,EAAArH,EAAA,QAACiN,4BAC/C,KAAgC,KACtC,GAAAjN,EACQ,UACR5I,cACA8V,oBACF,aAAA4B,EACC,GACL,EAAE1O,aAEG,mBAAMJ,EAAAmB,EAAA,CAAW,GACrBkG,QACC,CAAAjH,CACE,MAGF,GAEA,CAAAA,EACE,KAAmC,EAEtC,CAGQ,SAAA+D,GAAA,CACe,KAAAkD,EAEpBjQ,OACA8V,WAA6B,QAAAxI,EAAA,KACvBuI,EAAE,WAAA7U,EAAA,cAAAD,EAAsC,cAAAG,EAAC,uBAAAD,CAAA,GACnC,MAGZ,EAAAkX,CACM,EAAA1Y,GAAA,EACI+N,CACD0K,UACCtN,aACN,SAAAwN,CAEE,EAAArZ,EAEEyO,gCAEF+B,gBACF,UAAA3G,EAAA,OACQ,qBACR,SAAA9F,EAAA,KAAAuV,EAAA3S,IAAAgD,EAAA,OACAqN,oBAAmC,UAAAnN,UACzB,CACVhJ,YACSiW,oBACP,SAAAlM,EAAA,UAAA1I,EAAA,YAAAkX,EACoC,CACnC,oBACH,EAAAzS,EACQ,CACR1F,CACA8V,CACF,OAAA7F,EAEJ,kBAAEjH,WAEG,QAAC0C,GAAK,CAAW,MACtB1C,OACE,EAAAzT,EAAA,OAAAuN,EAAA4C,GACA/N,EACA2V,EAAAvO,CAAA,GAAAmL,aACI4D,CAAqB,yCAAA5D,YACvBpH,EAAA,uBAAYA,EAAA,OAEN4C,EAAA,GAAC4H,EAAAvO,CAAA,GACD,SACF6J,EAAAW,EAAA,MAEX,SAGPX,IAAA,IACOuP,EACC,CAEJT,WACF,EACsB,CAAU1O,CAEhC,KAAAtD,CAAA,EAAkB,GAAAgD,EAAC,MACZ,OACH,eAAC,SACL,CAAAE,EAAA,eACD,SACJ,2BAER,SAAAe,GAAA7G,EAAA,QAAA9B,EACD,aAEN8B,EAAA,SAEcwK,EAAAvO,CAAA,CACZkR,EACAlR,aACA4K,uBACgB,mBAAC,UAAAf,EAAA,SACjB5H,gBACAD,UACAG,WACAD,aACC,MACK,QAAAuK,CAAA,EAAEhM,SAAiBT,EAAA,SAAAyM,EACnB8B,EAAAvO,CAAA,CAAE+D,EAASC,WAAWqV,YAAarZ,EAEzC,KACE,SAAY,mBAAqCiK,SAC/CJ,GAAAmB,EAAA,CAAW,kBACAvN,WAAawO,CACT,MAAAjI,GAAaiG,WAEpBsP,SAAQ/iB,GAAA,CACH,MACE8iB,SACP1O,SACW1I,cACAkX,MAAE,wBAAAne,EAAA,WAAArC,CAAA,IAAAA,GAAAuJ,GAAAvJ,GAAAoJ,CAAA,QAAApJ,EAAA4gB,CAAA,IAAA3P,EAAA,gBAAAjR,EAAgB,SAAA4gB,EAAA,CAAC,EAAA5gB,CAAA,GAAC,GAC/BsY,OACW,aACP,eACJ3C,WAAgB,UACR,cAAE3V,4CACRmL,YAAanL,CACb2V,MAAY,CACd,EAAE,SAEJ1E,EAAAmB,EAAA,CACExC,GAAK,UACC,CACNoC,CAAwC,GAE9B6O,EACRlL,CAQV,SAAWgE,GAAAmH,EAAA,CAAczP,iBACvBJ,WAAA,SAAA8P,EAAA,OACO,KAAAA,EAAA,mBACC,CACkC1X,YACzB2X,EAAA,CACb7V,aAAQ2F,GACR6E,OAAY,MAAAqL,EAAA3lB,CAAA,aACd,OAAA2lB,EAAA3lB,CAAA,EAIF,OAAa2lB,CAAA,CACX,SAAAC,GACO,SAAA3Z,EACImZ,KACTzO,EACA8B,gBACQ,EAAED,sBACRzM,MACAuO,GACF,EAAA7N,GAAA,EAAE,CAEJ,MAAAI,CAAA,EAAAsQ,GAA8B,EAEhCzH,GAAA1I,CAAA,EAAAC,EAAA,WAAOgJ,CAAM4P,EAAAC,CAAA,EAAA7Y,EAAA,IAAY+I,GACvB+P,EAAA,EAAA9Y,EAAA,KAAA+Y,EAAAC,CAAA,EAAAhZ,EAAA,GAAAiZ,EACA,MAAAC,GAAA,MAAAA,GAAA,MAAAA,EACSpW,eACP4G,sBACA8B,GACQsN,GAAA,CAAEphB,SACRoH,EACY,EACZiK,KAEchP,CAELrC,IACTqI,EACK,SAASuY,GACJ5gB,cACE,QAEX,MAAAkI,EAAA,yBACI,EAAAuZ,EACH,SAEVxQ,QAAA,GAAW,EAAcI,GACvB,EACEzB,EAAK4R,CAAA,EACLlQ,EAAM,UACNU,OACAC,EAAe,QACb0D,CAAY,KACd,EAEA+L,EAAAtG,GAAAuG,EAAA,KAAApX,GAAyB,KAAAoX,GACnB,EACL,CAACA,CAAA,SACHC,EAAAnY,IAETc,GAAA,KAESsX,YACPC,EAAaA,gBAIV9Q,UAAe,QACV+Q,EAASC,QAAExI,eAAsBoI,EAAA,qBACjCK,EAASC,QAAE1I,aAAsBoI,EAAA,sBAIjCO,MACAC,QACAC,GACJV,GAA+BS,CAcjB,EAEf9K,CAAMnC,CAAI,GACf,MAAAmN,EAAApY,GAAA,CAEA,QAAyBA,EAAA,KACvBiN,EAAW5R,CAAoB,EAC7B+B,GAAmC,EAEvCqF,GAAA,aAEA,UAAkC0U,CAAA,EAChCkB,GACED,EAAWC,CAAkBlnB,CACb,EAChB,CACF,kBACO2lB,0BACT,GAEA,MAAAwB,GAAsB/Y,IACpBnC,UAAgB,YAAC+Z,EAAAH,EAAA,WACAG,EAAA,GACjBlM,KAEM,gBAAEtN,8CAAiB4a,GACnBA,EAAA,gBAAEva,kBAAc,eACfE,OAASC,QAChB,CAAO6Y,CAGP,GAAM,CAEAK,GACA,eAAWlgB,GACf,iBAAsB,SACtB,GACsBsL,GAAA,UAClB0U,EAAGqB,IACAC,KAEPrB,EAAAJ,EAAA,UAGIS,gBACJ,MAAWc,EAAAD,GAAA,mCACXna,GACaoa,EAAA,gBACP,kBACF,eACE5N,OAAG4M,UAEM,GACX,CACAN,GACAI,kBACAlZ,iBAAoB,YAEpBA,QAAkB,CAClBJ,mBACF,cACF,SAAG,GAAAX,GAAA2J,EAAA,UACL,cAEMyQ,oBAENnX,QAAgBjD,EACD,SAAA2J,EAAAW,EAAA,CACX+P,SAEEC,OAGFA,WAEIA,CACFA,CACAA,EAAuDvgB,CACzD,EAAA4P,EAAA,UACF,SAAAA,EAAA,QACG,SAAArT,GAAA,OAEL2M,EAAU,eAAM,GACS1Q,EAAA6nB,EAAA,cAAA7nB,EAAA,KAAA6nB,EACrBC,EACF,SAAA1Q,EAAA,SACEkE,MAEEmN,YACEM,cACNzL,MAAsB,QACd,YAAA0L,EAGVlW,CAGU4V,WACe,CACnBD,EACF,QAAA1kB,GAAA,CAEF,MACkB,MAAAoC,CAAA,EAChB8iB,SAEJpB,EAAA1hB,CAAA,GAGA2M,aAEQ,MACA0U,kBACFC,qBACK,mBACLA,WACF,aAAAnM,GAAA,EACA9K,EACE,EACA,GAAA4G,EAAkB,QAChBwR,2BAA4B,UAAAxR,EAAA,UAChBuR,GAAA,MACH,iBAAApa,IAAA,kCACC8Y,EAAA,KAAAhX,EAAA6D,IAAA,CACT,MAAAgV,EAAAL,EAAAxY,EAAA,IACH,OAAA6G,EAAA,MACE,MAAAhD,IAAAsT,EAAA,cAEN,UAAApQ,EAAAC,GAAA,CACkB,iBAChB4R,UAEJ,aAAAC,YAIQ,gBACmB,EACrBzB,eACK,cACYJ,eACnB,aACiBoB,EAAApY,CAAA,CACMsY,EACH,SAAAvR,EAAAW,EAAA,CAChB6Q,KAA4B,OAChB,UACH,IAAAI,EAER,CACH,WACE,CAEN,EACkB,EAChBC,EAA0B,EAE9B5Y,EAAA,GAEA,CACE6G,CAAQ,GAAA3I,IAAA,UAAA6I,EAAA,OAAsB,0BACzB3J,MACY,UAAe,CAAuBA,wBAAQ+J,iBACnD0C,SAAK9C,EAAA,KAAO4R,0BAAE,GAAO,QAAC,IAAG,CAGnC,SAAAxR,GACE,CACEoB,QACE7U,WACA8jB,eAGF,EAAErQ,gBAEF,EACOuQ,mBACG,GACH,MACC,EAAAoB,CACKH,OAAE,CAAAza,EAAAC,CAAA,EAAAC,EAAA,WAAA2a,EAAAxZ,EAAA,IAAiB,CAAAyZ,EAAAC,EAAA,EAAA7a,EAAA,IAAC8a,EAAA9T,GAAA,IAAA3F,GAAA,6CAC/BgM,EAAgBlM,IACRc,GAAA,KAAEvK,uBAAY3F,CACpBqnB,IACF,MAAA9H,EAAAT,CAAA,QAAAN,GAAA1Q,EAAAD,CAAA,EAAA0Q,EACa,QAAAO,EAAAgK,GACDvJ,CAAA,EAAAvR,EACG,gBACJ,CAAAA,EACP,SAC+B,IACpC,GACG,GAAC,MAET4I,EAAA3B,GAAA,WACG4R,GACC,aACOsB,mDAGJtB,KACO6B,oBAAgC7Y,SAIlCoH,IAHJlS,GAAAvF,EAAAopB,EACE,UADF,YAAAppB,EACE,OADF,MAAAuF,EAAA,KAAAvF,EACE4f,GAEEnI,YAAa+P,CAAgChQ,OAE7CJ,CAACC,EAAY,MAEXhH,CACA6Y,kBACStJ,EAAA,cACG4J,EAEdpS,EAAA,eAAAwI,CAAA,IACO6J,EACC,SAAAD,cACS,EAAAC,GAEfD,CAAA,EAAEhS,KAEGkS,EAAM9Z,IAAA,CAAA+Z,EAAYC,CAAA,EAAAnb,EAAA,MAAAob,EAAQb,uBAAE,MAAA7iB,CAAA,EAAApC,EAAA,OAAK,GAAAoC,EAAA,CAAC,MAAA8S,GAAAjZ,EAAA+e,EAAA,sBAAA/e,EAAA,OAAAmG,EAAA,OAAG8G,EAAA,GACnC2c,IACP,IAAA3K,KAAA,QAAA6K,GAAAvkB,EAAAmkB,EAEP,UAFO,YAAAnkB,EAEP,WAFO,MAAAukB,EAAA,KAAAvkB,EAEP,UAGHqkB,EAAW,KACF,GAAAP,CAAO,GAAA3Y,GAAE,KACb4K,IACS+N,GAAA,MAAAA,EACd,SAAAQ,EAAW,CAAUrS,QACnBA,OACE,GACC,GAAC8D,EAEJuO,EAAAR,CAAA,SACCU,GAAAC,GAAApK,GAAA,CACJtC,GAAA,MAAAA,EAAAsC,GAETnS,GAAA,MAAAA,IAEA,eAA2B,KACzBY,qDACAC,sDACgB,IAAC2b,EAAA,OAAAC,EAAA,KACA,QAAAtK,CAAA,IACjBtE,aACC2O,IAAA,OAAAlmB,GAAA,gBAAAwB,GAAAvF,EAAAopB,EAAA,sBAAAppB,EAAA,mBAAAuF,EAAA,KAAAvF,EAAAmqB,KAAA,YAAApmB,EAAA,aACKkmB,IAAA,aAAKhc,GAAc,uCAAAgc,CAAA,CACzB,EACMb,OACArB,EAAeuB,IACfC,eAGAxK,YACNrO,EAAgB,gBACdlC,EAAoB,gBACPuZ,EAAA,uBAAAA,EAAA,qBACPA,EAAA,qBAAAA,EAAA,sBAGFhJ,MACAuK,SACA9a,yBAAoB,cAEpBA,eAAkB4I,EAAA,UAClBhJ,cACF,oBACC,QAAAX,WACA2J,EAAAW,EAAA,CAECqS,SAEJ,IAAkBjB,EAIlB,YAEavf,CACMmH,CACb,EACF0Y,cAAoB,CACpB,UAAAvS,EAAA,OACF,UAAAE,EAAA,KACI,SAACoS,EAAgBa,GACTzK,WAAoB,CAChC,CACA4J,OAAgBa,cAAoBjT,EAAA+E,GAAA,IAAAjF,EAAA,SACrC,+BACqB,OAAA5I,CAAA,CACpBkb,GAA0BC,CAC5B,EAAArS,EAAA,QACOoS,aACLH,iBAAa,UAEKzZ,EAAO,GACtB+Z,GACDE,GACH9lB,IAAM6b,EAAA,aACGzZ,EAAUpC,SAAEvD,WACT,IAAAunB,EACT,KAAgBhJ,SACP9R,cAET2c,CACc7Y,WACT,CACL6Y,EACF,QAAAC,EAEDR,aACH,MACA3Y,YAAgB,MACV4K,qBACK,mBAAU,WAAEnV,aAAOmV,MAAkB,EAAG,GACjD,EAAAlE,EAAA,QACEkE,IAAmBuO,EAEjBE,aACHnK,OAAU,MACTtC,MAAWsC,2CACD,SAAA+J,EAAA,IAAA/J,GAAAxI,EAAA,MAEVkT,4BACMf,cACIlZ,CACF6Z,qBAKqBlD,sBACzBuC,EACK,WACLA,EAEAA,eAMAA,CAA2BA,WAC7B,2BAGMlZ,cAAY,SAAA+G,EAAA,MAAoD,CACvE,iBAEFkG,SACHlG,EAAA,cAEwBA,EAAAmB,EAAA,CACR,WACd,EACEwP,EAEIA,kBAAwB,eAAAqC,CAAA,QAAAC,EAAAtK,CAAA,OAAAA,GAAA,MAAAA,EAAA,SAAA7I,EAAA,OAC1B6Q,MAAShX,oBACTgX,SAAiBvjB,UACnB,uBACF,UACG,aAAA2kB,EAGK,CAA4B,WAChC,CACa,EAAe,aAAAA,EAC1B/R,CAAW,WAAO+R,IAAEkB,CAAA,GAAAA,CAAA,GAAAjT,EAAAmT,GAAA,CAAO,OAAAxK,EAAC,SAAAgK,EAAA,CAAG,EAGnC7S,IAAA,CAAAM,CACE,CAAAA,EACE,CAAAA,CACE,OAAA+S,GAA2BC,GAAA,EAAC,OAAAzK,EAK5B,SAAAzC,CAAa,IAAe9F,CAAa,MAC1C,KAAAzJ,CAGD6K,OACE7U,GAAiB0mB,CAAA,EAAAhc,EAAAxB,EAAA,EACX2S,WAAiB9K,EACvB,OAAAoC,EAAW,WACK,UAAA6I,EAAA,QAAUJ,UAAYvI,EAAAsT,GAAA,CACtC,MAAA9K,EACF,aAAEpI,QAEF,cACOuQ,IACA,YAAA4C,GAAAvT,EAAA,eACM+R,6BAAE,YAAAsB,EAAA3V,EAAA7H,EAAA,WAAAmK,EAAAmB,EAAA,CAAc,YAAC,QAC5BuD,EAAS+N,qBACI,EACD,GACG,EACJ,GACPa,GAC+BF,GAAA,QAAA5K,EACpC,QAAAxH,EACI,SAAAwS,CAET,IAAMnQ,CAAKiP,MACRC,MACW,QACC3e,gBAAK4U,cACZ,KAAAiL,EAAgC,CAAqBrT,UACjC,wBAChBoI,0CACAxH,EAAerU,EAAA,wBACC+mB,EAAA,KAAAC,EAAA,KAAUpL,IAC1BqL,EAAA,iBAAAA,EACQ,sBACTF,EAAA,MAAAC,EAAA,UAACC,EAPWrL,IAShB,cAGHzI,EAAA,qBAA+BM,EAChB,+BACX,CAAqBA,CACnB,EACE,OAAAN,EAAA,wBAAyC,UACxC,iBAAAkB,EAOC,aAAWwS,EAAA,OAAAhL,EAAA,UAAmBpI,iBAC5B,QAAWyT,EAAA,SACR,CAAA/T,EAAA,oBACaiS,+CAAE,2CAAA/R,EAAA,OAAe,4BAAC,IAAAwI,EAAA,KAAAA,EAAA,cAAAA,EAClBuJ,qBAAE,2BAAQ,iBAAC,GACzB,EAAAyB,KAAeP,IAAQ,SAEzBjT,KAAiBA,EAAA,QACf2I,uBACUgK,GACV,EAGT,GAGFmB,GAAA,YACJ3N,GAAA,CAET,QAAA9P,EAAA,KAEM8c,EAA2BxK,gBAAQzC,CAAS,EAAM,kBAChD,MAAEvP,SAAoBod,CAC5B,EAAAld,GAAkB,EACZ0c,IAA2B7V,eACjC,CACEoC,EAAAkU,CAAA,EAAA3c,EAAA,IAAA+I,EACGuI,EAAa,MAGVH,aACehQ,EAAA,GACJ8Z,EAAU/J,QACrB,SAAA0L,EAAA,CAAE,OAAA5mB,CAIJ,cAEQzE,EAAAsrB,EAAA,gBAAAtrB,EAAA,QAAAwO,EACG4J,SAAatD,GAA2B0C,+BAEjD,WAFiDA,eAEjD,uBAAQzJ,QAA+B,IAAC,SAAc,OAEzD,IACM,MAAAzM,EAAA,CAEZ,QAAAwG,GAEK4iB,YAAoBF,MAAQ5K,WAAOxH,SAASwS,6BAAe,OAAAnmB,EACzDwmB,OAAkB,YAGtB,EACelnB,EAAgBwnB,oDAAc,oBAAAjqB,CAAA,GACjC,4BACJypB,oBAAoC,GACpCD,aAAaU,IAAoC,aAApCA,cAAoC,WACjDR,KACNxc,EAAazE,SAAYA,CACvBihB,OACAA,UACF,CACEA,KACAA,CAAkCta,GAC7B,YACW+a,6BAClB,MACF,MAAAC,EAAAnK,GAAA,KACF8J,EAAA,CAEA,QACE,CACO,GACK,KACVjT,gBACA,sBACAuT,MAAgBV,QAChBW,SAASX,kBAASzT,cAElBA,oBAEI,UACgBqU,SACRzU,EAAAW,EAAA,CAGVX,SACE7N,IAAU4hB,GAGJ,WACC,CACPW,CAAQ,EACC,GACT1U,EAAA,UACK,SAEPF,SAAA,KAAAnF,EAEEyF,SAAamI,IAAiB5b,EAAA,iBAEjCsnB,EAAA,CACK,QAEZ,CAAC,CAEqB,EACtB,SAAwB,CAAAjU,EAAA,aAAkBkU,EAAC,mBAAoB,IAAC,YAAAH,EACxD,CAAEpd,WAAMC,CAAiB,EACxBO,SAAmB,GACV6c,mBACVrZ,kBACAuZ,eAAkB,MAClBS,mBACArC,WAEN,QAAmBgC,CAAA,CAAEjnB,aAAU,aAC7B2J,MAAyB,iBAAE3J,OAAQ,WACzBsM,YACVvC,IAAW2c,EAEJ,CACC,WACI,CACX,CACD,CAAa,EACP,EACF,GAAAjU,EAAM5V,OAAQ,KACHwG,EACTkT,MAAGsQ,IAAanlB,gCACR,CAAAoI,IAAA,WAAA6I,EAAA,aACD8T,oBACC9T,EAAA,KACR3S,sBACAga,WAAqBlG,EAAA,CACvB,WACA,EAEE,EACkB,GAElBwF,IAAYkB,WAAQ,GAAAjf,EAAAiZ,GAAA,YAAAA,EAAA,aAAAjZ,EAAA,SAAAoX,EAAA,OACRrG,iBACdqa,WAAmBjP,GAAA,CACnB3N,SAAoB,EAEpBA,wBAAW,OAAXA,cAAkB,UAAA0I,EAAAgF,GAAA,CAClB9N,YAAe,MACjB,SAAA6K,EAAA,SAAA3L,GAAA,CACC,MACL,GAAAF,EAEgB,OAAA4e,UAEX,SAAAxO,CAECkO,IACM,CAAU,mBAAAO,EAAG,yBAAAC,EAClB,aAAAC,aAGG,EAAAH,EAAyBI,EAAAH,GAAA,MAAAA,EAAA,IAAAA,EAAAC,GAAA,MAAAA,EAAA,IAAAA,EAAAC,MAC7B,CACa,IAAAlW,GAAe,KAAAoW,GAAuB5e,QAAQ+J,QAC9C,EAAA4U,EAAOjB,mBAAE/M,EAAA,KAAO,MAAAkO,EAAA,UAAArW,EAAA,EAACsW,GAAAD,EAAA,OAAAA,EAAA,SAAG,IAAAE,EAGnCpV,GAAAiV,GAAA,CAAA7U,SACE,UAAA6U,EAAA,EACOta,uBACL6G,CACI6T,OAAerV,EAAA,MACP,SAAAA,EAAA,UAAU,cAAG,aACzB,MAEAA,OACOkU,KACA,EAAAoB,EACAC,EAAAC,IAAAC,EACM1B,qCAAE1d,IAAA6P,EAAA,CAAa,IAAAwP,EAAC,KAAAF,GAAA,wBACnB,SAAApP,GAAArD,CAAA,CACK,CACD,EACG,SAAAjD,EAAA,UACJ,OACP,iBAAAlN,EAAA,IAGN,EACO,UAAAkN,EAAA,WACC,UAAAsV,GAAApV,EAAA,UACD1P,SACC,kBACC,EAAA0P,EAAA,OACJ+T,eAAE,OAAA/M,EAAA,eAAkB,iBAAC,IAAAZ,EACxB,6BACE,OAAAzZ,IAAA,CAERA,GAAA,0CAAW2lB,EAAkC,EAAwB,CACtD,EAAAtS,EAAA,cACA,SAAAoG,GAAArD,CAAA,GACT,CAAS,EAAe3C,CACtB,EAAApK,CAAA,EAAiC,EAChC,EAAA8J,EAAA,KAGN3I,MAAY,aACA,YAAAub,EAAA7Q,EAAA,yBAAA6Q,EAAA,WAAA5S,EAAA,UAAUM,KACnBJ,SAAc,oBAAE,SAAA7I,IAAA,UAGnB0K,YAAwB,OACvBzB,EACE,CACGyB,aAAajO,aAAbiO,cAA0B,QAAAiS,EACnB,EAAE9d,EAAI4e,eAAQ7R,oBAAOqD,YAAalQ,cAClC,YACJ2e,EACAC,GACAC,6JACAO,cACF,MAAIV,cACJ,aAAqC/V,UAKjC,mBAAEA,GAAKoW,mDAAMriB,CAAOoU,EAAO,SAAIgO,WAC/B,WAAe7T,EAAA,CACjBvO,WACS,GACX,MAAAoN,EAAAW,EAAA,CACMuU,oBACAC,GACFC,GACJ,GACQO,kBAAcC,EAAU,OACfD,iBACjB,SAAA3V,EAAA,KACA,qBACE,CAAAI,CACE,GAAAjJ,IACO,SAAA6I,EAAA,wBAEG,SAAAA,EAAA,KAAEwV,yBAAK3W,EACb,EACMqW,GACAC,GACE,EACC","names":["Combobox","input","list","tabInsertsSuggestions","defaultFirstOption","event","keyboardBindings","trackComposition","commitWithElement","_a","visible","indexDiff","focusEl","els","focusIndex","indexOfItem","newIndex","target","el","scrollTo","combobox","commit","fireCommitEvent","container","inViewport","element","scrollTop","containerBottom","top","bottom","boundary","query","text","key","cursor","multiWord","lookBackIndex","lastMatchPosition","keyIndex","pre","CustomHTMLElement","InputStyleCloneUpdateEvent","CloneRegistry","_InputStyleCloneElement","__privateAdd","_InputStyleCloneElement_instances","_styleObserver","__privateMethod","updateStyles_fn","_resizeObserver","requestUpdateLayout_fn","_inputRef","_container","_xOffset","_yOffset","_isLayoutUpdating","_onInput","updateText_fn","_onDocumentScrollOrResize","usingInput_fn","clone","__privateSet","__privateGet","input_get","fn","updateLayout_fn","inputStyle","inputRect","cloneRect","prop","propertiesToCopy","InputStyleCloneElement","e","_InputRange","startOffset","endOffset","_InputRange_instances","_inputElement","_startOffset","_endOffset","selectionStart","selectionEnd","offset","clampOffset_fn","toStart","createCloneRange_fn","styleClone_get","cloneElement_get","range","textNode","InputRange","states","TextExpander","expander","match","menu","_b","position","caretRect","targetPosition","currentPosition","delta","currentStyle","item","beginning","remaining","detail","suffix","value","found","providers","provide","result","x","TextExpanderElement","keysAttr","keys","multiWordAttr","globalMultiWord","state","ansiRegex","onlyFirst","pattern","regex","stripAnsi","string","segmenter","stringLength","countAnsiEscapeCodes","length","_","poweredByGiphyURL","PHANPY_IMG_ALT_API_URL","IMG_ALT_API_URL","PHANPY_GIPHY_API_KEY","GIPHY_API_KEY","import","supportedLanguagesMap","supportedLanguages","reduce","acc","l","code","common","native","expiryOptions","i18nDuration","expirySeconds","Object","oneDay","expiresInFromExpiresAt","expiresAt","Date","getTime","now","find","s","document","createElement","role","className","windowMargin","observer","IntersectionObserver","entries","forEach","entry","isIntersecting","left","width","boundingClientRect","innerWidth","window","insetInlineStart","isRTL","style","observe","DEFAULT_LANG","localeMatch","Intl","DateTimeFormat","resolvedOptions","locale","navigator","languages","map","urlRegexObj","RegExp","urlRegex","source","flags","usernameRegex","urlPlaceholder","countableText","inputText","replace","USERNAME_RE","MENTION_RE","HASHTAG_RE","SHORTCODE_RE_FRAGMENT","SCAN_RE","Segmenter","escapeHTML","highlightText","maxCharacters","Infinity","composerCharacterCount","withinLimitHTML","exceedLimitHTML","htmlSegments","segment","index","RTF","mem","RelativeTimeFormat","undefined","LF","ListFormat","CUSTOM_EMOJIS_COUNT","ADD_LABELS","media","id","customEmoji","gif","poll","Compose","onClose","replyToStatus","editStatus","draftStatus","standalone","hasOpener","i18n","t","_useLingui","rtf","lf","console","masto","instance","uiState","setUIState","useState","UID","uid","log","currentAccount","currentAccountInfo","maxMediaAttachments","charactersReservedPerUrl","imageMatrixLimit","supportedMimeTypes","imageSizeLimit","videoSizeLimit","videoMatrixLimit","videoFrameRateLimit","maxExpiration","maxOptions","maxCharactersPerOption","minExpiration","spoilerTextRef","useRef","textareaRef","store","prevLanguage","language","sensitive","setMediaAttachments","setLanguage","oninputTextarea","account","focusTextarea","dispatchEvent","setTimeout","spoilerText","useEffect","visibility2","language2","sensitive2","visibility","current","m","allMentions","prefs","setSensitive","poll2","mediaAttachments","options","expiresIn","statusSource","dataset","mediaAttachments2","setVisibility","composablePoll","status","o","formRef","canClose","_t","hasValue","hasMediaAttachments","isSelf","hasOnlyAcct","confirmClose","hasIDMediaAttachments","beforeUnloadCopy","handleBeforeUnload","sameWithSource","getCharCount","updateCharCount","supportsCloseWatcher","useHotkeys","yes","addEventListener","capture","modals","hasModal","hasOnlyComposer","prevBackgroundDraft","count","escDownRef","ignoreEventWhen","useCloseWatcher","draftKey","getCurrentAccountNS","backgroundDraft","useInterval","db","handleItems","username","acct","i2","items","unsupportedFiles","_i18n","drafts","set","updatedAt","f","debug","error","files","clipboardData","max","file","alert","mediaFiles","allowedFiles","1","2","handleDragover","setShowMentionPicker","showEmoji2Picker","showGIFPicker","useMemo","contentTranslationHideLanguages","autoDetectedLanguages","topLanguages","restLanguages","commonB","type","size","url","codeA","commonA","codeB","onMinimize","saveUnsavedDraft","gifPickerDisabled","onPollButtonClick","setPoll","removeEventListener","addSubToolbarRef","setShowAddButton","useResizeObserver","showMentionPicker","scrollWidth","settings","push","_jsxs","sort","_jsx","AccountBlock","showPollButton","pollButtonDisabled","children","class","confirmText","passData","__STATES__","opener","composerState","Icon","openCompose","showAddButton","avatarStatic","disabled","onClick","Status","replyToStatusMonthsAgo","_Trans","formData","components","0","onKeyDown","onSubmit","description","params2","res","attachment","results","mediaPromises","hasNoDescriptions","params","removeNullUndefined","newStatus","saveStatus","i","e2","media_attributes","in_reply_to_id","statuses","visibilityIconsMap","opacity","pointerEvents","checked","onChange","icon","title","limit","action","setShowEmoji2Picker","setAutoDetectedLanguages","Textarea","ref","fileID","newAttachments","attachments","_2","j","performSearch","q","v1","resolve","v2","fetch","onTrigger","defaultSearchTerm","Poll","newPoll","onDescriptionChange","Menu2","open","MenuItem","FilePickerInput","onInput","setShowGIFPicker","body","zIndex","_Fragment","Loader","CharCountMeter","alt","localeCode2Text","commonText","composerGIFPicker","restSupportedLanguages","textarea","textBeforeMention","spaceAfterMention","textAfterMention","newText","Modal","CustomEmojisModal","textBeforeEmoji","textAfterEmoji","spaceBeforeEmoji","emojiShortcode","spaceAfterEmoji","onSelect","GIFPickerModal","alt_text","slice","theToast","showToast","blob","newMediaAttachments","hidden","then","autoResizeTextarea","offsetHeight","scrollHeight","clientHeight","height","visibleEmojis","__vitePreload","langs","detectAll","lang","_t2","api","setText","textareaProps","props","searcherRef","getCustomEmojis","r","hasTextExpanderRef","textExpanderRef","handleChange","_getCustomEmojis","searcher","textExpanderTextRef","text2","cacheKeyArg","detectLangs","shortcode","emoji","html","encodeHTML","emojis","history","displayNameWithEmoji","emojifyText","displayName","search","total","cur","name","shortenNumber","Promise","matched","v","more","handleValue","handleCommited","handleActivate","handleDeactivate","slowHighlightPerf","composeHighlightRef","useThrottledCallback","throttleHighlightText","start","end","useDebouncedCallback","dom","Event","resizeObserver","hasTextExpander","lastLine","bullet","postSpaces","anything","number","preSpaces","pos","debouncedAutoDetectLanguage","cloneNode","mark","spellCheck","rows","cols","charCount","leftChars","setRangeText","setSelectionRange","scaleDimension","matrix","matrixLimit","scalingFactor","newHeight","newWidth","MediaAttachment","supportsEdit","supports","onScroll","checkMaxError","configuration","getCurrentInstanceConfiguration","maxError","setMaxError","snapStates","imageMatrix","setImageMatrix","Math","videoMatrix","setVideoMatrix","debouncedOnDescriptionChange","timer","details","_t3","toastRef","setDescription","showModal","imageSizeLimit2","descTextarea","prettyBytes","videoSize","videoSizeLimit2","videoMatrixLimit2","videoMatrix2","maxErrorToast","maxErrorText","err","imageSize","suffixType","naturalWidth","naturalHeight","3","4","5","videoWidth","videoHeight","6","7","values","9","10","11","setShowModal","src","onLoad","onLoadedMetadata","onRemove","subtype","response","menuButton","append","_t4","multiple","option","required","label","splice","str","char","obj","MentionModal","accounts","setAccounts","setRelationshipsMap","selectedIndex","setSelectedIndex","loadRelationships","accounts2","term","debouncedLoadAccounts","loadAccounts","inputRef","filterShortcodes","searchTerm","aLower","a","bLower","b","aContains","bContains","bothStartWith","selectAccount","selectedAccount","listRef","selectedItem","relationshipsMap","relationships","socialAddress","_t5","enableOnFormTags","relationship","_t6","customEmojisList","customEmojis","setCustomEmojis","recentlyUsedCustomEmojis","emojisCat","othersCat","scrollableRef","matches","setMatches","onFind","_c","onSelectEmoji","useCallback","recentlyUsedCustomEmojis2","recentlyUsedEmojiIndex","emoji2","customEmojisCatList","category","queueMicrotask","CustomEmojisList","memo","setMax","CustomEmojiButton","showMore","showCode","parent","selfRect","rect","targetClassList","addEdges","GIFS_PER_PAGE","_t7","setResults","fetchGIFs","qRef","closest","currentTarget","remove","debouncedOnInput","onPointerEnter","onFocus","staticUrl","loading","currentOffset","images","fixed_height_small","fixed_height_downsampled","fixed_height","theImage","webp","urlObj","strippedURL","strippedWebP","preventDefault","original","theURL","mp4","url2","strippedURL2","webpObj","parse"],"ignoreList":[0,1,2,3,4],"sources":["../../node_modules/@github/combobox-nav/dist/index.js","../../node_modules/@github/text-expander-element/dist/index.js","../../node_modules/ansi-regex/index.js","../../node_modules/strip-ansi/index.js","../../node_modules/string-length/index.js","../../src/assets/powered-by-giphy.svg","../../src/components/compose.jsx"],"sourcesContent":["export default class Combobox {\n    constructor(input, list, { tabInsertsSuggestions, defaultFirstOption } = {}) {\n        this.input = input;\n        this.list = list;\n        this.tabInsertsSuggestions = tabInsertsSuggestions !== null && tabInsertsSuggestions !== void 0 ? tabInsertsSuggestions : true;\n        this.defaultFirstOption = defaultFirstOption !== null && defaultFirstOption !== void 0 ? defaultFirstOption : false;\n        this.isComposing = false;\n        if (!list.id) {\n            list.id = `combobox-${Math.random().toString().slice(2, 6)}`;\n        }\n        this.ctrlBindings = !!navigator.userAgent.match(/Macintosh/);\n        this.keyboardEventHandler = event => keyboardBindings(event, this);\n        this.compositionEventHandler = event => trackComposition(event, this);\n        this.inputHandler = this.clearSelection.bind(this);\n        input.setAttribute('role', 'combobox');\n        input.setAttribute('aria-controls', list.id);\n        input.setAttribute('aria-expanded', 'false');\n        input.setAttribute('aria-autocomplete', 'list');\n        input.setAttribute('aria-haspopup', 'listbox');\n    }\n    destroy() {\n        this.clearSelection();\n        this.stop();\n        this.input.removeAttribute('role');\n        this.input.removeAttribute('aria-controls');\n        this.input.removeAttribute('aria-expanded');\n        this.input.removeAttribute('aria-autocomplete');\n        this.input.removeAttribute('aria-haspopup');\n    }\n    start() {\n        this.input.setAttribute('aria-expanded', 'true');\n        this.input.addEventListener('compositionstart', this.compositionEventHandler);\n        this.input.addEventListener('compositionend', this.compositionEventHandler);\n        this.input.addEventListener('input', this.inputHandler);\n        this.input.addEventListener('keydown', this.keyboardEventHandler);\n        this.list.addEventListener('click', commitWithElement);\n        this.indicateDefaultOption();\n    }\n    stop() {\n        this.clearSelection();\n        this.input.setAttribute('aria-expanded', 'false');\n        this.input.removeEventListener('compositionstart', this.compositionEventHandler);\n        this.input.removeEventListener('compositionend', this.compositionEventHandler);\n        this.input.removeEventListener('input', this.inputHandler);\n        this.input.removeEventListener('keydown', this.keyboardEventHandler);\n        this.list.removeEventListener('click', commitWithElement);\n    }\n    indicateDefaultOption() {\n        var _a;\n        if (this.defaultFirstOption) {\n            (_a = Array.from(this.list.querySelectorAll('[role=\"option\"]:not([aria-disabled=\"true\"])'))\n                .filter(visible)[0]) === null || _a === void 0 ? void 0 : _a.setAttribute('data-combobox-option-default', 'true');\n        }\n    }\n    navigate(indexDiff = 1) {\n        const focusEl = Array.from(this.list.querySelectorAll('[aria-selected=\"true\"]')).filter(visible)[0];\n        const els = Array.from(this.list.querySelectorAll('[role=\"option\"]')).filter(visible);\n        const focusIndex = els.indexOf(focusEl);\n        if ((focusIndex === els.length - 1 && indexDiff === 1) || (focusIndex === 0 && indexDiff === -1)) {\n            this.clearSelection();\n            this.input.focus();\n            return;\n        }\n        let indexOfItem = indexDiff === 1 ? 0 : els.length - 1;\n        if (focusEl && focusIndex >= 0) {\n            const newIndex = focusIndex + indexDiff;\n            if (newIndex >= 0 && newIndex < els.length)\n                indexOfItem = newIndex;\n        }\n        const target = els[indexOfItem];\n        if (!target)\n            return;\n        for (const el of els) {\n            el.removeAttribute('data-combobox-option-default');\n            if (target === el) {\n                this.input.setAttribute('aria-activedescendant', target.id);\n                target.setAttribute('aria-selected', 'true');\n                scrollTo(this.list, target);\n            }\n            else {\n                el.removeAttribute('aria-selected');\n            }\n        }\n    }\n    clearSelection() {\n        this.input.removeAttribute('aria-activedescendant');\n        for (const el of this.list.querySelectorAll('[aria-selected=\"true\"]')) {\n            el.removeAttribute('aria-selected');\n        }\n        this.indicateDefaultOption();\n    }\n}\nfunction keyboardBindings(event, combobox) {\n    if (event.shiftKey || event.metaKey || event.altKey)\n        return;\n    if (!combobox.ctrlBindings && event.ctrlKey)\n        return;\n    if (combobox.isComposing)\n        return;\n    switch (event.key) {\n        case 'Enter':\n            if (commit(combobox.input, combobox.list)) {\n                event.preventDefault();\n            }\n            break;\n        case 'Tab':\n            if (combobox.tabInsertsSuggestions && commit(combobox.input, combobox.list)) {\n                event.preventDefault();\n            }\n            break;\n        case 'Escape':\n            combobox.clearSelection();\n            break;\n        case 'ArrowDown':\n            combobox.navigate(1);\n            event.preventDefault();\n            break;\n        case 'ArrowUp':\n            combobox.navigate(-1);\n            event.preventDefault();\n            break;\n        case 'n':\n            if (combobox.ctrlBindings && event.ctrlKey) {\n                combobox.navigate(1);\n                event.preventDefault();\n            }\n            break;\n        case 'p':\n            if (combobox.ctrlBindings && event.ctrlKey) {\n                combobox.navigate(-1);\n                event.preventDefault();\n            }\n            break;\n        default:\n            if (event.ctrlKey)\n                break;\n            combobox.clearSelection();\n    }\n}\nfunction commitWithElement(event) {\n    if (!(event.target instanceof Element))\n        return;\n    const target = event.target.closest('[role=\"option\"]');\n    if (!target)\n        return;\n    if (target.getAttribute('aria-disabled') === 'true')\n        return;\n    fireCommitEvent(target);\n}\nfunction commit(input, list) {\n    const target = list.querySelector('[aria-selected=\"true\"], [data-combobox-option-default=\"true\"]');\n    if (!target)\n        return false;\n    if (target.getAttribute('aria-disabled') === 'true')\n        return true;\n    target.click();\n    return true;\n}\nfunction fireCommitEvent(target) {\n    target.dispatchEvent(new CustomEvent('combobox-commit', { bubbles: true }));\n}\nfunction visible(el) {\n    return (!el.hidden &&\n        !(el instanceof HTMLInputElement && el.type === 'hidden') &&\n        (el.offsetWidth > 0 || el.offsetHeight > 0));\n}\nfunction trackComposition(event, combobox) {\n    combobox.isComposing = event.type === 'compositionstart';\n    const list = document.getElementById(combobox.input.getAttribute('aria-controls') || '');\n    if (!list)\n        return;\n    combobox.clearSelection();\n}\nfunction scrollTo(container, target) {\n    if (!inViewport(container, target)) {\n        container.scrollTop = target.offsetTop;\n    }\n}\nfunction inViewport(container, element) {\n    const scrollTop = container.scrollTop;\n    const containerBottom = scrollTop + container.clientHeight;\n    const top = element.offsetTop;\n    const bottom = top + element.clientHeight;\n    return top >= scrollTop && bottom <= containerBottom;\n}\n","import Combobox from '@github/combobox-nav';\n\nconst boundary = /\\s|\\(|\\[/;\nfunction query(text, key, cursor, { multiWord, lookBackIndex, lastMatchPosition } = {\n    multiWord: false,\n    lookBackIndex: 0,\n    lastMatchPosition: null\n}) {\n    let keyIndex = text.lastIndexOf(key, cursor - 1);\n    if (keyIndex === -1)\n        return;\n    if (keyIndex < lookBackIndex)\n        return;\n    if (multiWord) {\n        if (lastMatchPosition != null) {\n            if (lastMatchPosition === keyIndex)\n                return;\n            keyIndex = lastMatchPosition - key.length;\n        }\n        const charAfterKey = text[keyIndex + 1];\n        if (charAfterKey === ' ' && cursor >= keyIndex + key.length + 1)\n            return;\n        const newLineIndex = text.lastIndexOf('\\n', cursor - 1);\n        if (newLineIndex > keyIndex)\n            return;\n        const dotIndex = text.lastIndexOf('.', cursor - 1);\n        if (dotIndex > keyIndex)\n            return;\n    }\n    else {\n        const spaceIndex = text.lastIndexOf(' ', cursor - 1);\n        if (spaceIndex > keyIndex)\n            return;\n    }\n    const pre = text[keyIndex - 1];\n    if (pre && !boundary.test(pre))\n        return;\n    const queryString = text.substring(keyIndex + key.length, cursor);\n    return {\n        text: queryString,\n        position: keyIndex + key.length\n    };\n}\n\n/**\n * A custom element is implemented as a class which extends HTMLElement (in the\n * case of autonomous elements) or the interface you want to customize (in the\n * case of customized built-in elements).\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks\n */\nclass CustomHTMLElement extends HTMLElement {\n}\n\nclass InputStyleCloneUpdateEvent extends Event {\n    constructor() {\n        super(\"update\");\n    }\n}\nconst CloneRegistry = new WeakMap();\n/**\n * Create an element that exactly matches an input pixel-for-pixel and automatically stays in sync with it. This\n * is a non-interactive overlay on to the input and can be used to affect the visual appearance of the input\n * without modifying its behavior. The clone element is hidden by default.\n *\n * This lower level API powers the `InputRange` but provides more advanced functionality including event updates.\n *\n * Emits `update` events whenever anything is recalculated: when the layout changes, when the user scrolls, when the\n * input is updated, etc. This event may be emitted more than once per change.\n *\n * @note There may be cases in which the clone cannot observe changes to the input and fails to automatically update.\n * For example, if the `value` property on the input is written to directly, no `input` event is emitted by the input\n * and the clone does not automatically update. In these cases, `forceUpdate` can be used to manually trigger an update.\n */\n// PRIOR ART: This approach was adapted from the following MIT-licensed sources:\n//  - primer/react (Copyright (c) 2018 GitHub, Inc.): https://github.com/primer/react/blob/a0db832302702b869aa22b0c4049ad9305ef631f/src/drafts/utils/character-coordinates.ts\n//  - component/textarea-caret-position (Copyright (c) 2015 Jonathan Ong me@jongleberry.com): https://github.com/component/textarea-caret-position/blob/b5db7a7e47dd149c2a66276183c69234e4dabe30/index.js\n//  - koddsson/textarea-caret-position (Copyright (c) 2015 Jonathan Ong me@jongleberry.com): https://github.com/koddsson/textarea-caret-position/blob/eba40ec8488eed4d77815f109af22e1d9c0751d3/index.js\nclass InputStyleCloneElement extends CustomHTMLElement {\n    #styleObserver = new MutationObserver(() => this.#updateStyles());\n    #resizeObserver = new ResizeObserver(() => this.#requestUpdateLayout());\n    // This class is unique in that it will prevent itself from getting garbage collected because of the subscribed\n    // observers (if never detached). Because of this, we want to avoid preventing the existence of this class from also\n    // preventing the garbage collection of the associated input. This also allows us to automatically detach if the\n    // input gets collected.\n    #inputRef;\n    #container;\n    /**\n     * Get the clone for an input, reusing an existing one if available. This avoids creating unecessary clones, which\n     * have a performance cost due to their high-frequency event-based updates. Because these elements are shared, they\n     * should be mutated with caution.\n     *\n     * Upon initial creation the clone element will automatically be inserted into the DOM and begin observing the\n     * linked input. Only one clone per input can ever exist at a time.\n     * @param input The target input to clone.\n     */\n    static for(input) {\n        let clone = CloneRegistry.get(input);\n        if (!clone) {\n            clone = new InputStyleCloneElement();\n            clone.connect(input);\n            CloneRegistry.set(input, clone);\n        }\n        return clone;\n    }\n    /**\n     * Connect this instance to a target input element and insert this instance into the DOM in the correct location.\n     *\n     * NOTE: calling the static `for` method is nearly always preferable as it will reuse an existing clone if available.\n     * However, if reusing clones is problematic (ie, if the clone needs to be mutated), a clone can be constructed\n     * directly with `new InputStyleCloneElement()` and then bound to an input and inserted into the DOM with\n     * `clone.connect(target)`.\n     */\n    connect(input) {\n        this.#inputRef = new WeakRef(input);\n        // We want position:absolute so it doesn't take space in the layout, but that doesn't work with display:table-cell\n        // used in the HTMLInputElement approach. So we need a wrapper.\n        this.#container = document.createElement(\"div\");\n        this.#container.style.position = \"absolute\";\n        this.#container.style.pointerEvents = \"none\";\n        input.after(this.#container);\n        this.#container.appendChild(this);\n    }\n    /**\n     * Force a recalculation. Will emit an `update` event. This is typically not needed unless the input has changed in\n     * an unobservable way, eg by directly writing to the `value` property.\n     */\n    forceUpdate() {\n        this.#updateStyles();\n        this.#updateText();\n    }\n    /** @private */\n    connectedCallback() {\n        this.#usingInput((input) => {\n            this.style.pointerEvents = \"none\";\n            this.style.userSelect = \"none\";\n            this.style.overflow = \"hidden\";\n            this.style.display = \"block\";\n            // Important not to use display:none which would not render the content at all\n            this.style.visibility = \"hidden\";\n            if (input instanceof HTMLTextAreaElement) {\n                this.style.whiteSpace = \"pre-wrap\";\n                this.style.wordWrap = \"break-word\";\n            }\n            else {\n                this.style.whiteSpace = \"nowrap\";\n                // text in single-line inputs is vertically centered\n                this.style.display = \"table-cell\";\n                this.style.verticalAlign = \"middle\";\n            }\n            this.setAttribute(\"aria-hidden\", \"true\");\n            this.#updateStyles();\n            this.#updateText();\n            this.#styleObserver.observe(input, {\n                attributeFilter: [\n                    \"style\",\n                    \"dir\", // users can right-click in some browsers to change the text direction dynamically\n                ],\n            });\n            this.#resizeObserver.observe(input);\n            document.addEventListener(\"scroll\", this.#onDocumentScrollOrResize, { capture: true });\n            window.addEventListener(\"resize\", this.#onDocumentScrollOrResize, { capture: true });\n            // capture so this happens first, so other things can respond to `input` events after this data updates\n            input.addEventListener(\"input\", this.#onInput, { capture: true });\n        });\n    }\n    /** @private */\n    disconnectedCallback() {\n        this.#container?.remove();\n        this.#styleObserver.disconnect();\n        this.#resizeObserver.disconnect();\n        document.removeEventListener(\"scroll\", this.#onDocumentScrollOrResize, { capture: true });\n        window.removeEventListener(\"resize\", this.#onDocumentScrollOrResize, { capture: true });\n        // Can't use `usingInput` here since that could infinitely recurse\n        const input = this.#input;\n        if (input) {\n            input.removeEventListener(\"input\", this.#onInput, { capture: true });\n            CloneRegistry.delete(input);\n        }\n    }\n    // --- private ---\n    get #input() {\n        return this.#inputRef?.deref();\n    }\n    /** Perform `fn` using the `input` if it is still available. If not, clean up the clone instead. */\n    #usingInput(fn) {\n        const input = this.#input;\n        if (!input)\n            return this.remove();\n        return fn(input);\n    }\n    /** Current relative x-adjustment in pixels, executed via CSS transform. */\n    #xOffset = 0;\n    /** Current relative y-adjustment in pixels, executed via CSS transform. */\n    #yOffset = 0;\n    /**\n     * Update only geometric properties without recalculating styles. Typically call `#requestUpdateLayout` instead to\n     * only update once per animation frame.\n     */\n    #updateLayout() {\n        // This runs often, so keep it as fast as possible! Avoid all unecessary updates.\n        this.#usingInput((input) => {\n            const inputStyle = window.getComputedStyle(input);\n            this.style.height = inputStyle.height;\n            this.style.width = inputStyle.width;\n            // Immediately re-adjust for browser inconsistencies in scrollbar handling, if necessary\n            if (input.clientHeight !== this.clientHeight)\n                this.style.height = `calc(${inputStyle.height} + ${input.clientHeight - this.clientHeight}px)`;\n            if (input.clientWidth !== this.clientWidth)\n                this.style.width = `calc(${inputStyle.width} + ${input.clientWidth - this.clientWidth}px)`;\n            // Position on top of the input\n            const inputRect = input.getBoundingClientRect();\n            const cloneRect = this.getBoundingClientRect();\n            this.#xOffset = this.#xOffset + inputRect.left - cloneRect.left;\n            this.#yOffset = this.#yOffset + inputRect.top - cloneRect.top;\n            this.style.transform = `translate(${this.#xOffset}px, ${this.#yOffset}px)`;\n            this.scrollTop = input.scrollTop;\n            this.scrollLeft = input.scrollLeft;\n            this.dispatchEvent(new InputStyleCloneUpdateEvent());\n        });\n    }\n    #isLayoutUpdating = false;\n    /** Request a layout update. Will only happen once per animation frame, to avoid unecessary updates. */\n    #requestUpdateLayout() {\n        if (this.#isLayoutUpdating)\n            return;\n        this.#isLayoutUpdating = true;\n        requestAnimationFrame(() => {\n            this.#updateLayout();\n            this.#isLayoutUpdating = false;\n        });\n    }\n    /** Update the styles of the clone based on the styles of the input, then request a layout update. */\n    #updateStyles() {\n        this.#usingInput((input) => {\n            const inputStyle = window.getComputedStyle(input);\n            for (const prop of propertiesToCopy)\n                this.style[prop] = inputStyle[prop];\n            this.#requestUpdateLayout();\n        });\n    }\n    /**\n     * Update the text content of the clone based on the text content of the input. Triggers a layout update in case the\n     * text update caused scrolling.\n     */\n    #updateText() {\n        this.#usingInput((input) => {\n            this.textContent = input.value;\n            // This is often unecessary on a pure text update, but text updates could potentially cause layout updates like\n            // scrolling or resizing. And we run the update on _every frame_ when scrolling, so this isn't that expensive.\n            // We don't requestUpdateLayout here because this one should happen synchronously, so that clients can react\n            // within their own `input` event handlers.\n            this.#updateLayout();\n        });\n    }\n    #onInput = () => this.#updateText();\n    #onDocumentScrollOrResize = (event) => {\n        this.#usingInput((input) => {\n            if (event.target === document ||\n                event.target === window ||\n                (event.target instanceof Node && event.target.contains(input)))\n                this.#requestUpdateLayout();\n        });\n    };\n}\n// Note that some browsers, such as Firefox, do not concatenate properties\n// into their shorthand (e.g. padding-top, padding-bottom etc. -> padding),\n// so we have to list every single property explicitly.\nconst propertiesToCopy = [\n    // RTL / vertical writing modes support:\n    \"direction\",\n    \"writingMode\",\n    \"unicodeBidi\",\n    \"textOrientation\",\n    \"boxSizing\",\n    \"borderTopWidth\",\n    \"borderRightWidth\",\n    \"borderBottomWidth\",\n    \"borderLeftWidth\",\n    \"borderStyle\",\n    \"paddingTop\",\n    \"paddingRight\",\n    \"paddingBottom\",\n    \"paddingLeft\",\n    // https://developer.mozilla.org/en-US/docs/Web/CSS/font\n    \"fontStyle\",\n    \"fontVariant\",\n    \"fontWeight\",\n    \"fontStretch\",\n    \"fontSize\",\n    \"fontSizeAdjust\",\n    \"lineHeight\",\n    \"fontFamily\",\n    \"textAlign\",\n    \"textTransform\",\n    \"textIndent\",\n    \"textDecoration\",\n    \"letterSpacing\",\n    \"wordSpacing\",\n    \"tabSize\",\n    \"MozTabSize\",\n];\n// Inspired by https://github.com/github/catalyst/blob/dc284dcf4f82329a9cac5c867462a8fa529b6c40/src/register.ts\ntry {\n    customElements.define(\"input-style-clone\", InputStyleCloneElement);\n}\ncatch (e) {\n    // Throws DOMException with NotSupportedError if already defined\n    if (!(e instanceof DOMException && e.name === \"NotSupportedError\"))\n        throw e;\n}\n\nclass InputRange {\n    #inputElement;\n    #startOffset;\n    #endOffset;\n    /**\n     * Construct a new `InputRange`.\n     * @param element The target input element that contains the content for the range.\n     * @param startOffset The inclusive 0-based start index for the range. Will be adjusted to fit in the input contents.\n     * @param endOffset The exclusive 0-based end index for the range. Will be adjusted to fit in the input contents.\n     */\n    constructor(element, startOffset = 0, endOffset = startOffset) {\n        this.#inputElement = element;\n        this.#startOffset = startOffset;\n        this.#endOffset = endOffset;\n    }\n    /**\n     * Create a new range from the current user selection. If the input is not focused, the range will just be the start\n     * of the input (offsets `0` to `0`).\n     *\n     * This can be used to get the caret coordinates: if the resulting range is `collapsed`, the location of the\n     * `getBoundingClientRect` will be the location of the caret caret (note, however, that the width will be `0` in\n     * this case).\n     */\n    static fromSelection(input) {\n        const { selectionStart, selectionEnd } = input;\n        return new InputRange(input, selectionStart ?? undefined, selectionEnd ?? undefined);\n    }\n    /** Returns true if the start is equal to the end of this range. */\n    get collapsed() {\n        return this.startOffset === this.endOffset;\n    }\n    /** Always returns the containing input element. */\n    get commonAncestorContainer() {\n        return this.#inputElement;\n    }\n    /** Always returns the containing input element. */\n    get endContainer() {\n        return this.#inputElement;\n    }\n    /** Always returns the containing input element. */\n    get startContainer() {\n        return this.#inputElement;\n    }\n    get startOffset() {\n        return this.#startOffset;\n    }\n    get endOffset() {\n        return this.#endOffset;\n    }\n    /** Update the inclusive start offset. Will be adjusted to fit within the content size. */\n    setStartOffset(offset) {\n        this.#startOffset = this.#clampOffset(offset);\n    }\n    /** Update the exclusive end offset. Will be adjusted to fit within the content size. */\n    setEndOffset(offset) {\n        this.#endOffset = this.#clampOffset(offset);\n    }\n    /**\n     * Collapse this range to one side.\n     * @param toStart If `true`, will collapse to the start side. Otherwise, will collapse to the end.\n     */\n    collapse(toStart = false) {\n        if (toStart)\n            this.setEndOffset(this.startOffset);\n        else\n            this.setStartOffset(this.endOffset);\n    }\n    /** Returns a `DocumentFragment` containing a new `Text` node containing the content in the range. */\n    cloneContents() {\n        return this.#createCloneRange().cloneContents();\n    }\n    /** Create a copy of this range. */\n    cloneRange() {\n        return new InputRange(this.#inputElement, this.startOffset, this.endOffset);\n    }\n    /**\n     * Obtain one rect that contains the entire contents of the range. If the range spans multiple lines, this box will\n     * contain all pieces of the range but may also contain some space outside the range.\n     * @see https://iansan5653.github.io/dom-input-range/demos/playground/\n     */\n    getBoundingClientRect() {\n        return this.#createCloneRange().getBoundingClientRect();\n    }\n    /**\n     * Obtain the rects that contain contents of this range. If the range spans multiple lines, there will be multiple\n     * bounding boxes. These boxes can be used, for example, to draw a highlight over the range.\n     * @see https://iansan5653.github.io/dom-input-range/demos/playground/\n     */\n    getClientRects() {\n        return this.#createCloneRange().getClientRects();\n    }\n    /** Get the contents of the range as a string. */\n    toString() {\n        return this.#createCloneRange().toString();\n    }\n    /**\n     * Get the underlying `InputStyleClone` instance powering these calculations. This can be used to listen for\n     * updates to trigger layout recalculation.\n     */\n    getStyleClone() {\n        return this.#styleClone;\n    }\n    // --- private ---\n    get #styleClone() {\n        return InputStyleCloneElement.for(this.#inputElement);\n    }\n    get #cloneElement() {\n        return this.#styleClone;\n    }\n    #clampOffset(offset) {\n        return Math.max(0, Math.min(offset, this.#inputElement.value.length));\n    }\n    #createCloneRange() {\n        // It's tempting to create a single Range and reuse it across the lifetime of the class. However, this wouldn't be\n        // accurate because the contents of the input can change and the contents of the range would become stale. So we\n        // must create a new range every time we need it.\n        const range = document.createRange();\n        const textNode = this.#cloneElement.childNodes[0];\n        if (textNode) {\n            range.setStart(textNode, this.startOffset);\n            range.setEnd(textNode, this.endOffset);\n        }\n        return range;\n    }\n}\n\nconst states = new WeakMap();\nclass TextExpander {\n    constructor(expander, input) {\n        this.expander = expander;\n        this.input = input;\n        this.combobox = null;\n        this.menu = null;\n        this.match = null;\n        this.justPasted = false;\n        this.lookBackIndex = 0;\n        this.oninput = this.onInput.bind(this);\n        this.onpaste = this.onPaste.bind(this);\n        this.onkeydown = this.onKeydown.bind(this);\n        this.oncommit = this.onCommit.bind(this);\n        this.onmousedown = this.onMousedown.bind(this);\n        this.onblur = this.onBlur.bind(this);\n        this.interactingWithList = false;\n        input.addEventListener('paste', this.onpaste);\n        input.addEventListener('input', this.oninput);\n        input.addEventListener('keydown', this.onkeydown);\n        input.addEventListener('blur', this.onblur);\n    }\n    destroy() {\n        this.input.removeEventListener('paste', this.onpaste);\n        this.input.removeEventListener('input', this.oninput);\n        this.input.removeEventListener('keydown', this.onkeydown);\n        this.input.removeEventListener('blur', this.onblur);\n    }\n    dismissMenu() {\n        if (this.deactivate()) {\n            this.lookBackIndex = this.input.selectionEnd || this.lookBackIndex;\n        }\n    }\n    activate(match, menu) {\n        var _a, _b;\n        if (this.input !== document.activeElement && this.input !== ((_b = (_a = document.activeElement) === null || _a === void 0 ? void 0 : _a.shadowRoot) === null || _b === void 0 ? void 0 : _b.activeElement)) {\n            return;\n        }\n        this.deactivate();\n        this.menu = menu;\n        if (!menu.id)\n            menu.id = `text-expander-${Math.floor(Math.random() * 100000).toString()}`;\n        this.expander.append(menu);\n        this.combobox = new Combobox(this.input, menu);\n        this.expander.dispatchEvent(new Event('text-expander-activate'));\n        this.positionMenu(menu, match.position);\n        this.combobox.start();\n        menu.addEventListener('combobox-commit', this.oncommit);\n        menu.addEventListener('mousedown', this.onmousedown);\n        this.combobox.navigate(1);\n    }\n    positionMenu(menu, position) {\n        const caretRect = new InputRange(this.input, position).getBoundingClientRect();\n        const targetPosition = { left: caretRect.left, top: caretRect.top + caretRect.height };\n        const currentPosition = menu.getBoundingClientRect();\n        const delta = {\n            left: targetPosition.left - currentPosition.left,\n            top: targetPosition.top - currentPosition.top\n        };\n        if (delta.left !== 0 || delta.top !== 0) {\n            const currentStyle = getComputedStyle(menu);\n            menu.style.left = currentStyle.left ? `calc(${currentStyle.left} + ${delta.left}px)` : `${delta.left}px`;\n            menu.style.top = currentStyle.top ? `calc(${currentStyle.top} + ${delta.top}px)` : `${delta.top}px`;\n        }\n    }\n    deactivate() {\n        const menu = this.menu;\n        if (!menu || !this.combobox)\n            return false;\n        this.expander.dispatchEvent(new Event('text-expander-deactivate'));\n        this.menu = null;\n        menu.removeEventListener('combobox-commit', this.oncommit);\n        menu.removeEventListener('mousedown', this.onmousedown);\n        this.combobox.destroy();\n        this.combobox = null;\n        menu.remove();\n        return true;\n    }\n    onCommit({ target }) {\n        var _a;\n        const item = target;\n        if (!(item instanceof HTMLElement))\n            return;\n        if (!this.combobox)\n            return;\n        const match = this.match;\n        if (!match)\n            return;\n        const beginning = this.input.value.substring(0, match.position - match.key.length);\n        const remaining = this.input.value.substring(match.position + match.text.length);\n        const detail = { item, key: match.key, value: null, continue: false };\n        const canceled = !this.expander.dispatchEvent(new CustomEvent('text-expander-value', { cancelable: true, detail }));\n        if (canceled)\n            return;\n        if (!detail.value)\n            return;\n        let suffix = (_a = this.expander.getAttribute('suffix')) !== null && _a !== void 0 ? _a : ' ';\n        if (detail.continue) {\n            suffix = '';\n        }\n        const value = `${detail.value}${suffix}`;\n        this.input.value = beginning + value + remaining;\n        const cursor = beginning.length + value.length;\n        this.deactivate();\n        this.input.focus({\n            preventScroll: true\n        });\n        this.input.selectionStart = cursor;\n        this.input.selectionEnd = cursor;\n        if (!detail.continue) {\n            this.lookBackIndex = cursor;\n            this.match = null;\n        }\n        this.expander.dispatchEvent(new CustomEvent('text-expander-committed', { cancelable: false, detail: { input: this.input } }));\n    }\n    onBlur() {\n        if (this.interactingWithList) {\n            this.interactingWithList = false;\n            return;\n        }\n        this.deactivate();\n    }\n    onPaste() {\n        this.justPasted = true;\n    }\n    async onInput() {\n        if (this.justPasted) {\n            this.justPasted = false;\n            return;\n        }\n        const match = this.findMatch();\n        if (match) {\n            this.match = match;\n            const menu = await this.notifyProviders(match);\n            if (!this.match)\n                return;\n            if (menu) {\n                this.activate(match, menu);\n            }\n            else {\n                this.deactivate();\n            }\n        }\n        else {\n            this.match = null;\n            this.deactivate();\n        }\n    }\n    findMatch() {\n        const cursor = this.input.selectionEnd || 0;\n        const text = this.input.value;\n        if (cursor <= this.lookBackIndex) {\n            this.lookBackIndex = cursor - 1;\n        }\n        for (const { key, multiWord } of this.expander.keys) {\n            const found = query(text, key, cursor, {\n                multiWord,\n                lookBackIndex: this.lookBackIndex,\n                lastMatchPosition: this.match ? this.match.position : null\n            });\n            if (found) {\n                return { text: found.text, key, position: found.position };\n            }\n        }\n    }\n    async notifyProviders(match) {\n        const providers = [];\n        const provide = (result) => providers.push(result);\n        const canceled = !this.expander.dispatchEvent(new CustomEvent('text-expander-change', { cancelable: true, detail: { provide, text: match.text, key: match.key } }));\n        if (canceled)\n            return;\n        const all = await Promise.all(providers);\n        const fragments = all.filter(x => x.matched).map(x => x.fragment);\n        return fragments[0];\n    }\n    onMousedown() {\n        this.interactingWithList = true;\n    }\n    onKeydown(event) {\n        if (event.key === 'Escape') {\n            this.match = null;\n            if (this.deactivate()) {\n                this.lookBackIndex = this.input.selectionEnd || this.lookBackIndex;\n                event.stopImmediatePropagation();\n                event.preventDefault();\n            }\n        }\n    }\n}\nclass TextExpanderElement extends HTMLElement {\n    get keys() {\n        const keysAttr = this.getAttribute('keys');\n        const keys = keysAttr ? keysAttr.split(' ') : [];\n        const multiWordAttr = this.getAttribute('multiword');\n        const multiWord = multiWordAttr ? multiWordAttr.split(' ') : [];\n        const globalMultiWord = multiWord.length === 0 && this.hasAttribute('multiword');\n        return keys.map(key => ({ key, multiWord: globalMultiWord || multiWord.includes(key) }));\n    }\n    set keys(value) {\n        this.setAttribute('keys', value);\n    }\n    connectedCallback() {\n        const input = this.querySelector('input[type=\"text\"], textarea');\n        if (!(input instanceof HTMLInputElement || input instanceof HTMLTextAreaElement))\n            return;\n        const state = new TextExpander(this, input);\n        states.set(this, state);\n    }\n    disconnectedCallback() {\n        const state = states.get(this);\n        if (!state)\n            return;\n        state.destroy();\n        states.delete(this);\n    }\n    dismiss() {\n        const state = states.get(this);\n        if (!state)\n            return;\n        state.dismissMenu();\n    }\n}\n\nif (!window.customElements.get('text-expander')) {\n    window.TextExpanderElement = TextExpanderElement;\n    window.customElements.define('text-expander', TextExpanderElement);\n}\n\nexport { TextExpanderElement as default };\n","export default function ansiRegex({onlyFirst = false} = {}) {\n\tconst pattern = [\n\t    '[\\\\u001B\\\\u009B][[\\\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\\\d\\\\/#&.:=?%@~_]+)*|[a-zA-Z\\\\d]+(?:;[-a-zA-Z\\\\d\\\\/#&.:=?%@~_]*)*)?\\\\u0007)',\n\t\t'(?:(?:\\\\d{1,4}(?:;\\\\d{0,4})*)?[\\\\dA-PR-TZcf-ntqry=><~]))'\n\t].join('|');\n\n\treturn new RegExp(pattern, onlyFirst ? undefined : 'g');\n}\n","import ansiRegex from 'ansi-regex';\n\nconst regex = ansiRegex();\n\nexport default function stripAnsi(string) {\n\tif (typeof string !== 'string') {\n\t\tthrow new TypeError(`Expected a \\`string\\`, got \\`${typeof string}\\``);\n\t}\n\n\t// Even though the regex is global, we don't need to reset the `.lastIndex`\n\t// because unlike `.exec()` and `.test()`, `.replace()` does it automatically\n\t// and doing it manually has a performance penalty.\n\treturn string.replace(regex, '');\n}\n","import stripAnsi from 'strip-ansi';\n\nconst segmenter = new Intl.Segmenter();\n\nexport default function stringLength(string, {countAnsiEscapeCodes = false} = {}) {\n\tif (string === '') {\n\t\treturn 0;\n\t}\n\n\tif (!countAnsiEscapeCodes) {\n\t\tstring = stripAnsi(string);\n\t}\n\n\tif (string === '') {\n\t\treturn 0;\n\t}\n\n\tlet length = 0;\n\n\tfor (const _ of segmenter.segment(string)) { // eslint-disable-line no-unused-vars\n\t\tlength++;\n\t}\n\n\treturn length;\n}\n","export default \"data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20version='1.0'%20viewBox='0%200%20641%20223'%3e%3cpath%20fill='%23aaa'%20d='M86%20214c-9-1-17-4-24-8l-6-3-5-5-5-4-4-6-4-6-3-8-2-8v-27l2-9%203-9%204-6%204-6%205-5%205-5%207-3%206-4%207-2%207-2%2012-1h12l7%201%208%202%207%204%207%203%205%205%205%204-10%2010-10%209-4-3-10-5-5-1H88l-5%202-6%203-3%204-4%204-2%205-2%206v6l-1%207%201%207%202%207%203%205%202%204%204%203%204%203%205%202%206%202h9l10-1%205-2%206-3v-16H91v-27h59v54l-1%203-2%203-5%204-4%204-5%203-5%202-8%202-8%202-10%201H92l-6-1zm266-62V91h34v46h44V91h34v121h-34v-46h-44v46h-34v-61zm-182-1V90h34v121h-34v-60zm59-1V90h35l36%201%205%202c3%200%208%202%2010%204l5%202%204%205%205%204%203%207%203%207%201%2013v13l-4%206-3%207-4%204-5%205-5%202-5%203-6%202-5%201-18%201h-18v32h-34v-61zm67-2%203-2%202-4%202-5v-5l-2-4-2-4-3-2-3-3h-30v31h30l3-2zm226%2039v-24l-8-12-18-28a1751%201751%200%200%200-20-31v-2h39l7%2012%2012%2021%206%209%2013-21%2013-21h38v2l-41%2061-7%2010v48h-34v-24zM109%2066l-4-1-5-5-5-4-1-5-3-9v-5l1-5c2-7%203-10%208-15l4-4%207-2%207-2h7l6%201%205%202%205%202%203%204%204%203%202%206%202%205v13l-2%205-2%206-4%204-3%203-5%202-4%202-9%201h-9l-5-2zm22-11%204-2%203-4%202-5V34l-2-4-2-4-3-2-4-3-5-1h-6l-4%202-5%202-2%204-3%205-1%203v4l1%205%202%205%202%202%205%203%204%202h10l4-2zM37%2039V11h33l3%201%203%202%204%203%203%203%201%205%201%204v5l-1%204-3%204-3%205-4%201-3%202-11%201H49v16H37V39zm31%200%203-2%201-2%201-2v-4l-1-3-3-2-2-2H49v18h15l4-1zm107%2025a512%20512%200%200%200-19-53h14l4%2014%206%2019%201%204%201-1%207-19%205-17h9l6%2019%207%2018v-1l2-6%205-17%204-13h14v1l-4%2012-16%2041v2h-5l-5-1-6-15-6-15-1%201-3%207-6%2015-2%208h-11l-1-3zm74-25V11h42v11h-29v2l-1%205v4h29v11h-28v11h2l15%201h13v11h-43V39zm55%200V11h33l5%203%205%202%202%204%202%205v10l-2%203-1%204-5%203-5%203%205%205%208%2010%203%204h-14l-7-9-8-10h-9v19h-12V39zm33-3%202-3v-6l-3-3-2-3h-18v16h1v1h17l2-2zm26%203V11h42v11h-29l-1%206v5h29v11h-28v5l-1%205%201%201v1h30v11h-43V39zm54%200V11h17l18%201%204%202%205%203%202%204%203%204%202%206%201%206v5c-1%206-3%2012-6%2015l-3%204-5%203-5%202-17%201h-16V39zm33%2014%205-5%202-3v-6l-1-6-1-3-1-3-4-3-3-2h-5l-6-1-3%201h-3v34h9l8-1%203-2zm50-14V11h34l5%202%204%202%202%203%202%203v9l-2%202-3%204-1%201%203%203%203%204%201%203%201%204-1%204-1%204-3%203-3%203-5%201-5%201h-31V39zm34%2015%202-1v-6l-2-2-2-2h-20v13h20l2-2zm-3-22%204-2v-6l-2-1-2-2h-19v12h16l4-1zm42%2024V45l-6-9-11-17-5-8h15l4%208%207%2011%202%203%207-11%207-11h14l-11%2016-11%2017v23h-12V56z'/%3e%3c/svg%3e\"","import './compose.css';\nimport '@github/text-expander-element';\n\nimport { msg, plural } from '@lingui/core/macro';\nimport { Trans, useLingui } from '@lingui/react/macro';\nimport { MenuItem } from '@szhsin/react-menu';\nimport { deepEqual } from 'fast-equals';\nimport Fuse from 'fuse.js';\nimport { forwardRef, memo } from 'preact/compat';\nimport {\n  useCallback,\n  useEffect,\n  useMemo,\n  useRef,\n  useState,\n} from 'preact/hooks';\nimport { useHotkeys } from 'react-hotkeys-hook';\nimport stringLength from 'string-length';\n// import { detectAll } from 'tinyld/light';\nimport { uid } from 'uid/single';\nimport { useDebouncedCallback, useThrottledCallback } from 'use-debounce';\nimport useResizeObserver from 'use-resize-observer';\nimport { useSnapshot } from 'valtio';\n\nimport poweredByGiphyURL from '../assets/powered-by-giphy.svg';\n\nimport Menu2 from '../components/menu2';\nimport supportedLanguages from '../data/status-supported-languages';\nimport urlRegex from '../data/url-regex';\nimport { api } from '../utils/api';\nimport db from '../utils/db';\nimport emojifyText from '../utils/emojify-text';\nimport i18nDuration from '../utils/i18n-duration';\nimport isRTL from '../utils/is-rtl';\nimport localeMatch from '../utils/locale-match';\nimport localeCode2Text from '../utils/localeCode2Text';\nimport mem from '../utils/mem';\nimport openCompose from '../utils/open-compose';\nimport pmem from '../utils/pmem';\nimport prettyBytes from '../utils/pretty-bytes';\nimport { fetchRelationships } from '../utils/relationships';\nimport shortenNumber from '../utils/shorten-number';\nimport showToast from '../utils/show-toast';\nimport states, { saveStatus } from '../utils/states';\nimport store from '../utils/store';\nimport {\n  getCurrentAccount,\n  getCurrentAccountNS,\n  getCurrentInstance,\n  getCurrentInstanceConfiguration,\n} from '../utils/store-utils';\nimport supports from '../utils/supports';\nimport useCloseWatcher from '../utils/useCloseWatcher';\nimport useInterval from '../utils/useInterval';\nimport visibilityIconsMap from '../utils/visibility-icons-map';\n\nimport AccountBlock from './account-block';\n// import Avatar from './avatar';\nimport Icon from './icon';\nimport Loader from './loader';\nimport Modal from './modal';\nimport Status from './status';\n\nconst {\n  PHANPY_IMG_ALT_API_URL: IMG_ALT_API_URL,\n  PHANPY_GIPHY_API_KEY: GIPHY_API_KEY,\n} = import.meta.env;\n\nconst supportedLanguagesMap = supportedLanguages.reduce((acc, l) => {\n  const [code, common, native] = l;\n  acc[code] = {\n    common,\n    native,\n  };\n  return acc;\n}, {});\n\n/* NOTES:\n  - Max character limit includes BOTH status text and Content Warning text\n*/\n\nconst expiryOptions = {\n  300: i18nDuration(5, 'minute'),\n  1_800: i18nDuration(30, 'minute'),\n  3_600: i18nDuration(1, 'hour'),\n  21_600: i18nDuration(6, 'hour'),\n  86_400: i18nDuration(1, 'day'),\n  259_200: i18nDuration(3, 'day'),\n  604_800: i18nDuration(1, 'week'),\n};\nconst expirySeconds = Object.keys(expiryOptions);\nconst oneDay = 24 * 60 * 60;\n\nconst expiresInFromExpiresAt = (expiresAt) => {\n  if (!expiresAt) return oneDay;\n  const delta = (new Date(expiresAt).getTime() - Date.now()) / 1000;\n  return expirySeconds.find((s) => s >= delta) || oneDay;\n};\n\nconst menu = document.createElement('ul');\nmenu.role = 'listbox';\nmenu.className = 'text-expander-menu';\n\n// Set IntersectionObserver on menu, reposition it because text-expander doesn't handle it\nconst windowMargin = 16;\nconst observer = new IntersectionObserver((entries) => {\n  entries.forEach((entry) => {\n    if (entry.isIntersecting) {\n      const { left, width } = entry.boundingClientRect;\n      const { innerWidth } = window;\n      if (left + width > innerWidth) {\n        const insetInlineStart = isRTL() ? 'right' : 'left';\n        menu.style[insetInlineStart] = innerWidth - width - windowMargin + 'px';\n      }\n    }\n  });\n});\nobserver.observe(menu);\n\nconst DEFAULT_LANG = localeMatch(\n  [new Intl.DateTimeFormat().resolvedOptions().locale, ...navigator.languages],\n  supportedLanguages.map((l) => l[0]),\n  'en',\n);\n\n// https://github.com/mastodon/mastodon/blob/c4a429ed47e85a6bbf0d470a41cc2f64cf120c19/app/javascript/mastodon/features/compose/util/counter.js\nconst urlRegexObj = new RegExp(urlRegex.source, urlRegex.flags);\nconst usernameRegex = /(^|[^\\/\\w])@(([a-z0-9_]+)@[a-z0-9\\.\\-]+[a-z0-9]+)/gi;\nconst urlPlaceholder = '$2xxxxxxxxxxxxxxxxxxxxxxx';\nfunction countableText(inputText) {\n  return inputText\n    .replace(urlRegexObj, urlPlaceholder)\n    .replace(usernameRegex, '$1@$3');\n}\n\n// https://github.com/mastodon/mastodon/blob/c03bd2a238741a012aa4b98dc4902d6cf948ab63/app/models/account.rb#L69\nconst USERNAME_RE = /[a-z0-9_]+([a-z0-9_.-]+[a-z0-9_]+)?/i;\nconst MENTION_RE = new RegExp(\n  `(^|[^=\\\\/\\\\w])(@${USERNAME_RE.source}(?:@[\\\\p{L}\\\\w.-]+[\\\\w]+)?)`,\n  'uig',\n);\n\n// AI-generated, all other regexes are too complicated\nconst HASHTAG_RE = new RegExp(\n  `(^|[^=\\\\/\\\\w])(#[a-z0-9_]+([a-z0-9_.]+[a-z0-9_]+)?)(?![\\\\/\\\\w])`,\n  'ig',\n);\n\n// https://github.com/mastodon/mastodon/blob/23e32a4b3031d1da8b911e0145d61b4dd47c4f96/app/models/custom_emoji.rb#L31\nconst SHORTCODE_RE_FRAGMENT = '[a-zA-Z0-9_]{2,}';\nconst SCAN_RE = new RegExp(\n  `(^|[^=\\\\/\\\\w])(:${SHORTCODE_RE_FRAGMENT}:)(?=[^A-Za-z0-9_:]|$)`,\n  'g',\n);\n\nconst segmenter = new Intl.Segmenter();\nfunction escapeHTML(text) {\n  return text\n    .replace(/&/g, '&amp;')\n    .replace(/</g, '&lt;')\n    .replace(/>/g, '&gt;')\n    .replace(/\"/g, '&quot;')\n    .replace(/'/g, '&apos;');\n}\nfunction highlightText(text, { maxCharacters = Infinity }) {\n  // Exceeded characters limit\n  const { composerCharacterCount } = states;\n  if (composerCharacterCount > maxCharacters) {\n    // Highlight exceeded characters\n    let withinLimitHTML = '',\n      exceedLimitHTML = '';\n    const htmlSegments = segmenter.segment(text);\n    for (const { segment, index } of htmlSegments) {\n      if (index < maxCharacters) {\n        withinLimitHTML += segment;\n      } else {\n        exceedLimitHTML += segment;\n      }\n    }\n    if (exceedLimitHTML) {\n      exceedLimitHTML =\n        '<mark class=\"compose-highlight-exceeded\">' +\n        escapeHTML(exceedLimitHTML) +\n        '</mark>';\n    }\n    return escapeHTML(withinLimitHTML) + exceedLimitHTML;\n  }\n\n  return escapeHTML(text)\n    .replace(urlRegexObj, '$2<mark class=\"compose-highlight-url\">$3</mark>') // URLs\n    .replace(MENTION_RE, '$1<mark class=\"compose-highlight-mention\">$2</mark>') // Mentions\n    .replace(HASHTAG_RE, '$1<mark class=\"compose-highlight-hashtag\">$2</mark>') // Hashtags\n    .replace(\n      SCAN_RE,\n      '$1<mark class=\"compose-highlight-emoji-shortcode\">$2</mark>',\n    ); // Emoji shortcodes\n}\n\n// const rtf = new Intl.RelativeTimeFormat();\nconst RTF = mem((locale) => new Intl.RelativeTimeFormat(locale || undefined));\nconst LF = mem((locale) => new Intl.ListFormat(locale || undefined));\n\nconst CUSTOM_EMOJIS_COUNT = 100;\n\nconst ADD_LABELS = {\n  media: msg`Add media`,\n  customEmoji: msg`Add custom emoji`,\n  gif: msg`Add GIF`,\n  poll: msg`Add poll`,\n};\n\nfunction Compose({\n  onClose,\n  replyToStatus,\n  editStatus,\n  draftStatus,\n  standalone,\n  hasOpener,\n}) {\n  const { i18n, _, t } = useLingui();\n  const rtf = RTF(i18n.locale);\n  const lf = LF(i18n.locale);\n\n  console.warn('RENDER COMPOSER');\n  const { masto, instance } = api();\n  const [uiState, setUIState] = useState('default');\n  const UID = useRef(draftStatus?.uid || uid());\n  console.log('Compose UID', UID.current);\n\n  const currentAccount = getCurrentAccount();\n  const currentAccountInfo = currentAccount.info;\n\n  const configuration = getCurrentInstanceConfiguration();\n  console.log('⚙️ Configuration', configuration);\n\n  const {\n    statuses: {\n      maxCharacters,\n      maxMediaAttachments, // Beware: it can be undefined!\n      charactersReservedPerUrl,\n    } = {},\n    mediaAttachments: {\n      supportedMimeTypes,\n      imageSizeLimit,\n      imageMatrixLimit,\n      videoSizeLimit,\n      videoMatrixLimit,\n      videoFrameRateLimit,\n    } = {},\n    polls: {\n      maxOptions,\n      maxCharactersPerOption,\n      maxExpiration,\n      minExpiration,\n    } = {},\n  } = configuration || {};\n\n  const textareaRef = useRef();\n  const spoilerTextRef = useRef();\n  const [visibility, setVisibility] = useState('public');\n  const [sensitive, setSensitive] = useState(false);\n  const [language, setLanguage] = useState(\n    store.session.get('currentLanguage') || DEFAULT_LANG,\n  );\n  const prevLanguage = useRef(language);\n  const [mediaAttachments, setMediaAttachments] = useState([]);\n  const [poll, setPoll] = useState(null);\n\n  const prefs = store.account.get('preferences') || {};\n\n  const oninputTextarea = () => {\n    if (!textareaRef.current) return;\n    textareaRef.current.dispatchEvent(new Event('input'));\n  };\n  const focusTextarea = () => {\n    setTimeout(() => {\n      if (!textareaRef.current) return;\n      // status starts with newline, focus on first position\n      if (draftStatus?.status?.startsWith?.('\\n')) {\n        textareaRef.current.selectionStart = 0;\n        textareaRef.current.selectionEnd = 0;\n      }\n      console.debug('FOCUS textarea');\n      textareaRef.current?.focus();\n    }, 300);\n  };\n\n  useEffect(() => {\n    if (replyToStatus) {\n      const { spoilerText, visibility, language, sensitive } = replyToStatus;\n      if (spoilerText && spoilerTextRef.current) {\n        spoilerTextRef.current.value = spoilerText;\n      }\n      const mentions = new Set([\n        replyToStatus.account.acct,\n        ...replyToStatus.mentions.map((m) => m.acct),\n      ]);\n      const allMentions = [...mentions].filter(\n        (m) => m !== currentAccountInfo.acct,\n      );\n      if (allMentions.length > 0) {\n        textareaRef.current.value = `${allMentions\n          .map((m) => `@${m}`)\n          .join(' ')} `;\n        oninputTextarea();\n      }\n      focusTextarea();\n      setVisibility(\n        visibility === 'public' && prefs['posting:default:visibility']\n          ? prefs['posting:default:visibility'].toLowerCase()\n          : visibility,\n      );\n      setLanguage(\n        language ||\n          prefs['posting:default:language']?.toLowerCase() ||\n          DEFAULT_LANG,\n      );\n      setSensitive(sensitive && !!spoilerText);\n    } else if (editStatus) {\n      const { visibility, language, sensitive, poll, mediaAttachments } =\n        editStatus;\n      const composablePoll = !!poll?.options && {\n        ...poll,\n        options: poll.options.map((o) => o?.title || o),\n        expiresIn: poll?.expiresIn || expiresInFromExpiresAt(poll.expiresAt),\n      };\n      setUIState('loading');\n      (async () => {\n        try {\n          const statusSource = await masto.v1.statuses\n            .$select(editStatus.id)\n            .source.fetch();\n          console.log({ statusSource });\n          const { text, spoilerText } = statusSource;\n          textareaRef.current.value = text;\n          textareaRef.current.dataset.source = text;\n          oninputTextarea();\n          focusTextarea();\n          spoilerTextRef.current.value = spoilerText;\n          setVisibility(visibility);\n          setLanguage(\n            language ||\n              prefs['posting:default:language']?.toLowerCase() ||\n              DEFAULT_LANG,\n          );\n          setSensitive(sensitive);\n          if (composablePoll) setPoll(composablePoll);\n          setMediaAttachments(mediaAttachments);\n          setUIState('default');\n        } catch (e) {\n          console.error(e);\n          alert(e?.reason || e);\n          setUIState('error');\n        }\n      })();\n    } else {\n      focusTextarea();\n      console.log('Apply prefs', prefs);\n      if (prefs['posting:default:visibility']) {\n        setVisibility(prefs['posting:default:visibility'].toLowerCase());\n      }\n      if (prefs['posting:default:language']) {\n        setLanguage(prefs['posting:default:language'].toLowerCase());\n      }\n      if (prefs['posting:default:sensitive']) {\n        setSensitive(!!prefs['posting:default:sensitive']);\n      }\n    }\n    if (draftStatus) {\n      const {\n        status,\n        spoilerText,\n        visibility,\n        language,\n        sensitive,\n        poll,\n        mediaAttachments,\n      } = draftStatus;\n      const composablePoll = !!poll?.options && {\n        ...poll,\n        options: poll.options.map((o) => o?.title || o),\n        expiresIn: poll?.expiresIn || expiresInFromExpiresAt(poll.expiresAt),\n      };\n      textareaRef.current.value = status;\n      oninputTextarea();\n      focusTextarea();\n      if (spoilerText) spoilerTextRef.current.value = spoilerText;\n      if (visibility) setVisibility(visibility);\n      setLanguage(\n        language ||\n          prefs['posting:default:language']?.toLowerCase() ||\n          DEFAULT_LANG,\n      );\n      if (sensitive !== null) setSensitive(sensitive);\n      if (composablePoll) setPoll(composablePoll);\n      if (mediaAttachments) setMediaAttachments(mediaAttachments);\n    }\n  }, [draftStatus, editStatus, replyToStatus]);\n\n  const formRef = useRef();\n\n  const beforeUnloadCopy = t`You have unsaved changes. Discard this post?`;\n  const canClose = () => {\n    const { value, dataset } = textareaRef.current;\n\n    // check if loading\n    if (uiState === 'loading') {\n      console.log('canClose', { uiState });\n      return false;\n    }\n\n    // check for status and media attachments\n    const hasValue = (value || '')\n      .trim()\n      .replace(/^\\p{White_Space}+|\\p{White_Space}+$/gu, '');\n    const hasMediaAttachments = mediaAttachments.length > 0;\n    if (!hasValue && !hasMediaAttachments) {\n      console.log('canClose', { value, mediaAttachments });\n      return true;\n    }\n\n    // check if all media attachments have IDs\n    const hasIDMediaAttachments =\n      mediaAttachments.length > 0 &&\n      mediaAttachments.every((media) => media.id);\n    if (hasIDMediaAttachments) {\n      console.log('canClose', { hasIDMediaAttachments });\n      return true;\n    }\n\n    // check if status contains only \"@acct\", if replying\n    const isSelf = replyToStatus?.account.id === currentAccountInfo.id;\n    const hasOnlyAcct =\n      replyToStatus && value.trim() === `@${replyToStatus.account.acct}`;\n    // TODO: check for mentions, or maybe just generic \"@username<space>\", including multiple mentions like \"@username1<space>@username2<space>\"\n    if (!isSelf && hasOnlyAcct) {\n      console.log('canClose', { isSelf, hasOnlyAcct });\n      return true;\n    }\n\n    // check if status is same with source\n    const sameWithSource = value === dataset?.source;\n    if (sameWithSource) {\n      console.log('canClose', { sameWithSource });\n      return true;\n    }\n\n    console.log('canClose', {\n      value,\n      hasMediaAttachments,\n      hasIDMediaAttachments,\n      poll,\n      isSelf,\n      hasOnlyAcct,\n      sameWithSource,\n      uiState,\n    });\n\n    return false;\n  };\n\n  const confirmClose = () => {\n    if (!canClose()) {\n      const yes = confirm(beforeUnloadCopy);\n      return yes;\n    }\n    return true;\n  };\n\n  useEffect(() => {\n    // Show warning if user tries to close window with unsaved changes\n    const handleBeforeUnload = (e) => {\n      if (!canClose()) {\n        e.preventDefault();\n        e.returnValue = beforeUnloadCopy;\n      }\n    };\n    window.addEventListener('beforeunload', handleBeforeUnload, {\n      capture: true,\n    });\n    return () =>\n      window.removeEventListener('beforeunload', handleBeforeUnload, {\n        capture: true,\n      });\n  }, []);\n\n  const getCharCount = () => {\n    const { value } = textareaRef.current;\n    const { value: spoilerText } = spoilerTextRef.current;\n    return stringLength(countableText(value)) + stringLength(spoilerText);\n  };\n  const updateCharCount = () => {\n    const count = getCharCount();\n    states.composerCharacterCount = count;\n  };\n  useEffect(updateCharCount, []);\n\n  const supportsCloseWatcher = window.CloseWatcher;\n  const escDownRef = useRef(false);\n  useHotkeys(\n    'esc',\n    () => {\n      escDownRef.current = true;\n      // This won't be true if this event is already handled and not propagated 🤞\n    },\n    {\n      enabled: !supportsCloseWatcher,\n      enableOnFormTags: true,\n    },\n  );\n  useHotkeys(\n    'esc',\n    () => {\n      if (!standalone && escDownRef.current && confirmClose()) {\n        onClose();\n      }\n      escDownRef.current = false;\n    },\n    {\n      enabled: !supportsCloseWatcher,\n      enableOnFormTags: true,\n      // Use keyup because Esc keydown will close the confirm dialog on Safari\n      keyup: true,\n      ignoreEventWhen: (e) => {\n        const modals = document.querySelectorAll('#modal-container > *');\n        const hasModal = !!modals;\n        const hasOnlyComposer =\n          modals.length === 1 && modals[0].querySelector('#compose-container');\n        return hasModal && !hasOnlyComposer;\n      },\n    },\n  );\n  useCloseWatcher(() => {\n    if (!standalone && confirmClose()) {\n      onClose();\n    }\n  }, [standalone, confirmClose, onClose]);\n\n  const prevBackgroundDraft = useRef({});\n  const draftKey = () => {\n    const ns = getCurrentAccountNS();\n    return `${ns}#${UID.current}`;\n  };\n  const saveUnsavedDraft = () => {\n    // Not enabling this for editing status\n    // I don't think this warrant a draft mode for a status that's already posted\n    // Maybe it could be a big edit change but it should be rare\n    if (editStatus) return;\n    if (states.composerState.minimized) return;\n    const key = draftKey();\n    const backgroundDraft = {\n      key,\n      replyTo: replyToStatus\n        ? {\n            /* Smaller payload of replyToStatus. Reasons:\n              - No point storing whole thing\n              - Could have media attachments\n              - Could be deleted/edited later\n            */\n            id: replyToStatus.id,\n            account: {\n              id: replyToStatus.account.id,\n              username: replyToStatus.account.username,\n              acct: replyToStatus.account.acct,\n            },\n          }\n        : null,\n      draftStatus: {\n        uid: UID.current,\n        status: textareaRef.current.value,\n        spoilerText: spoilerTextRef.current.value,\n        visibility,\n        language,\n        sensitive,\n        poll,\n        mediaAttachments,\n      },\n    };\n    if (\n      !deepEqual(backgroundDraft, prevBackgroundDraft.current) &&\n      !canClose()\n    ) {\n      console.debug('not equal', backgroundDraft, prevBackgroundDraft.current);\n      db.drafts\n        .set(key, {\n          ...backgroundDraft,\n          state: 'unsaved',\n          updatedAt: Date.now(),\n        })\n        .then(() => {\n          console.debug('DRAFT saved', key, backgroundDraft);\n        })\n        .catch((e) => {\n          console.error('DRAFT failed', key, e);\n        });\n      prevBackgroundDraft.current = structuredClone(backgroundDraft);\n    }\n  };\n  useInterval(saveUnsavedDraft, 5000); // background save every 5s\n  useEffect(() => {\n    saveUnsavedDraft();\n    // If unmounted, means user discarded the draft\n    // Also means pop-out 🙈, but it's okay because the pop-out will persist the ID and re-create the draft\n    return () => {\n      db.drafts.del(draftKey());\n    };\n  }, []);\n\n  useEffect(() => {\n    const handleItems = (e) => {\n      const { items } = e.clipboardData || e.dataTransfer;\n      const files = [];\n      const unsupportedFiles = [];\n      for (let i = 0; i < items.length; i++) {\n        const item = items[i];\n        if (item.kind === 'file') {\n          const file = item.getAsFile();\n          if (\n            supportedMimeTypes !== undefined &&\n            !supportedMimeTypes.includes(file.type)\n          ) {\n            unsupportedFiles.push(file);\n          } else {\n            files.push(file);\n          }\n        }\n      }\n      if (unsupportedFiles.length > 0) {\n        alert(\n          plural(unsupportedFiles.length, {\n            one: `File ${unsupportedFiles[0].name} is not supported.`,\n            other: `Files ${lf.format(\n              unsupportedFiles.map((f) => f.name),\n            )} are not supported.`,\n          }),\n        );\n      }\n      if (files.length > 0 && mediaAttachments.length >= maxMediaAttachments) {\n        alert(\n          plural(maxMediaAttachments, {\n            one: 'You can only attach up to 1 file.',\n            other: 'You can only attach up to # files.',\n          }),\n        );\n        return;\n      }\n      console.log({ files });\n      if (files.length > 0) {\n        e.preventDefault();\n        e.stopPropagation();\n        // Auto-cut-off files to avoid exceeding maxMediaAttachments\n        let allowedFiles = files;\n        if (maxMediaAttachments !== undefined) {\n          const max = maxMediaAttachments - mediaAttachments.length;\n          allowedFiles = allowedFiles.slice(0, max);\n          if (allowedFiles.length <= 0) {\n            alert(\n              plural(maxMediaAttachments, {\n                one: 'You can only attach up to 1 file.',\n                other: 'You can only attach up to # files.',\n              }),\n            );\n            return;\n          }\n        }\n        const mediaFiles = allowedFiles.map((file) => ({\n          file,\n          type: file.type,\n          size: file.size,\n          url: URL.createObjectURL(file),\n          id: null,\n          description: null,\n        }));\n        setMediaAttachments([...mediaAttachments, ...mediaFiles]);\n      }\n    };\n    window.addEventListener('paste', handleItems);\n    const handleDragover = (e) => {\n      // Prevent default if there's files\n      if (e.dataTransfer.items.length > 0) {\n        e.preventDefault();\n        e.stopPropagation();\n      }\n    };\n    window.addEventListener('dragover', handleDragover);\n    window.addEventListener('drop', handleItems);\n    return () => {\n      window.removeEventListener('paste', handleItems);\n      window.removeEventListener('dragover', handleDragover);\n      window.removeEventListener('drop', handleItems);\n    };\n  }, [mediaAttachments]);\n\n  const [showMentionPicker, setShowMentionPicker] = useState(false);\n  const [showEmoji2Picker, setShowEmoji2Picker] = useState(false);\n  const [showGIFPicker, setShowGIFPicker] = useState(false);\n\n  const [autoDetectedLanguages, setAutoDetectedLanguages] = useState(null);\n  const [topSupportedLanguages, restSupportedLanguages] = useMemo(() => {\n    const topLanguages = [];\n    const restLanguages = [];\n    const { contentTranslationHideLanguages = [] } = states.settings;\n    supportedLanguages.forEach((l) => {\n      const [code] = l;\n      if (\n        code === language ||\n        code === prevLanguage.current ||\n        code === DEFAULT_LANG ||\n        contentTranslationHideLanguages.includes(code) ||\n        (autoDetectedLanguages?.length && autoDetectedLanguages.includes(code))\n      ) {\n        topLanguages.push(l);\n      } else {\n        restLanguages.push(l);\n      }\n    });\n    topLanguages.sort(([codeA, commonA], [codeB, commonB]) => {\n      if (codeA === language) return -1;\n      if (codeB === language) return 1;\n      return commonA.localeCompare(commonB);\n    });\n    restLanguages.sort(([codeA, commonA], [codeB, commonB]) =>\n      commonA.localeCompare(commonB),\n    );\n    return [topLanguages, restLanguages];\n  }, [language, autoDetectedLanguages]);\n\n  const replyToStatusMonthsAgo = useMemo(\n    () =>\n      !!replyToStatus?.createdAt &&\n      Math.floor(\n        (Date.now() - new Date(replyToStatus.createdAt)) /\n          (1000 * 60 * 60 * 24 * 30),\n      ),\n    [replyToStatus],\n  );\n\n  const onMinimize = () => {\n    saveUnsavedDraft();\n    states.composerState.minimized = true;\n  };\n\n  const gifPickerDisabled =\n    uiState === 'loading' ||\n    (maxMediaAttachments !== undefined &&\n      mediaAttachments.length >= maxMediaAttachments) ||\n    !!poll;\n\n  // If maxOptions is not defined or defined and is greater than 1, show poll button\n  const showPollButton = maxOptions == null || maxOptions > 1;\n  const pollButtonDisabled =\n    uiState === 'loading' || !!poll || !!mediaAttachments.length;\n  const onPollButtonClick = () => {\n    setPoll({\n      options: ['', ''],\n      expiresIn: 24 * 60 * 60, // 1 day\n      multiple: false,\n    });\n  };\n\n  const addSubToolbarRef = useRef();\n  const [showAddButton, setShowAddButton] = useState(false);\n  useResizeObserver({\n    ref: addSubToolbarRef,\n    box: 'border-box',\n    onResize: ({ width }) => {\n      // If scrollable, it's truncated\n      const { scrollWidth } = addSubToolbarRef.current;\n      const truncated = scrollWidth > width;\n      const overTruncated = width < 84; // roughly two buttons width\n      setShowAddButton(overTruncated || truncated);\n      addSubToolbarRef.current.hidden = overTruncated;\n    },\n  });\n\n  return (\n    <div id=\"compose-container-outer\">\n      <div id=\"compose-container\" class={standalone ? 'standalone' : ''}>\n        <div class=\"compose-top\">\n          {currentAccountInfo?.avatarStatic && (\n            // <Avatar\n            //   url={currentAccountInfo.avatarStatic}\n            //   size=\"xl\"\n            //   alt={currentAccountInfo.username}\n            //   squircle={currentAccountInfo?.bot}\n            // />\n            <AccountBlock\n              account={currentAccountInfo}\n              accountInstance={currentAccount.instanceURL}\n              hideDisplayName\n              useAvatarStatic\n            />\n          )}\n          {!standalone ? (\n            <span class=\"compose-controls\">\n              <button\n                type=\"button\"\n                class=\"plain4 pop-button\"\n                disabled={uiState === 'loading'}\n                onClick={() => {\n                  // If there are non-ID media attachments (not yet uploaded), show confirmation dialog because they are not going to be passed to the new window\n                  // const containNonIDMediaAttachments =\n                  //   mediaAttachments.length > 0 &&\n                  //   mediaAttachments.some((media) => !media.id);\n                  // if (containNonIDMediaAttachments) {\n                  //   const yes = confirm(\n                  //     'You have media attachments that are not yet uploaded. Opening a new window will discard them and you will need to re-attach them. Are you sure you want to continue?',\n                  //   );\n                  //   if (!yes) {\n                  //     return;\n                  //   }\n                  // }\n\n                  // const mediaAttachmentsWithIDs = mediaAttachments.filter(\n                  //   (media) => media.id,\n                  // );\n\n                  const newWin = openCompose({\n                    editStatus,\n                    replyToStatus,\n                    draftStatus: {\n                      uid: UID.current,\n                      status: textareaRef.current.value,\n                      spoilerText: spoilerTextRef.current.value,\n                      visibility,\n                      language,\n                      sensitive,\n                      poll,\n                      mediaAttachments,\n                    },\n                  });\n\n                  if (!newWin) {\n                    return;\n                  }\n\n                  onClose();\n                }}\n              >\n                <Icon icon=\"popout\" alt={t`Pop out`} />\n              </button>\n              <button\n                type=\"button\"\n                class=\"plain4 min-button\"\n                onClick={onMinimize}\n              >\n                <Icon icon=\"minimize\" alt={t`Minimize`} />\n              </button>{' '}\n              <button\n                type=\"button\"\n                class=\"light close-button\"\n                disabled={uiState === 'loading'}\n                onClick={() => {\n                  if (confirmClose()) {\n                    onClose();\n                  }\n                }}\n              >\n                <Icon icon=\"x\" alt={t`Close`} />\n              </button>\n            </span>\n          ) : (\n            hasOpener && (\n              <button\n                type=\"button\"\n                class=\"light pop-button\"\n                disabled={uiState === 'loading'}\n                onClick={() => {\n                  // If there are non-ID media attachments (not yet uploaded), show confirmation dialog because they are not going to be passed to the new window\n                  // const containNonIDMediaAttachments =\n                  //   mediaAttachments.length > 0 &&\n                  //   mediaAttachments.some((media) => !media.id);\n                  // if (containNonIDMediaAttachments) {\n                  //   const yes = confirm(\n                  //     'You have media attachments that are not yet uploaded. Opening a new window will discard them and you will need to re-attach them. Are you sure you want to continue?',\n                  //   );\n                  //   if (!yes) {\n                  //     return;\n                  //   }\n                  // }\n\n                  if (!window.opener) {\n                    alert(t`Looks like you closed the parent window.`);\n                    return;\n                  }\n\n                  if (window.opener.__STATES__.showCompose) {\n                    if (window.opener.__STATES__.composerState?.publishing) {\n                      alert(\n                        t`Looks like you already have a compose field open in the parent window and currently publishing. Please wait for it to be done and try again later.`,\n                      );\n                      return;\n                    }\n\n                    let confirmText = t`Looks like you already have a compose field open in the parent window. Popping in this window will discard the changes you made in the parent window. Continue?`;\n                    const yes = confirm(confirmText);\n                    if (!yes) return;\n                  }\n\n                  // const mediaAttachmentsWithIDs = mediaAttachments.filter(\n                  //   (media) => media.id,\n                  // );\n\n                  onClose({\n                    fn: () => {\n                      const passData = {\n                        editStatus,\n                        replyToStatus,\n                        draftStatus: {\n                          uid: UID.current,\n                          status: textareaRef.current.value,\n                          spoilerText: spoilerTextRef.current.value,\n                          visibility,\n                          language,\n                          sensitive,\n                          poll,\n                          mediaAttachments,\n                        },\n                      };\n                      window.opener.__COMPOSE__ = passData; // Pass it here instead of `showCompose` due to some weird proxy issue again\n                      if (window.opener.__STATES__.showCompose) {\n                        window.opener.__STATES__.showCompose = false;\n                        setTimeout(() => {\n                          window.opener.__STATES__.showCompose = true;\n                        }, 10);\n                      } else {\n                        window.opener.__STATES__.showCompose = true;\n                      }\n                      if (window.opener.__STATES__.composerState.minimized) {\n                        // Maximize it\n                        window.opener.__STATES__.composerState.minimized = false;\n                      }\n                    },\n                  });\n                }}\n              >\n                <Icon icon=\"popin\" alt={t`Pop in`} />\n              </button>\n            )\n          )}\n        </div>\n        {!!replyToStatus && (\n          <div class=\"status-preview\">\n            <Status status={replyToStatus} size=\"s\" previewMode />\n            <div class=\"status-preview-legend reply-to\">\n              {replyToStatusMonthsAgo > 0 ? (\n                <Trans>\n                  Replying to @\n                  {replyToStatus.account.acct || replyToStatus.account.username}\n                  &rsquo;s post (\n                  <strong>\n                    {rtf.format(-replyToStatusMonthsAgo, 'month')}\n                  </strong>\n                  )\n                </Trans>\n              ) : (\n                <Trans>\n                  Replying to @\n                  {replyToStatus.account.acct || replyToStatus.account.username}\n                  &rsquo;s post\n                </Trans>\n              )}\n            </div>\n          </div>\n        )}\n        {!!editStatus && (\n          <div class=\"status-preview\">\n            <Status status={editStatus} size=\"s\" previewMode />\n            <div class=\"status-preview-legend\">\n              <Trans>Editing source post</Trans>\n            </div>\n          </div>\n        )}\n        <form\n          ref={formRef}\n          class={`form-visibility-${visibility}`}\n          style={{\n            pointerEvents: uiState === 'loading' ? 'none' : 'auto',\n            opacity: uiState === 'loading' ? 0.5 : 1,\n          }}\n          onKeyDown={(e) => {\n            if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) {\n              formRef.current.dispatchEvent(\n                new Event('submit', { cancelable: true }),\n              );\n            }\n          }}\n          onSubmit={(e) => {\n            e.preventDefault();\n\n            const formData = new FormData(e.target);\n            const entries = Object.fromEntries(formData.entries());\n            console.log('ENTRIES', entries);\n            let { status, visibility, sensitive, spoilerText } = entries;\n\n            // Pre-cleanup\n            sensitive = sensitive === 'on'; // checkboxes return \"on\" if checked\n\n            // Validation\n            /* Let the backend validate this\n          if (stringLength(status) > maxCharacters) {\n            alert(`Status is too long! Max characters: ${maxCharacters}`);\n            return;\n          }\n          if (\n            sensitive &&\n            stringLength(status) + stringLength(spoilerText) > maxCharacters\n          ) {\n            alert(\n              `Status and content warning is too long! Max characters: ${maxCharacters}`,\n            );\n            return;\n          }\n          */\n            if (poll) {\n              if (poll.options.length < 2) {\n                alert(t`Poll must have at least 2 options`);\n                return;\n              }\n              if (poll.options.some((option) => option === '')) {\n                alert(t`Some poll choices are empty`);\n                return;\n              }\n            }\n            // TODO: check for URLs and use `charactersReservedPerUrl` to calculate max characters\n\n            if (mediaAttachments.length > 0) {\n              // If there are media attachments, check if they have no descriptions\n              const hasNoDescriptions = mediaAttachments.some(\n                (media) => !media.description?.trim?.(),\n              );\n              if (hasNoDescriptions) {\n                const yes = confirm(\n                  t`Some media have no descriptions. Continue?`,\n                );\n                if (!yes) return;\n              }\n            }\n\n            // Post-cleanup\n            spoilerText = (sensitive && spoilerText) || undefined;\n            status = status === '' ? undefined : status;\n\n            // states.composerState.minimized = true;\n            states.composerState.publishing = true;\n            setUIState('loading');\n            (async () => {\n              try {\n                console.log('MEDIA ATTACHMENTS', mediaAttachments);\n                if (mediaAttachments.length > 0) {\n                  // Upload media attachments first\n                  const mediaPromises = mediaAttachments.map((attachment) => {\n                    const { file, description, id } = attachment;\n                    console.log('UPLOADING', attachment);\n                    if (id) {\n                      // If already uploaded\n                      return attachment;\n                    } else {\n                      const params = removeNullUndefined({\n                        file,\n                        description,\n                      });\n                      return masto.v2.media.create(params).then((res) => {\n                        if (res.id) {\n                          attachment.id = res.id;\n                        }\n                        return res;\n                      });\n                    }\n                  });\n                  const results = await Promise.allSettled(mediaPromises);\n\n                  // If any failed, return\n                  if (\n                    results.some((result) => {\n                      return result.status === 'rejected' || !result.value?.id;\n                    })\n                  ) {\n                    states.composerState.publishing = false;\n                    states.composerState.publishingError = true;\n                    setUIState('error');\n                    // Alert all the reasons\n                    results.forEach((result) => {\n                      if (result.status === 'rejected') {\n                        console.error(result);\n                        alert(result.reason || t`Attachment #${i} failed`);\n                      }\n                    });\n                    return;\n                  }\n\n                  console.log({ results, mediaAttachments });\n                }\n\n                /* NOTE:\n                Using snakecase here because masto.js's `isObject` returns false for `params`, ONLY happens when opening in pop-out window. This is maybe due to `window.masto` variable being passed from the parent window. The check that failed is `x.constructor === Object`, so maybe the `Object` in new window is different than parent window's?\n                Code: https://github.com/neet/masto.js/blob/dd0d649067b6a2b6e60fbb0a96597c373a255b00/src/serializers/is-object.ts#L2\n\n                // TODO: Note above is no longer true in Masto.js v6. Revisit this.\n              */\n                let params = {\n                  status,\n                  // spoilerText,\n                  spoiler_text: spoilerText,\n                  language,\n                  sensitive,\n                  poll,\n                  // mediaIds: mediaAttachments.map((attachment) => attachment.id),\n                  media_ids: mediaAttachments.map(\n                    (attachment) => attachment.id,\n                  ),\n                };\n                if (editStatus && supports('@mastodon/edit-media-attributes')) {\n                  params.media_attributes = mediaAttachments.map(\n                    (attachment) => {\n                      return {\n                        id: attachment.id,\n                        description: attachment.description,\n                        // focus\n                        // thumbnail\n                      };\n                    },\n                  );\n                } else if (!editStatus) {\n                  params.visibility = visibility;\n                  // params.inReplyToId = replyToStatus?.id || undefined;\n                  params.in_reply_to_id = replyToStatus?.id || undefined;\n                }\n                params = removeNullUndefined(params);\n                console.log('POST', params);\n\n                let newStatus;\n                if (editStatus) {\n                  newStatus = await masto.v1.statuses\n                    .$select(editStatus.id)\n                    .update(params);\n                  saveStatus(newStatus, instance, {\n                    skipThreading: true,\n                  });\n                } else {\n                  try {\n                    newStatus = await masto.v1.statuses.create(params, {\n                      requestInit: {\n                        headers: {\n                          'Idempotency-Key': UID.current,\n                        },\n                      },\n                    });\n                  } catch (_) {\n                    // If idempotency key fails, try again without it\n                    newStatus = await masto.v1.statuses.create(params);\n                  }\n                }\n                states.composerState.minimized = false;\n                states.composerState.publishing = false;\n                setUIState('default');\n\n                // Close\n                onClose({\n                  // type: post, reply, edit\n                  type: editStatus ? 'edit' : replyToStatus ? 'reply' : 'post',\n                  newStatus,\n                  instance,\n                });\n              } catch (e) {\n                states.composerState.publishing = false;\n                states.composerState.publishingError = true;\n                console.error(e);\n                alert(e?.reason || e);\n                setUIState('error');\n              }\n            })();\n          }}\n        >\n          <div class=\"toolbar stretch\">\n            <input\n              ref={spoilerTextRef}\n              type=\"text\"\n              name=\"spoilerText\"\n              placeholder={t`Content warning`}\n              disabled={uiState === 'loading'}\n              class=\"spoiler-text-field\"\n              lang={language}\n              spellCheck=\"true\"\n              dir=\"auto\"\n              style={{\n                opacity: sensitive ? 1 : 0,\n                pointerEvents: sensitive ? 'auto' : 'none',\n              }}\n              onInput={() => {\n                updateCharCount();\n              }}\n            />\n            <label\n              class={`toolbar-button ${sensitive ? 'highlight' : ''}`}\n              title={t`Content warning or sensitive media`}\n            >\n              <input\n                name=\"sensitive\"\n                type=\"checkbox\"\n                checked={sensitive}\n                disabled={uiState === 'loading'}\n                onChange={(e) => {\n                  const sensitive = e.target.checked;\n                  setSensitive(sensitive);\n                  if (sensitive) {\n                    spoilerTextRef.current?.focus();\n                  } else {\n                    textareaRef.current?.focus();\n                  }\n                }}\n              />\n              <Icon icon={`eye-${sensitive ? 'close' : 'open'}`} />\n            </label>{' '}\n            <label\n              class={`toolbar-button ${\n                visibility !== 'public' && !sensitive ? 'show-field' : ''\n              } ${visibility !== 'public' ? 'highlight' : ''}`}\n              title={visibility}\n            >\n              <Icon icon={visibilityIconsMap[visibility]} alt={visibility} />\n              <select\n                name=\"visibility\"\n                value={visibility}\n                onChange={(e) => {\n                  setVisibility(e.target.value);\n                }}\n                disabled={uiState === 'loading' || !!editStatus}\n                dir=\"auto\"\n              >\n                <option value=\"public\">\n                  <Trans>Public</Trans>\n                </option>\n                {(supports('@pleroma/local-visibility-post') ||\n                  supports('@akkoma/local-visibility-post')) && (\n                  <option value=\"local\">\n                    <Trans>Local</Trans>\n                  </option>\n                )}\n                <option value=\"unlisted\">\n                  <Trans>Unlisted</Trans>\n                </option>\n                <option value=\"private\">\n                  <Trans>Followers only</Trans>\n                </option>\n                <option value=\"direct\">\n                  <Trans>Private mention</Trans>\n                </option>\n              </select>\n            </label>{' '}\n          </div>\n          <Textarea\n            ref={textareaRef}\n            placeholder={\n              replyToStatus\n                ? t`Post your reply`\n                : editStatus\n                  ? t`Edit your post`\n                  : t`What are you doing?`\n            }\n            required={mediaAttachments?.length === 0}\n            disabled={uiState === 'loading'}\n            lang={language}\n            onInput={() => {\n              updateCharCount();\n            }}\n            maxCharacters={maxCharacters}\n            performSearch={(params) => {\n              const { type, q, limit } = params;\n              if (type === 'accounts') {\n                return masto.v1.accounts.search.list({\n                  q,\n                  limit,\n                  resolve: false,\n                });\n              }\n              return masto.v2.search.fetch(params);\n            }}\n            onTrigger={(action) => {\n              if (action?.name === 'custom-emojis') {\n                setShowEmoji2Picker({\n                  defaultSearchTerm: action?.defaultSearchTerm || null,\n                });\n              } else if (action?.name === 'mention') {\n                setShowMentionPicker({\n                  defaultSearchTerm: action?.defaultSearchTerm || null,\n                });\n              } else if (\n                action?.name === 'auto-detect-language' &&\n                action?.languages\n              ) {\n                setAutoDetectedLanguages(action.languages);\n              }\n            }}\n          />\n          {mediaAttachments?.length > 0 && (\n            <div class=\"media-attachments\">\n              {mediaAttachments.map((attachment, i) => {\n                const { id, file } = attachment;\n                const fileID = file?.size + file?.type + file?.name;\n                return (\n                  <MediaAttachment\n                    key={id || fileID || i}\n                    attachment={attachment}\n                    disabled={uiState === 'loading'}\n                    lang={language}\n                    onDescriptionChange={(value) => {\n                      setMediaAttachments((attachments) => {\n                        const newAttachments = [...attachments];\n                        newAttachments[i] = {\n                          ...newAttachments[i],\n                          description: value,\n                        };\n                        return newAttachments;\n                      });\n                    }}\n                    onRemove={() => {\n                      setMediaAttachments((attachments) => {\n                        return attachments.filter((_, j) => j !== i);\n                      });\n                    }}\n                  />\n                );\n              })}\n              <label class=\"media-sensitive\">\n                <input\n                  name=\"sensitive\"\n                  type=\"checkbox\"\n                  checked={sensitive}\n                  disabled={uiState === 'loading'}\n                  onChange={(e) => {\n                    const sensitive = e.target.checked;\n                    setSensitive(sensitive);\n                  }}\n                />{' '}\n                <span>\n                  <Trans>Mark media as sensitive</Trans>\n                </span>{' '}\n                <Icon icon={`eye-${sensitive ? 'close' : 'open'}`} />\n              </label>\n            </div>\n          )}\n          {!!poll && (\n            <Poll\n              lang={language}\n              maxOptions={maxOptions}\n              maxExpiration={maxExpiration}\n              minExpiration={minExpiration}\n              maxCharactersPerOption={maxCharactersPerOption}\n              poll={poll}\n              disabled={uiState === 'loading'}\n              onInput={(poll) => {\n                if (poll) {\n                  const newPoll = { ...poll };\n                  setPoll(newPoll);\n                } else {\n                  setPoll(null);\n                }\n              }}\n            />\n          )}\n          <div class=\"toolbar compose-footer\">\n            <span class=\"add-toolbar-button-group spacer\">\n              {showAddButton && (\n                <Menu2\n                  portal={{\n                    target: document.body,\n                  }}\n                  containerProps={{\n                    style: {\n                      zIndex: 1001,\n                    },\n                  }}\n                  menuButton={({ open }) => (\n                    <button\n                      type=\"button\"\n                      class={`toolbar-button add-button ${\n                        open ? 'active' : ''\n                      }`}\n                    >\n                      <Icon icon=\"plus\" title={t`Add`} />\n                    </button>\n                  )}\n                >\n                  <MenuItem className=\"compose-menu-add-media\">\n                    <label class=\"compose-menu-add-media-field\">\n                      <FilePickerInput\n                        hidden\n                        supportedMimeTypes={supportedMimeTypes}\n                        maxMediaAttachments={maxMediaAttachments}\n                        mediaAttachments={mediaAttachments}\n                        disabled={\n                          uiState === 'loading' ||\n                          mediaAttachments.length >= maxMediaAttachments ||\n                          !!poll\n                        }\n                        setMediaAttachments={setMediaAttachments}\n                      />\n                    </label>\n                    <Icon icon=\"media\" /> <span>{_(ADD_LABELS.media)}</span>\n                  </MenuItem>\n                  <MenuItem\n                    onClick={() => {\n                      setShowEmoji2Picker(true);\n                    }}\n                  >\n                    <Icon icon=\"emoji2\" />{' '}\n                    <span>{_(ADD_LABELS.customEmoji)}</span>\n                  </MenuItem>\n                  {!!states.settings.composerGIFPicker && (\n                    <MenuItem\n                      disabled={gifPickerDisabled}\n                      onClick={() => {\n                        setShowGIFPicker(true);\n                      }}\n                    >\n                      <span class=\"icon icon-gif\" role=\"img\" />\n                      <span>{_(ADD_LABELS.gif)}</span>\n                    </MenuItem>\n                  )}\n                  <MenuItem\n                    disabled={pollButtonDisabled}\n                    onClick={onPollButtonClick}\n                  >\n                    <Icon icon=\"poll\" /> <span>{_(ADD_LABELS.poll)}</span>\n                  </MenuItem>\n                </Menu2>\n              )}\n              <span class=\"add-sub-toolbar-button-group\" ref={addSubToolbarRef}>\n                <label class=\"toolbar-button\">\n                  <FilePickerInput\n                    supportedMimeTypes={supportedMimeTypes}\n                    maxMediaAttachments={maxMediaAttachments}\n                    mediaAttachments={mediaAttachments}\n                    disabled={\n                      uiState === 'loading' ||\n                      mediaAttachments.length >= maxMediaAttachments ||\n                      !!poll\n                    }\n                    setMediaAttachments={setMediaAttachments}\n                  />\n                  <Icon icon=\"media\" alt={_(ADD_LABELS.media)} />\n                </label>\n                {/* <button\n                type=\"button\"\n                class=\"toolbar-button\"\n                disabled={uiState === 'loading'}\n                onClick={() => {\n                  setShowMentionPicker(true);\n                }}\n              >\n                <Icon icon=\"at\" />\n              </button> */}\n                <button\n                  type=\"button\"\n                  class=\"toolbar-button\"\n                  disabled={uiState === 'loading'}\n                  onClick={() => {\n                    setShowEmoji2Picker(true);\n                  }}\n                >\n                  <Icon icon=\"emoji2\" alt={_(ADD_LABELS.customEmoji)} />\n                </button>\n                {!!states.settings.composerGIFPicker && (\n                  <button\n                    type=\"button\"\n                    class=\"toolbar-button gif-picker-button\"\n                    disabled={gifPickerDisabled}\n                    onClick={() => {\n                      setShowGIFPicker(true);\n                    }}\n                  >\n                    <span\n                      class=\"icon icon-gif\"\n                      aria-label={_(ADD_LABELS.gif)}\n                    />\n                  </button>\n                )}\n                {}\n                {showPollButton && (\n                  <>\n                    <button\n                      type=\"button\"\n                      class=\"toolbar-button\"\n                      disabled={pollButtonDisabled}\n                      onClick={onPollButtonClick}\n                    >\n                      <Icon icon=\"poll\" alt={_(ADD_LABELS.poll)} />\n                    </button>\n                  </>\n                )}\n              </span>\n            </span>\n            {/* <div class=\"spacer\" /> */}\n            {uiState === 'loading' ? (\n              <Loader abrupt />\n            ) : (\n              <CharCountMeter\n                maxCharacters={maxCharacters}\n                hidden={uiState === 'loading'}\n              />\n            )}\n            <label\n              class={`toolbar-button ${\n                language !== prevLanguage.current ||\n                (autoDetectedLanguages?.length &&\n                  !autoDetectedLanguages.includes(language))\n                  ? 'highlight'\n                  : ''\n              }`}\n            >\n              <span class=\"icon-text\">\n                {supportedLanguagesMap[language]?.native}\n              </span>\n              <select\n                name=\"language\"\n                value={language}\n                onChange={(e) => {\n                  const { value } = e.target;\n                  setLanguage(value || DEFAULT_LANG);\n                  store.session.set('currentLanguage', value || DEFAULT_LANG);\n                }}\n                disabled={uiState === 'loading'}\n                dir=\"auto\"\n              >\n                {topSupportedLanguages.map(([code, common, native]) => {\n                  const commonText = localeCode2Text({\n                    code,\n                    fallback: common,\n                  });\n                  const showCommon = commonText !== native;\n                  return (\n                    <option value={code} key={code}>\n                      {showCommon ? `${native} - ${commonText}` : commonText}\n                    </option>\n                  );\n                })}\n                <hr />\n                {restSupportedLanguages.map(([code, common, native]) => {\n                  const commonText = localeCode2Text({\n                    code,\n                    fallback: common,\n                  });\n                  const showCommon = commonText !== native;\n                  return (\n                    <option value={code} key={code}>\n                      {showCommon ? `${native} - ${commonText}` : commonText}\n                    </option>\n                  );\n                })}\n              </select>\n            </label>{' '}\n            <button type=\"submit\" disabled={uiState === 'loading'}>\n              {replyToStatus\n                ? t`Reply`\n                : editStatus\n                  ? t`Update`\n                  : t({\n                      message: 'Post',\n                      context: 'Submit button in composer',\n                    })}\n            </button>\n          </div>\n        </form>\n      </div>\n      {showMentionPicker && (\n        <Modal\n          onClick={(e) => {\n            if (e.target === e.currentTarget) {\n              setShowMentionPicker(false);\n            }\n          }}\n        >\n          <MentionModal\n            masto={masto}\n            instance={instance}\n            onClose={() => {\n              setShowMentionPicker(false);\n            }}\n            defaultSearchTerm={showMentionPicker?.defaultSearchTerm}\n            onSelect={(socialAddress) => {\n              const textarea = textareaRef.current;\n              if (!textarea) return;\n              const { selectionStart, selectionEnd } = textarea;\n              const text = textarea.value;\n              const textBeforeMention = text.slice(0, selectionStart);\n              const spaceBeforeMention = textBeforeMention\n                ? /[\\s\\t\\n\\r]$/.test(textBeforeMention)\n                  ? ''\n                  : ' '\n                : '';\n              const textAfterMention = text.slice(selectionEnd);\n              const spaceAfterMention = /^[\\s\\t\\n\\r]/.test(textAfterMention)\n                ? ''\n                : ' ';\n              const newText =\n                textBeforeMention +\n                spaceBeforeMention +\n                '@' +\n                socialAddress +\n                spaceAfterMention +\n                textAfterMention;\n              textarea.value = newText;\n              textarea.selectionStart = textarea.selectionEnd =\n                selectionEnd +\n                1 +\n                socialAddress.length +\n                spaceAfterMention.length;\n              textarea.focus();\n              textarea.dispatchEvent(new Event('input'));\n            }}\n          />\n        </Modal>\n      )}\n      {showEmoji2Picker && (\n        <Modal\n          onClick={(e) => {\n            if (e.target === e.currentTarget) {\n              setShowEmoji2Picker(false);\n            }\n          }}\n        >\n          <CustomEmojisModal\n            masto={masto}\n            instance={instance}\n            onClose={() => {\n              setShowEmoji2Picker(false);\n            }}\n            defaultSearchTerm={showEmoji2Picker?.defaultSearchTerm}\n            onSelect={(emojiShortcode) => {\n              const textarea = textareaRef.current;\n              if (!textarea) return;\n              const { selectionStart, selectionEnd } = textarea;\n              const text = textarea.value;\n              const textBeforeEmoji = text.slice(0, selectionStart);\n              const spaceBeforeEmoji = textBeforeEmoji\n                ? /[\\s\\t\\n\\r]$/.test(textBeforeEmoji)\n                  ? ''\n                  : ' '\n                : '';\n              const textAfterEmoji = text.slice(selectionEnd);\n              const spaceAfterEmoji = /^[\\s\\t\\n\\r]/.test(textAfterEmoji)\n                ? ''\n                : ' ';\n              const newText =\n                textBeforeEmoji +\n                spaceBeforeEmoji +\n                emojiShortcode +\n                spaceAfterEmoji +\n                textAfterEmoji;\n              textarea.value = newText;\n              textarea.selectionStart = textarea.selectionEnd =\n                selectionEnd + emojiShortcode.length + spaceAfterEmoji.length;\n              textarea.focus();\n              textarea.dispatchEvent(new Event('input'));\n            }}\n          />\n        </Modal>\n      )}\n      {showGIFPicker && (\n        <Modal\n          onClick={(e) => {\n            if (e.target === e.currentTarget) {\n              setShowGIFPicker(false);\n            }\n          }}\n        >\n          <GIFPickerModal\n            onClose={() => setShowGIFPicker(false)}\n            onSelect={({ url, type, alt_text }) => {\n              console.log('GIF URL', url);\n              if (mediaAttachments.length >= maxMediaAttachments) {\n                alert(\n                  plural(maxMediaAttachments, {\n                    one: 'You can only attach up to 1 file.',\n                    other: 'You can only attach up to # files.',\n                  }),\n                );\n                return;\n              }\n              // Download the GIF and insert it as media attachment\n              (async () => {\n                let theToast;\n                try {\n                  theToast = showToast({\n                    text: t`Downloading GIF…`,\n                    duration: -1,\n                  });\n                  const blob = await fetch(url, {\n                    referrerPolicy: 'no-referrer',\n                  }).then((res) => res.blob());\n                  const file = new File(\n                    [blob],\n                    type === 'video/mp4' ? 'video.mp4' : 'image.gif',\n                    {\n                      type,\n                    },\n                  );\n                  const newMediaAttachments = [\n                    ...mediaAttachments,\n                    {\n                      file,\n                      type,\n                      size: file.size,\n                      id: null,\n                      description: alt_text || '',\n                    },\n                  ];\n                  setMediaAttachments(newMediaAttachments);\n                  theToast?.hideToast?.();\n                } catch (err) {\n                  console.error(err);\n                  theToast?.hideToast?.();\n                  showToast(t`Failed to download GIF`);\n                }\n              })();\n            }}\n          />\n        </Modal>\n      )}\n    </div>\n  );\n}\n\nfunction FilePickerInput({\n  hidden,\n  supportedMimeTypes,\n  maxMediaAttachments,\n  mediaAttachments,\n  disabled = false,\n  setMediaAttachments,\n}) {\n  return (\n    <input\n      type=\"file\"\n      hidden={hidden}\n      accept={supportedMimeTypes?.join(',')}\n      multiple={\n        maxMediaAttachments === undefined ||\n        maxMediaAttachments - mediaAttachments >= 2\n      }\n      disabled={disabled}\n      onChange={(e) => {\n        const files = e.target.files;\n        if (!files) return;\n\n        const mediaFiles = Array.from(files).map((file) => ({\n          file,\n          type: file.type,\n          size: file.size,\n          url: URL.createObjectURL(file),\n          id: null, // indicate uploaded state\n          description: null,\n        }));\n        console.log('MEDIA ATTACHMENTS', files, mediaFiles);\n\n        // Validate max media attachments\n        if (mediaAttachments.length + mediaFiles.length > maxMediaAttachments) {\n          alert(\n            plural(maxMediaAttachments, {\n              one: 'You can only attach up to 1 file.',\n              other: 'You can only attach up to # files.',\n            }),\n          );\n        } else {\n          setMediaAttachments((attachments) => {\n            return attachments.concat(mediaFiles);\n          });\n        }\n        // Reset\n        e.target.value = '';\n      }}\n    />\n  );\n}\n\nfunction autoResizeTextarea(textarea) {\n  if (!textarea) return;\n  const { value, offsetHeight, scrollHeight, clientHeight } = textarea;\n  if (offsetHeight < window.innerHeight) {\n    // NOTE: This check is needed because the offsetHeight return 50000 (really large number) on first render\n    // No idea why it does that, will re-investigate in far future\n    const offset = offsetHeight - clientHeight;\n    const height = value ? scrollHeight + offset + 'px' : null;\n    textarea.style.height = height;\n  }\n}\n\nasync function _getCustomEmojis(instance, masto) {\n  const emojis = await masto.v1.customEmojis.list();\n  const visibleEmojis = emojis.filter((e) => e.visibleInPicker);\n  const searcher = new Fuse(visibleEmojis, {\n    keys: ['shortcode'],\n    findAllMatches: true,\n  });\n  return [visibleEmojis, searcher];\n}\nconst getCustomEmojis = pmem(_getCustomEmojis, {\n  // Limit by time to reduce memory usage\n  // Cached by instance\n  matchesArg: (cacheKeyArg, keyArg) => cacheKeyArg.instance === keyArg.instance,\n  maxAge: 30 * 60 * 1000, // 30 minutes\n});\n\nconst detectLangs = async (text) => {\n  const { detectAll } = await import('tinyld/light');\n  const langs = detectAll(text);\n  if (langs?.length) {\n    // return max 2\n    return langs.slice(0, 2).map((lang) => lang.lang);\n  }\n  return null;\n};\n\nconst Textarea = forwardRef((props, ref) => {\n  const { t } = useLingui();\n  const { masto, instance } = api();\n  const [text, setText] = useState(ref.current?.value || '');\n  const {\n    maxCharacters,\n    performSearch = () => {},\n    onTrigger = () => {},\n    ...textareaProps\n  } = props;\n  // const snapStates = useSnapshot(states);\n  // const charCount = snapStates.composerCharacterCount;\n\n  // const customEmojis = useRef();\n  const searcherRef = useRef();\n  useEffect(() => {\n    getCustomEmojis(instance, masto)\n      .then((r) => {\n        const [emojis, searcher] = r;\n        searcherRef.current = searcher;\n      })\n      .catch((e) => {\n        console.error(e);\n      });\n  }, []);\n\n  const textExpanderRef = useRef();\n  const textExpanderTextRef = useRef('');\n  const hasTextExpanderRef = useRef(false);\n  useEffect(() => {\n    let handleChange,\n      handleValue,\n      handleCommited,\n      handleActivate,\n      handleDeactivate;\n    if (textExpanderRef.current) {\n      handleChange = (e) => {\n        // console.log('text-expander-change', e);\n        const { key, provide, text } = e.detail;\n        textExpanderTextRef.current = text;\n\n        if (text === '') {\n          provide(\n            Promise.resolve({\n              matched: false,\n            }),\n          );\n          return;\n        }\n\n        if (key === ':') {\n          // const emojis = customEmojis.current.filter((emoji) =>\n          //   emoji.shortcode.startsWith(text),\n          // );\n          // const emojis = filterShortcodes(customEmojis.current, text);\n          const results = searcherRef.current?.search(text, {\n            limit: 5,\n          });\n          let html = '';\n          results.forEach(({ item: emoji }) => {\n            const { shortcode, url } = emoji;\n            html += `\n                <li role=\"option\" data-value=\"${encodeHTML(shortcode)}\">\n                <img src=\"${encodeHTML(\n                  url,\n                )}\" width=\"16\" height=\"16\" alt=\"\" loading=\"lazy\" /> \n                ${encodeHTML(shortcode)}\n              </li>`;\n          });\n          html += `<li role=\"option\" data-value=\"\" data-more=\"${text}\">${t`More…`}</li>`;\n          // console.log({ emojis, html });\n          menu.innerHTML = html;\n          provide(\n            Promise.resolve({\n              matched: results.length > 0,\n              fragment: menu,\n            }),\n          );\n          return;\n        }\n\n        const type = {\n          '@': 'accounts',\n          '#': 'hashtags',\n        }[key];\n        provide(\n          new Promise((resolve) => {\n            const searchResults = performSearch({\n              type,\n              q: text,\n              limit: 5,\n            });\n            searchResults.then((value) => {\n              if (text !== textExpanderTextRef.current) {\n                return;\n              }\n              console.log({ value, type, v: value[type] });\n              const results = value[type] || value;\n              console.log('RESULTS', value, results);\n              let html = '';\n              results.forEach((result) => {\n                const {\n                  name,\n                  avatarStatic,\n                  displayName,\n                  username,\n                  acct,\n                  emojis,\n                  history,\n                } = result;\n                const displayNameWithEmoji = emojifyText(displayName, emojis);\n                // const item = menuItem.cloneNode();\n                if (acct) {\n                  html += `\n                    <li role=\"option\" data-value=\"${encodeHTML(acct)}\">\n                      <span class=\"avatar\">\n                        <img src=\"${encodeHTML(\n                          avatarStatic,\n                        )}\" width=\"16\" height=\"16\" alt=\"\" loading=\"lazy\" />\n                      </span>\n                      <span>\n                        <b>${displayNameWithEmoji || username}</b>\n                        <br><span class=\"bidi-isolate\">@${encodeHTML(\n                          acct,\n                        )}</span>\n                      </span>\n                    </li>\n                  `;\n                } else {\n                  const total = history?.reduce?.(\n                    (acc, cur) => acc + +cur.uses,\n                    0,\n                  );\n                  html += `\n                    <li role=\"option\" data-value=\"${encodeHTML(name)}\">\n                      <span class=\"grow\">#<b>${encodeHTML(name)}</b></span>\n                      ${\n                        total\n                          ? `<span class=\"count\">${shortenNumber(total)}</span>`\n                          : ''\n                      }\n                    </li>\n                  `;\n                }\n              });\n              if (type === 'accounts') {\n                html += `<li role=\"option\" data-value=\"\" data-more=\"${text}\">${t`More…`}</li>`;\n              }\n              menu.innerHTML = html;\n              console.log('MENU', results, menu);\n              resolve({\n                matched: results.length > 0,\n                fragment: menu,\n              });\n            });\n          }),\n        );\n      };\n\n      textExpanderRef.current.addEventListener(\n        'text-expander-change',\n        handleChange,\n      );\n\n      handleValue = (e) => {\n        const { key, item } = e.detail;\n        const { value, more } = item.dataset;\n        if (key === ':') {\n          e.detail.value = value ? `:${value}:` : '​'; // zero-width space\n          if (more) {\n            // Prevent adding space after the above value\n            e.detail.continue = true;\n\n            setTimeout(() => {\n              onTrigger?.({\n                name: 'custom-emojis',\n                defaultSearchTerm: more,\n              });\n            }, 300);\n          }\n        } else if (key === '@') {\n          e.detail.value = value ? `@${value} ` : '​'; // zero-width space\n          if (more) {\n            e.detail.continue = true;\n            setTimeout(() => {\n              onTrigger?.({\n                name: 'mention',\n                defaultSearchTerm: more,\n              });\n            }, 300);\n          }\n        } else {\n          e.detail.value = `${key}${value}`;\n        }\n      };\n\n      textExpanderRef.current.addEventListener(\n        'text-expander-value',\n        handleValue,\n      );\n\n      handleCommited = (e) => {\n        const { input } = e.detail;\n        setText(input.value);\n        // fire input event\n        if (ref.current) {\n          const event = new Event('input', { bubbles: true });\n          ref.current.dispatchEvent(event);\n        }\n      };\n\n      textExpanderRef.current.addEventListener(\n        'text-expander-committed',\n        handleCommited,\n      );\n\n      handleActivate = () => {\n        hasTextExpanderRef.current = true;\n      };\n\n      textExpanderRef.current.addEventListener(\n        'text-expander-activate',\n        handleActivate,\n      );\n\n      handleDeactivate = () => {\n        hasTextExpanderRef.current = false;\n      };\n\n      textExpanderRef.current.addEventListener(\n        'text-expander-deactivate',\n        handleDeactivate,\n      );\n    }\n\n    return () => {\n      if (textExpanderRef.current) {\n        textExpanderRef.current.removeEventListener(\n          'text-expander-change',\n          handleChange,\n        );\n        textExpanderRef.current.removeEventListener(\n          'text-expander-value',\n          handleValue,\n        );\n        textExpanderRef.current.removeEventListener(\n          'text-expander-committed',\n          handleCommited,\n        );\n        textExpanderRef.current.removeEventListener(\n          'text-expander-activate',\n          handleActivate,\n        );\n        textExpanderRef.current.removeEventListener(\n          'text-expander-deactivate',\n          handleDeactivate,\n        );\n      }\n    };\n  }, []);\n\n  useEffect(() => {\n    // Resize observer for textarea\n    const textarea = ref.current;\n    if (!textarea) return;\n    const resizeObserver = new ResizeObserver(() => {\n      // Get height of textarea, set height to textExpander\n      if (textExpanderRef.current) {\n        const { height } = textarea.getBoundingClientRect();\n        textExpanderRef.current.style.height = height + 'px';\n      }\n    });\n    resizeObserver.observe(textarea);\n  }, []);\n\n  const slowHighlightPerf = useRef(0); // increment if slow\n  const composeHighlightRef = useRef();\n  const throttleHighlightText = useThrottledCallback((text) => {\n    if (!composeHighlightRef.current) return;\n    if (slowHighlightPerf.current > 3) {\n      // After 3 times of lag, disable highlighting\n      composeHighlightRef.current.innerHTML = '';\n      composeHighlightRef.current = null; // Destroy the whole thing\n      throttleHighlightText?.cancel?.();\n      return;\n    }\n    let start;\n    let end;\n    if (slowHighlightPerf.current <= 3) start = Date.now();\n    composeHighlightRef.current.innerHTML =\n      highlightText(text, {\n        maxCharacters,\n      }) + '\\n';\n    if (slowHighlightPerf.current <= 3) end = Date.now();\n    console.debug('HIGHLIGHT PERF', { start, end, diff: end - start });\n    if (start && end && end - start > 50) {\n      // if slow, increment\n      slowHighlightPerf.current++;\n    }\n    // Newline to prevent multiple line breaks at the end from being collapsed, no idea why\n  }, 500);\n\n  const debouncedAutoDetectLanguage = useDebouncedCallback(() => {\n    // Make use of the highlightRef to get the DOM\n    // Clone the dom\n    const dom = composeHighlightRef.current?.cloneNode(true);\n    if (!dom) return;\n    // Remove mark\n    dom.querySelectorAll('mark').forEach((mark) => {\n      mark.remove();\n    });\n    const text = dom.innerText?.trim();\n    if (!text) return;\n    (async () => {\n      const langs = await detectLangs(text);\n      if (langs?.length) {\n        onTrigger?.({\n          name: 'auto-detect-language',\n          languages: langs,\n        });\n      }\n    })();\n  }, 2000);\n\n  return (\n    <text-expander\n      ref={textExpanderRef}\n      keys=\"@ # :\"\n      class=\"compose-field-container\"\n    >\n      <textarea\n        class=\"compose-field\"\n        autoCapitalize=\"sentences\"\n        autoComplete=\"on\"\n        autoCorrect=\"on\"\n        spellCheck=\"true\"\n        dir=\"auto\"\n        rows=\"6\"\n        cols=\"50\"\n        {...textareaProps}\n        ref={ref}\n        name=\"status\"\n        value={text}\n        onKeyDown={(e) => {\n          // Get line before cursor position after pressing 'Enter'\n          const { key, target } = e;\n          const hasTextExpander = hasTextExpanderRef.current;\n          if (key === 'Enter' && !(e.ctrlKey || e.metaKey || hasTextExpander)) {\n            try {\n              const { value, selectionStart } = target;\n              const textBeforeCursor = value.slice(0, selectionStart);\n              const lastLine = textBeforeCursor.split('\\n').slice(-1)[0];\n              if (lastLine) {\n                // If line starts with \"- \" or \"12. \"\n                if (/^\\s*(-|\\d+\\.)\\s/.test(lastLine)) {\n                  // insert \"- \" at cursor position\n                  const [_, preSpaces, bullet, postSpaces, anything] =\n                    lastLine.match(/^(\\s*)(-|\\d+\\.)(\\s+)(.+)?/) || [];\n                  if (anything) {\n                    e.preventDefault();\n                    const [number] = bullet.match(/\\d+/) || [];\n                    const newBullet = number ? `${+number + 1}.` : '-';\n                    const text = `\\n${preSpaces}${newBullet}${postSpaces}`;\n                    target.setRangeText(text, selectionStart, selectionStart);\n                    const pos = selectionStart + text.length;\n                    target.setSelectionRange(pos, pos);\n                  } else {\n                    // trim the line before the cursor, then insert new line\n                    const pos = selectionStart - lastLine.length;\n                    target.setRangeText('', pos, selectionStart);\n                  }\n                  autoResizeTextarea(target);\n                  target.dispatchEvent(new Event('input'));\n                }\n              }\n            } catch (e) {\n              // silent fail\n              console.error(e);\n            }\n          }\n          if (composeHighlightRef.current) {\n            composeHighlightRef.current.scrollTop = target.scrollTop;\n          }\n        }}\n        onInput={(e) => {\n          const { target } = e;\n          // Replace zero-width space\n          const text = target.value.replace(/\\u200b/g, '');\n          setText(text);\n          autoResizeTextarea(target);\n          props.onInput?.(e);\n          throttleHighlightText(text);\n          debouncedAutoDetectLanguage();\n        }}\n        style={{\n          width: '100%',\n          height: '4em',\n          // '--text-weight': (1 + charCount / 140).toFixed(1) || 1,\n        }}\n        onScroll={(e) => {\n          if (composeHighlightRef.current) {\n            const { scrollTop } = e.target;\n            composeHighlightRef.current.scrollTop = scrollTop;\n          }\n        }}\n      />\n      <div\n        ref={composeHighlightRef}\n        class=\"compose-highlight\"\n        aria-hidden=\"true\"\n      />\n    </text-expander>\n  );\n});\n\nfunction CharCountMeter({ maxCharacters = 500, hidden }) {\n  const snapStates = useSnapshot(states);\n  const charCount = snapStates.composerCharacterCount;\n  const leftChars = maxCharacters - charCount;\n  if (hidden) {\n    return <span class=\"char-counter\" hidden />;\n  }\n  return (\n    <span\n      class=\"char-counter\"\n      title={`${leftChars}/${maxCharacters}`}\n      style={{\n        '--percentage': (charCount / maxCharacters) * 100,\n      }}\n    >\n      <meter\n        class={`${\n          leftChars <= -10\n            ? 'explode'\n            : leftChars <= 0\n              ? 'danger'\n              : leftChars <= 20\n                ? 'warning'\n                : ''\n        }`}\n        value={charCount}\n        max={maxCharacters}\n      />\n      <span class=\"counter\">{leftChars}</span>\n    </span>\n  );\n}\n\nfunction scaleDimension(matrix, matrixLimit, width, height) {\n  // matrix = number of pixels\n  // matrixLimit = max number of pixels\n  // Calculate new width and height, downsize to within the limit, preserve aspect ratio, no decimals\n  const scalingFactor = Math.sqrt(matrixLimit / matrix);\n  const newWidth = Math.floor(width * scalingFactor);\n  const newHeight = Math.floor(height * scalingFactor);\n  return { newWidth, newHeight };\n}\n\nfunction MediaAttachment({\n  attachment,\n  disabled,\n  lang,\n  onDescriptionChange = () => {},\n  onRemove = () => {},\n}) {\n  const { i18n, t } = useLingui();\n  const [uiState, setUIState] = useState('default');\n  const supportsEdit = supports('@mastodon/edit-media-attributes');\n  const { type, id, file } = attachment;\n  const url = useMemo(\n    () => (file ? URL.createObjectURL(file) : attachment.url),\n    [file, attachment.url],\n  );\n  console.log({ attachment });\n\n  const checkMaxError = !!file?.size;\n  const configuration = checkMaxError ? getCurrentInstanceConfiguration() : {};\n  const {\n    mediaAttachments: {\n      imageSizeLimit,\n      imageMatrixLimit,\n      videoSizeLimit,\n      videoMatrixLimit,\n      videoFrameRateLimit,\n    } = {},\n  } = configuration || {};\n\n  const [maxError, setMaxError] = useState(() => {\n    if (!checkMaxError) return null;\n    if (\n      type.startsWith('image') &&\n      imageSizeLimit &&\n      file.size > imageSizeLimit\n    ) {\n      return {\n        type: 'imageSizeLimit',\n        details: {\n          imageSize: file.size,\n          imageSizeLimit,\n        },\n      };\n    } else if (\n      type.startsWith('video') &&\n      videoSizeLimit &&\n      file.size > videoSizeLimit\n    ) {\n      return {\n        type: 'videoSizeLimit',\n        details: {\n          videoSize: file.size,\n          videoSizeLimit,\n        },\n      };\n    }\n    return null;\n  });\n\n  const [imageMatrix, setImageMatrix] = useState({});\n  useEffect(() => {\n    if (!checkMaxError || !imageMatrixLimit) return;\n    if (imageMatrix?.matrix > imageMatrixLimit) {\n      setMaxError({\n        type: 'imageMatrixLimit',\n        details: {\n          imageMatrix: imageMatrix?.matrix,\n          imageMatrixLimit,\n          width: imageMatrix?.width,\n          height: imageMatrix?.height,\n        },\n      });\n    }\n  }, [imageMatrix, imageMatrixLimit, checkMaxError]);\n\n  const [videoMatrix, setVideoMatrix] = useState({});\n  useEffect(() => {\n    if (!checkMaxError || !videoMatrixLimit) return;\n    if (videoMatrix?.matrix > videoMatrixLimit) {\n      setMaxError({\n        type: 'videoMatrixLimit',\n        details: {\n          videoMatrix: videoMatrix?.matrix,\n          videoMatrixLimit,\n          width: videoMatrix?.width,\n          height: videoMatrix?.height,\n        },\n      });\n    }\n  }, [videoMatrix, videoMatrixLimit, checkMaxError]);\n\n  const [description, setDescription] = useState(attachment.description);\n  const [suffixType, subtype] = type.split('/');\n  const debouncedOnDescriptionChange = useDebouncedCallback(\n    onDescriptionChange,\n    250,\n  );\n  useEffect(() => {\n    debouncedOnDescriptionChange(description);\n  }, [description, debouncedOnDescriptionChange]);\n\n  const [showModal, setShowModal] = useState(false);\n  const textareaRef = useRef(null);\n  useEffect(() => {\n    let timer;\n    if (showModal && textareaRef.current) {\n      timer = setTimeout(() => {\n        textareaRef.current.focus();\n      }, 100);\n    }\n    return () => {\n      clearTimeout(timer);\n    };\n  }, [showModal]);\n\n  const descTextarea = (\n    <>\n      {!!id && !supportsEdit ? (\n        <div class=\"media-desc\">\n          <span class=\"tag\">\n            <Trans>Uploaded</Trans>\n          </span>\n          <p title={description}>\n            {attachment.description || <i>No description</i>}\n          </p>\n        </div>\n      ) : (\n        <textarea\n          ref={textareaRef}\n          value={description || ''}\n          lang={lang}\n          placeholder={\n            {\n              image: t`Image description`,\n              video: t`Video description`,\n              audio: t`Audio description`,\n            }[suffixType]\n          }\n          autoCapitalize=\"sentences\"\n          autoComplete=\"on\"\n          autoCorrect=\"on\"\n          spellCheck=\"true\"\n          dir=\"auto\"\n          disabled={disabled || uiState === 'loading'}\n          class={uiState === 'loading' ? 'loading' : ''}\n          maxlength=\"1500\" // Not unicode-aware :(\n          // TODO: Un-hard-code this maxlength, ref: https://github.com/mastodon/mastodon/blob/b59fb28e90bc21d6fd1a6bafd13cfbd81ab5be54/app/models/media_attachment.rb#L39\n          onInput={(e) => {\n            const { value } = e.target;\n            setDescription(value);\n            // debouncedOnDescriptionChange(value);\n          }}\n        ></textarea>\n      )}\n    </>\n  );\n\n  const toastRef = useRef(null);\n  useEffect(() => {\n    return () => {\n      toastRef.current?.hideToast?.();\n    };\n  }, []);\n\n  const maxErrorToast = useRef(null);\n\n  const maxErrorText = (err) => {\n    const { type, details } = err;\n    switch (type) {\n      case 'imageSizeLimit': {\n        const { imageSize, imageSizeLimit } = details;\n        return t`File size too large. Uploading might encounter issues. Try reduce the file size from ${prettyBytes(\n          imageSize,\n        )} to ${prettyBytes(imageSizeLimit)} or lower.`;\n      }\n      case 'imageMatrixLimit': {\n        const { imageMatrix, imageMatrixLimit, width, height } = details;\n        const { newWidth, newHeight } = scaleDimension(\n          imageMatrix,\n          imageMatrixLimit,\n          width,\n          height,\n        );\n        return t`Dimension too large. Uploading might encounter issues. Try reduce dimension from ${i18n.number(\n          width,\n        )}×${i18n.number(height)}px to ${i18n.number(newWidth)}×${i18n.number(\n          newHeight,\n        )}px.`;\n      }\n      case 'videoSizeLimit': {\n        const { videoSize, videoSizeLimit } = details;\n        return t`File size too large. Uploading might encounter issues. Try reduce the file size from ${prettyBytes(\n          videoSize,\n        )} to ${prettyBytes(videoSizeLimit)} or lower.`;\n      }\n      case 'videoMatrixLimit': {\n        const { videoMatrix, videoMatrixLimit, width, height } = details;\n        const { newWidth, newHeight } = scaleDimension(\n          videoMatrix,\n          videoMatrixLimit,\n          width,\n          height,\n        );\n        return t`Dimension too large. Uploading might encounter issues. Try reduce dimension from ${i18n.number(\n          width,\n        )}×${i18n.number(height)}px to ${i18n.number(newWidth)}×${i18n.number(\n          newHeight,\n        )}px.`;\n      }\n      case 'videoFrameRateLimit': {\n        // Not possible to detect this on client-side for now\n        return t`Frame rate too high. Uploading might encounter issues.`;\n      }\n    }\n  };\n\n  return (\n    <>\n      <div class=\"media-attachment\">\n        <div\n          class=\"media-preview\"\n          tabIndex=\"0\"\n          onClick={() => {\n            setShowModal(true);\n          }}\n        >\n          {suffixType === 'image' ? (\n            <img\n              src={url}\n              alt=\"\"\n              onLoad={(e) => {\n                if (!checkMaxError) return;\n                const { naturalWidth, naturalHeight } = e.target;\n                setImageMatrix({\n                  matrix: naturalWidth * naturalHeight,\n                  width: naturalWidth,\n                  height: naturalHeight,\n                });\n              }}\n            />\n          ) : suffixType === 'video' || suffixType === 'gifv' ? (\n            <video\n              src={url + '#t=0.1'} // Make Safari show 1st-frame preview\n              playsinline\n              muted\n              disablePictureInPicture\n              preload=\"metadata\"\n              onLoadedMetadata={(e) => {\n                if (!checkMaxError) return;\n                const { videoWidth, videoHeight } = e.target;\n                if (videoWidth && videoHeight) {\n                  setVideoMatrix({\n                    matrix: videoWidth * videoHeight,\n                    width: videoWidth,\n                    height: videoHeight,\n                  });\n                }\n              }}\n            />\n          ) : suffixType === 'audio' ? (\n            <audio src={url} controls />\n          ) : null}\n        </div>\n        {descTextarea}\n        <div class=\"media-aside\">\n          <button\n            type=\"button\"\n            class=\"plain close-button\"\n            disabled={disabled}\n            onClick={onRemove}\n          >\n            <Icon icon=\"x\" alt={t`Remove`} />\n          </button>\n          {!!maxError && (\n            <button\n              type=\"button\"\n              class=\"media-error\"\n              title={maxErrorText(maxError)}\n              onClick={() => {\n                if (maxErrorToast.current) {\n                  maxErrorToast.current.hideToast();\n                }\n                maxErrorToast.current = showToast({\n                  text: maxErrorText(maxError),\n                  duration: 10_000,\n                });\n              }}\n            >\n              <Icon icon=\"alert\" alt={t`Error`} />\n            </button>\n          )}\n        </div>\n      </div>\n      {showModal && (\n        <Modal\n          onClose={() => {\n            setShowModal(false);\n          }}\n        >\n          <div id=\"media-sheet\" class=\"sheet sheet-max\">\n            <button\n              type=\"button\"\n              class=\"sheet-close\"\n              onClick={() => {\n                setShowModal(false);\n              }}\n            >\n              <Icon icon=\"x\" alt={t`Close`} />\n            </button>\n            <header>\n              <h2>\n                {\n                  {\n                    image: t`Edit image description`,\n                    video: t`Edit video description`,\n                    audio: t`Edit audio description`,\n                  }[suffixType]\n                }\n              </h2>\n            </header>\n            <main tabIndex=\"-1\">\n              <div class=\"media-preview\">\n                {suffixType === 'image' ? (\n                  <img src={url} alt=\"\" />\n                ) : suffixType === 'video' || suffixType === 'gifv' ? (\n                  <video src={url} playsinline controls />\n                ) : suffixType === 'audio' ? (\n                  <audio src={url} controls />\n                ) : null}\n              </div>\n              <div class=\"media-form\">\n                {descTextarea}\n                <footer>\n                  {suffixType === 'image' &&\n                    /^(png|jpe?g|gif|webp)$/i.test(subtype) &&\n                    !!states.settings.mediaAltGenerator &&\n                    !!IMG_ALT_API_URL && (\n                      <Menu2\n                        portal={{\n                          target: document.body,\n                        }}\n                        containerProps={{\n                          style: {\n                            zIndex: 1001,\n                          },\n                        }}\n                        align=\"center\"\n                        position=\"anchor\"\n                        overflow=\"auto\"\n                        menuButton={\n                          <button type=\"button\" class=\"plain\">\n                            <Icon icon=\"more\" size=\"l\" alt={t`More`} />\n                          </button>\n                        }\n                      >\n                        <MenuItem\n                          disabled={uiState === 'loading'}\n                          onClick={() => {\n                            setUIState('loading');\n                            toastRef.current = showToast({\n                              text: t`Generating description. Please wait…`,\n                              duration: -1,\n                            });\n                            // POST with multipart\n                            (async function () {\n                              try {\n                                const body = new FormData();\n                                body.append('image', file);\n                                const response = await fetch(IMG_ALT_API_URL, {\n                                  method: 'POST',\n                                  body,\n                                }).then((r) => r.json());\n                                if (response.error) {\n                                  throw new Error(response.error);\n                                }\n                                setDescription(response.description);\n                              } catch (e) {\n                                console.error(e);\n                                showToast(\n                                  e.message\n                                    ? t`Failed to generate description: ${e.message}`\n                                    : t`Failed to generate description`,\n                                );\n                              } finally {\n                                setUIState('default');\n                                toastRef.current?.hideToast?.();\n                              }\n                            })();\n                          }}\n                        >\n                          <Icon icon=\"sparkles2\" />\n                          {lang && lang !== 'en' ? (\n                            <small>\n                              <Trans>Generate description…</Trans>\n                              <br />\n                              (English)\n                            </small>\n                          ) : (\n                            <span>\n                              <Trans>Generate description…</Trans>\n                            </span>\n                          )}\n                        </MenuItem>\n                        {!!lang && lang !== 'en' && (\n                          <MenuItem\n                            disabled={uiState === 'loading'}\n                            onClick={() => {\n                              setUIState('loading');\n                              toastRef.current = showToast({\n                                text: t`Generating description. Please wait…`,\n                                duration: -1,\n                              });\n                              // POST with multipart\n                              (async function () {\n                                try {\n                                  const body = new FormData();\n                                  body.append('image', file);\n                                  const params = `?lang=${lang}`;\n                                  const response = await fetch(\n                                    IMG_ALT_API_URL + params,\n                                    {\n                                      method: 'POST',\n                                      body,\n                                    },\n                                  ).then((r) => r.json());\n                                  if (response.error) {\n                                    throw new Error(response.error);\n                                  }\n                                  setDescription(response.description);\n                                } catch (e) {\n                                  console.error(e);\n                                  showToast(\n                                    t`Failed to generate description${\n                                      e?.message ? `: ${e.message}` : ''\n                                    }`,\n                                  );\n                                } finally {\n                                  setUIState('default');\n                                  toastRef.current?.hideToast?.();\n                                }\n                              })();\n                            }}\n                          >\n                            <Icon icon=\"sparkles2\" />\n                            <small>\n                              <Trans>Generate description…</Trans>\n                              <br />\n                              <Trans>\n                                ({localeCode2Text(lang)}){' '}\n                                <span class=\"more-insignificant\">\n                                  — experimental\n                                </span>\n                              </Trans>\n                            </small>\n                          </MenuItem>\n                        )}\n                      </Menu2>\n                    )}\n                  <button\n                    type=\"button\"\n                    class=\"light block\"\n                    onClick={() => {\n                      setShowModal(false);\n                    }}\n                    disabled={uiState === 'loading'}\n                  >\n                    <Trans>Done</Trans>\n                  </button>\n                </footer>\n              </div>\n            </main>\n          </div>\n        </Modal>\n      )}\n    </>\n  );\n}\n\nfunction Poll({\n  lang,\n  poll,\n  disabled,\n  onInput = () => {},\n  maxOptions,\n  maxExpiration,\n  minExpiration,\n  maxCharactersPerOption,\n}) {\n  const { t } = useLingui();\n  const { options, expiresIn, multiple } = poll;\n\n  return (\n    <div class={`poll ${multiple ? 'multiple' : ''}`}>\n      <div class=\"poll-choices\">\n        {options.map((option, i) => (\n          <div class=\"poll-choice\" key={i}>\n            <input\n              required\n              type=\"text\"\n              value={option}\n              disabled={disabled}\n              maxlength={maxCharactersPerOption}\n              placeholder={t`Choice ${i + 1}`}\n              lang={lang}\n              spellCheck=\"true\"\n              dir=\"auto\"\n              onInput={(e) => {\n                const { value } = e.target;\n                options[i] = value;\n                onInput(poll);\n              }}\n            />\n            <button\n              type=\"button\"\n              class=\"plain2 poll-button\"\n              disabled={disabled || options.length <= 1}\n              onClick={() => {\n                options.splice(i, 1);\n                onInput(poll);\n              }}\n            >\n              <Icon icon=\"x\" size=\"s\" alt={t`Remove`} />\n            </button>\n          </div>\n        ))}\n      </div>\n      <div class=\"poll-toolbar\">\n        <button\n          type=\"button\"\n          class=\"plain2 poll-button\"\n          disabled={disabled || options.length >= maxOptions}\n          onClick={() => {\n            options.push('');\n            onInput(poll);\n          }}\n        >\n          +\n        </button>{' '}\n        <label class=\"multiple-choices\">\n          <input\n            type=\"checkbox\"\n            checked={multiple}\n            disabled={disabled}\n            onChange={(e) => {\n              const { checked } = e.target;\n              poll.multiple = checked;\n              onInput(poll);\n            }}\n          />{' '}\n          <Trans>Multiple choices</Trans>\n        </label>\n        <label class=\"expires-in\">\n          <Trans>Duration</Trans>{' '}\n          <select\n            value={expiresIn}\n            disabled={disabled}\n            onChange={(e) => {\n              const { value } = e.target;\n              poll.expiresIn = value;\n              onInput(poll);\n            }}\n          >\n            {Object.entries(expiryOptions)\n              .filter(([value]) => {\n                return value >= minExpiration && value <= maxExpiration;\n              })\n              .map(([value, label]) => (\n                <option value={value} key={value}>\n                  {label()}\n                </option>\n              ))}\n          </select>\n        </label>\n      </div>\n      <div class=\"poll-toolbar\">\n        <button\n          type=\"button\"\n          class=\"plain remove-poll-button\"\n          disabled={disabled}\n          onClick={() => {\n            onInput(null);\n          }}\n        >\n          <Trans>Remove poll</Trans>\n        </button>\n      </div>\n    </div>\n  );\n}\n\nfunction filterShortcodes(emojis, searchTerm) {\n  searchTerm = searchTerm.toLowerCase();\n\n  // Return an array of shortcodes that start with or contain the search term, sorted by relevance and limited to the first 5\n  return emojis\n    .sort((a, b) => {\n      let aLower = a.shortcode.toLowerCase();\n      let bLower = b.shortcode.toLowerCase();\n\n      let aStartsWith = aLower.startsWith(searchTerm);\n      let bStartsWith = bLower.startsWith(searchTerm);\n      let aContains = aLower.includes(searchTerm);\n      let bContains = bLower.includes(searchTerm);\n      let bothStartWith = aStartsWith && bStartsWith;\n      let bothContain = aContains && bContains;\n\n      return bothStartWith\n        ? a.length - b.length\n        : aStartsWith\n          ? -1\n          : bStartsWith\n            ? 1\n            : bothContain\n              ? a.length - b.length\n              : aContains\n                ? -1\n                : bContains\n                  ? 1\n                  : 0;\n    })\n    .slice(0, 5);\n}\n\nfunction encodeHTML(str) {\n  return str.replace(/[&<>\"']/g, function (char) {\n    return '&#' + char.charCodeAt(0) + ';';\n  });\n}\n\nfunction removeNullUndefined(obj) {\n  for (let key in obj) {\n    if (obj[key] === null || obj[key] === undefined) {\n      delete obj[key];\n    }\n  }\n  return obj;\n}\n\nfunction MentionModal({\n  onClose = () => {},\n  onSelect = () => {},\n  defaultSearchTerm,\n}) {\n  const { t } = useLingui();\n  const { masto } = api();\n  const [uiState, setUIState] = useState('default');\n  const [accounts, setAccounts] = useState([]);\n  const [relationshipsMap, setRelationshipsMap] = useState({});\n\n  const [selectedIndex, setSelectedIndex] = useState(0);\n\n  const loadRelationships = async (accounts) => {\n    if (!accounts?.length) return;\n    const relationships = await fetchRelationships(accounts, relationshipsMap);\n    if (relationships) {\n      setRelationshipsMap({\n        ...relationshipsMap,\n        ...relationships,\n      });\n    }\n  };\n\n  const loadAccounts = (term) => {\n    if (!term) return;\n    setUIState('loading');\n    (async () => {\n      try {\n        const accounts = await masto.v1.accounts.search.list({\n          q: term,\n          limit: 40,\n          resolve: false,\n        });\n        setAccounts(accounts);\n        loadRelationships(accounts);\n        setUIState('default');\n      } catch (e) {\n        setUIState('error');\n        console.error(e);\n      }\n    })();\n  };\n\n  const debouncedLoadAccounts = useDebouncedCallback(loadAccounts, 1000);\n\n  useEffect(() => {\n    loadAccounts();\n  }, [loadAccounts]);\n\n  const inputRef = useRef();\n  useEffect(() => {\n    if (inputRef.current) {\n      inputRef.current.focus();\n      // Put cursor at the end\n      if (inputRef.current.value) {\n        inputRef.current.selectionStart = inputRef.current.value.length;\n        inputRef.current.selectionEnd = inputRef.current.value.length;\n      }\n    }\n  }, []);\n\n  useEffect(() => {\n    if (defaultSearchTerm) {\n      loadAccounts(defaultSearchTerm);\n    }\n  }, [defaultSearchTerm]);\n\n  const selectAccount = (account) => {\n    const socialAddress = account.acct;\n    onSelect(socialAddress);\n    onClose();\n  };\n\n  useHotkeys(\n    'enter',\n    () => {\n      const selectedAccount = accounts[selectedIndex];\n      if (selectedAccount) {\n        selectAccount(selectedAccount);\n      }\n    },\n    {\n      preventDefault: true,\n      enableOnFormTags: ['input'],\n    },\n  );\n\n  const listRef = useRef();\n  useHotkeys(\n    'down',\n    () => {\n      if (selectedIndex < accounts.length - 1) {\n        setSelectedIndex(selectedIndex + 1);\n      } else {\n        setSelectedIndex(0);\n      }\n      setTimeout(() => {\n        const selectedItem = listRef.current.querySelector('.selected');\n        if (selectedItem) {\n          selectedItem.scrollIntoView({\n            behavior: 'smooth',\n            block: 'center',\n            inline: 'center',\n          });\n        }\n      }, 1);\n    },\n    {\n      preventDefault: true,\n      enableOnFormTags: ['input'],\n    },\n  );\n\n  useHotkeys(\n    'up',\n    () => {\n      if (selectedIndex > 0) {\n        setSelectedIndex(selectedIndex - 1);\n      } else {\n        setSelectedIndex(accounts.length - 1);\n      }\n      setTimeout(() => {\n        const selectedItem = listRef.current.querySelector('.selected');\n        if (selectedItem) {\n          selectedItem.scrollIntoView({\n            behavior: 'smooth',\n            block: 'center',\n            inline: 'center',\n          });\n        }\n      }, 1);\n    },\n    {\n      preventDefault: true,\n      enableOnFormTags: ['input'],\n    },\n  );\n\n  return (\n    <div id=\"mention-sheet\" class=\"sheet\">\n      {!!onClose && (\n        <button type=\"button\" class=\"sheet-close\" onClick={onClose}>\n          <Icon icon=\"x\" alt={t`Close`} />\n        </button>\n      )}\n      <header>\n        <form\n          onSubmit={(e) => {\n            e.preventDefault();\n            debouncedLoadAccounts.flush?.();\n            // const searchTerm = inputRef.current.value;\n            // debouncedLoadAccounts(searchTerm);\n          }}\n        >\n          <input\n            ref={inputRef}\n            required\n            type=\"search\"\n            class=\"block\"\n            placeholder={t`Search accounts`}\n            onInput={(e) => {\n              const { value } = e.target;\n              debouncedLoadAccounts(value);\n            }}\n            autocomplete=\"off\"\n            autocorrect=\"off\"\n            autocapitalize=\"off\"\n            spellCheck=\"false\"\n            dir=\"auto\"\n            defaultValue={defaultSearchTerm || ''}\n          />\n        </form>\n      </header>\n      <main>\n        {accounts?.length > 0 ? (\n          <ul\n            ref={listRef}\n            class={`accounts-list ${uiState === 'loading' ? 'loading' : ''}`}\n          >\n            {accounts.map((account, i) => {\n              const relationship = relationshipsMap[account.id];\n              return (\n                <li\n                  key={account.id}\n                  class={i === selectedIndex ? 'selected' : ''}\n                >\n                  <AccountBlock\n                    avatarSize=\"xxl\"\n                    account={account}\n                    relationship={relationship}\n                    showStats\n                    showActivity\n                  />\n                  <button\n                    type=\"button\"\n                    class=\"plain2\"\n                    onClick={() => {\n                      selectAccount(account);\n                    }}\n                  >\n                    <Icon icon=\"plus\" size=\"xl\" alt={t`Add`} />\n                  </button>\n                </li>\n              );\n            })}\n          </ul>\n        ) : uiState === 'loading' ? (\n          <div class=\"ui-state\">\n            <Loader abrupt />\n          </div>\n        ) : uiState === 'error' ? (\n          <div class=\"ui-state\">\n            <p>\n              <Trans>Error loading accounts</Trans>\n            </p>\n          </div>\n        ) : null}\n      </main>\n    </div>\n  );\n}\n\nfunction CustomEmojisModal({\n  masto,\n  instance,\n  onClose = () => {},\n  onSelect = () => {},\n  defaultSearchTerm,\n}) {\n  const { t } = useLingui();\n  const [uiState, setUIState] = useState('default');\n  const customEmojisList = useRef([]);\n  const [customEmojis, setCustomEmojis] = useState([]);\n  const recentlyUsedCustomEmojis = useMemo(\n    () => store.account.get('recentlyUsedCustomEmojis') || [],\n  );\n  const searcherRef = useRef();\n  useEffect(() => {\n    setUIState('loading');\n    (async () => {\n      try {\n        const [emojis, searcher] = await getCustomEmojis(instance, masto);\n        console.log('emojis', emojis);\n        searcherRef.current = searcher;\n        setCustomEmojis(emojis);\n        setUIState('default');\n      } catch (e) {\n        setUIState('error');\n        console.error(e);\n      }\n    })();\n  }, []);\n\n  const customEmojisCatList = useMemo(() => {\n    // Group emojis by category\n    const emojisCat = {\n      '--recent--': recentlyUsedCustomEmojis.filter((emoji) =>\n        customEmojis.find((e) => e.shortcode === emoji.shortcode),\n      ),\n    };\n    const othersCat = [];\n    customEmojis.forEach((emoji) => {\n      customEmojisList.current?.push?.(emoji);\n      if (!emoji.category) {\n        othersCat.push(emoji);\n        return;\n      }\n      if (!emojisCat[emoji.category]) {\n        emojisCat[emoji.category] = [];\n      }\n      emojisCat[emoji.category].push(emoji);\n    });\n    if (othersCat.length) {\n      emojisCat['--others--'] = othersCat;\n    }\n    return emojisCat;\n  }, [customEmojis]);\n\n  const scrollableRef = useRef();\n  const [matches, setMatches] = useState(null);\n  const onFind = useCallback(\n    (e) => {\n      const { value } = e.target;\n      if (value) {\n        const results = searcherRef.current?.search(value, {\n          limit: CUSTOM_EMOJIS_COUNT,\n        });\n        setMatches(results.map((r) => r.item));\n        scrollableRef.current?.scrollTo?.(0, 0);\n      } else {\n        setMatches(null);\n      }\n    },\n    [customEmojis],\n  );\n  useEffect(() => {\n    if (defaultSearchTerm && customEmojis?.length) {\n      onFind({ target: { value: defaultSearchTerm } });\n    }\n  }, [defaultSearchTerm, onFind, customEmojis]);\n\n  const onSelectEmoji = useCallback(\n    (emoji) => {\n      onSelect?.(emoji);\n      onClose?.();\n\n      queueMicrotask(() => {\n        let recentlyUsedCustomEmojis =\n          store.account.get('recentlyUsedCustomEmojis') || [];\n        const recentlyUsedEmojiIndex = recentlyUsedCustomEmojis.findIndex(\n          (e) => e.shortcode === emoji.shortcode,\n        );\n        if (recentlyUsedEmojiIndex !== -1) {\n          // Move emoji to index 0\n          recentlyUsedCustomEmojis.splice(recentlyUsedEmojiIndex, 1);\n          recentlyUsedCustomEmojis.unshift(emoji);\n        } else {\n          recentlyUsedCustomEmojis.unshift(emoji);\n          // Remove unavailable ones\n          recentlyUsedCustomEmojis = recentlyUsedCustomEmojis.filter((e) =>\n            customEmojisList.current?.find?.(\n              (emoji) => emoji.shortcode === e.shortcode,\n            ),\n          );\n          // Limit to 10\n          recentlyUsedCustomEmojis = recentlyUsedCustomEmojis.slice(0, 10);\n        }\n\n        // Store back\n        store.account.set('recentlyUsedCustomEmojis', recentlyUsedCustomEmojis);\n      });\n    },\n    [onSelect],\n  );\n\n  const inputRef = useRef();\n  useEffect(() => {\n    if (inputRef.current) {\n      inputRef.current.focus();\n      // Put cursor at the end\n      if (inputRef.current.value) {\n        inputRef.current.selectionStart = inputRef.current.value.length;\n        inputRef.current.selectionEnd = inputRef.current.value.length;\n      }\n    }\n  }, []);\n\n  return (\n    <div id=\"custom-emojis-sheet\" class=\"sheet\">\n      {!!onClose && (\n        <button type=\"button\" class=\"sheet-close\" onClick={onClose}>\n          <Icon icon=\"x\" alt={t`Close`} />\n        </button>\n      )}\n      <header>\n        <div>\n          <b>\n            <Trans>Custom emojis</Trans>\n          </b>{' '}\n          {uiState === 'loading' ? (\n            <Loader />\n          ) : (\n            <small class=\"insignificant\"> • {instance}</small>\n          )}\n        </div>\n        <form\n          onSubmit={(e) => {\n            e.preventDefault();\n            const emoji = matches[0];\n            if (emoji) {\n              onSelectEmoji(`:${emoji.shortcode}:`);\n            }\n          }}\n        >\n          <input\n            ref={inputRef}\n            type=\"search\"\n            placeholder={t`Search emoji`}\n            onInput={onFind}\n            autocomplete=\"off\"\n            autocorrect=\"off\"\n            autocapitalize=\"off\"\n            spellCheck=\"false\"\n            dir=\"auto\"\n            defaultValue={defaultSearchTerm || ''}\n          />\n        </form>\n      </header>\n      <main ref={scrollableRef}>\n        {matches !== null ? (\n          <ul class=\"custom-emojis-matches custom-emojis-list\">\n            {matches.map((emoji) => (\n              <li key={emoji.shortcode} class=\"custom-emojis-match\">\n                <CustomEmojiButton\n                  emoji={emoji}\n                  onClick={() => {\n                    onSelectEmoji(`:${emoji.shortcode}:`);\n                  }}\n                  showCode\n                />\n              </li>\n            ))}\n          </ul>\n        ) : (\n          <div class=\"custom-emojis-list\">\n            {uiState === 'error' && (\n              <div class=\"ui-state\">\n                <p>\n                  <Trans>Error loading custom emojis</Trans>\n                </p>\n              </div>\n            )}\n            {uiState === 'default' &&\n              Object.entries(customEmojisCatList).map(\n                ([category, emojis]) =>\n                  !!emojis?.length && (\n                    <div class=\"section-container\">\n                      <div class=\"section-header\">\n                        {{\n                          '--recent--': t`Recently used`,\n                          '--others--': t`Others`,\n                        }[category] || category}\n                      </div>\n                      <CustomEmojisList\n                        emojis={emojis}\n                        onSelect={onSelectEmoji}\n                      />\n                    </div>\n                  ),\n              )}\n          </div>\n        )}\n      </main>\n    </div>\n  );\n}\n\nconst CustomEmojisList = memo(({ emojis, onSelect }) => {\n  const { i18n } = useLingui();\n  const [max, setMax] = useState(CUSTOM_EMOJIS_COUNT);\n  const showMore = emojis.length > max;\n  return (\n    <section>\n      {emojis.slice(0, max).map((emoji) => (\n        <CustomEmojiButton\n          key={emoji.shortcode}\n          emoji={emoji}\n          onClick={() => {\n            onSelect(`:${emoji.shortcode}:`);\n          }}\n        />\n      ))}\n      {showMore && (\n        <button\n          type=\"button\"\n          class=\"plain small\"\n          onClick={() => setMax(max + CUSTOM_EMOJIS_COUNT)}\n        >\n          <Trans>{i18n.number(emojis.length - max)} more…</Trans>\n        </button>\n      )}\n    </section>\n  );\n});\n\nconst CustomEmojiButton = memo(({ emoji, onClick, showCode }) => {\n  const addEdges = (e) => {\n    // Add edge-left or edge-right class based on self position relative to scrollable parent\n    // If near left edge, add edge-left, if near right edge, add edge-right\n    const buffer = 88;\n    const parent = e.currentTarget.closest('main');\n    if (parent) {\n      const rect = parent.getBoundingClientRect();\n      const selfRect = e.currentTarget.getBoundingClientRect();\n      const targetClassList = e.currentTarget.classList;\n      if (selfRect.left < rect.left + buffer) {\n        targetClassList.add('edge-left');\n        targetClassList.remove('edge-right');\n      } else if (selfRect.right > rect.right - buffer) {\n        targetClassList.add('edge-right');\n        targetClassList.remove('edge-left');\n      } else {\n        targetClassList.remove('edge-left', 'edge-right');\n      }\n    }\n  };\n\n  return (\n    <button\n      type=\"button\"\n      className=\"plain4\"\n      onClick={onClick}\n      data-title={showCode ? undefined : emoji.shortcode}\n      onPointerEnter={addEdges}\n      onFocus={addEdges}\n    >\n      <picture>\n        {!!emoji.staticUrl && (\n          <source\n            srcSet={emoji.staticUrl}\n            media=\"(prefers-reduced-motion: reduce)\"\n          />\n        )}\n        <img\n          className=\"shortcode-emoji\"\n          src={emoji.url || emoji.staticUrl}\n          alt={emoji.shortcode}\n          width=\"24\"\n          height=\"24\"\n          loading=\"lazy\"\n          decoding=\"async\"\n        />\n      </picture>\n      {showCode && (\n        <>\n          {' '}\n          <code>{emoji.shortcode}</code>\n        </>\n      )}\n    </button>\n  );\n});\n\nconst GIFS_PER_PAGE = 20;\nfunction GIFPickerModal({ onClose = () => {}, onSelect = () => {} }) {\n  const { i18n, t } = useLingui();\n  const [uiState, setUIState] = useState('default');\n  const [results, setResults] = useState([]);\n  const formRef = useRef(null);\n  const qRef = useRef(null);\n  const currentOffset = useRef(0);\n  const scrollableRef = useRef(null);\n\n  function fetchGIFs({ offset }) {\n    console.log('fetchGIFs', { offset });\n    if (!qRef.current?.value) return;\n    setUIState('loading');\n    scrollableRef.current?.scrollTo?.({\n      top: 0,\n      left: 0,\n      behavior: 'smooth',\n    });\n    (async () => {\n      try {\n        const query = {\n          api_key: GIPHY_API_KEY,\n          q: qRef.current.value,\n          rating: 'g',\n          limit: GIFS_PER_PAGE,\n          bundle: 'messaging_non_clips',\n          offset,\n          lang: i18n.locale || 'en',\n        };\n        const response = await fetch(\n          'https://api.giphy.com/v1/gifs/search?' + new URLSearchParams(query),\n          {\n            referrerPolicy: 'no-referrer',\n          },\n        ).then((r) => r.json());\n        currentOffset.current = response.pagination?.offset || 0;\n        setResults(response);\n        setUIState('results');\n      } catch (e) {\n        setUIState('error');\n        console.error(e);\n      }\n    })();\n  }\n\n  useEffect(() => {\n    qRef.current?.focus();\n  }, []);\n\n  const debouncedOnInput = useDebouncedCallback(() => {\n    fetchGIFs({ offset: 0 });\n  }, 1000);\n\n  return (\n    <div id=\"gif-picker-sheet\" class=\"sheet\">\n      {!!onClose && (\n        <button type=\"button\" class=\"sheet-close\" onClick={onClose}>\n          <Icon icon=\"x\" alt={t`Close`} />\n        </button>\n      )}\n      <header>\n        <form\n          ref={formRef}\n          onSubmit={(e) => {\n            e.preventDefault();\n            fetchGIFs({ offset: 0 });\n          }}\n        >\n          <input\n            ref={qRef}\n            type=\"search\"\n            name=\"q\"\n            placeholder={t`Search GIFs`}\n            required\n            autocomplete=\"off\"\n            autocorrect=\"off\"\n            autocapitalize=\"off\"\n            spellCheck=\"false\"\n            dir=\"auto\"\n            onInput={debouncedOnInput}\n          />\n          <input\n            type=\"image\"\n            class=\"powered-button\"\n            src={poweredByGiphyURL}\n            width=\"86\"\n            height=\"30\"\n            alt={t`Powered by GIPHY`}\n          />\n        </form>\n      </header>\n      <main ref={scrollableRef} class={uiState === 'loading' ? 'loading' : ''}>\n        {uiState === 'default' && (\n          <div class=\"ui-state\">\n            <p class=\"insignificant\">\n              <Trans>Type to search GIFs</Trans>\n            </p>\n          </div>\n        )}\n        {uiState === 'loading' && !results?.data?.length && (\n          <div class=\"ui-state\">\n            <Loader abrupt />\n          </div>\n        )}\n        {results?.data?.length > 0 ? (\n          <>\n            <ul>\n              {results.data.map((gif) => {\n                const { id, images, title, alt_text } = gif;\n                const {\n                  fixed_height_small,\n                  fixed_height_downsampled,\n                  fixed_height,\n                  original,\n                } = images;\n                const theImage = fixed_height_small?.url\n                  ? fixed_height_small\n                  : fixed_height_downsampled?.url\n                    ? fixed_height_downsampled\n                    : fixed_height;\n                let { url, webp, width, height } = theImage;\n                if (+height > 100) {\n                  width = (width / height) * 100;\n                  height = 100;\n                }\n                const urlObj = URL.parse(url);\n                const strippedURL = urlObj.origin + urlObj.pathname;\n                let strippedWebP;\n                if (webp) {\n                  const webpObj = URL.parse(webp);\n                  strippedWebP = webpObj.origin + webpObj.pathname;\n                }\n                return (\n                  <li key={id}>\n                    <button\n                      type=\"button\"\n                      onClick={() => {\n                        const { mp4, url } = original;\n                        const theURL = mp4 || url;\n                        const urlObj = URL.parse(theURL);\n                        const strippedURL = urlObj.origin + urlObj.pathname;\n                        onClose();\n                        onSelect({\n                          url: strippedURL,\n                          type: mp4 ? 'video/mp4' : 'image/gif',\n                          alt_text: alt_text || title,\n                        });\n                      }}\n                    >\n                      <figure\n                        style={{\n                          '--figure-width': width + 'px',\n                          // width: width + 'px'\n                        }}\n                      >\n                        <picture>\n                          {strippedWebP && (\n                            <source srcset={strippedWebP} type=\"image/webp\" />\n                          )}\n                          <img\n                            src={strippedURL}\n                            width={width}\n                            height={height}\n                            loading=\"lazy\"\n                            decoding=\"async\"\n                            alt={alt_text}\n                            referrerpolicy=\"no-referrer\"\n                            onLoad={(e) => {\n                              e.target.style.backgroundColor = 'transparent';\n                            }}\n                          />\n                        </picture>\n                        <figcaption>{alt_text || title}</figcaption>\n                      </figure>\n                    </button>\n                  </li>\n                );\n              })}\n            </ul>\n            <p class=\"pagination\">\n              {results.pagination?.offset > 0 && (\n                <button\n                  type=\"button\"\n                  class=\"light small\"\n                  disabled={uiState === 'loading'}\n                  onClick={() => {\n                    fetchGIFs({\n                      offset: results.pagination?.offset - GIFS_PER_PAGE,\n                    });\n                  }}\n                >\n                  <Icon icon=\"chevron-left\" />\n                  <span>\n                    <Trans>Previous</Trans>\n                  </span>\n                </button>\n              )}\n              <span />\n              {results.pagination?.offset + results.pagination?.count <\n                results.pagination?.total_count && (\n                <button\n                  type=\"button\"\n                  class=\"light small\"\n                  disabled={uiState === 'loading'}\n                  onClick={() => {\n                    fetchGIFs({\n                      offset: results.pagination?.offset + GIFS_PER_PAGE,\n                    });\n                  }}\n                >\n                  <span>\n                    <Trans>Next</Trans>\n                  </span>{' '}\n                  <Icon icon=\"chevron-right\" />\n                </button>\n              )}\n            </p>\n          </>\n        ) : (\n          uiState === 'results' && (\n            <div class=\"ui-state\">\n              <p>No results</p>\n            </div>\n          )\n        )}\n        {uiState === 'error' && (\n          <div class=\"ui-state\">\n            <p>\n              <Trans>Error loading GIFs</Trans>\n            </p>\n          </div>\n        )}\n      </main>\n    </div>\n  );\n}\n\nexport default Compose;\n"],"file":"assets/compose-8rrDtgaW.js"}