{"version":3,"mappings":";m6BA4BA,eAAsB,IAAmC,CACvD,OAAO,EAAO,qBAAqB,CACrC,CAMA,eAAsB,IAAqC,CACzD,OAAO,EAAO,uBAAuB,CACvC,CAMA,eAAsB,IAA6D,CACjF,OAAO,EAAO,2BAA2B,CAC3C,CAMA,eAAsB,IAAiC,CACrD,OAAO,EAAO,mBAAmB,CACnC,CAkCA,eAAsB,GAAiB,EAAqD,CAC1F,OAAO,EAAO,qBAAsB,CAAM,CAC5C,CAMA,eAAsB,GAAgB,EAAoD,CACxF,OAAO,EAAO,oBAAqB,CAAM,CAC3C,CAEA,eAAsB,GAAuB,EAA2D,CACtG,OAAO,EAAO,4BAA6B,CAAM,CACnD,CAUA,eAAsB,GAAa,EAAiD,CAClF,OAAO,EAAO,iBAAkB,CAAM,CACxC,CAEA,eAAsB,GAAyB,EAA6D,CAC1G,OAAO,EAAO,8BAA+B,CAAM,CACrD,CAEA,eAAsB,GAAgB,EAAoD,CACxF,OAAO,EAAO,oBAAqB,CAAM,CAC3C,CAEA,eAAsB,IAA+C,CACnE,OAAO,EAAO,mBAAmB,CACnC,CAEA,eAAsB,GAAe,EAAsD,CACzF,OAAO,EAAO,mBAAoB,CAAM,CAC1C,CAEA,eAAsB,IAAiC,CACrD,OAAO,EAAO,mBAAmB,CACnC,CAMA,eAAsB,GAA8B,EAAkE,CACpH,OAAO,EAAO,oCAAqC,CAAM,CAC3D,CAMA,eAAsB,IAAoC,CACxD,OAAO,EAAO,sBAAsB,CACtC,CAEA,eAAsB,GAAoB,EAA6E,CACrH,OAAO,EAAO,wBAAyB,CAAM,CAC/C,CCzJA,IAAI,GAAU,OAAO,IAAI,eAAe,EACpC,GAAY,OAAO,IAAI,iBAAiB,EACxC,EAAc,OAAO,IAAI,aAAa,EAkC1C,SAAS,EAAI,EAAO,GAAG,EAAM,CAM3B,MAAU,MACR,8BAA8B,EAAM,wCACtC,CACF,CAGA,IAAI,EAAI,OACJ,EAAiB,EAAE,eACnB,GAAc,cACd,GAAY,YACZ,GAAe,eACf,GAAa,aACb,GAAW,WACX,GAAQ,QACR,EAAW,GAAU,CAAC,CAAC,GAAS,CAAC,CAAC,EAAM,GAC5C,SAAS,EAAY,EAAO,CAG1B,OAFK,EAEE,GAAc,CAAK,GAAK,GAAQ,CAAK,GAAK,CAAC,CAAC,EAAM,KAAc,CAAC,CAAC,EAAM,GAAY,GAAG,KAAc,GAAM,CAAK,GAAK,GAAM,CAAK,EAD9H,EAEX,CACA,IAAI,GAAmB,EAAE,GAAU,CAAC,GAAY,CAAC,SAAS,EACtD,GAAoC,IAAI,QAC5C,SAAS,GAAc,EAAO,CAC5B,GAAI,CAAC,GAAS,CAAC,GAAY,CAAK,EAC9B,MAAO,GACT,IAAM,EAAQ,EAAe,CAAK,EAClC,GAAI,IAAU,MAAQ,IAAU,EAAE,IAChC,MAAO,GACT,IAAM,EAAO,EAAE,eAAe,KAAK,EAAO,EAAW,GAAK,EAAM,IAChE,GAAI,IAAS,OACX,MAAO,GACT,GAAI,CAAC,EAAW,CAAI,EAClB,MAAO,GACT,IAAI,EAAa,GAAkB,IAAI,CAAI,EAK3C,OAJI,IAAe,IAAK,KACtB,EAAa,SAAS,SAAS,KAAK,CAAI,EACxC,GAAkB,IAAI,EAAM,CAAU,GAEjC,IAAe,EACxB,CAMA,SAAS,EAAK,EAAK,EAAM,EAAS,GAAM,CAClC,EAAY,CAAG,IAAM,GACV,EAAS,QAAQ,QAAQ,CAAG,EAAI,EAAE,KAAK,CAAG,GAClD,QAAS,GAAQ,CACpB,EAAK,EAAK,EAAI,GAAM,CAAG,CACzB,CAAC,EAED,EAAI,SAAS,EAAO,IAAU,EAAK,EAAO,EAAO,CAAG,CAAC,CAEzD,CACA,SAAS,EAAY,EAAO,CAC1B,IAAM,EAAQ,EAAM,GACpB,OAAO,EAAQ,EAAM,MAAQ,GAAQ,CAAK,EAAI,EAAgB,GAAM,CAAK,EAAI,EAAc,GAAM,CAAK,EAAI,EAAc,CAC1H,CACA,IAAI,IAAO,EAAO,EAAM,EAAO,EAAY,CAAK,IAAM,IAAS,EAAc,EAAM,IAAI,CAAI,EAAI,EAAE,GAAU,CAAC,eAAe,KAAK,EAAO,CAAI,EACvI,IAAO,EAAO,EAAM,EAAO,EAAY,CAAK,IAE9C,IAAS,EAAc,EAAM,IAAI,CAAI,EAAI,EAAM,GAE7C,IAAO,EAAO,EAAgB,EAAO,EAAO,EAAY,CAAK,IAAM,CACjE,IAAS,EACX,EAAM,IAAI,EAAgB,CAAK,EACxB,IAAS,EAChB,EAAM,IAAI,CAAK,EAEf,EAAM,GAAkB,CAC5B,EACA,SAAS,GAAG,EAAG,EAAG,CAId,OAHE,IAAM,EACD,IAAM,GAAK,EAAI,GAAM,EAAI,EAEzB,IAAM,GAAK,IAAM,CAE5B,CACA,IAAI,GAAU,MAAM,QAChB,GAAS,GAAW,aAAkB,IACtC,GAAS,GAAW,aAAkB,IACtC,GAAe,GAAW,OAAO,GAAW,SAC5C,EAAc,GAAW,OAAO,GAAW,WAC3C,GAAa,GAAW,OAAO,GAAW,UAC9C,SAAS,GAAa,EAAO,CAC3B,IAAM,EAAI,CAAC,EACX,OAAO,OAAO,UAAU,CAAC,GAAK,OAAO,CAAC,IAAM,CAC9C,CACA,IAAI,GAAiB,GACd,GAAY,CAAK,EAEf,IAAQ,GADN,KAGP,EAAU,GAAU,EAAM,OAAS,EAAM,MACzC,GAAY,GAAU,CACxB,IAAM,EAAa,GAAc,CAAK,EACtC,OAAO,EAAa,GAAc,CAAU,EAAI,CAClD,EACI,GAAiB,GAAU,EAAM,UAAY,EAAM,MAAQ,EAAM,MACrE,SAAS,GAAY,EAAM,EAAQ,CACjC,GAAI,GAAM,CAAI,EACZ,OAAO,IAAI,IAAI,CAAI,EAErB,GAAI,GAAM,CAAI,EACZ,OAAO,IAAI,IAAI,CAAI,EAErB,GAAI,GAAQ,CAAI,EACd,OAAO,MAAM,GAAU,CAAC,MAAM,KAAK,CAAI,EACzC,IAAM,EAAU,GAAc,CAAI,EAClC,GAAI,IAAW,IAAQ,IAAW,cAAgB,CAAC,EAAS,CAC1D,IAAM,EAAc,EAAE,0BAA0B,CAAI,EACpD,OAAO,EAAY,GACnB,IAAI,EAAO,QAAQ,QAAQ,CAAW,EACtC,IAAK,IAAI,EAAI,EAAG,EAAI,EAAK,OAAQ,IAAK,CACpC,IAAM,EAAM,EAAK,GACX,EAAO,EAAY,GACrB,EAAK,MAAc,KACrB,EAAK,IAAY,GACjB,EAAK,IAAgB,KAEnB,EAAK,KAAO,EAAK,OACnB,EAAY,GAAO,EAChB,IAAe,IACf,IAAW,IAEX,IAAa,EAAK,KAClB,IAAQ,EAAK,EAChB,EACJ,CACA,OAAO,EAAE,OAAO,EAAe,CAAI,EAAG,CAAW,CACnD,CAAO,CACL,IAAM,EAAQ,EAAe,CAAI,EACjC,GAAI,IAAU,MAAQ,EACpB,MAAO,CAAE,GAAG,CAAK,EAEnB,IAAM,EAAM,EAAE,OAAO,CAAK,EAC1B,OAAO,EAAE,OAAO,EAAK,CAAI,CAC3B,CACF,CACA,SAAS,GAAO,EAAK,EAAO,GAAO,CAoBjC,OAnBI,GAAS,CAAG,GAAK,EAAQ,CAAG,GAAK,CAAC,EAAY,CAAG,EAC5C,GACL,EAAY,CAAG,EAAI,GACrB,EAAE,iBAAiB,EAAK,CACtB,IAAK,GACL,IAAK,GACL,MAAO,GACP,OAAQ,EACV,CAAC,EAEH,EAAE,OAAO,CAAG,EACR,GACF,EACE,GACC,EAAM,IAAU,CACf,GAAO,EAAO,EAAI,CACpB,EACA,EACF,EACK,EACT,CACA,SAAS,IAA8B,CACrC,EAAI,CAAC,CACP,CACA,IAAI,GAA2B,EAC5B,IAAQ,EACX,EACA,SAAS,GAAS,EAAK,CAGrB,OAFI,IAAQ,MAAQ,CAAC,GAAY,CAAG,GAE7B,EAAE,SAAS,CAAG,CACvB,CAGA,IAAI,GAAe,SACf,GAAgB,UAChB,GAAqB,eACrB,GAAU,CAAC,EACf,SAAS,EAAU,EAAW,CAC5B,IAAM,EAAS,GAAQ,GAIvB,OAHK,GACH,EAAI,EAAG,CAAS,EAEX,CACT,CACA,IAAI,GAAkB,GAAc,CAAC,CAAC,GAAQ,GAC9C,SAAS,GAAW,EAAW,EAAgB,CACxC,GAAQ,KACX,GAAQ,GAAa,EACzB,CAGA,IAAI,GACA,OAAwB,GACxB,IAAe,EAAS,KAAY,CACtC,QAAS,CAAC,EACV,UACA,SAGA,eAAgB,GAChB,mBAAoB,EACpB,YAA6B,IAAI,IACjC,qBAAsC,IAAI,IAC1C,cAAe,GAAe,EAAY,EAAI,EAAU,EAAY,EAAI,IAAK,GAC7E,oBAAqB,GAAe,EAAkB,EAAI,EAAU,EAAkB,EAAI,IAAK,EACjG,GACA,SAAS,GAAkB,EAAO,EAAe,CAC3C,IACF,EAAM,aAAe,EAAU,EAAa,EAC5C,EAAM,SAAW,CAAC,EAClB,EAAM,gBAAkB,CAAC,EACzB,EAAM,eAAiB,EAE3B,CACA,SAAS,GAAY,EAAO,CAC1B,GAAW,CAAK,EAChB,EAAM,QAAQ,QAAQ,EAAW,EACjC,EAAM,QAAU,IAClB,CACA,SAAS,GAAW,EAAO,CACrB,IAAU,KACZ,GAAe,EAAM,QAEzB,CACA,IAAI,GAAc,GAAW,GAAe,GAAY,GAAc,CAAM,EAC5E,SAAS,GAAY,EAAO,CAC1B,IAAM,EAAQ,EAAM,GAChB,EAAM,QAAU,GAAkB,EAAM,QAAU,EACpD,EAAM,QAAQ,EAEd,EAAM,SAAW,EACrB,CAGA,SAAS,GAAc,EAAQ,EAAO,CACpC,EAAM,mBAAqB,EAAM,QAAQ,OACzC,IAAM,EAAY,EAAM,QAAQ,GAEhC,GADmB,IAAW,IAAK,IAAK,IAAW,EACnC,CACV,EAAU,EAAY,CAAC,YACzB,GAAY,CAAK,EACjB,EAAI,CAAC,GAEH,EAAY,CAAM,IACpB,EAAS,GAAS,EAAO,CAAM,GAEjC,GAAM,CAAE,gBAAiB,EACrB,GACF,EAAa,4BACX,EAAU,EAAY,CAAC,MACvB,EACA,CACF,CAEJ,KACE,GAAS,GAAS,EAAO,CAAS,EAOpC,OALA,GAAY,EAAO,EAAQ,EAAI,EAC/B,GAAY,CAAK,EACb,EAAM,UACR,EAAM,eAAe,EAAM,SAAU,EAAM,eAAe,EAErD,IAAW,GAAmB,IAAK,GAAd,CAC9B,CACA,SAAS,GAAS,EAAW,EAAO,CAClC,GAAI,GAAS,CAAK,EAChB,OAAO,EACT,IAAM,EAAQ,EAAM,GACpB,GAAI,CAAC,EAEH,OADmB,GAAY,EAAO,EAAU,YAAa,CAC7C,EAElB,GAAI,CAAC,GAAY,EAAO,CAAS,EAC/B,OAAO,EAET,GAAI,CAAC,EAAM,UACT,OAAO,EAAM,MAEf,GAAI,CAAC,EAAM,WAAY,CACrB,GAAM,CAAE,cAAe,EACvB,GAAI,EACF,KAAO,EAAW,OAAS,GAEzB,EAD4B,IACrB,CAAC,CAAC,CAAS,EAGtB,GAA2B,EAAO,CAAS,CAC7C,CACA,OAAO,EAAM,KACf,CACA,SAAS,GAAY,EAAO,EAAO,EAAO,GAAO,CAC3C,CAAC,EAAM,SAAW,EAAM,OAAO,aAAe,EAAM,gBACtD,GAAO,EAAO,CAAI,CAEtB,CACA,SAAS,GAAmB,EAAO,CACjC,EAAM,WAAa,GACnB,EAAM,OAAO,oBACf,CACA,IAAI,IAAe,EAAO,IAAc,EAAM,SAAW,EACrD,GAAyB,CAAC,EAC9B,SAAS,GAAoB,EAAQ,EAAY,EAAgB,EAAa,CAC5E,IAAM,EAAa,EAAO,CAAM,EAC1B,EAAa,EAAO,MAC1B,GAAI,IAAgB,IAAK,IACF,GAAI,EAAY,EAAa,CACnC,IAAM,EAAY,CAC/B,GAAI,EAAY,EAAa,EAAgB,CAAU,EACvD,MACF,CAEF,GAAI,CAAC,EAAO,gBAAiB,CAC3B,IAAM,EAAiB,EAAO,gBAAkC,IAAI,IACpE,EAAK,GAAa,EAAK,IAAU,CAC/B,GAAI,EAAQ,CAAK,EAAG,CAClB,IAAM,EAAO,EAAe,IAAI,CAAK,GAAK,CAAC,EAC3C,EAAK,KAAK,CAAG,EACb,EAAe,IAAI,EAAO,CAAI,CAChC,CACF,CAAC,CACH,CACA,IAAM,EAAY,EAAO,gBAAgB,IAAI,CAAU,GAAK,GAC5D,IAAK,IAAM,KAAY,EACrB,GAAI,EAAY,EAAU,EAAgB,CAAU,CAExD,CACA,SAAS,GAAkC,EAAQ,EAAO,EAAK,CAC7D,EAAO,WAAW,KAAK,SAAsB,EAAW,CACtD,IAAM,EAAQ,EACd,GAAI,CAAC,GAAS,CAAC,GAAY,EAAO,CAAS,EACzC,OAEF,EAAU,eAAe,eAAe,CAAK,EAC7C,IAAM,EAAiB,GAAc,CAAK,EAC1C,GAAoB,EAAQ,EAAM,QAAU,EAAO,EAAgB,CAAG,EACtE,GAA2B,EAAO,CAAS,CAC7C,CAAC,CACH,CACA,SAAS,GAA2B,EAAO,EAAW,CAEpD,GADuB,EAAM,WAAa,CAAC,EAAM,aAAe,EAAM,QAAU,GAAe,EAAM,QAAU,GAAiB,EAAM,wBAA0B,EAAM,WAAW,MAAQ,GAAK,GAC1K,CAClB,GAAM,CAAE,gBAAiB,EACzB,GAAI,EAAc,CAChB,IAAM,EAAW,EAAa,QAAQ,CAAK,EACvC,GACF,EAAa,iBAAiB,EAAO,EAAU,CAAS,CAE5D,CACA,GAAmB,CAAK,CAC1B,CACF,CACA,SAAS,GAAqB,EAAQ,EAAK,EAAO,CAChD,GAAM,CAAE,UAAW,EACnB,GAAI,EAAQ,CAAK,EAAG,CAClB,IAAM,EAAQ,EAAM,GAChB,GAAY,EAAO,CAAM,GAC3B,EAAM,WAAW,KAAK,UAAiC,CACrD,GAAY,CAAM,EAElB,GAAoB,EAAQ,EADL,GAAc,CACW,EAAG,CAAG,CACxD,CAAC,CAEL,MAAW,EAAY,CAAK,GAC1B,EAAO,WAAW,KAAK,UAA8B,CACnD,IAAM,EAAa,EAAO,CAAM,EAC5B,EAAO,QAAU,EACf,EAAW,IAAI,CAAK,GACtB,GAAY,EAAO,EAAO,YAAa,CAAM,EAG3C,GAAI,EAAY,EAAK,EAAO,KAAK,IAAM,GACrC,EAAO,QAAQ,OAAS,IAAM,EAAO,UAAU,IAAI,CAAG,GAAK,MAAW,IAAQ,EAAO,OACvF,GACE,GAAI,EAAO,MAAO,EAAK,EAAO,KAAK,EACnC,EAAO,YACP,CACF,CAIR,CAAC,CAEL,CACA,SAAS,GAAY,EAAQ,EAAY,EAAW,CAoBlD,MAnBI,CAAC,EAAU,OAAO,aAAe,EAAU,mBAAqB,GAGhE,EAAQ,CAAM,GAAK,EAAW,IAAI,CAAM,GAAK,CAAC,EAAY,CAAM,GAAK,GAAS,CAAM,EAC/E,GAET,EAAW,IAAI,CAAM,EACrB,EAAK,GAAS,EAAK,IAAU,CAC3B,GAAI,EAAQ,CAAK,EAAG,CAClB,IAAM,EAAQ,EAAM,GAChB,GAAY,EAAO,CAAS,IAE9B,GAAI,EAAQ,EADS,GAAc,CACP,EAAG,EAAO,KAAK,EAC3C,GAAmB,CAAK,EAE5B,MAAW,EAAY,CAAK,GAC1B,GAAY,EAAO,EAAY,CAAS,CAE5C,CAAC,EACM,EACT,CAGA,SAAS,GAAiB,EAAM,EAAQ,CACtC,IAAM,EAAc,GAAQ,CAAI,EAC1B,EAAQ,CACZ,MAAO,KAEP,OAAQ,EAAS,EAAO,OAAS,GAAgB,EAEjD,UAAW,GAEX,WAAY,GAGZ,UAAW,IAAK,GAEhB,QAAS,EAET,MAAO,EAEP,OAAQ,KAGR,MAAO,KAEP,QAAS,KACT,UAAW,GAEX,WAAY,IAAK,EACnB,EACI,EAAS,EACT,EAAQ,GACR,IACF,EAAS,CAAC,CAAK,EACf,EAAQ,GAEV,GAAM,CAAE,SAAQ,SAAU,MAAM,UAAU,EAAQ,CAAK,EAGvD,MAFA,GAAM,OAAS,EACf,EAAM,QAAU,EACT,CAAC,EAAO,CAAK,CACtB,CACA,IAAI,GAAc,CAChB,IAAI,EAAO,EAAM,CACf,GAAI,IAAS,EACX,OAAO,EACT,IAAI,EAAc,EAAM,OAAO,oBACzB,EAAwB,EAAM,QAAU,GAAiB,OAAO,GAAS,SAC/E,GAAI,GACE,GAAa,uBAAuB,CAAI,EAC1C,OAAO,EAAY,wBAAwB,EAAO,CAAI,EAG1D,IAAM,EAAS,EAAO,CAAK,EAC3B,GAAI,CAAC,GAAI,EAAQ,EAAM,EAAM,KAAK,EAChC,OAAO,GAAkB,EAAO,EAAQ,CAAI,EAE9C,IAAM,EAAQ,EAAO,GAIrB,GAHI,EAAM,YAAc,CAAC,EAAY,CAAK,GAGtC,GAAyB,EAAM,iBAAmB,GAAa,sBACjE,EAAM,eACR,GAAK,GAAa,CAAI,EACpB,OAAO,EAET,GAAI,IAAU,GAAK,EAAM,MAAO,CAAI,GAAK,GAAmB,EAAO,EAAM,CAAK,EAAG,CAC/E,GAAY,CAAK,EACjB,IAAM,EAAW,EAAM,QAAU,EAAgB,CAAC,EAAO,EACnD,EAAa,GAAY,EAAM,OAAQ,EAAO,EAAO,CAAQ,EACnE,MAAO,GAAM,MAAM,GAAY,CACjC,CACA,OAAO,CACT,EACA,IAAI,EAAO,EAAM,CACf,OAAO,KAAQ,EAAO,CAAK,CAC7B,EACA,QAAQ,EAAO,CACb,OAAO,QAAQ,QAAQ,EAAO,CAAK,CAAC,CACtC,EACA,IAAI,EAAO,EAAM,EAAO,CACtB,IAAM,EAAO,GAAuB,EAAO,CAAK,EAAG,CAAI,EACvD,GAAI,GAAM,IAER,OADA,EAAK,IAAI,KAAK,EAAM,OAAQ,CAAK,EAC1B,GAET,GAAI,CAAC,EAAM,UAAW,CACpB,IAAM,EAAW,GAAK,EAAO,CAAK,EAAG,CAAI,EACnC,EAAe,IAAW,GAChC,GAAI,GAAgB,EAAa,QAAU,EAGzC,MAFA,GAAM,MAAM,GAAQ,EACpB,EAAM,UAAU,IAAI,EAAM,EAAK,EACxB,GAET,GAAI,GAAG,EAAO,CAAQ,IAAM,IAAU,IAAK,IAAK,GAAI,EAAM,MAAO,EAAM,EAAM,KAAK,GAChF,MAAO,GACT,GAAY,CAAK,EACjB,EAAY,CAAK,CACnB,CAQA,OAPI,EAAM,MAAM,KAAU,IACzB,IAAU,IAAK,IAAK,GAAI,EAAM,MAAO,EAAM,EAAM,KAAK,IACvD,OAAO,MAAM,CAAK,GAAK,OAAO,MAAM,EAAM,MAAM,EAAK,EAC5C,IACT,EAAM,MAAM,GAAQ,EACpB,EAAM,UAAU,IAAI,EAAM,EAAI,EAC9B,GAAqB,EAAO,EAAM,CAAK,EAChC,GACT,EACA,eAAe,EAAO,EAAM,CAW1B,OAVA,GAAY,CAAK,EACb,GAAK,EAAM,MAAO,CAAI,IAAM,IAAK,IAAK,KAAQ,EAAM,OACtD,EAAM,UAAU,IAAI,EAAM,EAAK,EAC/B,EAAY,CAAK,GAEjB,EAAM,UAAU,OAAO,CAAI,EAEzB,EAAM,OACR,OAAO,EAAM,MAAM,GAEd,EACT,EAGA,yBAAyB,EAAO,EAAM,CACpC,IAAM,EAAQ,EAAO,CAAK,EACpB,EAAO,QAAQ,yBAAyB,EAAO,CAAI,EAGzD,OAFK,GAEE,EACJ,IAAW,IACX,IAAe,EAAM,QAAU,GAAiB,IAAS,UACzD,IAAa,EAAK,KAClB,IAAQ,EAAM,EACjB,CACF,EACA,gBAAiB,CACf,EAAI,EAAE,CACR,EACA,eAAe,EAAO,CACpB,OAAO,EAAe,EAAM,KAAK,CACnC,EACA,gBAAiB,CACf,EAAI,EAAE,CACR,CACF,EACI,EAAa,CAAC,EAClB,IAAK,IAAI,KAAO,GAAa,CAC3B,IAAI,EAAK,GAAY,GACrB,EAAW,GAAO,UAAW,CAC3B,IAAM,EAAO,UAEb,MADA,GAAK,GAAK,EAAK,EAAE,CAAC,GACX,EAAG,MAAM,KAAM,CAAI,CAC5B,CACF,CACA,EAAW,eAAiB,SAAS,EAAO,EAAM,CAGhD,OAAO,EAAW,IAAI,KAAK,KAAM,EAAO,EAAM,IAAK,EAAC,CACtD,EACA,EAAW,IAAM,SAAS,EAAO,EAAM,EAAO,CAG5C,OAAO,GAAY,IAAI,KAAK,KAAM,EAAM,GAAI,EAAM,EAAO,EAAM,EAAE,CACnE,EACA,SAAS,GAAK,EAAO,EAAM,CACzB,IAAM,EAAQ,EAAM,GAEpB,OADe,EAAQ,EAAO,CAAK,EAAI,GACzB,EAChB,CACA,SAAS,GAAmB,EAAO,EAAM,EAAO,CAI9C,OAHI,EAAM,QAAU,GAAiB,CAAC,EAAM,uBAAyB,EAAM,WAAW,IAAI,CAAI,GAAK,CAAC,EAAY,CAAK,GAAK,EAAM,GACvH,GAEF,EAAM,UAAU,IAAI,CAAK,CAClC,CACA,SAAS,GAAkB,EAAO,EAAQ,EAAM,CAC9C,IAAM,EAAO,GAAuB,EAAQ,CAAI,EAChD,OAAO,EAAO,MAAS,EAAO,EAAK,IAGjC,EAAK,KAAK,KAAK,EAAM,MAAM,EACzB,IAAK,EACX,CACA,SAAS,GAAuB,EAAQ,EAAM,CAC5C,GAAI,EAAE,KAAQ,GACZ,OACF,IAAI,EAAQ,EAAe,CAAM,EACjC,KAAO,GAAO,CACZ,IAAM,EAAO,OAAO,yBAAyB,EAAO,CAAI,EACxD,GAAI,EACF,OAAO,EACT,EAAQ,EAAe,CAAK,CAC9B,CAEF,CACA,SAAS,EAAY,EAAO,CACrB,EAAM,YACT,EAAM,UAAY,GACd,EAAM,SACR,EAAY,EAAM,OAAO,EAG/B,CACA,SAAS,GAAY,EAAO,CAC1B,CAEE,CAAM,SADN,EAAM,UAA4B,IAAI,IACxB,GACZ,EAAM,MACN,EAAM,OAAO,OAAO,qBACtB,EAEJ,CAGA,IAAI,GAAS,KAAM,CACjB,YAAY,EAAQ,CAClB,KAAK,YAAc,GACnB,KAAK,sBAAwB,GAC7B,KAAK,oBAAsB,GAoB3B,KAAK,SAAW,EAAM,EAAQ,IAAkB,CAC9C,GAAI,EAAW,CAAI,GAAK,CAAC,EAAW,CAAM,EAAG,CAC3C,IAAM,EAAc,EACpB,EAAS,EACT,IAAM,EAAO,KACb,OAAO,SAAwB,EAAQ,EAAa,GAAG,EAAM,CAC3D,OAAO,EAAK,QAAQ,EAAQ,GAAU,EAAO,KAAK,KAAM,EAAO,GAAG,CAAI,CAAC,CACzE,CACF,CACK,EAAW,CAAM,GACpB,EAAI,CAAC,EACH,IAAkB,IAAK,IAAK,CAAC,EAAW,CAAa,GACvD,EAAI,CAAC,EACP,IAAI,EACJ,GAAI,EAAY,CAAI,EAAG,CACrB,IAAM,EAAQ,GAAW,IAAI,EACvB,EAAQ,GAAY,EAAO,EAAM,IAAK,EAAC,EACzC,EAAW,GACf,GAAI,CACF,EAAS,EAAO,CAAK,EACrB,EAAW,EACb,QAAU,CACJ,EACF,GAAY,CAAK,EAEjB,GAAW,CAAK,CACpB,CAEA,OADA,GAAkB,EAAO,CAAa,EAC/B,GAAc,EAAQ,CAAK,CACpC,CAAO,GAAI,CAAC,GAAQ,CAAC,GAAY,CAAI,EAAG,CAQtC,GAPA,EAAS,EAAO,CAAI,EAChB,IAAW,IAAK,KAClB,EAAS,GACP,IAAW,KACb,EAAS,IAAK,IACZ,KAAK,aACP,GAAO,EAAQ,EAAI,EACjB,EAAe,CACjB,IAAM,EAAI,CAAC,EACL,EAAK,CAAC,EACZ,EAAU,EAAa,CAAC,CAAC,4BAA4B,EAAM,EAAQ,CACjE,SAAU,EACV,gBAAiB,CACnB,CAAC,EACD,EAAc,EAAG,CAAE,CACrB,CACA,OAAO,CACT,CACE,EAAI,EAAG,CAAI,CACf,EACA,KAAK,oBAAsB,EAAM,IAAW,CAC1C,GAAI,EAAW,CAAI,EACjB,OAAQ,EAAO,GAAG,IAAS,KAAK,mBAAmB,EAAQ,GAAU,EAAK,EAAO,GAAG,CAAI,CAAC,EAE3F,IAAI,EAAS,EAKb,MAAO,CAJQ,KAAK,QAAQ,EAAM,GAAS,EAAG,IAAO,CACnD,EAAU,EACV,EAAiB,CACnB,CACa,EAAG,EAAS,CAAc,CACzC,EACI,GAAU,GAAQ,UAAU,GAC9B,KAAK,cAAc,EAAO,UAAU,EAClC,GAAU,GAAQ,oBAAoB,GACxC,KAAK,wBAAwB,EAAO,oBAAoB,EACtD,GAAU,GAAQ,kBAAkB,GACtC,KAAK,sBAAsB,EAAO,kBAAkB,CACxD,CACA,YAAY,EAAM,CACX,EAAY,CAAI,GACnB,EAAI,CAAC,EACH,EAAQ,CAAI,IACd,EAAO,GAAQ,CAAI,GACrB,IAAM,EAAQ,GAAW,IAAI,EACvB,EAAQ,GAAY,EAAO,EAAM,IAAK,EAAC,EAG7C,MAFA,GAAM,EAAY,CAAC,UAAY,GAC/B,GAAW,CAAK,EACT,CACT,CACA,YAAY,EAAO,EAAe,CAChC,IAAM,EAAQ,GAAS,EAAM,IACzB,CAAC,GAAS,CAAC,EAAM,YACnB,EAAI,CAAC,EACP,GAAM,CAAE,OAAQ,GAAU,EAE1B,OADA,GAAkB,EAAO,CAAa,EAC/B,GAAc,IAAK,GAAG,CAAK,CACpC,CAMA,cAAc,EAAO,CACnB,KAAK,YAAc,CACrB,CAMA,wBAAwB,EAAO,CAC7B,KAAK,sBAAwB,CAC/B,CAOA,sBAAsB,EAAO,CAC3B,KAAK,oBAAsB,CAC7B,CACA,0BAA2B,CACzB,OAAO,KAAK,mBACd,CACA,aAAa,EAAM,EAAS,CAC1B,IAAI,EACJ,IAAK,EAAI,EAAQ,OAAS,EAAG,GAAK,EAAG,IAAK,CACxC,IAAM,EAAQ,EAAQ,GACtB,GAAI,EAAM,KAAK,SAAW,GAAK,EAAM,KAAO,UAAW,CACrD,EAAO,EAAM,MACb,KACF,CACF,CACI,EAAI,KACN,EAAU,EAAQ,MAAM,EAAI,CAAC,GAE/B,IAAM,EAAmB,EAAU,EAAa,CAAC,CAAC,cAIlD,OAHI,EAAQ,CAAI,EACP,EAAiB,EAAM,CAAO,EAEhC,KAAK,QACV,EACC,GAAU,EAAiB,EAAO,CAAO,CAC5C,CACF,CACF,EACA,SAAS,GAAY,EAAW,EAAO,EAAQ,EAAK,CAClD,GAAM,CAAC,EAAO,GAAS,GAAM,CAAK,EAAI,EAAU,EAAY,CAAC,CAAC,UAAU,EAAO,CAAM,EAAI,GAAM,CAAK,EAAI,EAAU,EAAY,CAAC,CAAC,UAAU,EAAO,CAAM,EAAI,GAAiB,EAAO,CAAM,EAgBzL,OAfc,GAAQ,QAAU,GAAgB,GAC1C,QAAQ,KAAK,CAAK,EACxB,EAAM,WAAa,GAAQ,YAAc,CAAC,EAC1C,EAAM,KAAO,EACT,GAAU,IAAQ,IAAK,GACzB,GAAkC,EAAQ,EAAO,CAAG,EAEpD,EAAM,WAAW,KAAK,SAA0B,EAAY,CAC1D,EAAW,eAAe,eAAe,CAAK,EAC9C,GAAM,CAAE,gBAAiB,EACrB,EAAM,WAAa,GACrB,EAAa,iBAAiB,EAAO,CAAC,EAAG,CAAU,CAEvD,CAAC,EAEI,CACT,CAGA,SAAS,GAAQ,EAAO,CAGtB,OAFK,EAAQ,CAAK,GAChB,EAAI,GAAI,CAAK,EACR,GAAY,CAAK,CAC1B,CACA,SAAS,GAAY,EAAO,CAC1B,GAAI,CAAC,EAAY,CAAK,GAAK,GAAS,CAAK,EACvC,OAAO,EACT,IAAM,EAAQ,EAAM,GAChB,EACA,EAAS,GACb,GAAI,EAAO,CACT,GAAI,CAAC,EAAM,UACT,OAAO,EAAM,MACf,EAAM,WAAa,GACnB,EAAO,GAAY,EAAO,EAAM,OAAO,OAAO,qBAAqB,EACnE,EAAS,EAAM,OAAO,OAAO,yBAAyB,CACxD,KACE,GAAO,GAAY,EAAO,EAAI,EAYhC,OAVA,EACE,GACC,EAAK,IAAe,CACnB,GAAI,EAAM,EAAK,GAAY,CAAU,CAAC,CACxC,EACA,CACF,EACI,IACF,EAAM,WAAa,IAEd,CACT,CAsTA,IAAI,GAAkB,WAAW,SAC7B,GAAkB,OAAO,IAAiB,MAAS,WACvD,SAAS,IAAe,CACtB,MAAM,UAAiB,GAAI,CACzB,YAAY,EAAQ,EAAQ,CAC1B,MAAM,EACN,KAAK,GAAe,CAClB,MAAO,EACP,QAAS,EACT,OAAQ,EAAS,EAAO,OAAS,GAAgB,EACjD,UAAW,GACX,WAAY,GACZ,MAAO,IAAK,GACZ,UAAW,IAAK,GAChB,MAAO,EACP,OAAQ,KACR,UAAW,GACX,SAAU,GACV,WAAY,CAAC,CACf,CACF,CACA,IAAI,MAAO,CACT,OAAO,EAAO,KAAK,EAAY,CAAC,CAAC,IACnC,CACA,IAAI,EAAK,CACP,OAAO,EAAO,KAAK,EAAY,CAAC,CAAC,IAAI,CAAG,CAC1C,CACA,IAAI,EAAK,EAAO,CACd,IAAM,EAAQ,KAAK,GAUnB,OATA,EAAgB,CAAK,GACjB,CAAC,EAAO,CAAK,CAAC,CAAC,IAAI,CAAG,GAAK,EAAO,CAAK,CAAC,CAAC,IAAI,CAAG,IAAM,KACxD,EAAe,CAAK,EACpB,EAAY,CAAK,EACjB,EAAM,UAAU,IAAI,EAAK,EAAI,EAC7B,EAAM,MAAM,IAAI,EAAK,CAAK,EAC1B,EAAM,UAAU,IAAI,EAAK,EAAI,EAC7B,GAAqB,EAAO,EAAK,CAAK,GAEjC,IACT,CACA,OAAO,EAAK,CACV,GAAI,CAAC,KAAK,IAAI,CAAG,EACf,MAAO,GAET,IAAM,EAAQ,KAAK,GAUnB,OATA,EAAgB,CAAK,EACrB,EAAe,CAAK,EACpB,EAAY,CAAK,EACb,EAAM,MAAM,IAAI,CAAG,EACrB,EAAM,UAAU,IAAI,EAAK,EAAK,EAE9B,EAAM,UAAU,OAAO,CAAG,EAE5B,EAAM,MAAM,OAAO,CAAG,EACf,EACT,CACA,OAAQ,CACN,IAAM,EAAQ,KAAK,GACnB,EAAgB,CAAK,EACjB,EAAO,CAAK,CAAC,CAAC,OAChB,EAAe,CAAK,EACpB,EAAY,CAAK,EACjB,EAAM,UAA4B,IAAI,IACtC,EAAK,EAAM,MAAQ,GAAQ,CACzB,EAAM,UAAU,IAAI,EAAK,EAAK,CAChC,CAAC,EACD,EAAM,MAAM,MAAM,EAEtB,CACA,QAAQ,EAAI,EAAS,CACnB,IAAM,EAAQ,KAAK,GACnB,EAAO,CAAK,CAAC,CAAC,SAAS,EAAQ,EAAK,IAAS,CAC3C,EAAG,KAAK,EAAS,KAAK,IAAI,CAAG,EAAG,EAAK,IAAI,CAC3C,CAAC,CACH,CACA,IAAI,EAAK,CACP,IAAM,EAAQ,KAAK,GACnB,EAAgB,CAAK,EACrB,IAAM,EAAQ,EAAO,CAAK,CAAC,CAAC,IAAI,CAAG,EAInC,GAHI,EAAM,YAAc,CAAC,EAAY,CAAK,GAGtC,IAAU,EAAM,MAAM,IAAI,CAAG,EAC/B,OAAO,EAET,IAAM,EAAQ,GAAY,EAAM,OAAQ,EAAO,EAAO,CAAG,EAGzD,OAFA,EAAe,CAAK,EACpB,EAAM,MAAM,IAAI,EAAK,CAAK,EACnB,CACT,CACA,MAAO,CACL,OAAO,EAAO,KAAK,EAAY,CAAC,CAAC,KAAK,CACxC,CACA,QAAS,CACP,IAAM,EAAW,KAAK,KAAK,EAC3B,OAAO,EAAa,CAClB,SAAY,CACV,IAAM,EAAI,EAAS,KAAK,EAIxB,OAHI,EAAE,KACG,EAEF,CACL,KAAM,GACN,MAHY,KAAK,IAAI,EAAE,KAGnB,CACN,CACF,CACF,CAAC,CACH,CACA,SAAU,CACR,IAAM,EAAW,KAAK,KAAK,EAC3B,OAAO,EAAa,CAClB,SAAY,CACV,IAAM,EAAI,EAAS,KAAK,EACxB,GAAI,EAAE,KACJ,OAAO,EACT,IAAM,EAAQ,KAAK,IAAI,EAAE,KAAK,EAC9B,MAAO,CACL,KAAM,GACN,MAAO,CAAC,EAAE,MAAO,CAAK,CACxB,CACF,CACF,CAAC,CACH,CACA,CAAe,OAAO,WAAa,CACjC,OAAO,KAAK,QAAQ,CACtB,CACF,CACA,SAAS,EAAa,EAAU,CAC9B,GAAI,GACF,OAAO,GAAgB,KAAK,CAAQ,EAEtC,IAAM,EAAW,CACf,GAAG,GACF,OAAO,cAAiB,CAC3B,EACA,OAAO,CACT,CACA,SAAS,EAAU,EAAQ,EAAQ,CACjC,IAAM,EAAM,IAAI,EAAS,EAAQ,CAAM,EACvC,MAAO,CAAC,EAAK,EAAI,EAAY,CAC/B,CACA,SAAS,EAAe,EAAO,CAC7B,CAEE,CAAM,SADN,EAAM,UAA4B,IAAI,IACxB,IAAI,IAAI,EAAM,KAAK,EAErC,CACA,MAAM,UAAiB,GAAI,CACzB,YAAY,EAAQ,EAAQ,CAC1B,MAAM,EACN,KAAK,GAAe,CAClB,MAAO,EACP,QAAS,EACT,OAAQ,EAAS,EAAO,OAAS,GAAgB,EACjD,UAAW,GACX,WAAY,GACZ,MAAO,IAAK,GACZ,MAAO,EACP,OAAQ,KACR,QAAyB,IAAI,IAC7B,SAAU,GACV,UAAW,GACX,UAAW,IAAK,GAChB,WAAY,CAAC,CACf,CACF,CACA,IAAI,MAAO,CACT,OAAO,EAAO,KAAK,EAAY,CAAC,CAAC,IACnC,CACA,IAAI,EAAO,CACT,IAAM,EAAQ,KAAK,GASnB,OARA,EAAgB,CAAK,EAChB,EAAM,MAKX,GAFI,EAAM,MAAM,IAAI,CAAK,GAErB,EAAM,QAAQ,IAAI,CAAK,GAAK,EAAM,MAAM,IAAI,EAAM,QAAQ,IAAI,CAAK,CAAC,GAJ/D,EAAM,MAAM,IAAI,CAAK,CAOhC,CACA,IAAI,EAAO,CACT,IAAM,EAAQ,KAAK,GAQnB,OAPA,EAAgB,CAAK,EAChB,KAAK,IAAI,CAAK,IACjB,EAAe,CAAK,EACpB,EAAY,CAAK,EACjB,EAAM,MAAM,IAAI,CAAK,EACrB,GAAqB,EAAO,EAAO,CAAK,GAEnC,IACT,CACA,OAAO,EAAO,CACZ,GAAI,CAAC,KAAK,IAAI,CAAK,EACjB,MAAO,GAET,IAAM,EAAQ,KAAK,GAInB,OAHA,EAAgB,CAAK,EACrB,EAAe,CAAK,EACpB,EAAY,CAAK,EACV,EAAM,MAAM,OAAO,CAAK,IAAM,EAAM,QAAQ,IAAI,CAAK,EAAI,EAAM,MAAM,OAAO,EAAM,QAAQ,IAAI,CAAK,CAAC,EAEzG,GAEJ,CACA,OAAQ,CACN,IAAM,EAAQ,KAAK,GACnB,EAAgB,CAAK,EACjB,EAAO,CAAK,CAAC,CAAC,OAChB,EAAe,CAAK,EACpB,EAAY,CAAK,EACjB,EAAM,MAAM,MAAM,EAEtB,CACA,QAAS,CACP,IAAM,EAAQ,KAAK,GAGnB,OAFA,EAAgB,CAAK,EACrB,EAAe,CAAK,EACb,EAAM,MAAM,OAAO,CAC5B,CACA,SAAU,CACR,IAAM,EAAQ,KAAK,GAGnB,OAFA,EAAgB,CAAK,EACrB,EAAe,CAAK,EACb,EAAM,MAAM,QAAQ,CAC7B,CACA,MAAO,CACL,OAAO,KAAK,OAAO,CACrB,CACA,CAAe,OAAO,WAAa,CACjC,OAAO,KAAK,OAAO,CACrB,CACA,QAAQ,EAAI,EAAS,CACnB,IAAM,EAAW,KAAK,OAAO,EACzB,EAAS,EAAS,KAAK,EAC3B,KAAO,CAAC,EAAO,MACb,EAAG,KAAK,EAAS,EAAO,MAAO,EAAO,MAAO,IAAI,EACjD,EAAS,EAAS,KAAK,CAE3B,CACF,CACA,SAAS,EAAU,EAAQ,EAAQ,CACjC,IAAM,EAAO,IAAI,EAAS,EAAQ,CAAM,EACxC,MAAO,CAAC,EAAM,EAAK,EAAY,CACjC,CACA,SAAS,EAAe,EAAO,CACxB,EAAM,QACT,EAAM,MAAwB,IAAI,IAClC,EAAM,MAAM,QAAS,GAAU,CAC7B,GAAI,EAAY,CAAK,EAAG,CACtB,IAAM,EAAQ,GAAY,EAAM,OAAQ,EAAO,EAAO,CAAK,EAC3D,EAAM,QAAQ,IAAI,EAAO,CAAK,EAC9B,EAAM,MAAM,IAAI,CAAK,CACvB,MACE,EAAM,MAAM,IAAI,CAAK,CAEzB,CAAC,EAEL,CACA,SAAS,EAAgB,EAAO,CAC1B,EAAM,UACR,EAAI,EAAG,KAAK,UAAU,EAAO,CAAK,CAAC,CAAC,CACxC,CACA,SAAS,EAAe,EAAQ,CAC9B,GAAI,EAAO,QAAU,GAAe,EAAO,MAAO,CAChD,IAAM,EAAO,IAAI,IAAI,EAAO,KAAK,EACjC,EAAO,MAAM,MAAM,EACnB,EAAK,QAAS,GAAU,CACtB,EAAO,MAAM,IAAI,GAAS,CAAK,CAAC,CAClC,CAAC,CACH,CACF,CACA,GAAW,GAAc,CAAE,YAAW,YAAW,gBAAe,CAAC,CACnE,CA0MA,IAAI,GAAU,IADE,GACF,EAAM,QC1nDd,GAAyB,iDAEzB,GAAwB,IAExB,GAAc,GAClB,OAAO,GAAU,SAAW,EAAQ,aAAiB,IAAM,EAAM,KAAO,EAAM,IAE1E,IAAiB,EAA0B,IAC3C,GAAM,OAAe,EAAK,OAAO,YAAY,EAC7C,aAAiB,QAAgB,EAAM,OAAO,YAAY,EACvD,MAGH,IAAqB,EAA0B,IACpC,GAAc,EAAO,CAChC,IAAW,OACR,GAAuB,KAAK,IAAI,IAAI,GAAW,CAAK,CAAC,CAAC,CAAC,QAAQ,EAGlE,GAAqB,GAAwC,CACjE,IAAM,EAAa,IAAI,gBACvB,IAAK,IAAM,KAAU,EAAS,CAC5B,GAAI,EAAO,QAET,OADA,EAAW,MAAM,EAAO,MAAM,EACvB,EAAW,OAEpB,EAAO,iBAAiB,YAAe,EAAW,MAAM,EAAO,MAAM,EAAG,CAAE,KAAM,EAAK,CAAC,CACxF,CACA,OAAO,EAAW,MACpB,EAsBa,KAhBqB,EAA0B,MACvB,EAAO,IAAS,CACjD,GAAI,CAAC,GAAkB,EAAO,CAAI,EAChC,OAAO,EAAU,EAAO,CAAI,EAG9B,IAAM,EAAU,YAAY,QAAQ,EAAqB,EACnD,EAAiB,GAAM,SAAW,aAAiB,QAAU,EAAM,OAAS,QAC5E,EAAS,EAAiB,GAAkB,CAAC,EAAgB,CAAO,CAAC,EAAI,EAE/E,OAAO,EAAU,EAAO,CAAE,GAAG,EAAM,QAAO,CAAC,CAC7C,EAKyB,CAAkB,EC5CvC,GAAqB,kBAErB,GAAe,GAA2B,GAAG,KAAqB,IAiB3D,GAA2B,GAAwC,CAC9E,IAAM,EAAW,GAAY,CAAM,EAE7B,EAA0B,EAC9B,EACC,GAAQ,CACP,IAAM,EAA4B,EAAoB,EAAK,CAAC,CAAC,EAC7D,OAAO,IAAI,IAAI,OAAO,QAAQ,CAAG,CAAC,CACpC,GACC,EAAK,IAAU,CACd,IAAM,EAA4B,OAAO,YAAY,CAAK,EAC1D,GAAoB,EAAK,CAAG,CAC9B,CACF,EAyBA,OAvB4B,GACzB,GAAQ,EAAI,CAAuB,GACnC,EAAK,EAAK,IAAW,CACpB,GAAI,EAAO,OAAS,SAAU,CAC5B,EACE,EACA,GAAQ,EAAI,CAAuB,EAAI,GAAU,CAC/C,EAAM,OAAO,EAAO,KAAK,CAC3B,CAAC,CACH,EACA,MACF,CACI,EAAO,OAAS,OAClB,EACE,EACA,GAAQ,EAAI,CAAuB,EAAI,GAAU,CAC/C,EAAM,IAAI,EAAO,MAAO,EAAO,IAAI,CACrC,CAAC,CACH,CAEJ,CAGK,CACT,EAEa,GAA6B,GAAmB,CAC3D,aAAa,WAAW,GAAY,CAAM,CAAC,CAC7C,cC1CM,EAAiB,IAAI,IACrB,GAAmB,IAAI,IACvB,EAAkC,CAAC,EACnC,GAA8B,IAEpC,SAAS,IAA+B,CACtC,KAAO,EAAsB,OAAS,IAA6B,CACjE,IAAM,EAAY,EAAsB,MAAM,EAC9C,GAAI,CAAC,EAAW,MAChB,IAAM,EAAQ,EAAe,IAAI,CAAS,EACtC,GAAS,EAAM,OAAS,GAAK,EAAM,UACjC,EAAM,WACR,IAAI,gBAAgB,EAAM,SAAS,EAErC,EAAe,OAAO,CAAS,EAEnC,CACF,CAEA,SAAS,GAAqB,EAAsB,EAAa,EAAgB,EAAW,CAC1F,IAAM,EAAgB,EAAgB,EAAI,aAAa,IAAkB,GACzE,MAAO,GAAG,EAAa,MAAM,GAA+B,CAAG,IAAI,GACrE,CAEA,SAAS,GAA4B,EAA6C,CAC3E,KACL,IAAI,EAAI,WAAW,OAAO,EAAG,OAAO,EAEpC,GAAI,CACF,IAAM,EAAS,IAAI,IAAI,CAAG,EAC1B,GAAI,EAAO,WAAa,SAAW,EAAO,WAAa,SACrD,OAAO,EAAO,SAAS,CAE3B,MAAQ,CACN,MACF,CAToC,CAYtC,CAEA,SAAS,GAAqB,EAAkB,EAA6B,CAC3E,IAAM,EAAQ,CACZ,KAAM,EACN,QAAS,GACT,UAAW,OACX,QAAS,QAAQ,QAAQ,EAAE,CAC7B,EAsBA,MApBA,GAAM,QAAU,GAAe,CAAG,CAAC,CAChC,KAAM,GAAS,CACd,IAAM,EAAY,IAAI,gBAAgB,CAAI,EAE1C,MADA,GAAM,UAAY,EACX,CACT,CAAC,CAAC,CACD,YAAc,CACb,EAAM,QAAU,GAChB,GAAiB,OAAO,CAAQ,EAC5B,EAAM,OAAS,GAAK,EAAM,YACvB,EAAsB,SAAS,CAAQ,GAC1C,EAAsB,KAAK,CAAQ,EAErC,GAAuB,EAE3B,CAAC,EAEH,EAAe,IAAI,EAAU,CAAK,EAClC,GAAiB,IAAI,EAAU,EAAM,OAAO,EAErC,CACT,CAEA,SAAS,GAAqB,EAAkB,EAA6B,CAC3E,IAAM,EAAQ,EAAe,IAAI,CAAQ,GAAK,GAAqB,EAAU,CAAG,EAChF,EAAM,MAAQ,EACd,IAAM,EAAa,EAAsB,QAAQ,CAAQ,EAIzD,OAHI,IAAe,IACjB,EAAsB,OAAO,EAAY,CAAC,EAErC,CACT,CAEA,SAAS,GAAsB,EAAwB,CACrD,IAAM,EAAQ,EAAe,IAAI,CAAQ,EACpC,IAEL,IAAM,KACF,IAAM,KAAO,GAAK,CAAC,EAAM,WAExB,EAAsB,SAAS,CAAQ,GAC1C,EAAsB,KAAK,CAAQ,EAErC,GAAuB,GACzB,CAKA,IAAM,GAAgB,IAAI,IAItB,GAAqB,EACnB,GAA8B,IAAI,IAExC,SAAS,GAA4B,EAAkC,CAErE,OADA,GAA4B,IAAI,CAAQ,MAC3B,CACX,GAA4B,OAAO,CAAQ,CAC7C,CACF,CAEA,SAAS,IAAgC,CACvC,OAAO,EACT,CAKA,SAAS,GAAmB,EAAoC,CAC9D,IAAM,EAAW,GAAc,IAAI,CAAW,EAC9C,GAAI,EAAU,OAAO,EAErB,IAAM,EAAuB,CAC3B,QAAS,EAAe,yBAA0B,CAAE,IAAK,CAAY,CAAC,CAAC,CACpE,KAAM,IACL,EAAM,IAAM,EACL,EACR,CAAC,CACD,WAEC,EAAM,IAAM,EACL,EACR,CACL,EAEA,OADA,GAAc,IAAI,EAAa,CAAK,EAC7B,CACT,CAGA,SAAgB,IAAmC,CACjD,GAAc,MAAM,EACpB,IAAsB,EACtB,IAAK,IAAM,KAAY,GACrB,EAAS,CAEb,CAYA,SAAgB,IAA2E,CACzF,MAAO,CAAE,UAAW,EAAe,KAAM,cAAe,GAAiB,IAAK,CAChF,CAEA,SAAgB,GACd,EACA,EAAgB,EACI,CACpB,IAAM,EAAQ,GAAQ,EAEhB,EADkB,GAAa,EAChB,GAAmB,GAA4B,EAC9D,EAAgB,GAA4B,CAAG,EAC/C,EACJ,GAAiB,CAAC,EAAc,WAAW,OAAO,EAC9C,GAAqB,EAAc,EAAe,CAAa,EAC/D,OAIA,CAAC,EAAsB,MAA2B,gBAChD,GAA4B,GAAK,EACzC,EACM,EAAc,EAAS,GAA6B,GAAO,IAAI,GAAK,OAAa,OACjF,EAAgB,GAAS,GAAiC,EAC1D,KAAa,wBACjB,GACA,GACA,EACF,EAEM,CAAC,EAAe,MAAoB,iBAIhC,CACR,OAAQ,EACR,IAAK,GAAS,EAAc,GAAc,IAAI,CAAW,CAAC,EAAE,IAAM,OAClE,YACF,EAAE,GAEF,mBAAgB,CACd,GAAI,CAAC,GAAiB,CAAC,EAAa,OACpC,IAAM,EAAQ,GAAmB,CAAW,EAC5C,GAAI,EAAM,IAAK,CACb,EAAiB,CAAE,OAAQ,EAAa,IAAK,EAAM,IAAK,YAAW,CAAC,EACpE,MACF,CACA,IAAI,EAAY,GAMhB,OALA,EAAW,QAAQ,KAAM,GAAa,CAC/B,GACH,EAAiB,CAAE,OAAQ,EAAa,IAAK,EAAU,YAAW,CAAC,CAEvE,CAAC,MACY,CACX,EAAY,EACd,CACF,EAAG,CAAC,EAAe,EAAa,CAAU,CAAC,EAC3C,IAAM,EAAY,CAAC,EACb,EAAwB,GAAe,WAAW,OAAO,GAAK,GAC9D,CAAC,EAAe,MAAoB,gBAAsC,CAC9E,IAAM,EAAc,EAAoB,EAAe,IAAI,CAAiB,EAAI,OAChF,MAAO,CACL,SAAU,EACV,IAAK,GAAa,CAAC,EAAwB,GAAa,UAAY,CACtE,CACF,CAAC,EAyDD,IAvDA,mBAAgB,CACV,MAKJ,OAHI,GAA4B,IAAM,QACpC,GAA6B,EAExB,GAA4B,CAAuB,CAC5D,EAAG,CAAC,CAAK,CAAC,GAEV,mBAAgB,CACd,GAAI,EAAO,OACX,GAAI,CAAC,EAAe,CAClB,EAAiB,CAAE,SAAU,OAAW,IAAK,MAAU,CAAC,EACxD,MACF,CAEA,GAAI,CAAC,EAAW,CACd,EAAiB,CAAE,SAAU,OAAW,IAAK,CAAc,CAAC,EAC5D,MACF,CAEA,GAAI,EAAuB,CACzB,EAAiB,CAAE,SAAU,OAAW,IAAK,CAAc,CAAC,EAC5D,MACF,CAEA,GAAI,CAAC,EAAmB,CACtB,EAAiB,CAAE,SAAU,OAAW,IAAK,MAAU,CAAC,EACxD,MACF,CAEA,IAAM,EAAQ,GAAqB,EAAmB,CAAa,EAC/D,EAAY,GACV,CAAE,aAAc,EAgBtB,OAdA,EAAiB,CAAE,SAAU,EAAmB,IAAK,CAAU,CAAC,EAEhE,EAAM,QACH,KAAM,GAAsB,CACtB,GACH,EAAiB,CAAE,SAAU,EAAmB,IAAK,CAAkB,CAAC,CAE5E,CAAC,CAAC,CACD,UAAY,CACN,GACH,EAAiB,CAAE,SAAU,EAAmB,IAAK,MAAU,CAAC,CAEpE,CAAC,MAEU,CACX,EAAY,GACZ,GAAsB,CAAiB,CACzC,CACF,EAAG,CAAC,EAAW,EAAmB,EAAe,EAAO,CAAqB,CAAC,EAE1E,EAUF,OAPK,EACA,EAGD,EAAc,SAAW,GAAe,EAAc,aAAe,EAChE,EAAc,IAEhB,GAAc,IAAI,CAAW,CAAC,EAAE,IANZ,EADT,OAUpB,GAAI,CAAC,GAAa,EAChB,OAAO,EAGL,KAAc,WAAa,EAI/B,OAAO,EAAc,GACvB,CAIA,SAAgB,GACd,EACA,EAAgB,EACI,CACpB,IAAM,EAAa,GAAO,EAAgB,EAAI,EAAsB,EAAK,CAAa,EAAI,EAG1F,OAFoB,GAAsB,EAAY,CAClD,IACG,GAAQ,EAAI,OAAY,EACjC,CAEA,IAAM,GAAyB,CAAC,IAAK,KAAM,IAAI,EAQ/C,SAAgB,GAAqB,EAA4C,CAC/E,GAAM,CAAC,EAAO,MAAY,YAAS,EAAK,EAClC,CAAC,EAAe,MAAoB,YAAS,CAAC,EAC9C,EAAW,GAAyB,EAAK,CAAa,EAyB5D,OAvBA,mBAAgB,CACd,EAAS,EAAK,EACd,EAAiB,CAAC,CACpB,EAAG,CAAC,CAAG,CAAC,GAGR,mBAAgB,CACd,EAAS,EAAK,CAChB,EAAG,CAAC,CAAQ,CAAC,GAEb,mBAAgB,CACd,GAAI,CAAC,EAAO,OACZ,IAAM,EAAQ,GAAuB,GACrC,GAAI,IAAU,OAAW,OACzB,IAAM,EAAQ,eAAiB,CAC7B,EAAS,EAAK,EACd,EAAkB,GAAa,EAAW,CAAC,CAC7C,EAAG,CAAK,EACR,UAAa,aAAa,CAAK,CACjC,EAAG,CAAC,EAAO,CAAa,CAAC,EAIlB,CAAE,WAAU,QAAO,WAFV,mBAAkB,EAAS,EAAI,EAAG,CAAC,CAEzB,CAAQ,CACpC,CCxXA,IAAM,GAAM,EAAa,kBAAkB,EAEvC,GAAoC,QAAQ,QAAQ,EACpD,GAAsC,GAEtC,GAES,IACX,EACA,EACA,IACkB,CAClB,GAAI,CAAC,GAAQ,EAAG,OAAO,QAAQ,QAAQ,EAEvC,IAAM,EAAQ,GAAmB,KAAK,SAAY,CAChD,GAAI,CACE,GAAW,GAGb,MAAM,GAAgB,CAAE,UAAS,MAAO,EAAa,MAAO,CAAO,CAAC,EAEhE,IAAgB,KAClB,GAA2B,EAC3B,GAAiB,KAGnB,MAAM,GAAkB,EACxB,GAA2B,EAC3B,GAAiB,OAErB,MAAQ,CAEN,GAAI,KAAK,sCAAsC,CACjD,CACF,CAAC,EAGD,MADA,IAAqB,EACd,CACT,EAEM,OAA6C,CACjD,IAAM,EAAU,GAAsB,EAEtC,OADK,EACE,GAAwB,EAAQ,QAAS,EAAQ,YAAa,EAAQ,MAAM,EAD9D,QAAQ,QAAQ,CAEvC,EAEa,OAA6C,CACxD,GAAI,CAAC,GAAQ,EAAG,OAAO,QAAQ,QAAQ,EAEvC,GAAI,CAAC,GAAqC,CACxC,IAAM,MAAa,CACjB,GAA2B,CAC7B,EACA,OAAO,iBAAiB,UAAW,CAAI,EACvC,OAAO,iBAAiB,wBAAyB,CAAI,EACrD,GAAsC,EACxC,CAEA,OAAO,GAAsB,CAC/B,EC7DA,SAAgB,GACd,EACA,EACA,EACe,CAiBf,OAhBI,GAAQ,EAEH,GAAwB,EAAS,EAAa,CAAM,GAGzD,EAAE,kBAAmB,YAAc,CAAC,UAAU,cAAc,YAIhE,UAAU,cAAc,WAAW,YAAY,CAC7C,KAAM,aACN,cACA,UACA,QAEF,CAAC,EATQ,QAAQ,QAAQ,EAW3B,CAIA,SAAgB,GAAyB,EAIvB,CAChB,IAAM,EAAU,GAAiB,EAAS,MAAM,GAAK,EACrD,OAAO,GAAgB,EAAQ,QAAS,EAAQ,YAAa,EAAQ,MAAM,CAC7E,CCvBA,IAAa,IACX,EACA,IACS,CACT,GAAI,EAAS,SAAW,EACtB,MAAU,MACR,yDAAyD,EAAe,aAAa,EAAS,QAChG,CAEJ,EAIM,GAAgB,IAAI,IACpB,GAAoB,IAAI,IACxB,GAAyB,qBAMzB,OAA0C,CAC9C,GAAI,OAAO,UAAc,IAAa,OACtC,IAAM,EAAS,UAA+C,MAC9D,OAAO,GAAS,OAAO,EAAM,SAAY,WAAa,EAAQ,MAChE,EAEM,GAAoB,GACxB,EAA+B,EAAqB,CAAC,CAAC,CAAC,CAAC,KACrD,GAAW,EAAO,SAAW,CAChC,EAEI,GAAmB,MAAU,EAAgB,IAA4C,CAE7F,IAAM,GADW,GAAc,IAAI,CAAM,GAAK,QAAQ,QAAQ,GACzC,UAAY,MAAS,CAAC,CAAC,KAAK,CAAS,EACpD,EAAU,EAAI,SACZ,WACA,MACR,EAEA,OADA,GAAc,IAAI,EAAQ,CAAO,EAC1B,CACT,EAEa,GAA6B,KAAO,IAAkC,CACjF,MAAM,GAAkB,IAAI,CAAM,CAAC,EAAE,UAAY,MAAS,CAC5D,EAEa,IACX,EACA,IACsC,CACtC,GAAM,CAAE,QAAS,EACjB,GAAI,CAAC,GAAQ,CAAC,EAAQ,aAAc,OAEpC,IAAM,EAAY,KAAO,IAAwC,CAC/D,EAAoB,EAAQ,OAAQ,CAClC,YAAa,EAAO,YACpB,aAAc,EAAO,aACrB,YAAa,EAAO,OAAS,EAAO,OAAO,QAAQ,EAAI,KAAK,IAAI,EAAI,MACtE,CAAC,EAEuB,wBAA4D,MAChF,IAAoB,EAAQ,QAC9B,MAAM,GAAgB,EAAQ,QAAS,EAAO,YAAa,EAAQ,MAAM,CAE7E,EAEI,EACE,OACJ,CACE,GAAwB,EACrB,gBAAgB,CAAC,CACjB,KAAM,GAAoC,CACzC,GAAyB,EAAK,OAAQ,CAAQ,EAC9C,IAAM,EAAS,IAAI,GAAO,EAAU,CAClC,SAAU,EAAK,SACf,YAAa,GAAa,EAC1B,SAAU,EAAQ,QACpB,CAAC,EACD,OAAO,IAAI,GAAe,EAAQ,CAAS,CAC7C,CAAC,CAAC,CACD,MAAO,GAAmB,CAEzB,KADA,GAAwB,OAClB,CACR,CAAC,EAEE,GAGT,MAAO,CACL,qBAAsB,KAAO,IAAiB,CAC5C,IAAM,EAAU,GAAiB,EAAQ,OAAQ,SAAY,CAC3D,IAAM,EAAiB,MAAM,EAAkB,EACzC,EAA0B,SAAY,CAE1C,IAAM,EAAgB,GAAiB,EAAQ,MAAM,EAC/C,EACJ,GAAe,cACf,EAA6B,EAAQ,MAAM,GAC3C,EACF,GAAI,GAAiB,IAAuB,EAC1C,MAAO,CACL,YAAa,EAAc,YAC3B,aAAc,CAChB,EAEF,IAAM,EAAS,MAAM,EAAe,qBAAqB,CAAkB,EAC3E,MAAO,CACL,GAAG,EAEH,aAAc,EAAO,cAAgB,CACvC,CACF,EAEM,EAAQ,GAAY,EAC1B,OAAO,EACH,EAAM,QAAQ,GAAwB,CAAuB,EAC7D,EAAwB,CAC9B,CAAC,EACD,GAAkB,IAAI,EAAQ,OAAQ,CAAO,EAC7C,GAAI,CACF,OAAO,MAAM,CACf,QAAU,CACJ,GAAkB,IAAI,EAAQ,MAAM,IAAM,GAC5C,GAAkB,OAAO,EAAQ,MAAM,CAE3C,CACF,CACF,CACF,EC1Ia,GAAmB,MAC9B,EACA,EACA,EACA,EACA,EAAiB,KACC,CAClB,IAAM,EAAW,MAAM,EAAQ,EAAS,oBAAqB,CAC3D,OAAQ,OACR,QAAS,CACP,OAAQ,mBACR,eAAgB,mCAClB,EACA,KAAM,IAAI,gBAAgB,CACxB,QACA,gBAAiB,EACjB,UAAW,CACb,CAAC,CACH,CAAC,EAED,GAAI,CAAC,EAAS,GACZ,MAAU,MAAM,kCAAkC,EAAS,OAAO,EAAE,CAExE,EC5BM,GAAoB,IAAI,IAE9B,SAAgB,GAAgB,EAAO,EAAY,CACjD,GAAI,EAAE,aAAsB,YAC1B,MAAU,MAAM,yCAAyC,EAE3D,GAAkB,IAAI,EAAO,CAAU,CACzC,CAEA,SAAS,GAAc,EAAO,CAC5B,OAAO,GAAkB,IAAI,CAAK,YAAa,UACjD,CAEA,SAAS,GAAc,EAAO,CAC5B,OAAO,GAAkB,IAAI,CAAK,CACpC,CAEA,SAAgB,IAAyB,CACvC,GAAkB,MAAM,CAC1B,CAEA,eAAe,GAAoB,CAAE,QAAQ,CAE3C,IAAM,EADS,OAAO,KAAK,CACb,EAAO,KAAK,EAAa,EAClC,KAEL,MAAO,CAAC,EADW,GAAc,CAClB,CAAU,CAC3B,CAEA,SAAS,GAAsB,EAAO,EAAS,EAAY,CACzD,GAAkB,IAAI,EAAO,CAAU,CACzC,CAEA,IAAa,GAAkB,CAC7B,uBACA,wBACF,ECDM,GAAM,EAAa,aAAa,EAChC,EAAW,EAAkB,aAAa,EAE1C,GAAc,SACd,GAAe,UACf,GAAsB,EAGtB,GAAyB,IAEzB,GAAiB,GACjB,GAA0B,KAE1B,GAA+B,IAC/B,GAA0B,IAG1B,GAAuB,EAEvB,GAA+B,cAC/B,GAA6B,YAC7B,GAAgC,eAChC,GAAyB,QACzB,GAA8B,cAC9B,GAAoC,oBACpC,GAA6B,GAC7B,GAA4B,IAC5B,GAAkC,GAClC,GAAsC,EAwCtC,IAAiB,EAA2B,IAC5C,OAAO,GAAU,UAAY,OAAO,MAAM,CAAK,GAAK,GAAS,EAAU,EACpE,KAAK,MAAM,CAAK,EAKnB,IAAqB,EAA6B,IACtD,EAAM,OAAU,EAAU,YAC1B,cAAe,GACf,EAAM,YAAc,EAIhB,IACJ,EACA,IACkB,CAClB,IAAK,IAAI,EAAI,EAAO,OAAS,EAAG,GAAK,EAAG,IAAQ,CAC9C,IAAM,EAAQ,EAAO,GACrB,GAAI,GAAS,GAAkB,EAAO,CAAM,EAAG,OAAO,CACxD,CAEF,EAEM,GAAgB,GAAgE,CACpF,IAAM,EAAU,GAAO,QACvB,OAAO,GAAW,OAAO,GAAY,SAC/B,EAAqC,WACvC,MACN,EAEM,GAAY,GAChB,OAAO,GAAU,SAAW,EAAQ,OAGhC,IACJ,EACA,EACA,IACsC,CAEtC,IAAM,EAAY,GAAmB,CAAC,EAEtC,MAAO,CACL,KAAM,EAAU,WAChB,UAAW,EACX,QAAS,EACT,OAAQ,EACR,SAAU,oBAAoB,IAC9B,iBAAkB,KAAK,IAAI,EAC3B,QAAS,CACP,WAAY,EAAgB,KAC5B,YAAa,GAAS,EAAS,WAAW,EAC1C,WAAY,GAAS,EAAS,UAAU,CAC1C,CACF,CACF,EAEM,OAA0E,CAC9E,CAAC,EAAU,WAAY,EAAE,EACzB,CAAC,EAAU,cAAe,EAAE,EAC5B,CAAC,EAAU,eAAgB,EAAE,EAC7B,CAAC,EAAU,WAAY,EAAE,EACzB,CAAC,EAAU,SAAU,EAAE,EACvB,CAAC,EAAU,mBAAoB,EAAE,EACjC,CAAC,EAAU,cAAe,EAAE,EAC5B,CAAC,EAAU,gBAAgC,EAC3C,CAAC,EAAU,gBAAiB,EAAE,EAC9B,CAAC,EAAU,yBAAuC,EAElD,CAAC,GAAkC,KAAM,EAAE,CAC7C,EAEM,GAAkE,CACtE,CAAC,EAAU,WAAY,EAAE,EACzB,CAAC,EAAU,SAAU,EAAE,EACvB,CAAC,EAAU,WAAY,EAAE,EACzB,CAAC,EAAU,mBAAoB,EAAE,EACjC,CAAC,EAAU,cAAe,EAAE,EAC5B,CAAC,EAAU,eAAgB,EAAE,EAC7B,CAAC,EAAU,cAAe,EAAE,EAC5B,CAAC,EAAiB,WAAY,EAAE,EAChC,CAAC,EAAU,cAA4B,EACvC,CAAC,EAAU,eAA6B,CAC1C,EAEM,GAAwE,CAE5E,CAAC,EAAU,gBAAiB,EAAE,EAC9B,CAAC,EAAU,SAAU,EAAE,EACvB,CAAC,EAAU,UAAW,EAAE,EACxB,CAAC,EAAU,WAAY,EAAE,EACzB,CAAC,EAAU,mBAAoB,EAAE,EACjC,CAAC,EAAU,cAAe,EAAE,EAC5B,CAAC,EAAU,sBAAuB,EAAE,EACpC,CAAC,EAAU,gBAAiB,EAAE,EAC9B,CAAC,EAAU,eAAgB,EAAE,EAC7B,CAAC,EAAU,cAAe,EAAE,EAC5B,CAAC,EAAU,WAAY,EAAE,EACzB,CAAC,EAAU,iBAAkB,EAAE,EAC/B,CAAC,EAAU,cAAe,EAAE,EAC5B,CAAC,EAAU,wBAAsC,EACjD,CAAC,EAAU,gBAAgC,EAC3C,CAAC,EAAU,WAAY,EAAsB,EAC7C,CAAC,EAAU,cAA4B,EACvC,CAAC,EAAU,eAA6B,EACxC,CAAC,EAAU,gBAAiB,EAAE,EAC9B,CAAC,EAAU,yBAAuC,EAClD,CAAC,GAAkC,KAAM,EAAE,EAC3C,GAAG,OAAO,OAAO,CAAgB,CAAC,CAAC,IAAK,GAAS,CAAC,KAAsB,CAAqB,CAC/F,EAEM,GAA8B,IAAoD,CACtF,eAAgB,EAChB,eAAgB,EAClB,GAEM,GAAgC,IAAoD,CACxF,eAAgB,EAChB,eAAgB,EAClB,GAEM,GAA6B,IAAoD,CACrF,eAAgB,EAGhB,eAAgB,CAAC,GAAG,GAA4B,CAAC,EAAU,cAA4B,CAAC,CAC1F,GAEM,GAAuE,CAC3E,CAAC,EAAiB,aAA2B,EAC7C,CAAC,EAAiB,oBAAkC,CACtD,EAEM,QAA6D,CACjE,eAAgB,EAChB,eAAgB,EAClB,GAIM,QAAkE,CACtE,eAAgB,EAChB,eAAgB,CAAC,GAAG,GAAsB,GAAG,EAAyB,CACxE,GAEM,QAAyD,CAC7D,eAAgB,EAChB,eAAgB,EAClB,GAEM,QAA+D,CACnE,eAAgB,GAChB,eAAgB,GAAuB,CACzC,GAEM,OAA6C,CACjD,IAAM,EAAQ,IAAI,IACZ,EAAoB,GAAuB,EAgBjD,OAdA,EAAM,IAAI,GAAa,CACrB,OAAQ,CAAC,CAAC,EAAG,EAAkB,CAAC,EAChC,eAAgB,GAChB,eAAgB,EAChB,QAAS,CAAE,UAAW,EAAM,CAC9B,CAAC,EAED,EAAM,IAAI,GAAc,CACtB,OAAQ,CAAC,CAAC,EAAG,EAAkB,CAAC,EAChC,eAAgB,GAChB,eAAgB,EAChB,QAAS,CAAE,UAAW,EAAK,CAC7B,CAAC,EAEM,CACT,EAEM,GAAmB,GAClB,GAAM,QAAQ,OACZ,EAAK,OAAO,QAAQ,EAAK,IAAU,KAAK,IAAI,EAAK,EAAM,IAAM,EAAE,EAAG,EAAE,EADzC,GAYvB,IACX,EACA,IACS,CACT,GAAI,CAAC,EAAY,OAEjB,IAAM,EAAU,EAAuC,OACvD,GAAI,CAAC,GAAU,OAAO,GAAW,SAAU,OAE3C,IAAM,EAAe,EACrB,EAAa,MAAQ,CAAC,EACtB,EAAa,MAAQ,CAAC,GAAG,CAAO,CAClC,EAoBa,IACX,EACA,EACA,IACmC,CACnC,GAAI,CAAC,GAAM,MAAO,OAAO,KACzB,IAAI,EAAmB,GACjB,EAGD,CAAC,EAEN,IAAK,GAAM,CAAC,EAAQ,KAAa,OAAO,QAAQ,EAAK,KAAK,EAAG,CAC3D,IAAM,EAAe,EACf,EAAwB,EAAa,UAAY,GACjD,EACJ,EAAa,oBAAsB,IAAQ,EAAa,6BAA+B,GACnF,EAAU,EAAa,SACvB,EAAW,MAAM,QAAQ,EAAa,QAAQ,EAAI,EAAa,SAAW,CAAC,EAC3E,EAAiB,EAAS,OAC1B,EAAO,GAAI,QAAQ,CAAM,EACzB,EAAc,GAAM,yBAAyB,EAC7C,EAAe,GAAM,gBAAgB,EACrC,EAAa,GAAc,UAAU,GAAK,CAAC,EAC7C,GAAyB,GAC3B,EAAU,2BAA2B,CAAC,CAAC,MAAO,GAAmB,CAC/D,EAAS,KAAK,OAAQ,oDAAqD,CACzE,SACA,MAAO,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,CAC9D,CAAC,CACH,CAAC,EAEH,IAAM,EAAyB,CAAC,EAChC,IAAK,IAAM,KAAS,EAAY,CAC9B,IAAM,EAAU,EAAM,MAAM,EACxB,GAAS,EAAa,KAAK,CAAO,CACxC,CACA,IAAM,EAAgB,IAAI,IAAI,CAAY,EACpC,EACJ,EAAa,UAAY,IACzB,OAAO,GAAY,UACnB,OAAO,UAAU,CAAO,GACxB,GAAW,GACX,EAAU,EACR,EAAuB,GAC3B,GAAI,CAAC,GAAmB,CAAC,GAAuB,EAAa,UAAY,GAAM,CAC7E,IAAI,EAAkB,GACtB,EAAuB,EAAS,KAAM,GAAU,CAC9C,IAAM,EAAU,EAAM,SAItB,OAHI,OAAO,GAAY,SACnB,EAAc,IAAI,CAAO,EAAU,GACvC,EAAkB,GACX,IAHiC,EAI1C,CAAC,CACH,CAEA,IAAM,EAAmB,EACtB,IAAK,GAAU,EAAM,QAAQ,CAAC,CAC9B,OAAQ,GAA+B,OAAO,GAAY,QAAQ,EAC/D,EAA0B,EAAiB,UAAW,GAC1D,EAAc,IAAI,CAAO,CAC3B,EACM,GACJ,EAA0B,EACtB,GACA,EAAa,QAAQ,EAAiB,EAAyB,EAC/D,GAAmB,EAA0B,GAAK,GAAsB,EAExE,GACJ,GAAmB,IAAI,CAAM,IAAM,IACnC,EAAc,KAAO,GACrB,EAA0B,EAEtB,GACJ,EAAiB,IAChB,GAAmB,GAAuB,GAAwB,IAEjE,KAAmB,EAAa,QAAU,IAE9C,IAAM,EAAW,EAA0B,GAAK,GAChD,GACE,EAAc,KAAO,GACrB,GACA,GACA,GACA,EAAiB,OAAS,GAC1B,OAAO,EAAa,YAAe,WAClC,EAAa,UAAY,IAAQ,EAAa,UAAY,IAC3D,CACA,IAAM,EAAgB,EAAW,OAAQ,GAAU,EAAM,UAAU,CAAC,EAChE,EAAc,OAAS,GACzB,EAAuB,KAAK,CAAE,cAAa,OAAQ,CAAc,CAAC,EAEpE,IAAM,EAAmB,EAAK,SAC9B,EAAY,kBACV,OAAO,EAAa,YAAe,SAAW,EAAa,WAAa,MAC1E,EACA,IAAM,EAAkB,EAAY,gBAAgB,EACpD,EAAK,SAAW,EAAgB,SAAS,EAAc,SAAS,EAChE,EAAK,aAAe,EAAgB,SAAS,EAAc,QAAQ,EAC/D,EAAK,WAAa,GACpB,EAAK,KAAK,GAAU,gBAAiB,EAAM,EAAkB,EAAK,QAAQ,EAE5E,EAAmB,GACnB,QACF,CAMA,GAAI,EAAa,UAAY,IAAQ,IAA4B,GAAK,GAAsB,EAAG,CAC7F,IAAM,EAAW,GAAc,mBAAmB,EAAc,SAAS,EACrE,OAAO,GAAa,WAAU,EAAa,WAAa,EAC9D,CAEK,OAID,OAAO,EAAa,YAAe,SAAU,CAC/C,IAAM,EAAQ,GACV,QAAQ,CAAM,CAAC,EACf,gBAAgB,CAAC,CAClB,mBAAmB,EAAc,SAAS,EACzC,OAAO,GAAU,WAAU,EAAa,WAAa,EAC3D,CACF,CAKA,OAHI,GAAkB,GAAI,sBAAsB,EAC5C,EAAuB,SAAW,EAAU,SAEnC,CACX,IAAK,GAAM,CAAE,cAAa,YAAY,EAAwB,CAC5D,IAAM,EAAe,EAAY,gBAAgB,EACjD,IAAK,IAAM,KAAS,EAAQ,CAC1B,IAAM,EAAU,EAAM,MAAM,EAE1B,EAAM,SAAW,MACjB,EAAM,SAAW,GAAY,WAC7B,CAAC,GACD,EAAY,cAAc,CAAO,GAInC,EAAY,mBAAmB,EAAO,EAAc,CAClD,kBAAmB,GACnB,WAAY,EACd,CAAC,CACH,CACF,CACF,CACF,EAEM,GAAqC,IAErC,GAAiB,GACjB,MAAM,QAAQ,CAAK,EAAU,IAAI,EAAM,IAAI,EAAa,CAAC,CAAC,KAAK,GAAG,EAAE,GAClD,OAAO,GAAU,UAAnC,EAMK,IALS,OAAO,KAAK,CAAgC,CAAC,CAC1D,SAAS,CAAC,CACV,IACE,GAAQ,GAAG,KAAK,UAAU,CAAG,EAAE,GAAG,GAAe,EAAkC,EAAI,GAEjF,EAAQ,KAAK,GAAG,EAAE,GAExB,KAAK,UAAU,CAAK,EAGhB,GAAwB,GAAwC,CAC3E,GAAI,CAAC,EAAM,OACX,IAAM,EAAa,EAAK,gBAAgB,CAAC,CAAC,UAAU,EAC9C,EAAgB,EAAW,OAC9B,GACC,EAAM,SAAW,MACjB,EAAM,SAAW,GAAY,WAC7B,EAAM,SAAW,GAAY,IACjC,EACA,GAAI,EAAc,SAAW,EAAG,OAEhC,IAAM,EAAkB,IAAI,IACtB,GAAoB,EAAwB,IAA+B,CAC/E,IAAM,EAAc,EAAU,MAAM,EAIpC,MAHI,CAAC,GAAe,IAAc,GAAQ,EAAgB,IAAI,CAAW,GACrE,EAAU,SAAW,MACrB,EAAU,UAAU,IAAM,EAAK,UAAU,EAAU,GAChD,CAAC,EAAU,WAAW,CAC/B,EAEA,IAAK,IAAM,KAAQ,EAAe,CAChC,IAAM,EAAQ,EAAK,SAAS,EACxB,EAAQ,EACR,EAAW,KACR,GACC,EAAiB,EAAW,CAAI,GAAK,EAAU,YAAY,CAAC,EAAE,iBAAmB,CACrF,EACA,OACJ,GAAI,CAAC,EAAO,CACV,IAAM,EAAW,EAAK,YAAY,EAC5B,EAAc,GAAc,EAAK,eAAe,CAAC,EACvD,EAAQ,EAAW,KAAM,GAAc,CAErC,GADI,CAAC,EAAiB,EAAW,CAAI,GACjC,EAAU,YAAY,IAAM,EAAU,MAAO,GACjD,IAAM,EAAe,EAAU,YAAY,CAAC,EAAE,eAG9C,OAFI,OAAO,GAAiB,UAAY,IAAiB,GACrD,EAAU,MAAM,EAAI,EAAK,MAAM,EAAI,GAA2C,GAC3E,GAAc,EAAU,eAAe,CAAC,IAAM,CACvD,CAAC,CACH,CACA,IAAM,EAAU,GAAO,MAAM,EAC7B,GAAI,CAAC,GAAS,CAAC,EAAS,SACxB,EAAgB,IAAI,CAAO,EAE3B,IAAM,EAAW,EAAM,YAAY,EAC/B,GAAS,OAAO,EAAS,gBAAmB,WAC9C,EAAS,eAAiB,EAC1B,EAAM,YAAY,CAAQ,GAE5B,EAAK,YAAY,CAAO,EACxB,EAAK,iBAAiB,EAAO,CAAI,EACjC,EAAS,KAAK,OAAQ,iCAAkC,CACtD,OAAQ,EAAK,OACb,YAAa,EAAK,MAAM,EACxB,cAAe,CACjB,CAAC,CACH,CACF,EAEa,GAAb,KAAgC,CAmKX,GACA,QAnKnB,SAAmB,GAEnB,SAEA,wBAA2C,IAAI,IAE/C,sBAAyC,IAAI,IAO7C,4BAA+C,IAAI,IAEnD,yBAA4C,IAAI,IAEhD,mBAAsC,IAAI,IAE1C,2BAAqC,IAAI,IAEzC,2BAA8C,IAAI,IAElD,+BAA6D,KAO7D,aAAgC,IAAI,IAEpC,2BAAqC,GAErC,kBAEA,aAEA,sBAAkD,QAAQ,QAAQ,EAAK,EAEvE,0BAIA,sBAEA,sBAAgC,GAEhC,gBAEA,mBAEA,YAMA,kBAKA,iBAA2B,GAE3B,8BAAwC,GAExC,uBAAiC,GAEjC,iCAA2C,GAE3C,wBAA2C,IAAI,IAE/C,qBAA+B,GAE/B,UAAoB,EAEpB,4BAEA,mBAA6B,GAE7B,yBAA4C,IAAI,IAIhD,iBAAoC,IAAI,QAKxC,yBAA4C,IAAI,QAKhD,0BAA6C,IAAI,IAEjD,6BAAgD,IAAI,IAEpD,2BAA8C,IAAI,IAElD,0BAA6C,IAAI,IAKjD,UAAoB,EAEpB,mBAAkD,IAAI,IAEtD,uBAA0C,IAAI,IAE9C,uBAA0C,IAAI,IAO9C,yBAA4C,IAAI,IAKhD,gCAAmD,IAAI,IAKvD,yBAA4C,IAAI,IAIhD,+BAAkD,IAAI,IAQtD,6BAAgD,IAAI,IAGpD,WAAoC,KAEpC,eAEA,kBAEA,OAAiB,GAEjB,mBAA6B,EAE7B,cAAiC,IAAI,IAGrC,gBAA8E,KAE9E,YAEA,YACE,EACA,EACA,EAA8B,CAAC,EAC/B,CAHiB,UACA,eAGjB,IAAM,EAAgB,GAAc,EAAQ,cAAe,EAAuB,EAClF,KAAK,eAAiB,EAAgB,GAA+B,GAErE,IAAM,EAAoB,GAAc,EAAQ,cAAe,EAA0B,EACzF,KAAK,kBAAoB,EACzB,KAAK,aAAe,IAAI,EAAwB,EAAG,cAAc,CAAC,EAElE,IAAM,EAAsB,GAA2B,CAAiB,EAClE,EAAQ,GAAW,EACzB,KAAK,SAAW,MAAM,KAAK,EAAM,KAAK,CAAC,EACvC,EAAM,SAAS,EAAM,IAAQ,CAC3B,KAAK,uBAAuB,IAAI,EAAK,GAAgB,CAAI,CAAC,CAC5D,CAAC,EACD,KAAK,YAAc,IAAI,GAAY,EAAS,EAAO,EAAqB,EAAI,CAAa,EAEzF,KAAK,YAAY,sBACf,GACA,GAA6B,CAAiB,CAChD,EACA,KAAK,YAAY,sBACf,GACA,GAA0B,CAAiB,CAC7C,EACA,KAAK,YAAY,sBACf,GACA,GAA6B,CAC/B,EACA,KAAK,YAAY,sBACf,GACA,GAA2B,CAC7B,EACA,KAAK,YAAY,sBAAsB,GAAwB,GAAuB,CAAC,EACvF,KAAK,YAAY,sBACf,GACA,GAAgC,CAClC,EAEA,KAAK,aAAe,EAAO,EAAM,IAAQ,CAmBvC,GAlBA,EAAS,KAAK,OAAQ,2BAA2B,IAAS,CACxD,QACA,SAAU,CAAC,CAAC,EACZ,cAAe,CAAC,KAAK,oBACvB,CAAC,EAEG,IACF,EAAS,MAAM,OAAQ,qBAAsB,CAC3C,MAAO,EACP,aAAc,EAAI,QAClB,WAAY,KAAK,UACjB,OACF,CAAC,EACD,EAAqB,mBAAoB,EAAG,CAC1C,WAAY,CAAE,UAAW,UAAW,OAAM,CAC5C,CAAC,GAGC,KAAK,SAAU,CACjB,EAAS,KAAK,OAAQ,uCAAwC,CAC5D,OACF,CAAC,EACD,MACF,CAIA,GAFA,KAAK,gBAAgB,EAEjB,IAAU,GAAiB,gBAAiB,CAC1C,CAAC,GAAO,IACV,KAAK,mBAAqB,GAC1B,KAAK,4BAA8B,YAAY,IAAI,GAErD,MACF,CAEA,GAAI,GAAO,CAAC,GAAQ,IAAU,GAAiB,SAAU,OAEzD,KAAK,yBAAyB,IAAI,CAAI,CAAC,GAAG,EAC1C,KAAK,yBAAyB,OAAO,CAAI,EACzC,IAAK,IAAM,KAAU,OAAO,KAAK,EAAK,OAAS,CAAC,CAAC,EAC/C,GAAqB,KAAK,GAAG,QAAQ,CAAM,CAAC,EAE9C,KAAK,4BAA4B,CAAI,EACrC,KAAK,wBAAwB,EAE7B,KAAK,+BAA+B,QAAS,GAC3C,KAAK,6BAA6B,EAAQ,EAAK,CACjD,EACA,KAAK,+BAA+B,MAAM,EAE1C,KAAK,WAAa,EAClB,KAAK,gBAAgB,CAAI,EAMzB,KAAK,6BAA6B,SAAS,EAAO,IAAW,CACvD,KAAK,UAAY,EAAQ,IAC7B,KAAK,6BAA6B,OAAO,CAAM,EAC/C,KAAK,6BAA6B,EAAQ,EAAK,EACjD,CAAC,EACD,EAAqB,mBAAoB,EAAG,CAC1C,WAAY,CAAE,UAAW,SAAU,CACrC,CAAC,EAED,KAAK,uBAAuB,SAAS,EAAU,IAAQ,CACrD,KAAK,uBAAuB,IAAI,EAAK,CAAQ,CAC/C,CAAC,EAED,IAAM,EAAgF,CAAC,EACnF,EAAiB,EACjB,EAAa,GAEjB,KAAK,SAAS,QAAS,GAAQ,CAE7B,IAAM,EADW,KAAK,YAAY,YAAY,CACzB,GAAU,aAAe,EACxC,EAAgB,KAAK,mBAAmB,IAAI,CAAG,GAAK,EAE1D,GAAkB,EAEd,IAAiB,IACnB,EAAQ,GAAO,CACb,SAAU,EACV,QAAS,EACT,MAAO,EAAe,CACxB,EACA,KAAK,mBAAmB,IAAI,EAAK,CAAY,EAC7C,EAAa,GAEjB,CAAC,GAEG,GAAc,CAAC,KAAK,uBACtB,EAAS,KAAK,OAAQ,oCAAqC,CACzD,WAAY,KAAK,UACjB,UACA,iBACA,cAAe,CAAC,KAAK,oBACvB,CAAC,EAGH,IAAM,EACJ,KAAK,8BAAgC,OACjC,EACA,YAAY,IAAI,EAAI,KAAK,4BAG/B,GAFA,KAAK,4BAA8B,OAE/B,CAAC,KAAK,qBAAsB,CAC9B,KAAK,qBAAuB,GAC5B,IAAM,EACJ,KAAK,YAAc,KAA6C,EAAtC,YAAY,IAAI,EAAI,KAAK,WACrD,EAAS,KAAK,OAAQ,yBAA0B,CAC9C,WAAY,KAAK,UACjB,iBACA,WAAY,OAAO,YACjB,KAAK,SAAS,IAAK,GAAQ,CAAC,EAAK,KAAK,YAAY,YAAY,CAAG,CAAC,EAAE,aAAe,CAAC,CAAC,CACvF,EACA,YAAa,GAAG,EAAe,QAAQ,CAAC,EAAE,GAC5C,CAAC,EACD,EAA4B,wBAAyB,EAAgB,CACnE,WAAY,CAAE,UAAW,SAAU,CACrC,CAAC,EACD,KAAK,iBAAiB,cAAc,CAClC,uBAAwB,KAAK,UAC7B,sBAAuB,CACzB,CAAC,EACD,KAAK,iBAAiB,IAAI,EAC1B,KAAK,gBAAkB,IACzB,CAEA,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EAExB,EAA4B,2BAA4B,EAAc,CACpE,WAAY,CAAE,UAAW,SAAU,CACrC,CAAC,EACG,EAAe,KACjB,EAAS,KAAK,OAAQ,2BAA4B,CAChD,WAAY,KAAK,UACjB,SAAU,GAAG,EAAa,QAAQ,CAAC,EAAE,IACrC,gBACF,CAAC,EAGH,CAAC,WAAY,cAAc,CAAC,CAAC,QAAS,GAAkB,CAItD,IAAM,EAHY,EAAK,aAAa,IAGX,OAAS,CAAC,EACnC,OAAO,QAAQ,CAAK,CAAC,CAAC,SAAS,CAAC,EAAQ,KAAU,CAC5C,IAAkB,gBAAkB,MAAM,QAAQ,CAAI,GAAK,EAAK,SAAW,GAC/E,KAAK,aAAa,IAAI,CAAM,CAC9B,CAAC,CACH,CAAC,EAED,KAAK,iCAAiC,CAAI,EAE1C,WAAW,mBAAqB,CAC9B,GAAI,KAAK,SAAU,OACnB,KAAK,mBAAqB,GAC1B,IAAM,EAAe,IAAI,IAAI,KAAK,YAAY,EAC9C,KAAK,aAAa,MAAM,EACxB,KAAK,yBAAyB,QAAS,GAAa,EAAS,CAAY,CAAC,CAC5E,CAAC,CACH,EAEA,KAAK,mBAAqB,EAAQ,IAAW,CACvC,EAAO,SAAW,KAAK,GAAG,UAAU,IACpC,EAAO,aAAe,EAAgB,OAAS,EAAO,aAAe,EAAgB,MAEzF,KAAK,6BAA6B,EAAO,MAAM,CACjD,EAEA,KAAK,iBAAmB,EAAQ,IAAS,CAIvC,GAHA,KAAK,aAAa,IAAI,CAAM,EAC5B,KAAK,aAAa,UAAU,EAAQ,CAAI,EAEpC,CAAC,KAAK,+BAAiC,KAAK,sBAAuB,OAEvE,IAAI,EAAuB,GACrB,EAA4B,KAAK,yBAAyB,OAAO,CAAM,EACzE,IAA2B,EAAuB,IAGpD,EAAK,UAAY,IACjB,CAAC,GACD,CAAC,KAAK,wBAAwB,IAAI,CAAM,IAExC,KAAK,yBAAyB,IAAI,CAAM,EACxC,EAAuB,IAGrB,GAAsB,KAAK,0BAA0B,CAC3D,EACA,KAAK,mBAAsB,GAAU,KAAK,aAAa,iBAAiB,CAAK,EAE7E,IAAK,IAAM,KAAU,EAAQ,gBAAkB,CAAC,EAC9C,KAAK,gBAAgB,CAAM,CAE/B,CAEA,QAAsB,CACpB,EAAS,KAAK,OAAQ,mCAAoC,CACxD,kBAAmB,KAAK,kBACxB,MAAO,KAAK,QACd,CAAC,EAED,KAAK,WAAa,YAAY,IAAI,EAClC,KAAK,gBAAkB,EAAyB,CAC9C,KAAM,eACN,GAAI,cACJ,WAAY,CACV,iBAAkB,SACpB,CACF,CAAC,EAED,KAAK,YAAY,GAAG,EAAiB,UAAW,KAAK,WAAW,EAChE,KAAK,YAAY,GAAG,EAAiB,SAAU,KAAK,eAAe,EACnE,KAAK,GAAG,GAAG,GAAgB,WAAY,KAAK,iBAAiB,EAC7D,KAAK,GAAG,GAAG,EAAY,YAAa,KAAK,kBAAkB,EAE3D,KAAK,gBAAgB,EAErB,EAAS,KAAK,OAAQ,8CAA8C,CACtE,CAOA,iBAAgC,CAC1B,KAAK,UAAY,KAAK,SAC1B,WAAW,aAAa,KAAK,iBAAiB,EAC9C,KAAK,kBAAoB,WAAW,eAAiB,CACnD,KAAK,kBAAoB,OACrB,MAAK,WACT,EAAS,KAAK,OAAQ,qEAAsE,CAC1F,eAAgB,KAAK,eACrB,WAAY,KAAK,SACnB,CAAC,EACD,KAAK,YAAY,OAAO,EACxB,KAAK,gBAAgB,EACvB,EAAG,KAAK,cAAc,EACxB,CAQA,OAAqB,CACnB,KAAK,mBAAqB,EACtB,OAAK,QAAU,KAAK,YACxB,KAAK,OAAS,GACd,WAAW,aAAa,KAAK,iBAAiB,EAC9C,KAAK,kBAAoB,OACzB,KAAK,YAAY,OAAO,EACxB,EAAS,KAAK,OAAQ,qBAAqB,EAC7C,CAEA,WAA0B,CACxB,KAAK,OAAS,GACd,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,CACvB,CAEA,QAAsB,CACpB,KAAK,mBAAqB,EACrB,KAAK,SACV,KAAK,UAAU,EACf,EAAS,KAAK,OAAQ,sBAAsB,EAC9C,CAGA,eAAgC,CAK9B,OAJI,KAAK,UAAY,CAAC,KAAK,OAAe,IAC1C,KAAK,mBAAqB,GAC1B,KAAK,UAAU,EACf,EAAS,KAAK,OAAQ,sDAAsD,EACrE,GACT,CAEA,gBAAwB,EAAwC,CAC9D,GAAI,KAAK,qBAAuB,EAAG,OAEnC,IAAM,IADW,EAAK,YAAY,YACP,QAAQ,QAAU,KAAO,EACpD,OAAK,mBACD,GAAC,GAAW,KAAK,mBAAqB,IAC1C,KAAK,MAAM,CACb,CAEA,UAA2B,CACzB,OAAO,KAAK,MACd,CAGA,eAAsC,CAEpC,OADK,KAAK,OACH,IAAI,QAAS,GAAY,CAC9B,KAAK,cAAc,IAAI,CAAO,CAChC,CAAC,EAHwB,QAAQ,QAAQ,CAI3C,CAEA,sBAAqC,CACnC,IAAM,EAAU,MAAM,KAAK,KAAK,aAAa,EAC7C,KAAK,cAAc,MAAM,EACzB,EAAQ,QAAS,GAAY,EAAQ,CAAC,CACxC,CAEA,SAAuB,CACjB,KAAK,WAET,EAAS,KAAK,OAAQ,yBAA0B,CAC9C,UAAW,KAAK,UAChB,qBAAsB,KAAK,oBAC7B,CAAC,EAED,KAAK,yBAAyB,MAAM,EACpC,KAAK,6BAA6B,MAAM,EACxC,KAAK,4BAA4B,MAAM,EACvC,KAAK,mBAAqB,GAC1B,KAAK,yBAAyB,MAAM,EACpC,KAAK,0BAA0B,MAAM,EACrC,KAAK,0BAA0B,QAAS,GAAU,WAAW,aAAa,CAAK,CAAC,EAChF,KAAK,0BAA0B,MAAM,EACrC,KAAK,6BAA6B,MAAM,EACxC,KAAK,2BAA2B,MAAM,EACtC,KAAK,aAAa,MAAM,EACxB,KAAK,+BAA+B,MAAM,EAC1C,KAAK,gCAAgC,QAAS,GAC5C,EAAU,QAAS,GAAa,EAAS,EAAK,CAAC,CACjD,EACA,KAAK,gCAAgC,MAAM,EAC3C,KAAK,yBAAyB,QAAS,GAAa,EAAS,EAAK,CAAC,EACnE,KAAK,yBAAyB,MAAM,EAEpC,KAAK,SAAW,GAChB,KAAK,OAAS,GACd,KAAK,mBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,WAAW,aAAa,KAAK,iBAAiB,EAC9C,KAAK,kBAAoB,OACzB,KAAK,YAAY,KAAK,EACtB,KAAK,YAAY,eAAe,EAAiB,UAAW,KAAK,WAAW,EAC5E,KAAK,YAAY,eAAe,EAAiB,SAAU,KAAK,eAAe,EAC/E,IAKE,CAAK,6BAJL,KAAK,YAAY,eACf,GAAmB,YACnB,KAAK,yBACP,EACiC,QAEnC,KAAK,wBAAwB,EAAK,EAClC,KAAK,sBAAwB,OAC7B,KAAK,GAAG,eAAe,GAAgB,WAAY,KAAK,iBAAiB,EACzE,KAAK,GAAG,eAAe,EAAY,YAAa,KAAK,kBAAkB,EACvE,KAAK,aAAa,QAAQ,EAE1B,EAAS,KAAK,OAAQ,qCAAsC,CAC1D,gBAAiB,KAAK,SACxB,CAAC,EACH,CAEA,4BAAoC,EAA4C,CAC9E,IAAM,EAAS,KAAK,GAAG,cAAc,EACrC,OAAO,QAAQ,EAAS,OAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAQ,KAAc,CACnE,IAAM,EAAa,GACjB,GACE,CAAC,GAAI,EAAS,gBAAkB,CAAC,EAAI,GAAI,EAAS,cAAgB,CAAC,CAAE,EACrE,CACF,CACF,EAEI,IAAe,EAAgB,OAAS,IAAe,EAAgB,IACzE,KAAK,wBAAwB,OAAO,CAAM,EAE1C,KAAK,wBAAwB,IAAI,CAAM,CAE3C,CAAC,CACH,CAEA,iCAAgD,CAC1C,KAAK,wBAA0B,KAAK,mCACxC,KAAK,iCAAmC,GAExC,KAAU,sBAAsB,KAAK,SAAY,CAC/C,GAAI,KAAK,UAAY,KAAK,uBAAwB,OAElD,IAAI,EACJ,GAAI,CAEF,GAAgB,MADO,KAAK,GAAG,eAAe,GACrB,YAC3B,OAAS,EAAO,CACd,EAAS,KAAK,OAAQ,iEAAkE,CACtF,MAAO,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,CAC9D,CAAC,EACD,MACF,CAEA,GAAI,KAAK,UAAY,KAAK,uBAAwB,OAClD,KAAK,uBAAyB,GAE9B,IAAM,EAAe,IAAI,IAAI,CAAC,GAAG,KAAK,wBAAyB,GAAG,CAAa,CAAC,EAEhF,KAAK,aAAa,yBAAyB,CAAa,EAExD,EAAc,QAAS,GAAW,CAChC,IAAM,EAAO,KAAK,GAAG,QAAQ,CAAM,EAC/B,GAAM,gBAAgB,IAAO,EAAgB,QAC/C,KAAK,gBAAgB,CAAI,CAE7B,CAAC,EAED,IAAM,EAAiB,KAAK,aAAa,eAAe,CAAY,EACpE,EAAe,QAAS,GAAW,CACjC,KAAK,GAAG,QAAQ,CAAM,CAAC,EAAE,mBAAmB,EAAgB,KAAK,EACjE,KAAK,oBAAoB,CAAM,CACjC,CAAC,EAEG,EAAe,OAAS,GAC1B,EAAS,KAAK,OAAQ,0DAA2D,CAC/E,iBAAkB,EAAe,OACjC,gBAAiB,EAAc,OAC/B,kBAAmB,KAAK,wBAAwB,IAClD,CAAC,CAEL,CAAC,EACH,CAEA,gBAAgD,CAC9C,MAAO,CACL,QAAS,KAAK,QACd,cAAe,KAAK,kBACpB,MAAO,KAAK,SAAS,IAAK,GAAQ,CAChC,IAAM,EAAW,KAAK,YAAY,YAAY,CAAG,EAC3C,EAAS,KAAK,YAAY,cAAc,CAAG,EACjD,MAAO,CACL,MACA,WAAY,GAAU,aAAe,EACrC,SAAU,KAAK,uBAAuB,IAAI,CAAG,GAAK,GAClD,kBAAmB,GAAgB,CAAM,CAC3C,CACF,CAAC,CACH,CACF,CAEA,8BAA4C,CACtC,KAAK,UAAY,KAAK,4BAE1B,KAAK,sBAAwB,IAAI,QAAkB,GAAY,CAC7D,KAAK,sBAAwB,CAC/B,CAAC,EAED,KAAK,0BAA6B,GAAc,CAC9C,GAAI,IAAc,EAAiB,SAAU,OAC7C,IAAM,EAAW,KAAK,0BAClB,GACF,KAAK,YAAY,eAAe,GAAmB,YAAa,CAAiB,EAEnF,KAAK,0BAA4B,OAEjC,WAAW,mBAAqB,CAC9B,KAAK,sBAAwB,GAC7B,KAAU,aACP,QAAQ,KAAK,GAAI,KAAK,WAAW,CAAC,CAClC,KAAM,GAAa,KAAK,wBAAwB,CAAQ,CAAC,CAAC,CAC1D,UAAY,KAAK,wBAAwB,EAAK,CAAC,CAAC,CAChD,YAAc,CACb,KAAK,sBAAwB,GAC7B,KAAK,sBAAwB,MAC/B,CAAC,CACL,CAAC,CACH,EAEA,KAAK,YAAY,GAAG,GAAmB,YAAa,KAAK,yBAAkC,EAC7F,CAEA,8BAAwD,CACtD,OAAO,KAAK,qBACd,CAEA,mBAAkC,CAEhC,GADI,CAAC,KAAK,sBACN,KAAK,8BAA+B,OAExC,IAAI,EAAmB,GACnB,EAAc,GAEZ,EAAqB,YAAY,IAAI,EACrC,EAWF,CAAC,EAEL,KAAK,SAAS,QAAS,GAAQ,CAE7B,IAAM,EADW,KAAK,YAAY,YAAY,CAC3B,GAAU,aAAe,EAC5C,GAAI,GAAc,EAAG,CACnB,EAAiB,GAAO,CAAE,OAAQ,QAAS,WAAY,CAAE,EACzD,MACF,CAGA,IAAM,EAAe,GADJ,KAAK,YAAY,cAAc,CACX,CAAQ,EACvC,EAAa,KAAK,uBAAuB,IAAI,CAAG,GAAK,GAErD,EAAS,EAAa,EAE5B,GAAI,EAAe,EAAY,CAC7B,EAAmB,GACnB,EAAiB,GAAO,CACtB,OAAQ,oBACR,aACA,aACA,WAAY,CACd,EACA,MACF,CAEA,GAAI,GAAc,EAAQ,CACxB,EAAiB,GAAO,CAAE,OAAQ,WAAY,aAAY,YAAW,EACrE,MACF,CAEA,EAAmB,GAEnB,IAAM,EAAa,KAAK,IAAI,EAAQ,EAAa,EAAc,EAE/D,GAAI,IAAe,EAAY,CAC7B,EAAiB,GAAO,CACtB,OAAQ,WACR,aACA,aACA,YACF,EACA,MACF,CAEA,KAAK,YAAY,cAAc,EAAK,CAAC,CAAC,EAAG,CAAU,CAAC,CAAC,EACrD,KAAK,uBAAuB,IAAI,EAAK,CAAU,EAC/C,EAAc,GAEd,EAAiB,GAAO,CACtB,OAAQ,YACR,aACA,YAAa,EACb,OAAQ,EACR,YAAa,EAAa,CAC5B,EAEA,EAAS,KAAK,OAAQ,mBAAmB,EAAI,WAAY,CACvD,KAAM,EACN,aACA,YAAa,EACb,OAAQ,EACR,YAAa,EAAa,CAC5B,CAAC,CACH,CAAC,EAED,IAAM,EAAoB,YAAY,IAAI,EAAI,EACxC,EAAgB,OAAO,OAAO,CAAgB,CAAC,CAAC,KAAM,GAAM,EAAE,SAAW,WAAW,EAC1F,GAAI,EACE,KAAC,KAAK,iBAAkB,CAC1B,KAAK,iBAAmB,GACxB,KAAK,8BAAgC,GACrC,KAAK,yBAAyB,QAAS,GAAa,EAAS,EAAK,CAAC,EACnE,KAAK,gCAAgC,EACrC,WAAW,eAAiB,KAAK,2BAA2B,EAAG,CAAC,EAChE,GAAI,IAAI,2CAA2C,KAAK,GAAG,UAAU,GAAG,EACxE,IAAM,GACH,KAAK,YAAY,YAAY,EAAW,CAAC,EAAE,aAAe,IAC1D,KAAK,YAAY,YAAY,EAAY,CAAC,EAAE,aAAe,GACxD,EACJ,KAAK,YAAc,KAAyD,EAAlD,KAAK,MAAM,YAAY,IAAI,EAAI,KAAK,UAAU,EAC1E,EAA4B,6BAA8B,EAAe,CACvE,WAAY,CAAE,UAAW,SAAU,CACrC,CAAC,EACD,EAAqB,yBAA0B,EAAY,CACzD,WAAY,CAAE,UAAW,SAAU,CACrC,CAAC,CACH,OACS,IACT,IACE,CAAK,mBAAmB,GAE1B,KAAK,yBAAyB,QAAS,GACrC,EAAS,GAAM,KAAK,qBAAqB,CAAC,CAC5C,EACA,GAAI,IAAI,uCAAuC,KAAK,GAAG,UAAU,GAAG,GAGlE,GACF,EAAS,KAAK,OAAQ,2BAA4B,CAChD,WAAY,KAAK,UACjB,MAAO,EACP,YAAa,GAAG,EAAkB,QAAQ,CAAC,EAAE,GAC/C,CAAC,EAGC,EAAoB,KACtB,EAAS,KAAK,OAAQ,+BAAgC,CACpD,SAAU,GAAG,EAAkB,QAAQ,CAAC,EAAE,IAC1C,cAAe,OAAO,KAAK,CAAgB,CAAC,CAAC,OAC1C,GAAQ,EAAiB,EAAI,EAAE,SAAW,WAC7C,CACF,CAAC,CAEL,CAIA,oBAAmC,CAC5B,KAAK,+BAEV,KAAK,SAAS,QAAS,GAAQ,CAE7B,IAAM,GADa,KAAK,YAAY,YAAY,CAAG,CAAC,EAAE,aAAe,GACrC,EAC5B,GAAc,GAAgB,KAAK,YAAY,cAAc,CAAG,CAAC,IAErE,KAAK,YAAY,cAAc,EAAK,CAAC,CAAC,EAAG,CAAU,CAAC,CAAC,EACrD,KAAK,uBAAuB,IAAI,EAAK,CAAU,EAC/C,EAAS,KAAK,OAAQ,kBAAkB,EAAI,+BAAgC,CAC1E,KAAM,EACN,OAAQ,CACV,CAAC,EACH,CAAC,CACH,CAEA,qBAA4B,EAAiB,EAAoD,CAC/F,IAAI,EAAO,KAAK,YAAY,cAAc,CAAO,EACjD,GAAI,CAAC,EACH,EAAO,CACL,OAAQ,CAAC,CAAC,EAAG,EAAkB,CAAC,EAChC,eAAgB,GAChB,eAAgB,GAAuB,EACvC,GAAG,CACL,MACK,CACL,IAAM,EAAU,CAAE,GAAG,EAAM,GAAG,CAAW,EACzC,GAAI,KAAK,UAAU,CAAI,IAAM,KAAK,UAAU,CAAO,EAAG,OAAO,EAC7D,EAAO,CACT,CAEA,GAAI,CACE,EAAW,QAAU,OAAO,KAAK,CAAU,CAAC,CAAC,SAAW,EAC1D,KAAK,YAAY,cAAc,EAAS,EAAW,MAAM,EAEzD,KAAK,YAAY,QAAQ,EAAS,CAAI,CAE1C,OAAS,EAAO,CACd,EAAS,KAAK,OAAQ,0BAA0B,EAAQ,GAAI,CAC1D,KAAM,EACN,MAAO,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EAC5D,WAAY,EAAW,QAAU,OAAO,KAAK,CAAU,CAAC,CAAC,SAAW,EAAI,SAAW,MACrF,CAAC,CACH,CACA,OAAO,KAAK,YAAY,cAAc,CAAO,GAAK,CACpD,CAEA,aAAoB,EAAyB,CAC3C,OAAO,KAAK,wBAAwB,IAAI,CAAM,CAChD,CAEA,sBAAiD,CAC/C,IAAI,EAAc,EACd,EAAa,EAWjB,OAVA,KAAK,SAAS,QAAS,GAAQ,CAE7B,IAAM,EADW,KAAK,YAAY,YAAY,CAC3B,GAAU,aAAe,EACtC,EAAa,KAAK,uBAAuB,IAAI,CAAG,GAAK,GAEvD,EAAa,IACf,GAAc,EACd,GAAe,KAAK,IAAI,EAAY,EAAa,CAAC,EAEtD,CAAC,EACM,CAAE,cAAa,YAAW,CACnC,CAEA,mBAAoC,CAClC,MAAO,CAAC,KAAK,gBACf,CAEA,wBACE,EACY,CAMZ,OALA,KAAK,yBAAyB,IAAI,CAAQ,EAC1C,EACE,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EAAI,KAAK,qBAAqB,EAAI,MAC3D,MACa,CACX,KAAK,yBAAyB,OAAO,CAAQ,CAC/C,CACF,CAEA,sBAAuC,CACrC,OAAO,KAAK,kBACd,CAEA,2BACE,EACY,CAEZ,OADA,KAAK,yBAAyB,IAAI,CAAQ,MAC7B,KAAK,yBAAyB,OAAO,CAAQ,CAC5D,CAEA,yBACE,EACgD,CAChD,IAAM,EAAY,EAAE,KAAK,UACnB,EAAsB,IAAI,IAAI,CAAO,EAC3C,MAAQ,IAAa,CACnB,KAAK,iBAAiB,IAAI,EAAU,CAAE,YAAW,qBAAoB,CAAC,CACxE,CACF,CAEA,6BACE,EACA,EACM,CACN,KAAK,yBAAyB,IAAI,EAAU,CAAU,CACxD,CAEA,wBAA+B,EAAgB,EAAkC,CAC/E,KAAK,0BAA0B,CAAM,EACrC,IAAM,EAAY,KAAK,aAAa,CAAM,EACpC,EAAqC,CACzC,eAAgB,KAAK,UACrB,6BAA8B,CAAC,EAC/B,UACF,EACM,EAAY,KAAK,0BAA0B,IAAI,CAAM,GAAK,IAAI,IASpE,OARA,EAAU,IAAI,CAAQ,EACtB,KAAK,0BAA0B,IAAI,EAAQ,CAAS,EAC/C,EACA,KAAK,YAAY,OAAO,EADb,KAAK,gBAAgB,CAAM,EAEvC,CAAC,GAAa,KAAK,aAAa,CAAM,GACxC,KAAK,2BAA2B,IAAI,CAAM,MAG/B,CACX,EAAU,OAAO,CAAQ,EACrB,EAAU,OAAS,GAAG,KAAK,0BAA0B,OAAO,CAAM,CACxE,CACF,CAEA,oCAA2C,EAAsB,CAE/D,GADA,KAAK,0BAA0B,CAAM,EACjC,CAAC,KAAK,2BAA2B,IAAI,CAAM,EAAG,OAClD,GAAI,KAAK,6BAA6B,IAAI,CAAM,EAAG,CACjD,KAAK,2BAA2B,OAAO,CAAM,EAC7C,MACF,CAEA,IAAM,EAAQ,WAAW,eAAiB,CACxC,KAAK,0BAA0B,OAAO,CAAM,EAE1C,KAAK,2BAA2B,IAAI,CAAM,GAC1C,CAAC,KAAK,6BAA6B,IAAI,CAAM,GAE7C,KAAK,oBAAoB,CAAM,CAEnC,EAAG,EAAyB,EAC5B,KAAK,0BAA0B,IAAI,EAAQ,CAAK,CAClD,CAEA,0BAAkC,EAAsB,CACtD,IAAM,EAAQ,KAAK,0BAA0B,IAAI,CAAM,EACnD,IAAU,SACd,WAAW,aAAa,CAAK,EAC7B,KAAK,0BAA0B,OAAO,CAAM,EAC9C,CAEA,4BAAmC,EAAyB,CAC1D,OAAO,KAAK,2BAA2B,IAAI,CAAM,CACnD,CAEA,iCAAyC,EAA4C,CACnF,IAAM,EAAU,KAAK,iBAAiB,IAAI,CAAQ,EAC7C,GAEL,KAAK,0BAA0B,SAAS,EAAW,IAAW,CAC5D,CAAC,GAAG,CAAS,CAAC,CAAC,QAAS,GAAa,CAEjC,EAAQ,UAAY,EAAS,iBAC5B,CAAC,EAAS,8BAAgC,EAAQ,oBAAoB,IAAI,CAAM,KAEnF,EAAU,OAAO,CAAQ,EACzB,EAAS,SAAS,EACpB,CAAC,EACG,EAAU,OAAS,GAAG,KAAK,0BAA0B,OAAO,CAAM,CACxE,CAAC,CACH,CAaA,yBAAwC,CAClC,QAAK,4BAA4B,OAAS,EAC9C,IAAK,GAAM,CAAC,EAAQ,KAAY,KAAK,4BAA6B,CAChE,IAAM,EAAO,KAAK,GAAG,QAAQ,CAAM,EACnC,GAAI,CAAC,EAAM,CACT,KAAK,4BAA4B,OAAO,CAAM,EAC9C,QACF,CACA,KAAK,gBAAgB,CAAI,EAGvB,CAAC,EAAQ,uBACT,KAAK,UAAY,EAAQ,mBAAqB,KAE9C,EAAQ,sBAAwB,GAChC,KAAK,qBAAqB,CAAM,GAG9B,KAAK,UAAY,EAAQ,mBAAqB,KAChD,EAAS,KAAK,OAAQ,gEAAiE,CACrF,SACA,WAAY,EACd,CAAC,EACD,KAAK,4BAA4B,OAAO,CAAM,EAElD,CACF,CAQA,qBAA6B,EAAsB,CACjD,KAAU,GACP,eAAe,CAAC,CAChB,KAAM,GAAa,CACd,KAAK,UAAY,CAAC,KAAK,4BAA4B,IAAI,CAAM,GAC7D,EAAS,aAAa,SAAS,CAAM,IAEzC,KAAK,4BAA4B,OAAO,CAAM,EAC9C,EAAS,KAAK,OAAQ,kEAAmE,CACvF,QACF,CAAC,EACD,EAAqB,CACnB,SAAU,eACV,QAAS,kEACT,MAAO,SACT,CAAC,EACH,CAAC,CAAC,CACD,MAAO,GAAmB,CACzB,EAAS,KAAK,OAAQ,0DAA2D,CAC/E,SACA,MAAO,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,CAC9D,CAAC,CACH,CAAC,CACL,CAOA,gBAAwB,EAAkB,CACpC,EAAK,gBAAgB,IAAO,EAAgB,MAC9C,EAAK,mBAAmB,EAAgB,IAAI,EAE9C,KAAK,0BAA0B,CAAI,CACrC,CAEA,0BAAkC,EAAkB,CAClD,IAAM,EAAW,KAAK,GAAG,UAAU,EACnC,GAAI,CAAC,EAAU,OACf,IAAM,EAAY,EAAK,gBAAgB,CAAC,CAAC,SAAS,EAAc,QAAQ,EACxE,GAAI,CAAC,EAAW,OAChB,IAAM,EAAW,EAAU,eAAe,EAAU,WAAY,CAAQ,CAAC,EAAE,WAAW,EAClF,GAAU,aAAe,EAAgB,MAE7C,EAAU,eAAe,CACvB,IAAI,GAAY,GAAmB,EAAK,OAAQ,EAAU,CAAQ,CAAC,CACrE,CAAC,CACH,CAUA,+BAAsC,EAA+C,CACnF,GAAI,CAAC,GAAM,OAAS,KAAK,4BAA4B,OAAS,EAAG,OACjE,IAAM,EAAW,KAAK,GAAG,UAAU,EAC9B,KAEL,IAAK,GAAM,CAAC,EAAQ,KAAY,KAAK,4BAA6B,CAChE,IAAM,EAAW,EAAK,MAAM,GAC5B,GAAI,CAAC,EAAU,SAEf,EAAQ,kBAAoB,KAAK,UAEjC,IAAM,EAAc,GAAoB,EAAS,gBAAkB,CAAC,EAAG,CAAQ,EACzE,EACJ,GAAa,CAAW,GACxB,GAAa,GAAoB,EAAS,UAAY,CAAC,EAAG,CAAQ,CAAC,EAC/D,EAAc,GAAoB,EAAS,cAAgB,CAAC,EAAG,CAAQ,EAE7E,GACE,IAAa,QACb,IAAc,EAAgB,QAC9B,IAAc,EAAgB,MAC9B,CAEA,KAAK,4BAA4B,OAAO,CAAM,EAE1C,IAAc,EAAgB,MAAiB,OAAO,EAAS,aACnE,QACF,CAEA,GAAI,CAAC,EAAS,aAAc,CAE1B,KAAK,4BAA4B,OAAO,CAAM,EAC9C,QACF,CAIA,OAAO,EAAS,aAChB,EAAS,eAAiB,CACxB,IAAI,EAAS,gBAAkB,CAAC,GAAG,OAAQ,GAAU,CAAC,GAAkB,EAAO,CAAQ,CAAC,EACxF,GAAmB,EAAQ,EAAU,GAAa,SAAW,GAAa,OAAO,CACnF,EAEA,EAAS,KAAK,OAAQ,4DAA6D,CACjF,SACA,WACA,UAAW,KAAK,SAClB,CAAC,EACD,EAAqB,CACnB,SAAU,eACV,QAAS,4DACT,MAAO,OACP,KAAM,CAAE,WAAU,UAAW,KAAK,SAAU,CAC9C,CAAC,CACH,CACF,CAEA,wBACE,EACA,EACM,CACN,IAAM,EAAO,KAAK,GAAG,QAAQ,CAAM,EAGnC,GAFA,GAAM,mBAAmB,CAAU,EAE/B,IAAe,EAAgB,KAAM,CACnC,GAAM,KAAK,0BAA0B,CAAI,EAG7C,KAAK,aAAa,yBAAyB,CAAC,CAAM,CAAC,EAGnD,KAAK,4BAA4B,IAAI,EAAQ,CAC3C,kBAAmB,KAAK,UACxB,kBAAmB,KAAK,UACxB,sBAAuB,EACzB,CAAC,EAGD,KAAK,gBAAgB,CAAM,EAC3B,MACF,CAEI,IAAe,EAAgB,QACjC,KAAK,4BAA4B,OAAO,CAAM,EAC9C,KAAK,6BAA6B,CAAM,EACxC,KAAK,GAAG,MAAM,WAAW,CAAM,EAEnC,CAEA,6BAAqC,EAAsB,CACzD,KAAK,aAAa,WAAW,CAAM,EACnC,IAAM,EAA6B,KAAK,2BAA2B,CAAM,EACrE,KAAK,wBAAwB,IAAI,CAAM,EACzC,KAAK,oBAAoB,CAAM,EACtB,GACT,KAAK,0BAA0B,CAEnC,CAGA,2BAAmC,EAAyB,CAC1D,IAAM,EAAe,KAAK,mBAAmB,OAAO,CAAM,EACpD,EAAiB,KAAK,yBAAyB,OAAO,CAAM,EAC5D,EAAmB,KAAK,2BAA2B,OAAO,CAAM,EAGtE,OAFA,KAAK,2BAA2B,OAAO,CAAM,EAC7C,KAAK,gCAAgC,OAAO,CAAM,EAC3C,GAAgB,GAAkB,CAC3C,CAEA,4BAA2C,CACzC,GAAI,KAAK,UAAY,CAAC,KAAK,iBAAkB,OAE7C,IAAM,EAAS,KAAK,2BACpB,KAAK,2BAA6B,IAAI,IACtC,KAAK,sBAAsB,CAAM,EAEjC,IAAM,EAAa,KAAK,+BACxB,KAAK,+BAAiC,KAClC,GAAY,KAAK,0BAA0B,CAAU,CAC3D,CAEA,2BAA0C,CACpC,KAAK,UAAY,KAAK,6BAC1B,KAAK,2BAA6B,GAClC,WAAW,mBAAqB,CAC9B,KAAK,2BAA6B,GAC7B,KAAK,UAAU,KAAK,sBAAsB,CACjD,CAAC,EACH,CAEA,uBAAsC,CAGpC,IAAM,EAAuB,IAAI,IAC7B,EAAU,EACd,CACE,KAAK,sBACL,KAAK,wBACL,KAAK,yBACL,KAAK,mBACL,KAAK,0BACP,CAAC,CAAC,QAAS,GACT,EAAM,QAAS,GAAW,CACpB,MAAqB,IAAI,CAAM,EACnC,IAAI,EAAqB,MAAQ,GAAwB,CACvD,GAAW,EACX,MACF,CACA,EAAqB,IAAI,CAAM,CAD/B,CAEF,CAAC,CACH,EACI,EAAU,GACZ,GAAI,KACF,wBAAwB,EAAQ,+BAA+B,GAAuB,KACxF,EAGF,EAAqB,QAAS,GAAW,CACnC,KAAK,sBAAsB,IAAI,CAAM,EACvC,KAAK,YAAY,sBAAsB,EAAQ,EAA0B,EAChE,KAAK,wBAAwB,IAAI,CAAM,EAChD,KAAK,YAAY,sBAAsB,EAAQ,EAA4B,EAClE,KAAK,yBAAyB,IAAI,CAAM,EACjD,KAAK,YAAY,sBAAsB,EAAQ,EAA6B,EACnE,KAAK,mBAAmB,IAAI,CAAM,EAC3C,KAAK,YAAY,sBACf,EACA,KAAK,2BAA2B,IAAI,CAAM,EACtC,GACA,EACN,EAEA,KAAK,YAAY,sBAAsB,EAAQ,EAA2B,CAE9E,CAAC,EAED,KAAK,YAAY,wBAAwB,CAAoB,CAC/D,CAEA,+BAA8C,CAC5C,KAAK,SAAS,QAAS,GAAQ,CAC7B,IAAM,EAAe,KAAK,uBAAuB,IAAI,CAAG,GAAK,GACzD,EAAe,GAEE,GAAgB,KAAK,YAAY,cAAc,CAAG,CACnE,GAAgB,IAEpB,KAAK,YAAY,cAAc,EAAK,CAAC,CAAC,EAAG,CAAY,CAAC,CAAC,EACvD,KAAK,uBAAuB,IAAI,EAAK,CAAY,EACnD,CAAC,CACH,CAEA,0BAAiC,EAAiC,CAChE,GAAI,KAAK,SAAU,OACnB,IAAM,EAAO,IAAI,IAAI,CAAO,EAC5B,GAAI,CAAC,KAAK,iBAAkB,CAC1B,KAAK,+BAAiC,EACtC,MACF,CAEE,EAAK,OAAS,KAAK,2BAA2B,MAC9C,CAAC,GAAG,CAAI,CAAC,CAAC,MAAO,GAAW,KAAK,2BAA2B,IAAI,CAAM,CAAC,IAGzE,KAAK,2BAA2B,MAAM,EACtC,EAAK,QAAS,GAAW,KAAK,2BAA2B,IAAI,CAAM,CAAC,EACpE,KAAK,sBAAsB,EAC7B,CAGA,WAAkB,EAAgB,EAAkC,CAClE,IAAM,EAAW,GAAuB,CAElC,IAAe,GAAQ,WAAW,WAAW,EAAU,CAAC,CAC9D,EAEA,OADA,KAAK,YAAY,GAAG,EAAiB,SAAU,CAAO,MACzC,KAAK,YAAY,eAAe,EAAiB,SAAU,CAAO,CACjF,CAEA,yBACE,EACA,EACY,CACZ,IAAM,EAAY,KAAK,gCAAgC,IAAI,CAAM,GAAK,IAAI,IAK1E,OAJA,EAAU,IAAI,CAAQ,EACtB,KAAK,gCAAgC,IAAI,EAAQ,CAAS,EAC1D,EAAS,KAAK,0BAA0B,CAAM,CAAC,MAElC,CACX,EAAU,OAAO,CAAQ,EACrB,EAAU,OAAS,GAAG,KAAK,gCAAgC,OAAO,CAAM,CAC9E,CACF,CAEA,0BAAiC,EAAyB,CACxD,OACE,KAAK,6BAA6B,IAAI,CAAM,GAC5C,KAAK,+BAA+B,IAAI,CAAM,CAElD,CAEA,6BAAqC,EAAgB,EAAwB,CAC3E,KAAK,gCAAgC,IAAI,CAAM,CAAC,EAAE,QAAS,GAAa,EAAS,CAAO,CAAC,CAC3F,CAEA,0BAAkC,EAAyB,CACzD,GAAI,KAAK,wBAAwB,IAAI,CAAM,EAAG,MAAO,GACrD,IAAM,EAAO,KAAK,GAAG,QAAQ,CAAM,EAC7B,EAAc,KAAK,GAAG,gBAAgB,CAAM,EAClD,KAAK,wBAAwB,IAAI,CAAM,EACvC,KAAK,8BAA8B,EACnC,GAAI,IAAI,gDAAgD,GAAQ,EAChE,EAAS,KAAK,OAAQ,wCAAyC,CAC7D,UAAW,EACX,YAAa,CAAC,EACd,oBAAqB,KAAK,wBAAwB,KAClD,UAAW,KAAK,SAClB,CAAC,EACD,EAAqB,CACnB,SAAU,eACV,QAAS,8BACT,MAAO,OACP,KAAM,CACJ,UAAW,EACX,oBAAqB,KAAK,wBAAwB,IACpD,CACF,CAAC,EACD,IAAM,EAAmB,KAAK,yBAAyB,IAAI,CAAM,EAC7D,GACF,KAAK,YAAY,eAAe,EAAiB,SAAU,CAAgB,EAE7E,IAAM,EAAc,YAAY,IAAI,EAC9B,EAAmB,GAAuB,CAE9C,GADI,IAAe,GACf,KAAK,sBAAuB,OAChC,IAAM,EAAY,KAAK,MAAM,YAAY,IAAI,EAAI,CAAW,EAEtD,EADiB,KAAK,GAAG,QAAQ,CACpB,GAAgB,gBAAgB,CAAC,CAAC,UAAU,CAAC,CAAC,QAAU,EAC3E,EAAS,KAAK,OAAQ,mDAAoD,CACxE,YACA,UAAW,KAAK,UAChB,YACF,CAAC,EACD,EAA4B,iCAAkC,EAAW,CACvE,WAAY,CAAE,UAAW,SAAU,CACrC,CAAC,EACD,EAA4B,kCAAmC,EAAY,CACzE,WAAY,CAAE,UAAW,SAAU,CACrC,CAAC,EACD,EAAqB,CACnB,SAAU,eACV,QAAS,mCAAmC,EAAW,WAAW,EAAU,KAC5E,MAAO,OACP,KAAM,CAAE,YAAW,aAAY,UAAW,KAAK,SAAU,CAC3D,CAAC,EACD,KAAK,YAAY,eAAe,EAAiB,SAAU,CAAe,EAC1E,KAAK,yBAAyB,OAAO,CAAM,EAC3C,KAAK,6BAA6B,OAAO,CAAM,EAC/C,KAAK,+BAA+B,IAAI,CAAM,CAChD,EAKA,OAJA,KAAK,yBAAyB,IAAI,EAAQ,CAAe,EACzD,KAAK,6BAA6B,IAAI,EAAQ,KAAK,SAAS,EAC5D,KAAK,YAAY,GAAG,EAAiB,SAAU,CAAe,EAC9D,KAAK,6BAA6B,EAAQ,EAAI,EACvC,EACT,CAEA,6BAAqC,EAAyB,CAC5D,GAAI,CAAC,KAAK,wBAAwB,IAAI,CAAM,EAAG,MAAO,GACtD,KAAK,0BAA0B,CAAM,EACrC,KAAK,2BAA2B,OAAO,CAAM,EAC7C,IAAM,EAAkB,KAAK,yBAAyB,IAAI,CAAM,EAchE,OAbI,IACF,KAAK,YAAY,eAAe,EAAiB,SAAU,CAAe,EAC1E,KAAK,yBAAyB,OAAO,CAAM,GAE7C,KAAK,6BAA6B,OAAO,CAAM,EAC/C,KAAK,+BAA+B,OAAO,CAAM,EACjD,KAAK,6BAA6B,EAAQ,EAAK,EAC/C,KAAK,wBAAwB,OAAO,CAAM,EAC1C,GAAI,IAAI,kDAAkD,GAAQ,EAClE,EAAS,KAAK,OAAQ,sCAAuC,CAC3D,uBAAwB,KAAK,wBAAwB,KACrD,UAAW,KAAK,SAClB,CAAC,EACM,EACT,CAEA,+BAA8C,CAC5C,EAAqB,kCAAmC,KAAK,wBAAwB,KAAM,CACzF,WAAY,CAAE,UAAW,SAAU,CACrC,CAAC,CACH,CAEA,2BAAkC,EAAiC,CACjE,GAAI,KAAK,SAAU,OACnB,IAAM,EAAO,IAAI,IAAI,CAAO,EAC5B,KAAK,6BAA6B,MAAM,EACxC,EAAK,QAAS,GAAW,CACvB,KAAK,6BAA6B,IAAI,CAAM,EAC5C,KAAK,2BAA2B,OAAO,CAAM,CAC/C,CAAC,EACD,KAAK,0BAA0B,SAAS,EAAQ,IAC9C,KAAK,0BAA0B,CAAM,CACvC,EACA,IAAI,EAAU,GAEd,KAAK,wBAAwB,QAAS,GAAW,CAC1C,EAAK,IAAI,CAAM,IAAG,EAAU,KAAK,6BAA6B,CAAM,GAAK,EAChF,CAAC,EACD,EAAK,QAAS,GAAW,CAClB,KAAK,wBAAwB,IAAI,CAAM,IAC1C,EAAU,KAAK,0BAA0B,CAAM,GAAK,EAExD,CAAC,EAEI,IACL,KAAK,sBAAsB,EAC3B,KAAK,8BAA8B,EACrC,CAEA,8BAAgD,CAC9C,MAAO,CAAC,GAAG,KAAK,uBAAuB,CACzC,CAEA,gBAAuB,EAAsB,CAC3C,KAAK,0BAA0B,CAAM,EACrC,KAAK,2BAA2B,OAAO,CAAM,EACzC,OAAK,UAAY,CAAC,KAAK,0BAA0B,CAAM,KAC3D,KAAK,sBAAsB,EAC3B,KAAK,8BAA8B,EACrC,CAEA,oBAA2B,EAAsC,CAK/D,OAJI,KAAK,aAAuB,QAEhC,KAAK,sBAAsB,IAAI,CAAM,EACrC,KAAK,sBAAsB,MACd,KAAK,wBAAwB,CAAM,EAClD,CAEA,wBAA+B,EAAsB,CAC/C,KAAK,UAAY,CAAC,KAAK,sBAAsB,OAAO,CAAM,GAC9D,KAAK,sBAAsB,CAC7B,CAEA,oBAA2B,EAAsB,CAC/C,KAAK,0BAA0B,CAAM,EACjC,OAAK,UAAY,CAAC,KAAK,6BAA6B,CAAM,KAC9D,KAAK,sBAAsB,EAC3B,KAAK,8BAA8B,EACrC,CAEA,sBAA6B,EAAiC,CAC5D,GAAI,KAAK,SAAU,OACnB,IAAM,EAAO,IAAI,IAAI,CAAO,EAC5B,GAAI,CAAC,KAAK,iBAAkB,CAC1B,KAAK,2BAA6B,EAClC,MACF,CAEE,EAAK,OAAS,KAAK,mBAAmB,MACtC,CAAC,GAAG,CAAI,CAAC,CAAC,MAAO,GAAW,KAAK,mBAAmB,IAAI,CAAM,CAAC,IAGjE,KAAK,mBAAmB,MAAM,EAC9B,EAAK,QAAS,GAAW,KAAK,mBAAmB,IAAI,CAAM,CAAC,EAC5D,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACzB,CACF,ECjhEM,GAAW,EAAkB,cAAc,EAYpC,GAAb,KAAiC,CAgBZ,GACA,cACA,kBAjBnB,SAAmB,GAEnB,QAAkB,GAElB,mBAA6B,GAAY,OAEzC,cAA8C,KAE9C,gBAEA,cAEA,UAEA,YACE,EACA,EAAyC,IACzC,EAA6C,IAC7C,CAHiB,UACA,qBACA,yBAEjB,GAAS,KAAK,OAAQ,iCAAiC,CACzD,CAEA,mBAA0B,EAAwB,CAC5C,QAAK,UAAY,EAGrB,IAFA,KAAK,QAAU,EAEX,CAAC,EAAS,CACR,KAAK,gBAAkB,QAAW,aAAa,KAAK,aAAa,EACrE,KAAK,cAAgB,OACrB,KAAK,iBAAiB,MAAM,EAC5B,MACF,CAEI,CAAC,KAAK,eAAiB,CAAC,KAAK,UAAU,KAAK,KAAK,CAFrD,CAGF,CAEA,mBAA0B,EAA6B,CACrD,KAAK,mBAAqB,CAC5B,CAEA,OAAqB,CACf,KAAK,UAAY,KAAK,eAAiB,CAAC,KAAK,SACjD,KAAK,KAAK,CACZ,CAEA,SAAuB,CACrB,KAAK,SAAW,GAChB,KAAK,QAAU,GACX,KAAK,gBAAkB,QAAW,aAAa,KAAK,aAAa,EACrE,KAAK,cAAgB,OACrB,KAAK,iBAAiB,MAAM,CAC9B,CAEA,MAAc,cAAc,EAA+C,CACzE,IAAM,EAAS,KAAK,GAAG,UAAU,EACjC,GAAI,CAAC,EAAQ,OAEb,IAAM,EAAiB,EAAS,WAAW,QAAU,CAAC,EACtD,GAAI,EAAe,OAAS,EAAG,CAC7B,IAAM,EAAkB,MAAM,EAAO,2BAA2B,CAAc,EAC9E,GAAwB,EAAiB,KAAK,EAAE,CAClD,CAEI,EAAS,cACX,MAAM,EAAO,mBAAmB,EAAS,YAAY,EAGvD,MAAM,EAAO,iBACX,EAAS,2BACT,EAAS,kCACP,EAAS,sDACb,EACA,EAAO,gBAAgB,CAAE,cAAe,EAAS,UAAW,CAAC,CAC/D,CAEA,gBAAwB,EAAsC,CAC5D,IAAM,EAAS,EAAS,UAAU,OAClC,GAAI,CAAC,GAAU,CAAC,MAAM,QAAQ,CAAM,EAAG,OAEvC,IAAM,EAAS,KAAK,GAAG,eAAe,EACtC,EAAO,QAAS,GAAa,CAC3B,GACE,OAAO,GAAa,UACpB,CAAC,GACA,EAAqC,OAAU,EAAU,SAE1D,OAEF,IAAM,EAAgB,EAAO,CAAQ,EAC/B,EACJ,EAAc,UAAU,GAAM,EAAc,WAAW,CAAC,CAAC,QAC3D,GAAI,CAAC,EAAQ,OAEb,IAAI,EAAO,KAAK,GAAG,MAAM,QAAQ,CAAM,EAClC,IACH,EAAO,GAAK,WAAW,EAAQ,KAAK,EAAE,EACtC,KAAK,GAAG,MAAM,UAAU,CAAI,GAE9B,EAAK,iBAAiB,CAAa,EACnC,KAAK,GAAG,KAAK,EAAY,MAAO,CAAa,CAC/C,CAAC,CACH,CAEA,MAAqB,CACnB,GAAI,CAAC,KAAK,SAAW,KAAK,SAAU,OAEpC,KAAK,gBAAkB,IAAI,gBAC3B,GAAM,CAAE,UAAW,KAAK,gBAExB,KAAK,eAAiB,SAAY,CAChC,GAAI,CACF,IAAM,EAAS,IAAI,GAAO,KAAK,GAAG,UAAU,CAAC,EAC7C,EAAO,cAAc,CACnB,KAAM,CAAE,MAAO,CAAC,CAAE,EAClB,aAAc,CAAE,MAAO,CAAC,CAAE,EAC1B,SAAU,CAAE,MAAO,CAAC,EAAU,QAAQ,CAAE,CAC1C,CAAC,EAED,IAAM,EAAW,MAAM,KAAK,GAAG,kBAAkB,gBAAiB,CAAM,EAClE,EAAW,MAAM,KAAK,GAAG,KAAK,cAClC,GAAO,IACP,QACA,CACE,OAAQ,EACR,MAAO,KAAK,UACZ,QAAS,KAAK,cACd,aAAc,KAAK,kBACrB,EACA,OACA,CAAE,YAAa,CAAO,CACxB,EAEA,MAAM,KAAK,cAAc,CAAQ,EACjC,KAAK,gBAAgB,CAAQ,EAC7B,KAAK,UAAY,EAAS,WAE1B,GAAS,KAAK,OAAQ,mCAAoC,CACxD,eAAgB,EAAS,UAAU,QAAQ,QAAU,EACrD,eAAgB,EAAS,WAAW,QAAQ,QAAU,EACtD,aAAc,EAAS,6BAA+B,MACxD,CAAC,CACH,OAAS,EAAK,CACR,CAAC,EAAO,SAAW,CAAC,KAAK,UAC3B,GAAS,MAAM,OAAQ,wCAAyC,CAAG,CAEvE,CACF,GAAG,EAEH,KAAU,cAAc,YAAc,CACpC,KAAK,cAAgB,KACrB,KAAK,gBAAkB,OAEnB,KAAK,SAAW,CAAC,KAAK,WACxB,KAAK,cAAgB,eAAiB,CACpC,KAAK,cAAgB,OACrB,KAAK,KAAK,CACZ,EAAG,KAAK,iBAAiB,EAE7B,CAAC,CACH,CACF,ECrLM,GAAW,EAAkB,sBAAsB,EAMnD,GAAwB,IAGxB,GAAyB,IAEzB,GAAkB,IAAI,QAItB,IAAiB,EAAoB,IACzC,OAAO,OAAO,EAAM,WAA2B,CAAC,CAAC,CAAC,KAAM,GACtD,OAAO,OAAO,CAAa,CAAC,CAAC,KAAM,GAAW,KAAU,CAAM,CAChE,EAEW,GAA+B,GAA2B,CACrE,GAAgB,IAAI,CAAE,CAAC,GAAG,EAE1B,IAAI,EAAc,EACd,EAAW,GACX,EAEE,MAAuB,CAC3B,IAAM,EAAM,KAAK,IAAI,EAcrB,OAbI,GAAY,EAAM,EAAc,GAA8B,IAClE,EAAW,GACX,EAAc,EACd,EAAQ,MACL,KAAK,EAAI,CAAC,CACV,MAAO,GAAmB,CACzB,GAAS,KAAK,OAAQ,6BAA8B,CAClD,MAAO,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,CAC9D,CAAC,CACH,CAAC,CAAC,CACD,YAAc,CACb,EAAW,EACb,CAAC,EACI,GACT,EAEM,MAA6B,CAC7B,IAAiB,SACrB,EAAe,WAAW,eAAiB,CACzC,EAAe,OACV,EAAM,GAAG,EAAqB,CACrC,EAAG,EAAsB,EAC3B,EAEM,MAA2B,CAC3B,SAAS,kBAAoB,UAAU,EAAM,CACnD,EAEM,MAAmB,CACvB,EAAM,CACR,EAEM,EAAa,GAAuB,CACxC,IAAM,EAAS,EAAG,UAAU,EACxB,CAAC,GAAU,CAAC,GAAc,EAAO,CAAM,GAC3C,EAAqB,CACvB,EAEA,SAAS,iBAAiB,mBAAoB,CAAkB,EAChE,OAAO,iBAAiB,WAAY,CAAU,EAC9C,EAAG,GAAG,GAAU,QAAS,CAAS,EAElC,GAAgB,IAAI,MAAU,CACxB,IAAiB,QAAW,WAAW,aAAa,CAAY,EACpE,SAAS,oBAAoB,mBAAoB,CAAkB,EACnE,OAAO,oBAAoB,WAAY,CAAU,EACjD,EAAG,eAAe,GAAU,QAAS,CAAS,EAC9C,GAAgB,OAAO,CAAE,CAC3B,CAAC,CACH,EAEa,GAA+B,GAA2B,CACrE,GAAgB,IAAI,CAAE,CAAC,GAAG,CAC5B,ECpFM,GAAgB,EAChB,GAAmB,OACZ,GAAyB,IAEhC,GAAwB,KACxB,GAAmB,yBACnB,GAA4B,CAAC,yBAA0B,wBAAwB,EAQ/E,GAAY,GAChB,GAAG,KAAmB,mBAAmB,CAAa,IAClD,GAAmB,GACvB,GAA0B,IAAK,GAAW,GAAG,IAAS,mBAAmB,CAAa,GAAG,EAErF,GAAY,GAChB,OAAO,GAAU,YAAY,GAAkB,CAAC,MAAM,QAAQ,CAAK,EAExD,IACX,EACA,EAAM,KAAK,IAAI,IACiB,CAChC,GAAI,CACF,GAAgB,CAAa,CAAC,CAAC,QAAS,GAAQ,WAAW,cAAc,WAAW,CAAG,CAAC,EACxF,IAAM,EAAM,WAAW,cAAc,QAAQ,GAAS,CAAa,CAAC,EACpE,GAAI,CAAC,EAAK,MAAO,CAAC,EAElB,IAAM,EAAS,KAAK,MAAM,CAAG,EAC7B,GACE,EAAO,UAAY,IACnB,OAAO,EAAO,SAAY,UAC1B,EAAM,EAAO,QAAU,IACvB,CAAC,MAAM,QAAQ,EAAO,QAAQ,EAE9B,MAAO,CAAC,EAGV,IAAM,EAAwC,CAAC,EAa/C,OAZA,EAAO,SAAS,MAAM,IAAoB,CAAC,CAAC,QAAS,GAAU,CAC7D,GAAI,CAAC,MAAM,QAAQ,CAAK,GAAK,EAAM,SAAW,EAAG,OACjD,GAAM,CAAC,EAAQ,GAAW,EAC1B,GAAI,OAAO,GAAW,UAAY,CAAC,GAAS,CAAO,EAAG,OACtD,IAAM,EAAe,EACf,EAAY,EAAa,WACzB,EACJ,OAAO,GAAc,UACrB,OAAO,SAAS,CAAS,GACzB,EAAM,MACR,EAAS,GAAU,CAAE,GAAG,EAAc,SAAU,CAAQ,CAC1D,CAAC,EACM,CACT,MAAQ,CACN,MAAO,CAAC,CACV,CACF,EAEa,IACX,EACA,EACA,EAAM,KAAK,IAAI,IACN,CACT,GAAI,CACF,IAAI,EAAU,OAAO,QAAQ,CAAQ,CAAC,CACnC,QAAQ,EAAG,KACV,OAAO,KAAK,CAAO,CAAC,CAAC,KAAM,GAAQ,IAAQ,YAAc,IAAQ,YAAY,CAC/E,CAAC,CACA,MAAM,IAAoB,CAAC,CAC3B,KAAK,CAAC,EAAQ,KAAa,CAC1B,GAAM,CAAE,SAAU,EAAU,GAAG,GAAqB,EACpD,MAAO,CAAC,EAAQ,CAAgB,CAClC,CAAC,EAEC,EAAa,KAAK,UAAU,CAAE,QAAS,GAAe,QAAS,EAAK,SAAU,CAAQ,CAAC,EAC3F,KAAO,EAAW,OAAS,IAAyB,EAAQ,OAAS,GACnE,EAAU,EAAQ,MAAM,KAAK,IAAI,EAAG,KAAK,KAAK,EAAQ,OAAS,EAAE,CAAC,CAAC,EACnE,EAAa,KAAK,UAAU,CAAE,QAAS,GAAe,QAAS,EAAK,SAAU,CAAQ,CAAC,EAGzF,WAAW,cAAc,QAAQ,GAAS,CAAa,EAAG,CAAU,CACtE,MAAQ,CAER,CACF,EAEa,GAA2B,GAAgC,CACtE,GAAI,CACF,CAAC,GAAS,CAAa,EAAG,GAAG,GAAgB,CAAa,CAAC,CAAC,CAAC,QAAS,GACpE,WAAW,cAAc,WAAW,CAAG,CACzC,CACF,MAAQ,CAER,CACF,EC/FM,GAAS,MACT,IAAU,EAAiB,IAC/B,uBAAuB,EAAQ,GAAG,IAQ9B,IAAa,EAAiB,IAA+C,CACjF,GAAI,CACF,IAAM,EAAM,aAAa,QAAQ,GAAO,EAAS,CAAM,CAAC,EACxD,GAAI,CAAC,EAAK,OACV,IAAM,EAAS,KAAK,MAAM,CAAG,EAG7B,OAFI,OAAO,EAAO,WAAc,UAC5B,KAAK,IAAI,EAAI,EAAO,UAAY,GAAQ,OACrC,CACT,MAAQ,CACN,MACF,CACF,EAEM,IACJ,EACA,EACA,IACS,CACT,GAAI,CACF,IAAM,EAAwB,CAAE,GAAG,EAAM,UAAW,KAAK,IAAI,CAAE,EAC/D,aAAa,QAAQ,GAAO,EAAS,CAAM,EAAG,KAAK,UAAU,CAAK,CAAC,CACrE,MAAQ,CAER,CACF,EAGa,GAA0B,MACrC,EACA,EACA,IACkB,CAClB,GAAI,CACF,IAAM,EAAO,MAAM,EAAG,YAAY,EAClC,GAAW,EAAS,EAAQ,CAC1B,SAAU,EAAK,SACf,kBAAmB,EAAK,iBAC1B,CAAC,CACH,MAAQ,CAER,CACF,EAOa,GAAyB,MACpC,EACA,EACA,IACqB,CACrB,IAAM,EAAS,GAAU,EAAS,CAAM,EACxC,GAAI,CAAC,EAAQ,MAAO,GACpB,IAAM,EAAiB,CACrB,SAAU,EAAO,SACjB,kBAAmB,EAAO,mBAAqB,CAAC,CAClD,EAKA,MAJA,GAA2E,sBACzE,QAAQ,QAAQ,CAAc,EAChC,EAAyD,WACvD,MAAM,GAAuB,CAA8D,EACtF,EACT,EAMa,GAA0B,MACrC,EACA,EACA,IACkB,CAClB,GAAI,CAQF,IAAM,EAAO,MAPM,EAAG,KAAK,cACzB,GAAO,IACP,2BACA,OACA,OACA,CAAE,OAAQ,EAAG,CACf,EAEA,GAAW,EAAS,EAAQ,CAC1B,SAAU,EAAK,SACf,kBAAmB,EAAK,iBAC1B,CAAC,EACD,EAEE,sBAAwB,QAAQ,QAAQ,CAAI,EAC9C,EAAyD,WACvD,MAAM,GAAuB,CAAoD,EACnF,GAAM,CAAE,UAAS,OAAM,iBAAkB,MAAM,EAAG,wBAAwB,EAC1E,GAAO,qBAAqB,CAAO,EACnC,GAAO,yBAAyB,CAAI,EACpC,GAAO,kCAAkC,CAAa,CACxD,MAAQ,CAER,CACF,EAGa,IACX,EACA,EACA,IACY,GAAU,EAAS,CAAM,CAAC,EAAE,oBAAoB,KAAa,GAG9D,IAAuB,EAAiB,IAAyB,CAC5E,GAAI,CACF,aAAa,WAAW,GAAO,EAAS,CAAM,CAAC,CACjD,MAAQ,CAER,CACF,ECxEM,EAAM,EAAa,YAAY,EAC/B,EAAW,EAAkB,YAAY,EACzC,GAAsB,IAAI,QAC1B,GAAkC,IAAI,QACtC,GAAuB,IAAI,QAEpB,GAA0B,GAA+B,CACpE,GAAI,CAAC,EAAS,MAAO,GACrB,IAAM,EAAW,EAA8B,EAAqB,CAAC,CAAC,EAChE,EAAkB,EAAwC,GAAoB,MAAS,EAE7F,OADsB,EAAS,KAAM,GAAS,EAAK,SAAW,CAAe,GAAK,EAAS,KACrE,SAAW,EAAQ,MAC3C,EACM,GAA+B,IAAI,QACnC,GAA+B,KAC/B,GAAsC,IAG/B,GAAwB,GACnC,IACC,GAAc,EAAI,GAAsC,IAErD,GAAsB,GAC1B,IAAU,GAAU,UAAY,IAAU,GAAU,SAAW,IAAU,GAAU,QAE/E,IACJ,EACA,IACiB,CACjB,IAAI,EAAU,GACV,EAEE,MAAc,CACd,IACJ,EAAU,GACV,GAA6B,OAAO,CAAE,EACtC,EAAG,eAAe,EAAY,KAAM,CAAM,EAC1C,EAAQ,MAAM,EAChB,EAEM,MAAsB,CACtB,IAAe,SACnB,EAAa,WAAW,eAAiB,CACvC,EAAa,OACb,EAAM,CACR,EAAG,CAAC,EACN,EAEM,EAAU,GAAqB,CAC/B,GAAmB,CAAK,GAAG,EAAc,CAC/C,EAEI,GAAmB,EAAG,aAAa,CAAC,EAAG,EAAc,EACpD,EAAG,GAAG,EAAY,KAAM,CAAM,EAEnC,IAAM,MAAgB,CAChB,IAAe,QAAW,WAAW,aAAa,CAAU,EAChE,EAAG,eAAe,EAAY,KAAM,CAAM,EAC1C,GAA6B,OAAO,CAAE,CACxC,EAEA,OADA,GAA6B,IAAI,EAAI,CAAO,EACrC,CACT,EAGa,GAAoC,GAA2B,CAC1E,IAAM,MAAgB,CACpB,EAAG,eAAe,EAAY,KAAM,CAAM,EAC1C,IAAM,EAAS,EAAG,UAAU,EACvB,GACL,EAAO,wBAAwB,CAAC,CAAC,MAAO,GAAmB,CACzD,EAAS,KAAK,OAAQ,mDAAoD,CACxE,MAAO,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,CAC9D,CAAC,CACH,CAAC,CACH,EAEM,EAAU,GAAqB,CAC/B,GAAmB,CAAK,GAAG,EAAQ,CACzC,EAEI,GAAmB,EAAG,aAAa,CAAC,EAAG,EAAQ,EAC9C,EAAG,GAAG,EAAY,KAAM,CAAM,CACrC,EAIM,GAAsB,MAC1B,EACA,EACA,IACe,CACf,IAAM,EAAY,YAAY,IAAI,EAClC,GAAI,CACF,IAAM,EAAS,MAAM,EAAK,EAI1B,OAHA,EAA4B,yBAA0B,YAAY,IAAI,EAAI,EAAW,CACnF,WAAY,CAAE,QAAO,QAAS,UAAW,GAAG,CAAW,CACzD,CAAC,EACM,CACT,OAAS,EAAO,CAId,MAHA,EAA4B,yBAA0B,YAAY,IAAI,EAAI,EAAW,CACnF,WAAY,CAAE,QAAO,QAAS,QAAS,GAAG,CAAW,CACvD,CAAC,EACK,CACR,CACF,EAEM,GAAoC,IAAI,QAkBjC,OACX,SAAS,WAAW,QAAQ,aAAa,CAAC,CAAC,MAAM,EAAG,CAAC,GAAK,GAAG,KAAK,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,MAE/G,SAAgB,GACd,EACA,EACM,CACN,GAAkC,IAAI,CAAE,CAAC,GAAG,EAE5C,IAAM,EAAS,GAAqB,EAC9B,EAAa,EACb,EAAW,EAAG,YAAY,KAAK,CAAE,EACvC,EAAW,YAAc,MAAO,EAAS,EAAS,IAAgB,CAChE,IAAM,EAAM,EACN,EAAoB,IAAI,IAAI,OAAO,KAAK,EAAI,oBAAsB,CAAC,CAAC,CAAC,EACrE,EAAgB,EAAQ,yBAAyB,CAAiB,EAGxE,GAAI,EAAQ,SAAS,EAAG,CACtB,MAAM,EAAQ,cAAc,EAC5B,IAAM,EAAc,MAAM,wCAAwC,EAElE,KADA,GAAQ,KAAO,aACT,CACR,CAEI,EAAI,UAAY,SAClB,EAAI,QAAU,GAGhB,IAAM,EAAU,EAAQ,6BAA6B,EACrD,GAAqB,EAAI,WAAY,CAAO,EAE5C,IAAM,EAAW,MAAM,EAAS,EAAS,EAAS,CAAW,EAC7D,EAAc,CAAQ,EAGtB,GAAI,CACF,IAAM,EAAwB,GAA4B,EAAU,EAAI,CAAiB,EACrF,GACF,EAAQ,6BAA6B,EAAU,CAAqB,EAEtE,EAAQ,+BAA+B,CAAQ,CACjD,OAAS,EAAO,CACd,EAAwB,EAAO,CAAE,KAAM,CAAE,KAAM,uBAAwB,CAAE,CAAC,EAC1E,EAAS,MAAM,OAAQ,0CAA2C,CAChE,MAAO,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,CAC9D,CAAC,CACH,CACA,OAAO,CACT,EAEA,GAAkC,IAAI,MAAU,CAC9C,GAAkC,OAAO,CAAE,EAC3C,EAAW,YAAc,CAC3B,CAAC,CACH,CAEA,IAAM,EAAkB,GACtB,IAAI,QAAS,GAAY,CACvB,IAAM,EAAM,OAAO,UAAU,eAAe,CAAI,EAChD,EAAI,iBAAiB,cAAiB,EAAQ,CAAC,EAC/C,EAAI,iBAAiB,YAAe,EAAQ,CAAC,EAC7C,EAAI,iBAAiB,cAAiB,EAAQ,CAAC,CACjD,CAAC,EAEG,GAAsB,KAAO,IAA+C,CAChF,MAAM,QAAQ,IAAI,CAChB,EAAe,EAAU,IAAI,EAC7B,EAAe,EAAU,MAAM,EAC/B,EAAe,GAAG,EAAU,iBAAiB,oBAAoB,CACnE,CAAC,CACH,EAEM,GAAc,GAA0B,CAC5C,IAAM,EAAM,aAAe,MAAQ,EAAI,QAAU,OAAO,CAAG,EAC3D,OACE,EAAI,SAAS,eAAe,GAC5B,EAAI,SAAS,gBAAgB,GAC7B,EAAI,SAAS,sBAAsB,GACnC,EAAI,SAAS,4BAA4B,CAE7C,EAOM,GAAc,KAAO,IAA2C,CACpE,IAAM,EAAY,EAAoB,CAAO,EAEvC,EAAiB,IAAI,GAAe,CACxC,UAAW,OAAO,UAClB,aAAc,OAAO,aACrB,OAAQ,EAAU,IACpB,CAAC,EAEK,EAAoB,IAAI,GAAqB,OAAO,UAAW,EAAU,MAAM,EAM/E,EAAiB,GAA4B,EAJhC,GAAa,CAC9B,QAAS,EAAQ,QACjB,QAAS,EACX,CAC4D,CAAU,EAiBtE,MAAO,CAAE,GAfE,GAAa,CACtB,QAAS,EAAQ,QACjB,QAAS,GACT,YAAa,EAAQ,YACrB,aAAc,EAAQ,aACtB,OAAQ,EAAQ,OAChB,MAAO,EACP,YAAa,EACb,SAAU,EAAQ,SAClB,gBAAiB,GACA,mBACjB,oBAAqB,CAAC,UAAU,EAChC,qBAAsB,GAAgB,oBACxC,CAES,EAAI,gBAAe,CAC9B,EAMM,GAAmB,MACvB,EACA,IACwC,CACxC,IAAI,EACJ,GAAI,CACF,EAAc,MAAM,GAAY,CAAO,CACzC,OAAS,EAAO,CACd,MAAO,CAAE,GAAI,GAAO,QAAO,MAAO,YAAa,CACjD,CACA,GAAM,CAAE,KAAI,kBAAmB,EAE/B,GAA4B,EAAI,EAAQ,QAAS,EAAQ,MAAM,CAAC,CAAC,KAAM,GAAW,CAC5E,EAAQ,GAA6B,EAAI,EAAQ,QAAS,EAAQ,MAAM,EACvE,GAA6B,EAAI,EAAQ,QAAS,EAAQ,MAAM,CACvE,CAAC,EAED,IAAM,EAAmB,GAAoB,iBAAoB,EAAe,QAAQ,CAAC,EACnF,EAAgB,GAAoB,kBACxC,EAAG,eAAe,CAAE,sBAAqB,CAAC,CAC5C,EACM,CAAC,EAAiB,GAAgB,MAAM,QAAQ,WAAW,CAC/D,EACA,CACF,CAAC,EAWD,OATI,EAAgB,SAAW,YAC7B,EAAG,WAAW,EACP,CAAE,GAAI,GAAO,MAAO,EAAgB,OAAQ,MAAO,YAAa,GAErE,EAAa,SAAW,YAC1B,EAAG,WAAW,EACP,CAAE,GAAI,GAAO,MAAO,EAAa,OAAQ,MAAO,aAAc,GAGhE,CAAE,GAAI,GAAM,IAAG,CACxB,EAEa,GAAa,KAAO,IAA4C,CAC3E,IAAM,EAAY,EAAoB,CAAO,EAC7C,EAAS,KAAK,OAAQ,6BAA8B,CAClD,OAAQ,EAAQ,OAChB,QAAS,EAAQ,OACnB,CAAC,EAED,IAAM,EAAgB,SAAY,CAChC,EAAI,KAAK,oCAAqC,EAAQ,MAAM,EAC5D,EAAS,KAAK,OAAQ,oCAAqC,CACzD,OAAQ,EAAQ,MAClB,CAAC,EACD,EAAqB,CACnB,SAAU,SACV,QAAS,2DACT,MAAO,SACT,CAAC,EACD,EAAqB,0BAA2B,CAAC,EACjD,MAAM,GAAoB,CAAS,EACnC,GAAI,CACF,IAAM,EAAS,MAAM,OAAO,UAAU,UAAU,EAChD,MAAM,QAAQ,IACZ,EAAO,IAAI,MAAO,CAAE,UAAW,CACzB,GAAQ,EAAK,SAAS,EAAQ,MAAM,IACtC,EAAI,KAAK,6BAA8B,CAAI,EAC3C,MAAM,EAAe,CAAI,EAE7B,CAAC,CACH,CACF,MAAQ,CAER,CACF,EAEM,EAAgB,YAAY,IAAI,EAClC,EAAc,UAClB,GAAI,CACF,IAAM,EAAS,MAAM,GAAiB,EAAS,EAAU,gBAAgB,EACzE,GAAI,CAAC,EAAO,GAgBV,MAfK,GAAW,EAAO,KAAK,GAQ5B,EAAI,KAAK,+BAA+B,EAAO,MAAM,0BAA2B,EAAO,KAAK,EAC5F,EAAS,KAAK,OAAQ,+DAAgE,CACpF,MAAO,EAAO,MACd,MAAO,EAAO,KAChB,CAAC,EACD,MAAM,EAAc,EACpB,OAAO,SAAS,OAAO,EACjB,EAAO,QAdX,EAAS,MAAM,OAAQ,8BAA+B,CACpD,MAAO,EAAO,MACd,MAAO,EAAO,KAChB,CAAC,EACK,EAAO,OAcjB,OADA,EAAO,GAAG,gBAAgB,EAAE,EACrB,EAAO,EAChB,OAAS,EAAO,CAEd,KADA,GAAc,QACR,CACR,QAAU,CACR,EAA4B,yBAA0B,YAAY,IAAI,EAAI,EAAe,CACvF,WAAY,CAAE,MAAO,cAAe,QAAS,CAAY,CAC3D,CAAC,CACH,CACF,EAiBM,GAAgC,gCAEhC,GAAqC,IAK9B,GAAsB,MACjC,EACA,IAII,CACJ,IAAI,EACE,EAAU,IAAI,QAA8B,GAAY,CAC5D,EAAQ,WAAW,eAAiB,EAAQ,MAAS,EAAG,EAAkC,CAC5F,CAAC,EAEG,EACJ,GAAI,CACF,EAAY,MAAM,QAAQ,KAAK,CAC7B,EAAG,iCAAiC,EAA6B,EACjE,CACF,CAAC,CACH,MAAQ,CACN,EAAY,MACd,QAAU,CACR,WAAW,aAAa,CAAK,CAC/B,CAEA,GAAI,IAAc,OAChB,MAAO,CAAE,UAAW,EAAW,OAAQ,EAAY,aAAe,cAAe,EAGnF,IAAM,EAAS,GACb,EACA,EAAG,cAAc,EACjB,EACF,EACA,MAAO,CAAE,UAAW,EAAQ,OAAQ,EAAS,SAAW,SAAU,CACpE,EAEM,GAAsB,GAA2B,CACrD,GAAgC,IAAI,CAAE,CAAC,GAAG,EAC1C,IAAM,EAAU,GAAoB,IAAI,CAAE,EACrC,IACL,EAAQ,QAAQ,EAChB,GAAoB,OAAO,CAAE,EAC/B,EAOM,IACJ,EACA,IACS,CACT,GAAgC,IAAI,CAAE,CAAC,GAAG,EAE1C,IAAM,EAAa,EAGb,EAAmB,EAAG,SAEtB,EAAgB,EAAG,MAEzB,EAAW,SAAW,MAAO,GAAG,IAAS,CACvC,IAAM,EAAO,MAAM,EAAiB,MAAM,EAAI,CAAI,EAElD,OADA,EAAQ,wBAAwB,EAAK,OAAQ,EAAgB,IAAI,EAC1D,CACT,EACA,EAAW,MAAQ,MAAO,GAAG,IAAS,CACpC,IAAM,EAAS,MAAM,EAAc,MAAM,EAAI,CAAI,EAEjD,OADA,EAAQ,wBAAwB,EAAK,GAAI,EAAgB,KAAK,EACvD,CACT,EAEA,GAAgC,IAAI,MAAU,CAC5C,GAAgC,OAAO,CAAE,EACzC,EAAW,SAAW,EACtB,EAAW,MAAQ,CACrB,CAAC,CACH,EAEM,GAAuB,GAA2B,CACtD,GAA6B,IAAI,CAAE,CAAC,GAAG,EACvC,IAAM,EAAU,GAAqB,IAAI,CAAE,EACtC,IACL,EAAQ,QAAQ,EAChB,GAAqB,OAAO,CAAE,EAChC,EAEa,GAAyB,GACpC,GAAoB,IAAI,CAAE,EAEf,GAA0B,GACrC,GAAqB,IAAI,CAAE,EAEhB,GAAc,MAAO,EAAkB,IAA8C,CAChG,GAAmB,CAAE,EACrB,GAAoB,CAAE,EAEtB,IAAM,EAAU,GAAQ,SAAW,EAAG,QAChC,EAAmB,GAAQ,0BAA4B,GACvD,EAAiB,EACnB,MAAM,GAAoB,EAAI,CAAO,EACrC,CAAE,UAAW,GAAO,OAAQ,cAAwB,EAClD,EAAa,GAAoB,EAAe,UAElD,GAAoB,CAAC,IACvB,EAAS,KAAK,OAAQ,+BAAgC,CACpD,OAAQ,EAAG,UAAU,EACrB,UACA,OAAQ,EAAe,MACzB,CAAC,EACD,EAAqB,iCAAkC,EAAG,CACxD,WAAY,CAAE,OAAQ,EAAe,MAAO,CAC9C,CAAC,GAGH,EAAS,KAAK,OAAQ,yBAA0B,CAAE,OAAQ,EAAG,UAAU,CAAE,CAAC,EAE1E,IAAI,EAEJ,GAAI,EAAY,CACd,IAAM,EAAkB,IAAI,GAAoB,CAAE,EAClD,GAAqB,IAAI,EAAI,CAAe,EAC5C,GAA8B,EAAI,CAAe,EAEjD,EAAU,IAAI,GAAmB,EAAI,EAAS,CAC5C,cAAe,GAAqB,GAAQ,aAAa,EACzD,cAAe,GAAQ,cACvB,eAAgB,GAAQ,cAC1B,CAAC,EAED,GAA+B,EAAI,CAAO,EAE1C,EAAQ,OAAO,EACf,EAAQ,6BAA6B,EACrC,GAAsC,EAAI,CAAO,EACjD,GAAoB,IAAI,EAAI,CAAO,CACrC,CAEA,GAAI,CACF,MAAM,GACJ,mBAEE,EAAG,YAAY,CACb,gBAAiB,GACjB,YAAa,GAAS,YACtB,cAAe,EACjB,CAAC,EACH,CAAE,UAAW,EAAa,UAAY,SAAU,CAClD,EACK,GAAY,GAA4B,CAAE,EAC/C,GAAiC,CAAE,EAC/B,GAAY,MAAM,EAAQ,6BAA6B,GACzD,GAAQ,sBAAsB,CAElC,OAAS,EAAK,CAWZ,MAVA,EAAS,MAAM,UAAW,2CAA4C,CACpE,MAAO,aAAe,MAAQ,EAAI,QAAU,OAAO,CAAG,EACtD,OAAQ,EAAG,UAAU,EACrB,QAAS,EAAa,EAAU,OAChC,MAAO,aAAe,MAAQ,EAAI,MAAQ,MAC5C,CAAC,EACD,GAAkC,IAAI,CAAE,CAAC,GAAG,EAC5C,GAAgC,IAAI,CAAE,CAAC,GAAG,EAC1C,GAAmB,CAAE,EACrB,GAAoB,CAAE,EAChB,CACR,CACF,EAEa,GAAc,GAA2B,CACpD,EAAI,IAAI,aAAc,EAAG,UAAU,CAAC,EACpC,EAAS,KAAK,OAAQ,kBAAmB,CAAE,OAAQ,EAAG,UAAU,CAAE,CAAC,EACnE,GAAkC,IAAI,CAAE,CAAC,GAAG,EAC5C,GAA4B,CAAE,EAC9B,GAAmB,CAAE,EACrB,GAAoB,CAAE,EACtB,EAAG,WAAW,CAChB,EAEa,GAAsB,KAAO,IAAqB,CAC7D,EAAI,IAAI,sBAAuB,EAAG,UAAU,CAAC,EAC7C,GAAW,CAAE,EACb,GAA0B,EAAG,cAAc,CAAC,EAC5C,EAAwB,MAAM,EAAG,cAAc,CAAC,EAChD,GAAwB,EAAG,cAAc,CAAC,EAC1C,MAAM,EAAG,MAAM,cAAc,EAC7B,OAAO,SAAS,OAAO,CACzB,EAEa,GAA4B,GAA4C,CACnF,IAAM,EAAiB,GAAoB,IAAI,CAAE,EACjD,MAAO,CACL,UAAW,EAAiB,UAAY,UACxC,UAAW,EAAG,aAAa,EAC3B,QAAS,GAAgB,eAAe,CAC1C,CACF,EAEM,GAAoB,MAAO,EAAkB,IAAoC,CACrF,IAAM,EAAO,EAAQ,KACrB,GAAI,CAAC,EAAM,OACX,IAAM,EAAW,MAAM,EAAG,gBAAgB,EAC1C,GAAyB,EAAK,OAAQ,CAAQ,EAE9C,IAAM,EAAe,EAA6B,EAAQ,MAAM,GAAK,EAAQ,aACvE,EAAQ,GAAgB,EAAG,eAAe,GAAK,OAChD,KAEL,GAAI,CACF,MAAM,GACJ,EACA,EAAK,SACL,EACA,EAAe,gBAAkB,cACnC,CACF,MAAQ,CACN,EAAS,KAAK,UAAW,qCAAsC,CAAE,OAAQ,EAAQ,MAAO,CAAC,CAC3F,CACF,EAOa,GAAe,MAAO,EAAkB,IAAsB,CACzE,EAAI,IAAI,eAAgB,CACtB,OAAQ,EAAG,UAAU,EACrB,cAAe,GAAS,MAC1B,CAAC,EACD,EAAS,KAAK,UAAW,qBAAsB,CAAE,OAAQ,EAAG,UAAU,CAAE,CAAC,EACzE,GAAW,CAAE,EACb,GAAI,CACE,GAAS,KACX,MAAM,GAAkB,EAAI,CAAO,EAEnC,MAAM,EAAG,OAAO,EAElB,EAAS,KAAK,UAAW,oBAAqB,CAAE,OAAQ,EAAG,UAAU,CAAE,CAAC,CAC1E,MAAQ,CAER,CAEA,GAAI,EAAS,CACX,EAAwB,MAAM,EAAQ,MAAM,EAC5C,GAAoB,EAAQ,QAAS,EAAQ,MAAM,EACnD,GAAwB,EAAQ,MAAM,EACtC,GAAuB,EACvB,EAA8B,EAAQ,MAAM,EAC5C,EAA4B,EAAQ,MAAM,EAC1C,IAAM,EAA8B,EAAoB,CAAO,EAC/D,MAAM,EAAG,YAAY,CAAE,qBAAsB,EAAU,gBAAiB,CAAC,EACzE,MAAM,EAAe,EAAU,IAAI,EACnC,MAAM,EAAe,EAAU,MAAM,EACrC,MAAM,EAAe,GAAG,EAAU,iBAAiB,oBAAoB,CACzE,MACE,MAAM,EAAG,YAAY,EACrB,OAAO,aAAa,MAAM,EAG5B,GAAI,CACF,MAAM,GAAgB,CACxB,QAAU,CACJ,GAAuB,CAAO,GAEhC,MAAM,GAAgB,CAE1B,CACF,EAEa,GAAiB,SAAY,CACxC,EAAS,KAAK,UAAW,uCAAuC,GAEhE,MADkB,OAAO,UAAU,UAAU,GACzC,QAAS,GAAY,CACvB,GAAM,CAAE,QAAS,EACb,GAAM,OAAO,UAAU,eAAe,CAAI,CAChD,CAAC,EACD,OAAO,aAAa,MAAM,EAC1B,MAAM,GAAgB,EACtB,OAAO,SAAS,OAAO,CACzB,EC7sBa,GAA4B,sDAEnC,GAA0B,cACnB,GAA4B,oBA6BnC,IAAa,EAAgB,IAA6B,CAC9D,GAAI,OAAO,GAAU,SAAU,OAAO,EACtC,IAAM,EAAa,EAAM,KAAK,EAC9B,OAAO,EAAW,OAAS,EAAI,EAAa,CAC9C,EAEM,GAAsB,GAAyC,CACnE,GAAI,CAAC,GAAW,OAAO,GAAY,SAAU,OAC7C,GAAM,CAAE,QAAS,EACjB,GAAI,OAAO,GAAS,SAAU,OAC9B,IAAM,EAAa,EAAK,KAAK,EAC7B,OAAO,EAAW,OAAS,EAAI,EAAa,MAC9C,EAEa,GAAkC,CAC7C,UACA,YACA,kBACA,qBACA,iCACsC,CAEtC,GAAI,IAAc,cAAgB,GAAW,OAAO,GAAY,SAAU,CACxE,IAAM,EAAa,EAAoC,gBACvD,GAAI,GAAa,OAAO,GAAc,SAAU,CAC9C,GAAM,CAAE,OAAQ,EAChB,GAAI,OAAO,GAAQ,SACjB,MAAO,gBAAgB,GAE3B,CACA,MAAO,kBACT,CAEA,IAAM,EAAmB,GAAmB,IAAc,EAAU,qBAYpE,OAVK,EAGD,GAAoB,CAAC,EAChB,GAGI,GAAmB,CAC5B,IAEG,EAAmB,GAA4B,IAT7C,EAAmB,GAA4B,EAU1D,EAGM,GAAe,GAA2B,EAAO,MAAM,YAAY,CAAC,GAAG,IAAM,EAEtE,IAAgC,CAC3C,WACA,WACA,aACA,cACA,SACA,UACA,OACA,iBACuD,CACvD,IAAM,EAAS,GAAU,EAAU,SAAS,EACtC,EAAO,GAAU,EAAU,SAAS,EACpC,EAAU,GAAU,EAAa,EAAuB,EACxD,EAAS,GAAU,EAAY,EAAyB,EAG9D,MAAO,CACL,MAAO,GAAG,EAAO,MAAM,IAHD,EAAc,MAAM,GAAY,CAAW,IAAM,KAIvE,QAAS,CACP,KAAM,EACN,MAAO,uDACP,KAAM,GAAG,EAAO,IAAI,IACpB,SACA,IAAK,GAAW,GAAG,EAAK,GAAG,IAC3B,MACF,CACF,CACF,EC9FA,eAAsB,GAA+D,CACnF,IAAM,EAAmB,aAAM,OAAO,iDACtC,MAAO,CACL,oBAAqB,EAAiB,oBACtC,kBAAmB,EAAiB,kBACpC,6BAA+B,GAC7B,EAAgC,uDAAwD,CACtF,QACA,SAAU,aACZ,CAAC,EACH,+BAAgC,EAAiB,+BACjD,iBAAkB,EAAiB,iBACnC,eAAgB,EAAiB,eACjC,SAAU,EAAiB,QAC7B,CACF,CCiBA,IAAM,GAA4B,0BAElC,SAAgB,GAAsB,EAAwB,CAC5D,GAAI,aAAiB,MAAO,OAAO,EAAM,QACzC,GAAI,OAAO,GAAU,SAAU,OAAO,EACtC,GAAI,GAAS,OAAO,GAAU,SAAU,CACtC,IAAM,EAAU,YAAa,EAAS,EAAgC,QAAU,OAChF,GAAI,OAAO,GAAY,SAAU,OAAO,EACxC,IAAM,EAAO,SAAU,EAAS,EAA6B,KAAO,OACpE,GAAI,OAAO,GAAS,SAAU,OAAO,CACvC,CACA,OAAO,OAAO,CAAK,CACrB,CAEA,SAAS,GAAmB,EAAwB,CAQlD,MAPI,CAAC,GAAS,OAAO,GAAU,SAAiB,GAC5C,SAAU,GAAS,OAAQ,EAA6B,MAAS,SAC5D,OAAQ,EAA4B,IAAI,CAAC,CAAC,YAAY,EAE3D,SAAU,GAAS,OAAQ,EAA6B,MAAS,SAC5D,OAAQ,EAA4B,IAAI,CAAC,CAAC,YAAY,EAExD,EACT,CAEA,SAAgB,GACd,EACiE,CACjE,IAAM,EAAU,GAAsB,CAAK,CAAC,CAAC,YAAY,EACnD,EAAO,GAAmB,CAAK,EAsBrC,OAnBE,EAAK,SAAS,kBAAkB,GAChC,EAAK,SAAS,uBAAuB,GACrC,EAAQ,SAAS,kBAAkB,GACnC,EAAQ,SAAS,kBAAkB,GACnC,EAAQ,SAAS,yBAAyB,EAEnC,mBAIP,EAAK,SAAS,qBAAqB,GACnC,EAAQ,SAAS,qBAAqB,GACtC,EAAQ,SAAS,4BAA4B,GAC7C,EAAQ,SAAS,gBAAgB,GACjC,EAAQ,SAAS,mCAAmC,EAE7C,sBAGF,cACT,CAEA,eAAe,IAAqE,CAClF,IAAM,EAAM,MAAM,EAA2B,EAC7C,GAAI,MAAM,EAAI,oBAAoB,EAAG,MAAO,UAE5C,IAAM,EAAa,MAAM,EAAI,kBAAkB,EAC/C,OAAO,IAAe,UAAY,UAAY,CAChD,CAEA,eAAsB,IAA0D,CAE9E,OAAO,MADW,EAA2B,GAClC,oBAAoB,CACjC,CAEA,eAAe,IAAgD,CAE7D,OAAO,MADW,EAA2B,GAClC,iBAAiB,CAC9B,CAEA,eAAe,IAA8D,CAE3E,MAAO,CAAE,YADW,aAAa,QAAQ,EAAyB,GAAK,EAClD,CACvB,CAEA,eAAe,GAA2B,EAAoC,CAC5E,aAAa,QAAQ,GAA2B,CAAW,EAE3D,MAAM,MADY,EAA2B,GACnC,eAAe,CAAW,CACtC,CAEA,eAAsB,IAAwE,CAC5F,GAAM,CAAC,EAAmB,GAAsB,MAAM,QAAQ,WAAW,CACvE,GAA0B,EAC1B,GAA2B,CAC7B,CAAC,EAEK,EACJ,EAAmB,SAAW,aAC1B,EAAkB,SAAW,YAC3B,EAAkB,MAAM,YACxB,GAEF,EAAe,EAAmB,SAAW,YAAc,EAAmB,MAAQ,CAAC,EAE7F,GAAI,GAAoB,EAAa,SAAS,CAAgB,EAC5D,MAAO,CAAE,eAAc,oBAAqB,CAAiB,EAG/D,GAAI,EAAa,SAAW,EAAG,CAC7B,GAAM,CAAC,GAAmB,EAC1B,GAAI,EAEF,OADA,MAAM,GAA2B,CAAe,EACzC,CAAE,eAAc,oBAAqB,CAAgB,CAEhE,CAEA,MAAO,CAAE,eAAc,oBAAqB,EAAG,CACjD,CAEA,eAAsB,GACpB,EACA,EACiB,CACjB,IAAM,EACJ,GAAuB,EAAa,SAAS,CAAmB,EAC5D,EACA,EAAa,GAKnB,OAHK,GAEL,MAAM,GAA2B,CAAW,EACrC,GAHkB,EAI3B,CAEA,eAAsB,GAAmC,EAAoC,CAC3F,MAAM,GAA2B,CAAW,CAC9C,CAEA,eAAsB,GACpB,EACA,EACA,EACY,CACZ,GAAI,IAAoB,EACtB,OAAO,EAAS,EAGlB,MAAM,GAA2B,CAAe,EAEhD,GAAI,CACF,OAAO,MAAM,EAAS,CACxB,OAAS,EAAO,CAEd,MADA,MAAM,GAA2B,CAAmB,EAC9C,CACR,CACF,CAEA,eAAsB,GACpB,EACwC,CACxC,IAAI,EAA8C,UAC9C,EAEJ,GAAI,CAEF,GADA,EAAkB,MAAM,GAA8B,EAClD,IAAoB,UACtB,MAAO,CACL,OAAQ,SACR,kBACA,MACE,IAAoB,SAChB,gCACA,kCACR,EAGF,GAAM,CAAE,eAAc,oBAAqB,GACzC,MAAM,GAAgC,EAExC,GADA,EAAsB,GAAe,OACjC,CAAC,EACH,MAAO,CACL,OAAQ,sBACR,gBAAiB,UACjB,eACA,MACE,EAAa,SAAW,EACpB,uCACA,qCACR,EAIF,IAAM,EAAe,MAAM,MADT,EAA2B,GACd,6BAA6B,CAAK,EAC3D,EAAW,GAAc,YAU/B,MATI,CAAC,GAAY,CAAC,EAAS,KAAK,EACvB,CACL,OAAQ,eACR,gBAAiB,UACjB,MAAO,wDACP,GAAI,EAAsB,CAAE,YAAa,CAAoB,EAAI,CAAC,CACpE,EAGK,CACL,OAAQ,aACR,gBAAiB,UACjB,WACA,cACA,OAAQ,EAAa,OACrB,KAAM,EAAa,IACrB,CACF,OAAS,EAAO,CAEd,MAAO,CACL,OAFoB,GAA2B,CAEvC,EACR,kBACA,MAAO,GAAsB,CAAK,EAClC,GAAI,EAAsB,CAAE,YAAa,CAAoB,EAAI,CAAC,CACpE,CACF,CACF,CAEA,eAAsB,IAAgD,CAEpE,MAAM,MADY,EAA2B,GACnC,+BAA+B,CAC3C,CCzQA,SAAgB,GACd,EACA,EACA,CACA,MAAQ,IAAkC,CACxC,EAAQ,CAAI,CAAC,CAAC,MAAM,CAAO,CAC7B,CACF,CAEA,SAAgB,GAAwB,EAA8C,CACpF,IAAM,EAAW,GAA+B,QAChD,GAAI,OAAO,GAAY,SAAU,OAAO,KAExC,IAAI,EACJ,GAAI,CACF,EAAU,KAAK,MAAM,CAAO,CAC9B,MAAQ,CACN,OAAO,IACT,CACA,GAAI,CAAC,GAAW,OAAO,GAAY,SAAU,OAAO,KAEpD,IAAM,EAAgB,EAAuC,aAI7D,OAHI,GAAgB,OAAO,GAAiB,SACnC,EAEF,CACT,CCxBA,SAAgB,GACd,EACA,EACQ,CACR,IAAM,EAAY,GAAU,KAAK,GAAK,GAAe,KAAK,EAC1D,GAAI,CAAC,EACH,MAAU,MAAM,qEAAqE,EAEvF,IAAI,EACJ,GAAI,CACF,EAAM,IAAI,IAAI,CAAS,CACzB,MAAQ,CACN,MAAU,MAAM,8DAA8D,CAChF,CACA,GACE,EAAI,WAAa,UACjB,EAAI,UACJ,EAAI,UACJ,EAAI,MACJ,EAAI,WAAa,0BAEjB,MAAU,MAAM,4EAA4E,EAE9F,OAAO,EAAI,SAAS,CACtB,CAEA,SAAgB,GACd,EACA,EAAsB,GACiB,CACvC,OAAO,EAAsB,EAAO,CAAE,GAAG,EAAM,OAAQ,eAAgB,CACzE,gMCHM,GAAoB,gEACb,GAA8B,eACrC,EAAiB,EAAkB,aAAa,EAqBhD,GAAyB,IAIzB,GAAsB,cACtB,GAAqB,UACrB,GAA6B,WAEnC,eAAe,GACb,EACe,CACf,MAAM,EAAiB,cAAc,CACnC,GAAI,GACJ,KAAM,WACN,YAAa,+BACb,WAAY,EAAiB,WAAW,KACxC,UAAW,EACb,CAAC,EACD,MAAM,EAAiB,cAAc,CACnC,GAAI,GACJ,KAAM,cACN,YAAa,6BACb,WAAY,EAAiB,WAAW,QACxC,UAAW,EACb,CAAC,EACD,MAAM,EAAiB,cAAc,EAA0B,CAAC,CAAC,UAAY,CAE7E,CAAC,CACH,CAgBA,SAAS,GAAgB,EAA+C,CAEtE,OADgB,GAAO,KAAK,GACV,MACpB,CAEA,SAAS,GACP,EACyB,CACzB,MAAO,CACL,MAAO,GAAgB,GAAQ,gBAAgB,kBAC/C,WAAY,GAAgB,GAAQ,qBAAqB,CAC3D,CACF,CAWA,eAAe,GACb,EACwC,CACxC,IAAI,EACE,EAAU,IAAI,SAAgB,EAAG,IAAW,CAChD,EAAY,eAAiB,CAC3B,EAAW,MAAM,oCAAoC,CAAC,CACxD,EAAG,EAAsB,CAC3B,CAAC,EAED,GAAI,CACF,OAAO,MAAM,QAAQ,KAAK,CAAC,GAA6B,CAAK,EAAG,CAAO,CAAC,CAC1E,QAAU,CACJ,IAAc,QAChB,aAAa,CAAS,CAE1B,CACF,CAEA,eAAsB,GACpB,EACA,EACkC,CAElC,MAAM,GAA2B,MADF,EAAyB,CACP,EAEjD,IAAM,EAAe,MAAM,GAA+B,GAAQ,cAAc,EAEhF,GAAI,EAAa,SAAW,aAC1B,OAAO,EAGT,GAAM,CAAE,YAAa,EACf,GACH,MAAM,EAAG,UAAU,EAAG,YAAY,GAAK,EAAE,IAAI,cAAgB,iBAEhE,GAAI,EAAa,QAAU,EAAa,MAAQ,GAAQ,cAAgB,GAAQ,cAAe,CAC7F,IAAM,EAAgB,GAAqB,EAAO,cAAe,GAAQ,qBAAqB,EAqB9F,OApBA,MAAM,EAAG,UAAU,CACjB,KAAM,OACN,OAAQ,EAAO,aACf,QAAS,EAAa,OACtB,iBAAkB,sBAClB,oBAAqB,EACrB,KAAM,UAAU,UAAY,KAC5B,KAAM,GACJ,CACE,IAAK,EACL,WACA,OAAQ,EAAa,OACrB,KAAM,EAAa,KACnB,gBAAiB,CAAE,QAAS,EAAG,cAAc,CAAE,CACjD,EACA,GAAQ,mBACV,EACA,OAAQ,EACV,CAA8B,EAEvB,CACL,OAAQ,aACR,WACA,WAAY,EACZ,YAAa,EAAa,WAC5B,CACF,CAEA,IAAM,EAAiB,GAA+B,CAAM,EACtD,EAAa,EAAe,YAAc,GAgBhD,OAdA,MAAM,EAAG,UAAU,CACjB,KAAM,OACN,OAAQ,EAAe,MACvB,QAAS,EACT,iBAAkB,sBAClB,oBAAqB,EACrB,KAAM,UAAU,UAAY,KAC5B,KAAM,GACJ,CAAE,IAAK,EAAY,gBAAiB,CAAE,QAAS,EAAG,cAAc,CAAE,CAAE,EACpE,GAAQ,mBACV,EACA,OAAQ,EACV,CAA8B,EAEvB,CACL,OAAQ,aACR,WACA,aACA,YAAa,EAAa,WAC5B,CACF,CAEA,eAAsB,GACpB,EACA,EACmD,CACnD,IAAM,EAAS,MAAM,GAAqB,EAAI,CAAM,EACpD,GAAI,EAAO,SAAW,aACpB,MAAU,MAAM,EAAO,OAAS,iCAAiC,EAGnE,MAAO,CACL,SAAU,EAAO,SACjB,WAAY,EAAO,UACrB,CACF,CAEA,SAAS,GAAiB,EAAiC,CACzD,OAAO,OAAO,GAAU,UAAY,EAAM,KAAK,CAAC,CAAC,OAAS,CAC5D,CAEA,eAAe,GACb,EACA,EACmB,CACnB,IAAM,EAAW,EAAG,YAAY,GAAK,GACrC,GAAI,CAAC,EACH,MAAO,CAAC,EAIV,IAAM,GAAoB,MADE,EAAG,UAAU,CAAQ,IACR,aAOzC,OANK,IAKW,MADO,EAAG,WAAW,GACZ,SAAW,CAAC,GAElC,OACE,GACC,EAAO,SAAW,GAClB,EAAO,sBAAwB,GAC/B,EAAO,OAAS,QAChB,GAAiB,EAAO,OAAO,CACnC,CAAC,CACA,IAAK,GAAW,EAAO,OAAO,EAbxB,CAAC,CAcZ,CAEA,eAAe,GACb,EACA,EACA,EACmB,CACnB,IAAM,EAAW,IAAI,IASrB,OAPI,GAAiB,CAAO,GAC1B,EAAS,IAAI,CAAO,GAItB,MADoC,GAAoC,EAAI,CAAK,GAC3D,QAAS,GAAc,EAAS,IAAI,CAAS,CAAC,EAE7D,MAAM,KAAK,CAAQ,CAC5B,CAOA,eAAsB,GACpB,EACA,EAAqC,CAAC,EACvB,CACf,GAAM,CAAE,SAAU,GAA+B,EAAQ,MAAM,EACzD,EAAW,MAAM,GAA8B,EAAI,EAAO,EAAQ,OAAO,EAE/E,MAAM,QAAQ,WACZ,EAAS,IAAK,GACZ,EAAG,UAAU,CACX,KAAM,KACN,OAAQ,EACR,SACF,CAA8B,CAChC,CACF,EAEA,IAAM,EAAe,GAAgB,EAAQ,QAAQ,YAAY,EACjE,GAAI,GAAgB,IAAiB,EAAO,CAC1C,IAAM,EAAc,MAAM,GAAoC,EAAI,CAAY,EAC9E,MAAM,QAAQ,WACZ,EAAY,IAAK,GACf,EAAG,UAAU,CACX,KAAM,KACN,OAAQ,EACR,SACF,CAA8B,CAChC,CACF,CACF,CAEA,MAAM,GAA+B,CACvC,CAUA,IAAM,GAAkB,kBAClB,GAAe,GACf,GAAqB,IACrB,GAAoC,IAa1C,SAAS,GAAS,EAAqB,CACrC,IAAI,EAAO,EACX,IAAK,IAAI,EAAI,EAAG,EAAI,EAAI,OAAQ,GAAK,EAEnC,EAAQ,KAAK,KAAK,GAAI,CAAI,EAAI,EAAI,WAAW,CAAC,EAAK,EAErD,OAAO,KAAK,IAAI,CAAI,CACtB,CAEA,eAAe,GACb,EACA,EACA,EACkC,CAClC,GAAI,CACF,IAAM,EAAM,MAAM,EAAG,eAAe,EAAQ,CAAO,EAC7C,EAAS,IAAI,GAAY,CAAG,EAIlC,OAHI,EAAO,YAAY,GACrB,MAAM,EAAG,qBAAqB,CAAM,EAE/B,CACT,OAAS,EAAO,CACd,EAAe,KACb,eACA,iDACA,aAAiB,MAAQ,EAAY,MAAM,OAAO,CAAK,CAAC,CAC1D,EACA,MACF,CACF,CAMA,SAAS,GACP,EACA,EACA,EACyB,CACpB,KAAS,QACd,OAAO,IAAI,GAAY,CACrB,KAAM,mBACN,QAAS,EAAS,QAClB,QAAS,EACT,SAAU,EACV,OAAQ,EAAS,OACjB,iBAAkB,KAAK,IAAI,CAC7B,CAAC,CACH,CAEA,SAAS,GAAe,EAA6B,CACnD,MACE,CAAC,EAAM,oBAAoB,GAAK,EAAM,QAAQ,IAAM,EAAU,qBAAqB,SAAS,CAEhG,CAQA,SAAS,GAAc,EAAoB,EAAkC,CAC3E,GAAI,GAAe,CAAK,EAAG,CACzB,EAAW,EACX,MACF,CAEA,IAAM,MAAoB,CACnB,GAAe,CAAK,IACzB,EAAM,IAAI,GAAiB,UAAW,CAAW,EACjD,aAAa,CAAgB,EAC7B,EAAW,EACb,EAEA,EAAM,GAAG,GAAiB,UAAW,CAAW,EAChD,IAAM,EAAmB,eAAiB,CACxC,EAAM,IAAI,GAAiB,UAAW,CAAW,EACjD,EAAe,KAAK,eAAgB,uDAAuD,CAC7F,EAAG,EAAiC,CACtC,CAEA,IAAM,IAAe,EAAgB,IAAmB,GAAS,GAAG,EAAO,QAAQ,GAAQ,EACrF,GAAkB,GAAmB,GAAS,4BAA4B,GAAQ,EAYlF,EAAkB,IAAI,IACtB,GAAuB,IAAI,IAC3B,GAAkB,IAAI,IAE5B,SAAS,GAAwB,EAAa,EAAyC,CAErF,IAAM,GADW,GAAgB,IAAI,CAAG,GAAK,QAAQ,QAAQ,GACvC,KAAK,EAAW,CAAS,EACzC,EAAa,EAAK,SAChB,WACA,MACR,EAKA,OAJA,GAAgB,IAAI,EAAK,CAAU,EACnC,EAAgB,SAAW,CACrB,GAAgB,IAAI,CAAG,IAAM,GAAY,GAAgB,OAAO,CAAG,CACzE,CAAC,EACM,CACT,CAEA,SAAS,GAAqB,EAAgB,EAAgB,EAAkC,CAC9F,IAAM,EAAM,GAAG,EAAO,QAAQ,IAC1B,EAAQ,EAAgB,IAAI,CAAG,EAcnC,OAbK,IACH,EAAQ,CACN,MACA,WAAY,GAAqB,IAAI,CAAG,GAAK,EAC7C,WACA,SAAU,CAAC,EACX,gBAAiB,IAAI,IACrB,aAAc,IAAI,IAClB,oBAAqB,EACvB,EACA,EAAgB,IAAI,EAAK,CAAK,GAEhC,EAAM,SAAW,EACV,CACT,CAEA,SAAS,GAAmB,EAAgC,CAC1D,OACE,EAAgB,IAAI,EAAM,GAAG,IAAM,IAClC,GAAqB,IAAI,EAAM,GAAG,GAAK,KAAO,EAAM,UAEzD,CAUA,eAAe,GAA0B,EAA+B,CACjE,KACL,GAAI,CAEF,MAAM,MADyB,EAAyB,GACjC,aAAa,CAAC,CAAE,GAAI,GAAe,CAAM,CAAE,CAAC,CAAC,CACtE,MAAQ,CAER,CACF,CAGA,eAAsB,GAAsB,EAAgB,EAAgB,CAC1E,IAAM,EAAM,GAAG,EAAO,QAAQ,IAC9B,MAAM,GAAqB,EAAK,SAAY,CAC1C,EAAgB,OAAO,CAAG,EAC1B,GAAqB,IAAI,GAAM,GAAqB,IAAI,CAAG,GAAK,GAAK,CAAC,EACtE,GAAI,CAEF,MAAM,MADyB,EAAyB,GACjC,aAAa,CAAC,CAAE,GAAI,GAAY,EAAQ,CAAM,CAAE,CAAC,CAAC,CAC3E,MAAQ,CAER,CACF,CAAC,CACH,CAEA,eAAe,GACb,EACA,EACA,EACA,EACA,EACA,EACkB,CAClB,IAAM,EAAmB,MAAM,EAAyB,EACxD,GAAI,GAAa,CAAC,EAAU,EAAG,MAAO,GACtC,GAAM,CAAE,WAAU,YAAa,EACzB,EAAY,EAAS,EAAS,OAAS,GACvC,EAAa,EAAY,GAAG,EAAU,QAAQ,MAAQ,MAAM,IAAI,EAAU,OAAS,GAEnF,EAAa,EAAS,MAAM,EAAE,CAAC,CAAC,IAAK,GAAM,GAAG,EAAE,QAAQ,MAAQ,MAAM,IAAI,EAAE,MAAM,EAwBxF,OAtBA,MAAM,EAAiB,iBAAiB,CACtC,GAAI,GAAY,EAAQ,CAAM,EAC9B,MAAO,EACP,KAAM,EACN,UAAW,GACX,MAAO,GACP,KAAM,oBACN,OAAQ,EACR,WAAY,GACZ,QACA,GAAI,GAAc,EAAI,CAAE,aAAc,eAAgB,EAAI,CAAC,EAE3D,SAAU,EAAS,IAAK,IAAO,CAC7B,KAAM,EAAE,KACR,UAAW,EAAE,UACb,WAAY,EAAE,QAAQ,KACtB,UAAW,EAAE,QAAQ,GACvB,EAAE,EACF,kBAAmB,EAAM,oBACzB,WAAY,EAAW,OAAS,EAAI,EAAa,OACjD,UAAW,EAAW,OAAS,EAAI,OAAY,CACjD,CAAC,EACM,EACT,CAGA,eAAe,GACb,EACA,EACA,EACA,EACA,CACA,IAAM,EAAY,EAAS,KAE3B,OAAQ,EAAR,CACE,KAAK,EAAU,YACf,KAAK,EAAU,QACf,KAAK,EAAU,qBAAsB,CACnC,IAAM,EAAc,IAAc,EAAU,qBAExC,EAAc,EAA+B,CAC/C,QAAS,GAAU,QACnB,UAAW,GAAU,KACrB,gBAAiB,EACjB,mBAAoB,EAAS,mBAC7B,4BAA6B,EAAS,2BACxC,CAAC,EAEK,EAA6B,GAAU,QACvC,EACJ,GAAU,WAAa,GAAU,qBAAuB,eACpD,EAAiC,GAAU,oBAC3C,EAA+B,GAAU,OACzC,EAAW,CAAC,EAAS,yBAE3B,GAAI,CAAC,EAAQ,CAEX,MAAM,MADyB,EAAyB,GACjC,iBAAiB,CACtC,MAAO,EACP,KAAM,EAAa,GAAG,EAAW,IAAI,IAAgB,EACrD,UAAW,GACX,KAAM,oBACN,OAAQ,EACR,WAAY,EACd,CAAC,EACD,KACF,CAEA,IAAM,EAA8B,GAAU,SAE1C,EAAkC,GAEtC,GACE,yBACA,GACA,EAAS,oBACT,EAAS,4BACT,CAGA,IAAM,EADO,EAAS,GAAG,QAAQ,CAClB,GACX,gBAAgB,CAAC,CAClB,UAAU,CAAC,CACX,KAAM,GAAM,EAAE,MAAM,IAAM,CAAO,EAChC,GACF,EAAc,EAA+B,CAC3C,QAAS,EAAO,WAAW,EAC3B,UAAW,EAAO,QAAQ,EAC1B,gBAAiB,GACjB,mBAAoB,EAAS,mBAC7B,4BAA6B,EAAS,2BACxC,CAAC,EACD,EACE,EAAO,QAAQ,IAAM,EAAU,qBAAqB,SAAS,GAE/D,EAAkC,EAEtC,CAEA,IAAM,EAAkC,EACpC,CAAE,KAAM,EAAY,IAAK,CAAS,EAClC,OAEE,EAAwB,CAC5B,KAAM,EACN,UAAW,KAAK,IAAI,EACpB,QACF,EAEM,EAAM,GAAG,EAAO,QAAQ,IAC1B,EACA,EA8CF,MA7CmB,GAAqB,EAAK,SAAY,CACzD,IAAM,EAAQ,GAAqB,EAAQ,EAAQ,CAAQ,EAC3D,GAAI,IAAY,EAAM,gBAAgB,IAAI,CAAO,GAAK,EAAM,aAAa,IAAI,CAAO,GAClF,MAAO,GAEL,GAAS,EAAM,gBAAgB,IAAI,CAAO,EAC9C,IAAM,EAAmB,EAAM,SAAS,MAAM,EAC9C,EAAM,SAAS,KAAK,CAAO,EACvB,EAAM,SAAS,OAAS,KAC1B,EAAM,SAAW,EAAM,SAAS,MAAM,GAAa,GAGrD,IAAM,EAAc,EAAS,GAAG,QAAQ,CAAM,EAC1C,IACF,EAAM,qBAAuB,EAAY,qBAAqB,GAAK,GAAK,GAG1E,GAAI,CACF,MAAM,GAAqB,EAAQ,EAAQ,EAAO,EAAU,CAC1D,QAAS,EACT,SAAU,GAAU,SACpB,QAAS,GAAU,OACrB,CAAC,CACH,MAAQ,CAKN,MAJA,GAAM,SAAW,EACb,GAAS,EAAM,gBAAgB,OAAO,CAAO,EAC7C,EAAM,SAAS,SAAW,GAAG,EAAgB,OAAO,EAAM,GAAG,EACjE,EAAe,KAAK,eAAgB,0CAA0C,EACvE,EACT,CAEA,GAAI,IACF,EAAM,gBAAgB,OAAO,CAAO,EACpC,EAAM,aAAa,IAAI,CAAO,EAC1B,EAAM,aAAa,KAAO,IAAoB,CAChD,IAAM,EAAS,EAAM,aAAa,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,MAC9C,IAAW,QAAW,EAAM,aAAa,OAAO,CAAM,CAC5D,CAIF,MAFA,GAAkB,EAClB,EAAoB,EACb,EACT,CAAC,GAIC,GACA,GACA,GACA,GAEA,GACE,EACA,EACA,EACA,EACA,EACA,EACA,CACF,EAEF,KACF,CACA,KAAK,EAAU,WAAY,CACzB,GAAI,GAAU,SAAS,aAAe,SAAU,MAChD,IAAM,EAAiC,GAAU,oBAC3C,EAA+B,GAAU,UAC3C,EAAO,GACP,GAAc,EAAU,EAAO,GAAG,EAAW,kBAAkB,IAC1D,EAAY,EAAO,QAAQ,IAC3B,IAAU,EAAO,MAAM,KAGhC,MAAM,MADyB,EAAyB,GACjC,iBAAiB,CACtC,MAAO,iBACP,OACA,UAAW,EACX,UAAW,GACX,MAAO,GACP,KAAM,oBACN,WAAY,GACZ,MAAO,CACL,KAAM,SACN,QAAS,GAAU,QACnB,SAAU,GAAU,SACpB,QAAS,GAAU,OACrB,CACF,CAAC,EACD,KACF,CAGF,CACF,CAEA,SAAS,GACP,EACA,EACA,EACA,EACA,EACA,EACA,EACM,CACN,IAAM,EAAkB,EAAY,EACpC,GAAI,CAAC,EAAgB,oBAAsB,CAAC,EAAgB,4BAA6B,OAEzF,IAAM,EAAS,EAAgB,GAAG,UAAU,EACtC,EAAY,GAA2B,EAAQ,EAAS,CAAQ,EAClE,CAAC,GAAU,CAAC,IAoEhB,GAAc,EAAW,SAlEgC,CACvD,MAAM,GAAqB,EAAM,IAAK,SAAY,CAChD,IAAM,EAAe,EAAY,EAKjC,GAAI,EAHF,EAAa,oBACb,EAAa,6BACb,EAAE,SAAS,kBAAoB,WAAa,EAAa,yBACzC,CAAC,GAAmB,CAAK,GAAK,CAAC,EAAM,SAAS,SAAS,CAAO,EAC9E,OAGF,IAAM,EAAkB,EAA+B,CACrD,QAAS,EAAU,WAAW,EAC9B,UAAW,EAAU,QAAQ,EAC7B,gBAAiB,GACjB,mBAAoB,EAAa,mBACjC,4BAA6B,EAAa,2BAC5C,CAAC,EACD,GAAI,CAAC,GAAmB,wBAA+C,OAEvE,IAAM,EAAW,EAAa,GAAG,QAAQ,CAAM,EACzC,EAAkB,EAAU,UAAU,EACtC,EAAa,EACd,GAAU,UAAU,CAAe,CAAC,EAAE,MACvC,EAAiB,CAAe,GAChC,EACA,OACE,EAAe,EAAQ,KACvB,EAAiB,EAAQ,OAC/B,EAAQ,KAAO,EACf,EAAQ,OAAS,EAAa,CAAE,KAAM,EAAY,IAAK,CAAgB,EAAI,EAAQ,OAEnF,IAAM,MAAgB,CACpB,IAAM,EAAkB,EAAY,EACpC,OACE,GAAmB,CAAK,GACxB,EAAM,SAAS,SAAS,CAAO,GAC/B,EAAgB,oBAChB,EAAgB,6BAChB,EAAE,SAAS,kBAAoB,WAAa,EAAgB,sBAEhE,EACA,GAAI,CAaG,MAZgB,GACnB,EACA,EACA,EACA,GACA,CACE,QAAS,EACT,SAAU,EACV,QAAS,GAAU,OACrB,EACA,CACF,IAEE,EAAQ,KAAO,EACf,EAAQ,OAAS,EAErB,MAAQ,CACN,EAAQ,KAAO,EACf,EAAQ,OAAS,CACnB,CACF,CAAC,CACH,CAE8C,EAC9C,EAAqB,GAAG,qBAAqB,CAAS,CAAC,CAAC,UAAY,CAClE,EAAe,KAAK,eAAgB,qCAAqC,CAC3E,CAAC,EACH,CAMA,eAAe,GACb,EACA,EACA,EACA,EACA,CACA,IAAM,EAA6B,GAAU,QACvC,EAA8B,GAAU,SACxC,EACJ,OAAO,GAAU,QAAQ,QAAW,SAAW,EAAS,OAAO,OAAS,OAE1E,GAAI,CAAC,EAAQ,OAGb,GAAI,IAAW,EAAG,CAChB,MAAM,GAAsB,EAAQ,CAAM,EAC1C,MACF,CAEA,IAAM,EAAO,EAAS,GAAG,QAAQ,CAAM,EACjC,EAAW,GAAM,MAAQ,GAAU,qBAAuB,eAC1D,EAAkB,EAAO,CAAC,CAAC,EAAc,EAAM,EAAU,cAAc,EAAI,GAE7E,EACA,EACA,EACJ,GAAI,GAAQ,EAAS,CAEnB,IAAM,EADW,EAAK,gBAAgB,CAAC,CAAC,UACzB,EAAS,KAAM,GAAM,EAAE,MAAM,IAAM,CAAO,EACzD,GAAI,EAAQ,CACV,IAAM,EAAS,EAAO,UAAU,EAC5B,IAEF,EADe,EAAK,UAAU,CACjB,GAAQ,MAAQ,EAAiB,CAAM,GAAK,EACzD,EAAW,GAGb,EAAc,EAA+B,CAC3C,QAAS,EAAO,WAAW,EAC3B,UAAW,EAAO,QAAQ,EAC1B,kBACA,mBAAoB,EAAS,mBAC7B,4BAA6B,EAAS,2BACxC,CAAC,CACH,CACF,CAEA,IAAM,EAAqB,EAAQ,EACnC,CACE,GAAc,EAAkB,oBAAsB,cAGxD,IAAM,EAAkC,EACpC,CAAE,KAAM,EAAY,IAAK,CAAS,EAClC,OAEE,EAAwB,CAC5B,KAAM,EACN,UAAW,KAAK,IAAI,EACpB,QACF,EAEM,EAAM,GAAG,EAAO,QAAQ,IAC1B,EAwCJ,GAAI,CAAC,MAvCgB,GAAqB,EAAK,SAAY,CACzD,IAAM,EAAQ,GAAqB,EAAQ,EAAQ,CAAQ,EAC3D,GAAI,IAAY,EAAM,gBAAgB,IAAI,CAAO,GAAK,EAAM,aAAa,IAAI,CAAO,GAClF,MAAO,GACL,GAAS,EAAM,gBAAgB,IAAI,CAAO,EAC9C,IAAM,EAAmB,EAAM,SAAS,MAAM,EAC9C,EAAM,SAAS,KAAK,CAAO,EACvB,EAAM,SAAS,OAAS,KAC1B,EAAM,SAAW,EAAM,SAAS,MAAM,GAAa,GAGjD,IACF,EAAM,qBAAuB,EAAK,qBAAqB,GAAK,GAAK,GAGnE,GAAI,CACF,MAAM,GAAqB,EAAQ,EAAQ,EAAO,CAAC,EAAS,yBAA0B,CACpF,QAAS,EACT,SAAU,EACV,QAAS,GAAU,OACrB,CAAC,CACH,OAAS,EAAO,CAId,KAHA,GAAM,SAAW,EACb,GAAS,EAAM,gBAAgB,OAAO,CAAO,EAC7C,EAAM,SAAS,SAAW,GAAG,EAAgB,OAAO,EAAM,GAAG,EAC3D,CACR,CAEA,GAAI,IACF,EAAM,gBAAgB,OAAO,CAAO,EACpC,EAAM,aAAa,IAAI,CAAO,EAC1B,EAAM,aAAa,KAAO,IAAoB,CAChD,IAAM,EAAS,EAAM,aAAa,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,MAC9C,IAAW,QAAW,EAAM,aAAa,OAAO,CAAM,CAC5D,CAGF,MADA,GAAgB,EACT,EACT,CAAC,GACc,CAAC,EAAe,OAC/B,IAAM,EAAQ,EAGZ,CAAC,GACD,GACA,EAAS,qBACR,CAAC,GAAmB,EAAS,8BAE9B,GAAoB,EAAS,GAAI,EAAQ,CAAO,CAAC,CAC9C,KAAM,GAAY,CACZ,GAoEL,GAAc,MAjEZ,GAAqB,EAAM,IAAK,SAAY,CAC1C,IAAM,EAAe,EAAY,EAC3B,EAAiB,GAAmB,EAAQ,YAAY,EAK9D,GAAI,EAHF,EAAa,qBACZ,CAAC,GAAkB,EAAa,8BACjC,EAAE,SAAS,kBAAoB,WAAa,EAAa,yBACzC,CAAC,GAAmB,CAAK,GAAK,CAAC,EAAM,SAAS,SAAS,CAAO,EAC9E,OAGF,IAAM,EAAkB,EAA+B,CACrD,QAAS,EAAQ,WAAW,EAC5B,UAAW,EAAQ,QAAQ,EAC3B,gBAAiB,EACjB,mBAAoB,EAAa,mBACjC,4BAA6B,EAAa,2BAC5C,CAAC,EACD,GAAI,CAAC,EAAiB,OAEtB,IAAM,EAAgB,EAAQ,UAAU,EAClC,EAAW,EAAa,GAAG,QAAQ,CAAM,EACzC,EAAiB,EAClB,GAAU,UAAU,CAAa,CAAC,EAAE,MACrC,EAAiB,CAAa,GAC9B,EACA,OACE,EAAe,EAAQ,KACvB,EAAiB,EAAQ,OAC/B,EAAQ,KAAO,EACf,EAAQ,OAAS,EAAiB,CAAE,KAAM,EAAgB,IAAK,CAAc,EAAI,EAEjF,IAAM,MAAgB,CACpB,IAAM,EAAkB,EAAY,EACpC,OACE,GAAmB,CAAK,GACxB,EAAM,SAAS,SAAS,CAAO,GAC/B,EAAgB,qBACf,CAAC,GAAkB,EAAgB,8BACpC,EAAE,SAAS,kBAAoB,WAAa,EAAgB,sBAEhE,EACA,GAAI,CAaG,MAZc,GACjB,EACA,EACA,EACA,GACA,CACE,QAAS,EACT,SAAU,EACV,QAAS,GAAU,OACrB,EACA,CACF,IAEE,EAAQ,KAAO,EACf,EAAQ,OAAS,EAErB,MAAQ,CACN,EAAQ,KAAO,EACf,EAAQ,OAAS,CACnB,CACF,CAAC,CAEuC,CAC5C,CAAC,CAAC,CACD,MAAO,GAAU,CAChB,EAAe,KACb,eACA,kCACA,aAAiB,MAAQ,EAAY,MAAM,OAAO,CAAK,CAAC,CAC1D,CACF,CAAC,CAEP,CAEA,eAAe,GACb,EACA,EACA,CACA,IAAM,EAAW,EAAY,EAG7B,GAAI,SAAS,kBAAoB,WAAa,EAAS,sBACrD,OAGF,IAAM,EAAY,EAAI,OAAS,EACzB,EAAY,GAAU,KACtB,EAAS,GAAiB,GAAU,OAAO,EAAI,EAAS,QAAQ,KAAK,EAAI,OAC/E,GAAI,CAAC,GAAU,IAAW,EAAS,GAAG,UAAU,EAAG,CACjD,EAAe,KAAK,eAAgB,qDAAqD,EACzF,MACF,CAEI,EACF,MAAM,GAAsB,EAAU,EAAU,EAAQ,CAAW,EAEnE,MAAM,GAAyB,EAAU,EAAU,EAAQ,CAAW,CAE1E,CAEA,IAAM,GAAmC,wDAEzC,eAAsB,GAA6B,EAAyC,CAC1F,IAAM,EAAW,GACd,GAAiB,GAAyB,EAAc,CAAW,EACnE,GAAU,CACT,EAAe,MACb,eACA,sCACA,aAAiB,MAAQ,EAAY,MAAM,OAAO,CAAK,CAAC,CAC1D,CACF,CACF,EAEM,EAAW,MAAM,GAAkB,gBAAiB,eAAiB,GAAkB,CAC3F,IAAM,EAAe,GAAwB,CAAI,EAC5C,IACL,GAAsB,EAAY,CAAC,CAAC,EAAE,CAAC,EAAE,cAAc,EACvD,EAAS,CAAY,EACvB,CAAC,EAED,GAAI,CACF,MAAM,EAAO,GAAkC,CAAE,OAAQ,EAAK,CAAC,CACjE,OAAS,EAAO,CAEd,MADA,MAAM,EAAS,WAAW,CAAC,CAAC,UAAY,CAAC,CAAC,EACpC,CACR,CAIA,OAFA,GAA+B,EAAY,CAAC,CAAC,GAAG,UAAU,GAAK,EAAE,EAE1D,CACL,WAAY,SAAY,CACtB,GAAI,CACF,MAAM,EAAO,GAAkC,CAAE,OAAQ,EAAM,CAAC,CAClE,QAAU,CACR,MAAM,EAAS,WAAW,CAC5B,CACF,CACF,CACF","names":[],"ignoreList":[1],"sources":["../../src/app/generated/tauri/commands.ts","../../node_modules/.pnpm/immer@11.1.18/node_modules/immer/dist/immer.mjs","../../src/client/matrixFetch.ts","../../src/app/state/navToActivePath.ts","../../src/app/hooks/useRenderableMediaUrl.ts","../../src/app/utils/tauriMediaAuth.ts","../../src/sw-session.ts","../../src/client/oidcTokenRefresher.ts","../../src/client/oauthTokenRevocation.ts","../../src/client/secretStorageKeys.js","../../src/client/slidingSync.ts","../../src/client/presenceSync.ts","../../src/client/syncStorePersistence.ts","../../src/client/userProfileCache.ts","../../src/client/versionsCache.ts","../../src/client/initMatrix.ts","../../src/app/utils/notificationStyle.ts","../../src/app/features/settings/notifications/UnifiedPushTransportApiClient.ts","../../src/app/features/settings/notifications/UnifiedPushTransport.ts","../../src/app/features/settings/notifications/UnifiedPushMessageListener.ts","../../src/app/features/settings/notifications/PushPusherConfig.ts","../../src/app/features/settings/notifications/UnifiedPushNotifications.ts"],"sourcesContent":["/**\n * Auto-generated TypeScript bindings for Tauri commands\n * Generated by tauri-typegen v0.5.0\n * Generated at: 2026-08-22T11:19:48.664987491+00:00\n * Generator: none\n *\n * Do not edit manually - regenerate using: cargo tauri-typegen generate\n */\n\nimport { invoke, Channel } from '@tauri-apps/api/core';\nimport * as types from './types';\n\nexport async function abortLoopbackFetch(params: types.AbortLoopbackFetchParams): Promise<void> {\n  return invoke('abort_loopback_fetch', params);\n}\n\nexport async function abortNativeUpload(params: types.AbortNativeUploadParams): Promise<void> {\n  return invoke('abort_native_upload', params);\n}\n\nexport async function activateCallAudioSession(): Promise<void> {\n  return invoke('activate_call_audio_session');\n}\n\nexport async function buildDiagnosticsArchive(params: types.BuildDiagnosticsArchiveParams): Promise<number[]> {\n  return invoke('build_diagnostics_archive', params);\n}\n\nexport async function clearMediaSession(): Promise<void> {\n  return invoke('clear_media_session');\n}\n\nexport async function deactivateCallAudioSession(): Promise<void> {\n  return invoke('deactivate_call_audio_session');\n}\n\nexport async function ensureLoopbackMedia(): Promise<void> {\n  return invoke('ensure_loopback_media');\n}\n\nexport async function exportDiagnostics(params: types.ExportDiagnosticsParams): Promise<string | null> {\n  return invoke('export_diagnostics', params);\n}\n\nexport async function getDesktopRuntimeState(): Promise<types.DesktopRuntimeState> {\n  return invoke('get_desktop_runtime_state');\n}\n\nexport async function hapticFeedback(params: types.HapticFeedbackParams): Promise<void> {\n  return invoke('haptic_feedback', params);\n}\n\nexport async function hideSnapOverlay(): Promise<void> {\n  return invoke('hide_snap_overlay');\n}\n\nexport async function isWindowTrackingActive(): Promise<boolean> {\n  return invoke('is_window_tracking_active');\n}\n\nexport async function loopbackFetch(params: types.LoopbackFetchParams): Promise<types.LoopbackFetchResponse> {\n  return invoke('loopback_fetch', params);\n}\n\nexport async function nativeUpload(params: types.NativeUploadParams): Promise<types.NativeUploadResponse> {\n  return invoke('native_upload', params);\n}\n\nexport async function playNotificationSound(params: types.PlayNotificationSoundParams): Promise<void> {\n  return invoke('play_notification_sound', params);\n}\n\nexport async function prepareLoopbackMedia(params: types.PrepareLoopbackMediaParams): Promise<string> {\n  return invoke('prepare_loopback_media', params);\n}\n\nexport async function saveDownload(params: types.SaveDownloadParams): Promise<boolean> {\n  return invoke('save_download', params);\n}\n\nexport async function saveMediaDownload(params: types.SaveMediaDownloadParams): Promise<boolean> {\n  return invoke('save_media_download', params);\n}\n\nexport async function saveMediaToPhotos(params: types.SaveMediaToPhotosParams): Promise<void> {\n  return invoke('save_media_to_photos', params);\n}\n\nexport async function setImmersiveMode(params: types.SetImmersiveModeParams): Promise<void> {\n  return invoke('set_immersive_mode', params);\n}\n\nexport async function setMediaEncryption(params: types.SetMediaEncryptionParams): Promise<void> {\n  return invoke('set_media_encryption', params);\n}\n\nexport async function setMediaSession(params: types.SetMediaSessionParams): Promise<void> {\n  return invoke('set_media_session', params);\n}\n\nexport async function setNativeSentryEnabled(params: types.SetNativeSentryEnabledParams): Promise<void> {\n  return invoke('set_native_sentry_enabled', params);\n}\n\nexport async function setNavigationBarColor(params: types.SetNavigationBarColorParams): Promise<void> {\n  return invoke('set_navigation_bar_color', params);\n}\n\nexport async function setStatusBarColor(params: types.SetStatusBarColorParams): Promise<void> {\n  return invoke('set_status_bar_color', params);\n}\n\nexport async function setTrayBadge(params: types.SetTrayBadgeParams): Promise<void> {\n  return invoke('set_tray_badge', params);\n}\n\nexport async function setWindowBackgroundColor(params: types.SetWindowBackgroundColorParams): Promise<void> {\n  return invoke('set_window_background_color', params);\n}\n\nexport async function shareInboxClear(params: types.ShareInboxClearParams): Promise<void> {\n  return invoke('share_inbox_clear', params);\n}\n\nexport async function shareInboxDrain(): Promise<types.ShareBatch[]> {\n  return invoke('share_inbox_drain');\n}\n\nexport async function shareInboxRead(params: types.ShareInboxReadParams): Promise<unknown> {\n  return invoke('share_inbox_read', params);\n}\n\nexport async function showSnapOverlay(): Promise<void> {\n  return invoke('show_snap_overlay');\n}\n\nexport async function startCallForegroundService(): Promise<void> {\n  return invoke('start_call_foreground_service');\n}\n\nexport async function startWindowTrackingWithTarget(params: types.StartWindowTrackingWithTargetParams): Promise<void> {\n  return invoke('start_window_tracking_with_target', params);\n}\n\nexport async function stopCallForegroundService(): Promise<void> {\n  return invoke('stop_call_foreground_service');\n}\n\nexport async function stopWindowTracking(): Promise<void> {\n  return invoke('stop_window_tracking');\n}\n\nexport async function syncDesktopSettings(params: types.SyncDesktopSettingsParams): Promise<types.DesktopRuntimeState> {\n  return invoke('sync_desktop_settings', params);\n}\n\nexport async function uploadWriteChunk(params: types.UploadWriteChunkParams): Promise<void> {\n  return invoke('upload_write_chunk', params);\n}\n","// src/utils/env.ts\nvar NOTHING = Symbol.for(\"immer-nothing\");\nvar DRAFTABLE = Symbol.for(\"immer-draftable\");\nvar DRAFT_STATE = Symbol.for(\"immer-state\");\n\n// src/utils/errors.ts\nvar errors = process.env.NODE_ENV !== \"production\" ? [\n  // All error codes, starting by 0:\n  function(plugin) {\n    return `The plugin for '${plugin}' has not been loaded into Immer. To enable the plugin, import and call \\`enable${plugin}()\\` when initializing your application.`;\n  },\n  function(thing) {\n    return `produce can only be called on things that are draftable: plain objects, arrays, Map, Set or classes that are marked with '[immerable]: true'. Got '${thing}'`;\n  },\n  \"This object has been frozen and should not be mutated\",\n  function(data) {\n    return \"Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? \" + data;\n  },\n  \"An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft.\",\n  \"Immer forbids circular references\",\n  \"The first or second argument to `produce` must be a function\",\n  \"The third argument to `produce` must be a function or undefined\",\n  \"First argument to `createDraft` must be a plain object, an array, or an immerable object\",\n  \"First argument to `finishDraft` must be a draft returned by `createDraft`\",\n  function(thing) {\n    return `'current' expects a draft, got: ${thing}`;\n  },\n  \"Object.defineProperty() cannot be used on an Immer draft\",\n  \"Object.setPrototypeOf() cannot be used on an Immer draft\",\n  \"Immer only supports deleting array indices\",\n  \"Immer only supports setting array indices and the 'length' property\",\n  function(thing) {\n    return `'original' expects a draft, got: ${thing}`;\n  }\n  // Note: if more errors are added, the errorOffset in Patches.ts should be increased\n  // See Patches.ts for additional errors\n] : [];\nfunction die(error, ...args) {\n  if (process.env.NODE_ENV !== \"production\") {\n    const e = errors[error];\n    const msg = isFunction(e) ? e.apply(null, args) : e;\n    throw new Error(`[Immer] ${msg}`);\n  }\n  throw new Error(\n    `[Immer] minified error nr: ${error}. Full error at: https://bit.ly/3cXEKWf`\n  );\n}\n\n// src/utils/common.ts\nvar O = Object;\nvar getPrototypeOf = O.getPrototypeOf;\nvar CONSTRUCTOR = \"constructor\";\nvar PROTOTYPE = \"prototype\";\nvar CONFIGURABLE = \"configurable\";\nvar ENUMERABLE = \"enumerable\";\nvar WRITABLE = \"writable\";\nvar VALUE = \"value\";\nvar isDraft = (value) => !!value && !!value[DRAFT_STATE];\nfunction isDraftable(value) {\n  if (!value)\n    return false;\n  return isPlainObject(value) || isArray(value) || !!value[DRAFTABLE] || !!value[CONSTRUCTOR]?.[DRAFTABLE] || isMap(value) || isSet(value);\n}\nvar objectCtorString = O[PROTOTYPE][CONSTRUCTOR].toString();\nvar cachedCtorStrings = /* @__PURE__ */ new WeakMap();\nfunction isPlainObject(value) {\n  if (!value || !isObjectish(value))\n    return false;\n  const proto = getPrototypeOf(value);\n  if (proto === null || proto === O[PROTOTYPE])\n    return true;\n  const Ctor = O.hasOwnProperty.call(proto, CONSTRUCTOR) && proto[CONSTRUCTOR];\n  if (Ctor === Object)\n    return true;\n  if (!isFunction(Ctor))\n    return false;\n  let ctorString = cachedCtorStrings.get(Ctor);\n  if (ctorString === void 0) {\n    ctorString = Function.toString.call(Ctor);\n    cachedCtorStrings.set(Ctor, ctorString);\n  }\n  return ctorString === objectCtorString;\n}\nfunction original(value) {\n  if (!isDraft(value))\n    die(15, value);\n  return value[DRAFT_STATE].base_;\n}\nfunction each(obj, iter, strict = true) {\n  if (getArchtype(obj) === 0 /* Object */) {\n    const keys = strict ? Reflect.ownKeys(obj) : O.keys(obj);\n    keys.forEach((key) => {\n      iter(key, obj[key], obj);\n    });\n  } else {\n    obj.forEach((entry, index) => iter(index, entry, obj));\n  }\n}\nfunction getArchtype(thing) {\n  const state = thing[DRAFT_STATE];\n  return state ? state.type_ : isArray(thing) ? 1 /* Array */ : isMap(thing) ? 2 /* Map */ : isSet(thing) ? 3 /* Set */ : 0 /* Object */;\n}\nvar has = (thing, prop, type = getArchtype(thing)) => type === 2 /* Map */ ? thing.has(prop) : O[PROTOTYPE].hasOwnProperty.call(thing, prop);\nvar get = (thing, prop, type = getArchtype(thing)) => (\n  // @ts-ignore\n  type === 2 /* Map */ ? thing.get(prop) : thing[prop]\n);\nvar set = (thing, propOrOldValue, value, type = getArchtype(thing)) => {\n  if (type === 2 /* Map */)\n    thing.set(propOrOldValue, value);\n  else if (type === 3 /* Set */) {\n    thing.add(value);\n  } else\n    thing[propOrOldValue] = value;\n};\nfunction is(x, y) {\n  if (x === y) {\n    return x !== 0 || 1 / x === 1 / y;\n  } else {\n    return x !== x && y !== y;\n  }\n}\nvar isArray = Array.isArray;\nvar isMap = (target) => target instanceof Map;\nvar isSet = (target) => target instanceof Set;\nvar isObjectish = (target) => typeof target === \"object\";\nvar isFunction = (target) => typeof target === \"function\";\nvar isBoolean = (target) => typeof target === \"boolean\";\nfunction isArrayIndex(value) {\n  const n = +value;\n  return Number.isInteger(n) && String(n) === value;\n}\nvar getProxyDraft = (value) => {\n  if (!isObjectish(value))\n    return null;\n  return value?.[DRAFT_STATE];\n};\nvar latest = (state) => state.copy_ || state.base_;\nvar getValue = (value) => {\n  const proxyDraft = getProxyDraft(value);\n  return proxyDraft ? getFinalValue(proxyDraft) : value;\n};\nvar getFinalValue = (state) => state.modified_ ? state.copy_ : state.base_;\nfunction shallowCopy(base, strict) {\n  if (isMap(base)) {\n    return new Map(base);\n  }\n  if (isSet(base)) {\n    return new Set(base);\n  }\n  if (isArray(base))\n    return Array[PROTOTYPE].slice.call(base);\n  const isPlain = isPlainObject(base);\n  if (strict === true || strict === \"class_only\" && !isPlain) {\n    const descriptors = O.getOwnPropertyDescriptors(base);\n    delete descriptors[DRAFT_STATE];\n    let keys = Reflect.ownKeys(descriptors);\n    for (let i = 0; i < keys.length; i++) {\n      const key = keys[i];\n      const desc = descriptors[key];\n      if (desc[WRITABLE] === false) {\n        desc[WRITABLE] = true;\n        desc[CONFIGURABLE] = true;\n      }\n      if (desc.get || desc.set)\n        descriptors[key] = {\n          [CONFIGURABLE]: true,\n          [WRITABLE]: true,\n          // could live with !!desc.set as well here...\n          [ENUMERABLE]: desc[ENUMERABLE],\n          [VALUE]: base[key]\n        };\n    }\n    return O.create(getPrototypeOf(base), descriptors);\n  } else {\n    const proto = getPrototypeOf(base);\n    if (proto !== null && isPlain) {\n      return { ...base };\n    }\n    const obj = O.create(proto);\n    return O.assign(obj, base);\n  }\n}\nfunction freeze(obj, deep = false) {\n  if (isFrozen(obj) || isDraft(obj) || !isDraftable(obj))\n    return obj;\n  if (getArchtype(obj) > 1) {\n    O.defineProperties(obj, {\n      set: dontMutateMethodOverride,\n      add: dontMutateMethodOverride,\n      clear: dontMutateMethodOverride,\n      delete: dontMutateMethodOverride\n    });\n  }\n  O.freeze(obj);\n  if (deep)\n    each(\n      obj,\n      (_key, value) => {\n        freeze(value, true);\n      },\n      false\n    );\n  return obj;\n}\nfunction dontMutateFrozenCollections() {\n  die(2);\n}\nvar dontMutateMethodOverride = {\n  [VALUE]: dontMutateFrozenCollections\n};\nfunction isFrozen(obj) {\n  if (obj === null || !isObjectish(obj))\n    return true;\n  return O.isFrozen(obj);\n}\n\n// src/utils/plugins.ts\nvar PluginMapSet = \"MapSet\";\nvar PluginPatches = \"Patches\";\nvar PluginArrayMethods = \"ArrayMethods\";\nvar plugins = {};\nfunction getPlugin(pluginKey) {\n  const plugin = plugins[pluginKey];\n  if (!plugin) {\n    die(0, pluginKey);\n  }\n  return plugin;\n}\nvar isPluginLoaded = (pluginKey) => !!plugins[pluginKey];\nfunction loadPlugin(pluginKey, implementation) {\n  if (!plugins[pluginKey])\n    plugins[pluginKey] = implementation;\n}\n\n// src/core/scope.ts\nvar currentScope;\nvar getCurrentScope = () => currentScope;\nvar createScope = (parent_, immer_) => ({\n  drafts_: [],\n  parent_,\n  immer_,\n  // Whenever the modified draft contains a draft from another scope, we\n  // need to prevent auto-freezing so the unowned draft can be finalized.\n  canAutoFreeze_: true,\n  unfinalizedDrafts_: 0,\n  handledSet_: /* @__PURE__ */ new Set(),\n  processedForPatches_: /* @__PURE__ */ new Set(),\n  mapSetPlugin_: isPluginLoaded(PluginMapSet) ? getPlugin(PluginMapSet) : void 0,\n  arrayMethodsPlugin_: isPluginLoaded(PluginArrayMethods) ? getPlugin(PluginArrayMethods) : void 0\n});\nfunction usePatchesInScope(scope, patchListener) {\n  if (patchListener) {\n    scope.patchPlugin_ = getPlugin(PluginPatches);\n    scope.patches_ = [];\n    scope.inversePatches_ = [];\n    scope.patchListener_ = patchListener;\n  }\n}\nfunction revokeScope(scope) {\n  leaveScope(scope);\n  scope.drafts_.forEach(revokeDraft);\n  scope.drafts_ = null;\n}\nfunction leaveScope(scope) {\n  if (scope === currentScope) {\n    currentScope = scope.parent_;\n  }\n}\nvar enterScope = (immer2) => currentScope = createScope(currentScope, immer2);\nfunction revokeDraft(draft) {\n  const state = draft[DRAFT_STATE];\n  if (state.type_ === 0 /* Object */ || state.type_ === 1 /* Array */)\n    state.revoke_();\n  else\n    state.revoked_ = true;\n}\n\n// src/core/finalize.ts\nfunction processResult(result, scope) {\n  scope.unfinalizedDrafts_ = scope.drafts_.length;\n  const baseDraft = scope.drafts_[0];\n  const isReplaced = result !== void 0 && result !== baseDraft;\n  if (isReplaced) {\n    if (baseDraft[DRAFT_STATE].modified_) {\n      revokeScope(scope);\n      die(4);\n    }\n    if (isDraftable(result)) {\n      result = finalize(scope, result);\n    }\n    const { patchPlugin_ } = scope;\n    if (patchPlugin_) {\n      patchPlugin_.generateReplacementPatches_(\n        baseDraft[DRAFT_STATE].base_,\n        result,\n        scope\n      );\n    }\n  } else {\n    result = finalize(scope, baseDraft);\n  }\n  maybeFreeze(scope, result, true);\n  revokeScope(scope);\n  if (scope.patches_) {\n    scope.patchListener_(scope.patches_, scope.inversePatches_);\n  }\n  return result !== NOTHING ? result : void 0;\n}\nfunction finalize(rootScope, value) {\n  if (isFrozen(value))\n    return value;\n  const state = value[DRAFT_STATE];\n  if (!state) {\n    const finalValue = handleValue(value, rootScope.handledSet_, rootScope);\n    return finalValue;\n  }\n  if (!isSameScope(state, rootScope)) {\n    return value;\n  }\n  if (!state.modified_) {\n    return state.base_;\n  }\n  if (!state.finalized_) {\n    const { callbacks_ } = state;\n    if (callbacks_) {\n      while (callbacks_.length > 0) {\n        const callback = callbacks_.pop();\n        callback(rootScope);\n      }\n    }\n    generatePatchesAndFinalize(state, rootScope);\n  }\n  return state.copy_;\n}\nfunction maybeFreeze(scope, value, deep = false) {\n  if (!scope.parent_ && scope.immer_.autoFreeze_ && scope.canAutoFreeze_) {\n    freeze(value, deep);\n  }\n}\nfunction markStateFinalized(state) {\n  state.finalized_ = true;\n  state.scope_.unfinalizedDrafts_--;\n}\nvar isSameScope = (state, rootScope) => state.scope_ === rootScope;\nvar EMPTY_LOCATIONS_RESULT = [];\nfunction updateDraftInParent(parent, draftValue, finalizedValue, originalKey) {\n  const parentCopy = latest(parent);\n  const parentType = parent.type_;\n  if (originalKey !== void 0) {\n    const currentValue = get(parentCopy, originalKey, parentType);\n    if (currentValue === draftValue) {\n      set(parentCopy, originalKey, finalizedValue, parentType);\n      return;\n    }\n  }\n  if (!parent.draftLocations_) {\n    const draftLocations = parent.draftLocations_ = /* @__PURE__ */ new Map();\n    each(parentCopy, (key, value) => {\n      if (isDraft(value)) {\n        const keys = draftLocations.get(value) || [];\n        keys.push(key);\n        draftLocations.set(value, keys);\n      }\n    });\n  }\n  const locations = parent.draftLocations_.get(draftValue) ?? EMPTY_LOCATIONS_RESULT;\n  for (const location of locations) {\n    set(parentCopy, location, finalizedValue, parentType);\n  }\n}\nfunction registerChildFinalizationCallback(parent, child, key) {\n  parent.callbacks_.push(function childCleanup(rootScope) {\n    const state = child;\n    if (!state || !isSameScope(state, rootScope)) {\n      return;\n    }\n    rootScope.mapSetPlugin_?.fixSetContents(state);\n    const finalizedValue = getFinalValue(state);\n    updateDraftInParent(parent, state.draft_ ?? state, finalizedValue, key);\n    generatePatchesAndFinalize(state, rootScope);\n  });\n}\nfunction generatePatchesAndFinalize(state, rootScope) {\n  const shouldFinalize = state.modified_ && !state.finalized_ && (state.type_ === 3 /* Set */ || state.type_ === 1 /* Array */ && state.allIndicesReassigned_ || (state.assigned_?.size ?? 0) > 0);\n  if (shouldFinalize) {\n    const { patchPlugin_ } = rootScope;\n    if (patchPlugin_) {\n      const basePath = patchPlugin_.getPath(state);\n      if (basePath) {\n        patchPlugin_.generatePatches_(state, basePath, rootScope);\n      }\n    }\n    markStateFinalized(state);\n  }\n}\nfunction handleCrossReference(target, key, value) {\n  const { scope_ } = target;\n  if (isDraft(value)) {\n    const state = value[DRAFT_STATE];\n    if (isSameScope(state, scope_)) {\n      state.callbacks_.push(function crossReferenceCleanup() {\n        prepareCopy(target);\n        const finalizedValue = getFinalValue(state);\n        updateDraftInParent(target, value, finalizedValue, key);\n      });\n    }\n  } else if (isDraftable(value)) {\n    target.callbacks_.push(function nestedDraftCleanup() {\n      const targetCopy = latest(target);\n      if (target.type_ === 3 /* Set */) {\n        if (targetCopy.has(value)) {\n          handleValue(value, scope_.handledSet_, scope_);\n        }\n      } else {\n        if (get(targetCopy, key, target.type_) === value) {\n          if (scope_.drafts_.length > 1 && (target.assigned_.get(key) ?? false) === true && target.copy_) {\n            handleValue(\n              get(target.copy_, key, target.type_),\n              scope_.handledSet_,\n              scope_\n            );\n          }\n        }\n      }\n    });\n  }\n}\nfunction handleValue(target, handledSet, rootScope) {\n  if (!rootScope.immer_.autoFreeze_ && rootScope.unfinalizedDrafts_ < 1) {\n    return target;\n  }\n  if (isDraft(target) || handledSet.has(target) || !isDraftable(target) || isFrozen(target)) {\n    return target;\n  }\n  handledSet.add(target);\n  each(target, (key, value) => {\n    if (isDraft(value)) {\n      const state = value[DRAFT_STATE];\n      if (isSameScope(state, rootScope)) {\n        const updatedValue = getFinalValue(state);\n        set(target, key, updatedValue, target.type_);\n        markStateFinalized(state);\n      }\n    } else if (isDraftable(value)) {\n      handleValue(value, handledSet, rootScope);\n    }\n  });\n  return target;\n}\n\n// src/core/proxy.ts\nfunction createProxyProxy(base, parent) {\n  const baseIsArray = isArray(base);\n  const state = {\n    type_: baseIsArray ? 1 /* Array */ : 0 /* Object */,\n    // Track which produce call this is associated with.\n    scope_: parent ? parent.scope_ : getCurrentScope(),\n    // True for both shallow and deep changes.\n    modified_: false,\n    // Used during finalization.\n    finalized_: false,\n    // Track which properties have been assigned (true) or deleted (false).\n    // actually instantiated in `prepareCopy()`\n    assigned_: void 0,\n    // The parent draft state.\n    parent_: parent,\n    // The base state.\n    base_: base,\n    // The base proxy.\n    draft_: null,\n    // set below\n    // The base copy with any updated values.\n    copy_: null,\n    // Called by the `produce` function.\n    revoke_: null,\n    isManual_: false,\n    // `callbacks` actually gets assigned in `createProxy`\n    callbacks_: void 0\n  };\n  let target = state;\n  let traps = objectTraps;\n  if (baseIsArray) {\n    target = [state];\n    traps = arrayTraps;\n  }\n  const { revoke, proxy } = Proxy.revocable(target, traps);\n  state.draft_ = proxy;\n  state.revoke_ = revoke;\n  return [proxy, state];\n}\nvar objectTraps = {\n  get(state, prop) {\n    if (prop === DRAFT_STATE)\n      return state;\n    let arrayPlugin = state.scope_.arrayMethodsPlugin_;\n    const isArrayWithStringProp = state.type_ === 1 /* Array */ && typeof prop === \"string\";\n    if (isArrayWithStringProp) {\n      if (arrayPlugin?.isArrayOperationMethod(prop)) {\n        return arrayPlugin.createMethodInterceptor(state, prop);\n      }\n    }\n    const source = latest(state);\n    if (!has(source, prop, state.type_)) {\n      return readPropFromProto(state, source, prop);\n    }\n    const value = source[prop];\n    if (state.finalized_ || !isDraftable(value)) {\n      return value;\n    }\n    if (isArrayWithStringProp && state.operationMethod && arrayPlugin?.isMutatingArrayMethod(\n      state.operationMethod\n    ) && isArrayIndex(prop)) {\n      return value;\n    }\n    if (value === peek(state.base_, prop) || isRelocatedBaseRef(state, prop, value)) {\n      prepareCopy(state);\n      const childKey = state.type_ === 1 /* Array */ ? +prop : prop;\n      const childDraft = createProxy(state.scope_, value, state, childKey);\n      return state.copy_[childKey] = childDraft;\n    }\n    return value;\n  },\n  has(state, prop) {\n    return prop in latest(state);\n  },\n  ownKeys(state) {\n    return Reflect.ownKeys(latest(state));\n  },\n  set(state, prop, value) {\n    const desc = getDescriptorFromProto(latest(state), prop);\n    if (desc?.set) {\n      desc.set.call(state.draft_, value);\n      return true;\n    }\n    if (!state.modified_) {\n      const current2 = peek(latest(state), prop);\n      const currentState = current2?.[DRAFT_STATE];\n      if (currentState && currentState.base_ === value) {\n        state.copy_[prop] = value;\n        state.assigned_.set(prop, false);\n        return true;\n      }\n      if (is(value, current2) && (value !== void 0 || has(state.base_, prop, state.type_)))\n        return true;\n      prepareCopy(state);\n      markChanged(state);\n    }\n    if (state.copy_[prop] === value && // special case: handle new props with value 'undefined'\n    (value !== void 0 || has(state.copy_, prop, state.type_)) || // special case: NaN\n    Number.isNaN(value) && Number.isNaN(state.copy_[prop]))\n      return true;\n    state.copy_[prop] = value;\n    state.assigned_.set(prop, true);\n    handleCrossReference(state, prop, value);\n    return true;\n  },\n  deleteProperty(state, prop) {\n    prepareCopy(state);\n    if (peek(state.base_, prop) !== void 0 || prop in state.base_) {\n      state.assigned_.set(prop, false);\n      markChanged(state);\n    } else {\n      state.assigned_.delete(prop);\n    }\n    if (state.copy_) {\n      delete state.copy_[prop];\n    }\n    return true;\n  },\n  // Note: We never coerce `desc.value` into an Immer draft, because we can't make\n  // the same guarantee in ES5 mode.\n  getOwnPropertyDescriptor(state, prop) {\n    const owner = latest(state);\n    const desc = Reflect.getOwnPropertyDescriptor(owner, prop);\n    if (!desc)\n      return desc;\n    return {\n      [WRITABLE]: true,\n      [CONFIGURABLE]: state.type_ !== 1 /* Array */ || prop !== \"length\",\n      [ENUMERABLE]: desc[ENUMERABLE],\n      [VALUE]: owner[prop]\n    };\n  },\n  defineProperty() {\n    die(11);\n  },\n  getPrototypeOf(state) {\n    return getPrototypeOf(state.base_);\n  },\n  setPrototypeOf() {\n    die(12);\n  }\n};\nvar arrayTraps = {};\nfor (let key in objectTraps) {\n  let fn = objectTraps[key];\n  arrayTraps[key] = function() {\n    const args = arguments;\n    args[0] = args[0][0];\n    return fn.apply(this, args);\n  };\n}\narrayTraps.deleteProperty = function(state, prop) {\n  if (process.env.NODE_ENV !== \"production\" && isNaN(parseInt(prop)))\n    die(13);\n  return arrayTraps.set.call(this, state, prop, void 0);\n};\narrayTraps.set = function(state, prop, value) {\n  if (process.env.NODE_ENV !== \"production\" && prop !== \"length\" && isNaN(parseInt(prop)))\n    die(14);\n  return objectTraps.set.call(this, state[0], prop, value, state[0]);\n};\nfunction peek(draft, prop) {\n  const state = draft[DRAFT_STATE];\n  const source = state ? latest(state) : draft;\n  return source[prop];\n}\nfunction isRelocatedBaseRef(state, prop, value) {\n  if (state.type_ !== 1 /* Array */ || !state.allIndicesReassigned_ || state.assigned_?.get(prop) || !isDraftable(value) || value[DRAFT_STATE]) {\n    return false;\n  }\n  return state.baseRefs_.has(value);\n}\nfunction readPropFromProto(state, source, prop) {\n  const desc = getDescriptorFromProto(source, prop);\n  return desc ? VALUE in desc ? desc[VALUE] : (\n    // This is a very special case, if the prop is a getter defined by the\n    // prototype, we should invoke it with the draft as context!\n    desc.get?.call(state.draft_)\n  ) : void 0;\n}\nfunction getDescriptorFromProto(source, prop) {\n  if (!(prop in source))\n    return void 0;\n  let proto = getPrototypeOf(source);\n  while (proto) {\n    const desc = Object.getOwnPropertyDescriptor(proto, prop);\n    if (desc)\n      return desc;\n    proto = getPrototypeOf(proto);\n  }\n  return void 0;\n}\nfunction markChanged(state) {\n  if (!state.modified_) {\n    state.modified_ = true;\n    if (state.parent_) {\n      markChanged(state.parent_);\n    }\n  }\n}\nfunction prepareCopy(state) {\n  if (!state.copy_) {\n    state.assigned_ = /* @__PURE__ */ new Map();\n    state.copy_ = shallowCopy(\n      state.base_,\n      state.scope_.immer_.useStrictShallowCopy_\n    );\n  }\n}\n\n// src/core/immerClass.ts\nvar Immer2 = class {\n  constructor(config) {\n    this.autoFreeze_ = true;\n    this.useStrictShallowCopy_ = false;\n    this.useStrictIteration_ = false;\n    /**\n     * The `produce` function takes a value and a \"recipe function\" (whose\n     * return value often depends on the base state). The recipe function is\n     * free to mutate its first argument however it wants. All mutations are\n     * only ever applied to a __copy__ of the base state.\n     *\n     * Pass only a function to create a \"curried producer\" which relieves you\n     * from passing the recipe function every time.\n     *\n     * Only plain objects and arrays are made mutable. All other objects are\n     * considered uncopyable.\n     *\n     * Note: This function is __bound__ to its `Immer` instance.\n     *\n     * @param {any} base - the initial state\n     * @param {Function} recipe - function that receives a proxy of the base state as first argument and which can be freely modified\n     * @param {Function} patchListener - optional function that will be called with all the patches produced here\n     * @returns {any} a new state, or the initial state if nothing was modified\n     */\n    this.produce = (base, recipe, patchListener) => {\n      if (isFunction(base) && !isFunction(recipe)) {\n        const defaultBase = recipe;\n        recipe = base;\n        const self = this;\n        return function curriedProduce(base2 = defaultBase, ...args) {\n          return self.produce(base2, (draft) => recipe.call(this, draft, ...args));\n        };\n      }\n      if (!isFunction(recipe))\n        die(6);\n      if (patchListener !== void 0 && !isFunction(patchListener))\n        die(7);\n      let result;\n      if (isDraftable(base)) {\n        const scope = enterScope(this);\n        const proxy = createProxy(scope, base, void 0);\n        let hasError = true;\n        try {\n          result = recipe(proxy);\n          hasError = false;\n        } finally {\n          if (hasError)\n            revokeScope(scope);\n          else\n            leaveScope(scope);\n        }\n        usePatchesInScope(scope, patchListener);\n        return processResult(result, scope);\n      } else if (!base || !isObjectish(base)) {\n        result = recipe(base);\n        if (result === void 0)\n          result = base;\n        if (result === NOTHING)\n          result = void 0;\n        if (this.autoFreeze_)\n          freeze(result, true);\n        if (patchListener) {\n          const p = [];\n          const ip = [];\n          getPlugin(PluginPatches).generateReplacementPatches_(base, result, {\n            patches_: p,\n            inversePatches_: ip\n          });\n          patchListener(p, ip);\n        }\n        return result;\n      } else\n        die(1, base);\n    };\n    this.produceWithPatches = (base, recipe) => {\n      if (isFunction(base)) {\n        return (state, ...args) => this.produceWithPatches(state, (draft) => base(draft, ...args));\n      }\n      let patches, inversePatches;\n      const result = this.produce(base, recipe, (p, ip) => {\n        patches = p;\n        inversePatches = ip;\n      });\n      return [result, patches, inversePatches];\n    };\n    if (isBoolean(config?.autoFreeze))\n      this.setAutoFreeze(config.autoFreeze);\n    if (isBoolean(config?.useStrictShallowCopy))\n      this.setUseStrictShallowCopy(config.useStrictShallowCopy);\n    if (isBoolean(config?.useStrictIteration))\n      this.setUseStrictIteration(config.useStrictIteration);\n  }\n  createDraft(base) {\n    if (!isDraftable(base))\n      die(8);\n    if (isDraft(base))\n      base = current(base);\n    const scope = enterScope(this);\n    const proxy = createProxy(scope, base, void 0);\n    proxy[DRAFT_STATE].isManual_ = true;\n    leaveScope(scope);\n    return proxy;\n  }\n  finishDraft(draft, patchListener) {\n    const state = draft && draft[DRAFT_STATE];\n    if (!state || !state.isManual_)\n      die(9);\n    const { scope_: scope } = state;\n    usePatchesInScope(scope, patchListener);\n    return processResult(void 0, scope);\n  }\n  /**\n   * Pass true to automatically freeze all copies created by Immer.\n   *\n   * By default, auto-freezing is enabled.\n   */\n  setAutoFreeze(value) {\n    this.autoFreeze_ = value;\n  }\n  /**\n   * Pass true to enable strict shallow copy.\n   *\n   * By default, immer does not copy the object descriptors such as getter, setter and non-enumrable properties.\n   */\n  setUseStrictShallowCopy(value) {\n    this.useStrictShallowCopy_ = value;\n  }\n  /**\n   * Pass false to use faster iteration that skips non-enumerable properties\n   * but still handles symbols for compatibility.\n   *\n   * By default, strict iteration is enabled (includes all own properties).\n   */\n  setUseStrictIteration(value) {\n    this.useStrictIteration_ = value;\n  }\n  shouldUseStrictIteration() {\n    return this.useStrictIteration_;\n  }\n  applyPatches(base, patches) {\n    let i;\n    for (i = patches.length - 1; i >= 0; i--) {\n      const patch = patches[i];\n      if (patch.path.length === 0 && patch.op === \"replace\") {\n        base = patch.value;\n        break;\n      }\n    }\n    if (i > -1) {\n      patches = patches.slice(i + 1);\n    }\n    const applyPatchesImpl = getPlugin(PluginPatches).applyPatches_;\n    if (isDraft(base)) {\n      return applyPatchesImpl(base, patches);\n    }\n    return this.produce(\n      base,\n      (draft) => applyPatchesImpl(draft, patches)\n    );\n  }\n};\nfunction createProxy(rootScope, value, parent, key) {\n  const [draft, state] = isMap(value) ? getPlugin(PluginMapSet).proxyMap_(value, parent) : isSet(value) ? getPlugin(PluginMapSet).proxySet_(value, parent) : createProxyProxy(value, parent);\n  const scope = parent?.scope_ ?? getCurrentScope();\n  scope.drafts_.push(draft);\n  state.callbacks_ = parent?.callbacks_ ?? [];\n  state.key_ = key;\n  if (parent && key !== void 0) {\n    registerChildFinalizationCallback(parent, state, key);\n  } else {\n    state.callbacks_.push(function rootDraftCleanup(rootScope2) {\n      rootScope2.mapSetPlugin_?.fixSetContents(state);\n      const { patchPlugin_ } = rootScope2;\n      if (state.modified_ && patchPlugin_) {\n        patchPlugin_.generatePatches_(state, [], rootScope2);\n      }\n    });\n  }\n  return draft;\n}\n\n// src/core/current.ts\nfunction current(value) {\n  if (!isDraft(value))\n    die(10, value);\n  return currentImpl(value);\n}\nfunction currentImpl(value) {\n  if (!isDraftable(value) || isFrozen(value))\n    return value;\n  const state = value[DRAFT_STATE];\n  let copy;\n  let strict = true;\n  if (state) {\n    if (!state.modified_)\n      return state.base_;\n    state.finalized_ = true;\n    copy = shallowCopy(value, state.scope_.immer_.useStrictShallowCopy_);\n    strict = state.scope_.immer_.shouldUseStrictIteration();\n  } else {\n    copy = shallowCopy(value, true);\n  }\n  each(\n    copy,\n    (key, childValue) => {\n      set(copy, key, currentImpl(childValue));\n    },\n    strict\n  );\n  if (state) {\n    state.finalized_ = false;\n  }\n  return copy;\n}\n\n// src/plugins/patches.ts\nfunction enablePatches() {\n  const errorOffset = 16;\n  if (process.env.NODE_ENV !== \"production\") {\n    errors.push(\n      'Sets cannot have \"replace\" patches.',\n      function(op) {\n        return \"Unsupported patch operation: \" + op;\n      },\n      function(path) {\n        return \"Cannot apply patch, path doesn't resolve: \" + path;\n      },\n      \"Patching reserved attributes like __proto__, prototype and constructor is not allowed\"\n    );\n  }\n  function getPath(state, path = []) {\n    if (state.key_ !== void 0) {\n      const parentCopy = state.parent_.copy_ ?? state.parent_.base_;\n      const proxyDraft = getProxyDraft(get(parentCopy, state.key_));\n      const valueAtKey = get(parentCopy, state.key_);\n      if (valueAtKey === void 0) {\n        return null;\n      }\n      if (valueAtKey !== state.draft_ && valueAtKey !== state.base_ && valueAtKey !== state.copy_) {\n        return null;\n      }\n      if (proxyDraft != null && proxyDraft.base_ !== state.base_) {\n        return null;\n      }\n      const isSet2 = state.parent_.type_ === 3 /* Set */;\n      let key;\n      if (isSet2) {\n        const setParent = state.parent_;\n        key = Array.from(setParent.drafts_.keys()).indexOf(state.key_);\n      } else {\n        key = state.key_;\n      }\n      if (!(isSet2 && parentCopy.size > key || has(parentCopy, key))) {\n        return null;\n      }\n      path.push(key);\n    }\n    if (state.parent_) {\n      return getPath(state.parent_, path);\n    }\n    path.reverse();\n    try {\n      resolvePath(state.copy_, path);\n    } catch (e) {\n      return null;\n    }\n    return path;\n  }\n  function resolvePath(base, path) {\n    let current2 = base;\n    for (let i = 0; i < path.length - 1; i++) {\n      const key = path[i];\n      current2 = get(current2, key);\n      if (!isObjectish(current2) || current2 === null) {\n        throw new Error(`Cannot resolve path at '${path.join(\"/\")}'`);\n      }\n    }\n    return current2;\n  }\n  const REPLACE = \"replace\";\n  const ADD = \"add\";\n  const REMOVE = \"remove\";\n  function generatePatches_(state, basePath, scope) {\n    if (state.scope_.processedForPatches_.has(state)) {\n      return;\n    }\n    state.scope_.processedForPatches_.add(state);\n    const { patches_, inversePatches_ } = scope;\n    switch (state.type_) {\n      case 0 /* Object */:\n      case 2 /* Map */:\n        return generatePatchesFromAssigned(\n          state,\n          basePath,\n          patches_,\n          inversePatches_\n        );\n      case 1 /* Array */:\n        return generateArrayPatches(\n          state,\n          basePath,\n          patches_,\n          inversePatches_\n        );\n      case 3 /* Set */:\n        return generateSetPatches(\n          state,\n          basePath,\n          patches_,\n          inversePatches_\n        );\n    }\n  }\n  function generateArrayPatches(state, basePath, patches, inversePatches) {\n    let { base_, assigned_ } = state;\n    let copy_ = state.copy_;\n    if (copy_.length < base_.length) {\n      ;\n      [base_, copy_] = [copy_, base_];\n      [patches, inversePatches] = [inversePatches, patches];\n    }\n    const allReassigned = state.allIndicesReassigned_ === true;\n    for (let i = 0; i < base_.length; i++) {\n      const copiedItem = copy_[i];\n      const baseItem = base_[i];\n      const isAssigned = allReassigned || assigned_?.get(i.toString());\n      if (isAssigned && copiedItem !== baseItem) {\n        const childState = copiedItem?.[DRAFT_STATE];\n        if (childState && childState.modified_) {\n          continue;\n        }\n        const path = basePath.concat([i]);\n        patches.push({\n          op: REPLACE,\n          path,\n          // Need to maybe clone it, as it can in fact be the original value\n          // due to the base/copy inversion at the start of this function\n          value: clonePatchValueIfNeeded(copiedItem)\n        });\n        inversePatches.push({\n          op: REPLACE,\n          path,\n          value: clonePatchValueIfNeeded(baseItem)\n        });\n      }\n    }\n    for (let i = base_.length; i < copy_.length; i++) {\n      const path = basePath.concat([i]);\n      patches.push({\n        op: ADD,\n        path,\n        // Need to maybe clone it, as it can in fact be the original value\n        // due to the base/copy inversion at the start of this function\n        value: clonePatchValueIfNeeded(copy_[i])\n      });\n    }\n    for (let i = copy_.length - 1; base_.length <= i; --i) {\n      const path = basePath.concat([i]);\n      inversePatches.push({\n        op: REMOVE,\n        path\n      });\n    }\n  }\n  function generatePatchesFromAssigned(state, basePath, patches, inversePatches) {\n    const { base_, copy_, type_ } = state;\n    each(state.assigned_, (key, assignedValue) => {\n      const origValue = get(base_, key, type_);\n      const value = get(copy_, key, type_);\n      const op = !assignedValue ? REMOVE : has(base_, key) ? REPLACE : ADD;\n      if (origValue === value && op === REPLACE)\n        return;\n      const path = basePath.concat(key);\n      patches.push(\n        op === REMOVE ? { op, path } : { op, path, value: clonePatchValueIfNeeded(value) }\n      );\n      inversePatches.push(\n        op === ADD ? { op: REMOVE, path } : op === REMOVE ? { op: ADD, path, value: clonePatchValueIfNeeded(origValue) } : { op: REPLACE, path, value: clonePatchValueIfNeeded(origValue) }\n      );\n    });\n  }\n  function generateSetPatches(state, basePath, patches, inversePatches) {\n    let { base_, copy_ } = state;\n    let i = 0;\n    base_.forEach((value) => {\n      if (!copy_.has(value)) {\n        const path = basePath.concat([i]);\n        patches.push({\n          op: REMOVE,\n          path,\n          value\n        });\n        inversePatches.unshift({\n          op: ADD,\n          path,\n          value\n        });\n      }\n      i++;\n    });\n    i = 0;\n    copy_.forEach((value) => {\n      if (!base_.has(value)) {\n        const path = basePath.concat([i]);\n        patches.push({\n          op: ADD,\n          path,\n          value\n        });\n        inversePatches.unshift({\n          op: REMOVE,\n          path,\n          value\n        });\n      }\n      i++;\n    });\n  }\n  function generateReplacementPatches_(baseValue, replacement, scope) {\n    const { patches_, inversePatches_ } = scope;\n    patches_.push({\n      op: REPLACE,\n      path: [],\n      value: replacement === NOTHING ? void 0 : replacement\n    });\n    inversePatches_.push({\n      op: REPLACE,\n      path: [],\n      value: baseValue\n    });\n  }\n  function applyPatches_(draft, patches) {\n    patches.forEach((patch) => {\n      const { path, op } = patch;\n      let base = draft;\n      for (let i = 0; i < path.length - 1; i++) {\n        const parentType = getArchtype(base);\n        let p = path[i];\n        if (typeof p !== \"string\" && typeof p !== \"number\") {\n          p = \"\" + p;\n        }\n        if ((parentType === 0 /* Object */ || parentType === 1 /* Array */) && (p === \"__proto__\" || p === CONSTRUCTOR))\n          die(errorOffset + 3);\n        if (isFunction(base) && p === PROTOTYPE)\n          die(errorOffset + 3);\n        base = get(base, p);\n        if (base === null || !isObjectish(base))\n          die(errorOffset + 2, path.join(\"/\"));\n      }\n      const type = getArchtype(base);\n      const value = deepClonePatchValue(patch.value);\n      const key = path[path.length - 1];\n      switch (op) {\n        case REPLACE:\n          switch (type) {\n            case 2 /* Map */:\n              return base.set(key, value);\n            case 3 /* Set */:\n              die(errorOffset);\n            default:\n              return base[key] = value;\n          }\n        case ADD:\n          switch (type) {\n            case 1 /* Array */:\n              return key === \"-\" ? base.push(value) : base.splice(key, 0, value);\n            case 2 /* Map */:\n              return base.set(key, value);\n            case 3 /* Set */:\n              return base.add(value);\n            default:\n              return base[key] = value;\n          }\n        case REMOVE:\n          switch (type) {\n            case 1 /* Array */:\n              return base.splice(key, 1);\n            case 2 /* Map */:\n              return base.delete(key);\n            case 3 /* Set */:\n              return base.delete(patch.value);\n            default:\n              return delete base[key];\n          }\n        default:\n          die(errorOffset + 1, op);\n      }\n    });\n    return draft;\n  }\n  function deepClonePatchValue(obj) {\n    if (!isDraftable(obj))\n      return obj;\n    if (isArray(obj))\n      return obj.map(deepClonePatchValue);\n    if (isMap(obj))\n      return new Map(\n        Array.from(obj.entries()).map(([k, v]) => [k, deepClonePatchValue(v)])\n      );\n    if (isSet(obj))\n      return new Set(Array.from(obj).map(deepClonePatchValue));\n    const cloned = Object.create(getPrototypeOf(obj));\n    for (const key in obj)\n      cloned[key] = deepClonePatchValue(obj[key]);\n    if (has(obj, DRAFTABLE))\n      cloned[DRAFTABLE] = obj[DRAFTABLE];\n    return cloned;\n  }\n  function clonePatchValueIfNeeded(obj) {\n    if (isDraft(obj)) {\n      return deepClonePatchValue(obj);\n    } else\n      return obj;\n  }\n  loadPlugin(PluginPatches, {\n    applyPatches_,\n    generatePatches_,\n    generateReplacementPatches_,\n    getPath\n  });\n}\n\n// src/plugins/mapset.ts\nvar _globalIterator = globalThis.Iterator;\nvar hasIteratorFrom = typeof _globalIterator?.from === \"function\";\nfunction enableMapSet() {\n  class DraftMap extends Map {\n    constructor(target, parent) {\n      super();\n      this[DRAFT_STATE] = {\n        type_: 2 /* Map */,\n        parent_: parent,\n        scope_: parent ? parent.scope_ : getCurrentScope(),\n        modified_: false,\n        finalized_: false,\n        copy_: void 0,\n        assigned_: void 0,\n        base_: target,\n        draft_: this,\n        isManual_: false,\n        revoked_: false,\n        callbacks_: []\n      };\n    }\n    get size() {\n      return latest(this[DRAFT_STATE]).size;\n    }\n    has(key) {\n      return latest(this[DRAFT_STATE]).has(key);\n    }\n    set(key, value) {\n      const state = this[DRAFT_STATE];\n      assertUnrevoked(state);\n      if (!latest(state).has(key) || latest(state).get(key) !== value) {\n        prepareMapCopy(state);\n        markChanged(state);\n        state.assigned_.set(key, true);\n        state.copy_.set(key, value);\n        state.assigned_.set(key, true);\n        handleCrossReference(state, key, value);\n      }\n      return this;\n    }\n    delete(key) {\n      if (!this.has(key)) {\n        return false;\n      }\n      const state = this[DRAFT_STATE];\n      assertUnrevoked(state);\n      prepareMapCopy(state);\n      markChanged(state);\n      if (state.base_.has(key)) {\n        state.assigned_.set(key, false);\n      } else {\n        state.assigned_.delete(key);\n      }\n      state.copy_.delete(key);\n      return true;\n    }\n    clear() {\n      const state = this[DRAFT_STATE];\n      assertUnrevoked(state);\n      if (latest(state).size) {\n        prepareMapCopy(state);\n        markChanged(state);\n        state.assigned_ = /* @__PURE__ */ new Map();\n        each(state.base_, (key) => {\n          state.assigned_.set(key, false);\n        });\n        state.copy_.clear();\n      }\n    }\n    forEach(cb, thisArg) {\n      const state = this[DRAFT_STATE];\n      latest(state).forEach((_value, key, _map) => {\n        cb.call(thisArg, this.get(key), key, this);\n      });\n    }\n    get(key) {\n      const state = this[DRAFT_STATE];\n      assertUnrevoked(state);\n      const value = latest(state).get(key);\n      if (state.finalized_ || !isDraftable(value)) {\n        return value;\n      }\n      if (value !== state.base_.get(key)) {\n        return value;\n      }\n      const draft = createProxy(state.scope_, value, state, key);\n      prepareMapCopy(state);\n      state.copy_.set(key, draft);\n      return draft;\n    }\n    keys() {\n      return latest(this[DRAFT_STATE]).keys();\n    }\n    values() {\n      const iterator = this.keys();\n      return iteratorFrom({\n        next: () => {\n          const r = iterator.next();\n          if (r.done)\n            return r;\n          const value = this.get(r.value);\n          return {\n            done: false,\n            value\n          };\n        }\n      });\n    }\n    entries() {\n      const iterator = this.keys();\n      return iteratorFrom({\n        next: () => {\n          const r = iterator.next();\n          if (r.done)\n            return r;\n          const value = this.get(r.value);\n          return {\n            done: false,\n            value: [r.value, value]\n          };\n        }\n      });\n    }\n    [(DRAFT_STATE, Symbol.iterator)]() {\n      return this.entries();\n    }\n  }\n  function iteratorFrom(iterable) {\n    if (hasIteratorFrom) {\n      return _globalIterator.from(iterable);\n    }\n    const iterator = {\n      ...iterable,\n      [Symbol.iterator]: () => iterator\n    };\n    return iterator;\n  }\n  function proxyMap_(target, parent) {\n    const map = new DraftMap(target, parent);\n    return [map, map[DRAFT_STATE]];\n  }\n  function prepareMapCopy(state) {\n    if (!state.copy_) {\n      state.assigned_ = /* @__PURE__ */ new Map();\n      state.copy_ = new Map(state.base_);\n    }\n  }\n  class DraftSet extends Set {\n    constructor(target, parent) {\n      super();\n      this[DRAFT_STATE] = {\n        type_: 3 /* Set */,\n        parent_: parent,\n        scope_: parent ? parent.scope_ : getCurrentScope(),\n        modified_: false,\n        finalized_: false,\n        copy_: void 0,\n        base_: target,\n        draft_: this,\n        drafts_: /* @__PURE__ */ new Map(),\n        revoked_: false,\n        isManual_: false,\n        assigned_: void 0,\n        callbacks_: []\n      };\n    }\n    get size() {\n      return latest(this[DRAFT_STATE]).size;\n    }\n    has(value) {\n      const state = this[DRAFT_STATE];\n      assertUnrevoked(state);\n      if (!state.copy_) {\n        return state.base_.has(value);\n      }\n      if (state.copy_.has(value))\n        return true;\n      if (state.drafts_.has(value) && state.copy_.has(state.drafts_.get(value)))\n        return true;\n      return false;\n    }\n    add(value) {\n      const state = this[DRAFT_STATE];\n      assertUnrevoked(state);\n      if (!this.has(value)) {\n        prepareSetCopy(state);\n        markChanged(state);\n        state.copy_.add(value);\n        handleCrossReference(state, value, value);\n      }\n      return this;\n    }\n    delete(value) {\n      if (!this.has(value)) {\n        return false;\n      }\n      const state = this[DRAFT_STATE];\n      assertUnrevoked(state);\n      prepareSetCopy(state);\n      markChanged(state);\n      return state.copy_.delete(value) || (state.drafts_.has(value) ? state.copy_.delete(state.drafts_.get(value)) : (\n        /* istanbul ignore next */\n        false\n      ));\n    }\n    clear() {\n      const state = this[DRAFT_STATE];\n      assertUnrevoked(state);\n      if (latest(state).size) {\n        prepareSetCopy(state);\n        markChanged(state);\n        state.copy_.clear();\n      }\n    }\n    values() {\n      const state = this[DRAFT_STATE];\n      assertUnrevoked(state);\n      prepareSetCopy(state);\n      return state.copy_.values();\n    }\n    entries() {\n      const state = this[DRAFT_STATE];\n      assertUnrevoked(state);\n      prepareSetCopy(state);\n      return state.copy_.entries();\n    }\n    keys() {\n      return this.values();\n    }\n    [(DRAFT_STATE, Symbol.iterator)]() {\n      return this.values();\n    }\n    forEach(cb, thisArg) {\n      const iterator = this.values();\n      let result = iterator.next();\n      while (!result.done) {\n        cb.call(thisArg, result.value, result.value, this);\n        result = iterator.next();\n      }\n    }\n  }\n  function proxySet_(target, parent) {\n    const set2 = new DraftSet(target, parent);\n    return [set2, set2[DRAFT_STATE]];\n  }\n  function prepareSetCopy(state) {\n    if (!state.copy_) {\n      state.copy_ = /* @__PURE__ */ new Set();\n      state.base_.forEach((value) => {\n        if (isDraftable(value)) {\n          const draft = createProxy(state.scope_, value, state, value);\n          state.drafts_.set(value, draft);\n          state.copy_.add(draft);\n        } else {\n          state.copy_.add(value);\n        }\n      });\n    }\n  }\n  function assertUnrevoked(state) {\n    if (state.revoked_)\n      die(3, JSON.stringify(latest(state)));\n  }\n  function fixSetContents(target) {\n    if (target.type_ === 3 /* Set */ && target.copy_) {\n      const copy = new Set(target.copy_);\n      target.copy_.clear();\n      copy.forEach((value) => {\n        target.copy_.add(getValue(value));\n      });\n    }\n  }\n  loadPlugin(PluginMapSet, { proxyMap_, proxySet_, fixSetContents });\n}\n\n// src/plugins/arrayMethods.ts\nfunction enableArrayMethods() {\n  const SHIFTING_METHODS = /* @__PURE__ */ new Set([\"shift\", \"unshift\"]);\n  const QUEUE_METHODS = /* @__PURE__ */ new Set([\"push\", \"pop\"]);\n  const RESULT_RETURNING_METHODS = /* @__PURE__ */ new Set([\n    ...QUEUE_METHODS,\n    ...SHIFTING_METHODS\n  ]);\n  const REORDERING_METHODS = /* @__PURE__ */ new Set([\"reverse\", \"sort\"]);\n  const MUTATING_METHODS = /* @__PURE__ */ new Set([\n    ...RESULT_RETURNING_METHODS,\n    ...REORDERING_METHODS,\n    \"splice\"\n  ]);\n  const FIND_METHODS = /* @__PURE__ */ new Set([\"find\", \"findLast\"]);\n  const NON_MUTATING_METHODS = /* @__PURE__ */ new Set([\n    \"filter\",\n    \"slice\",\n    \"concat\",\n    \"flat\",\n    ...FIND_METHODS,\n    \"findIndex\",\n    \"findLastIndex\",\n    \"some\",\n    \"every\",\n    \"indexOf\",\n    \"lastIndexOf\",\n    \"includes\",\n    \"join\",\n    \"toString\",\n    \"toLocaleString\"\n  ]);\n  function isMutatingArrayMethod(method) {\n    return MUTATING_METHODS.has(method);\n  }\n  function isNonMutatingArrayMethod(method) {\n    return NON_MUTATING_METHODS.has(method);\n  }\n  function isArrayOperationMethod(method) {\n    return isMutatingArrayMethod(method) || isNonMutatingArrayMethod(method);\n  }\n  function enterOperation(state, method) {\n    state.operationMethod = method;\n  }\n  function exitOperation(state) {\n    state.operationMethod = void 0;\n  }\n  function executeArrayMethod(state, operation, markLength = true) {\n    prepareCopy(state);\n    const result = operation();\n    markArrayChanged(state, markLength);\n    return result;\n  }\n  function markArrayChanged(state, markLength = true) {\n    markChanged(state);\n    if (markLength)\n      state.assigned_.set(\"length\", true);\n  }\n  function markAllIndicesReassigned(state) {\n    state.allIndicesReassigned_ = true;\n    state.baseRefs_ = new Set(state.base_);\n  }\n  function normalizeSliceIndex(index, length) {\n    if (index < 0) {\n      return Math.max(length + index, 0);\n    }\n    return Math.min(index, length);\n  }\n  function handleInsertedValues(state, startIndex, values) {\n    for (let i = 0; i < values.length; i++) {\n      const index = \"\" + (startIndex + i);\n      state.assigned_.set(index, true);\n      handleCrossReference(state, index, values[i]);\n    }\n  }\n  function handleSimpleOperation(state, method, args) {\n    const isInsert = method === \"push\" || method === \"unshift\";\n    if (isInsert ? args.length === 0 : latest(state).length === 0) {\n      return isInsert ? latest(state).length : void 0;\n    }\n    prepareCopy(state);\n    const lengthBefore = state.copy_.length;\n    const result = state.copy_[method](...args);\n    markArrayChanged(state);\n    if (SHIFTING_METHODS.has(method)) {\n      markAllIndicesReassigned(state);\n    }\n    if (method === \"push\") {\n      handleInsertedValues(state, lengthBefore, args);\n    } else if (method === \"unshift\") {\n      handleInsertedValues(state, 0, args);\n    }\n    return RESULT_RETURNING_METHODS.has(method) ? result : state.draft_;\n  }\n  function handleReorderingOperation(state, method, args) {\n    if (latest(state).length <= 1)\n      return state.draft_;\n    return executeArrayMethod(\n      state,\n      () => {\n        ;\n        state.copy_[method](...args);\n        markAllIndicesReassigned(state);\n        return state.draft_;\n      },\n      false\n    );\n  }\n  function createMethodInterceptor(state, originalMethod) {\n    return function interceptedMethod(...args) {\n      const method = originalMethod;\n      enterOperation(state, method);\n      try {\n        if (isMutatingArrayMethod(method)) {\n          if (RESULT_RETURNING_METHODS.has(method)) {\n            return handleSimpleOperation(state, method, args);\n          }\n          if (REORDERING_METHODS.has(method)) {\n            return handleReorderingOperation(state, method, args);\n          }\n          if (method === \"splice\") {\n            const insertCount = args.length > 2 ? args.length - 2 : 0;\n            if (insertCount === 0) {\n              const length = latest(state).length;\n              if (args.length === 0 || normalizeSliceIndex(args[0] ?? 0, length) === length || args.length > 1 && !(args[1] >= 1)) {\n                return [];\n              }\n            }\n            prepareCopy(state);\n            const res = state.copy_.splice(\n              ...args\n            );\n            if (res.length === 0 && insertCount === 0) {\n              return res;\n            }\n            markArrayChanged(state);\n            markAllIndicesReassigned(state);\n            if (insertCount > 0) {\n              const startIndex = normalizeSliceIndex(\n                args[0] ?? 0,\n                state.copy_.length\n              );\n              handleInsertedValues(state, startIndex, args.slice(2));\n            }\n            return res;\n          }\n        } else {\n          return handleNonMutatingOperation(state, method, args);\n        }\n      } finally {\n        exitOperation(state);\n      }\n    };\n  }\n  function handleNonMutatingOperation(state, method, args) {\n    const source = latest(state);\n    if (method === \"filter\") {\n      const predicate = args[0];\n      const result = [];\n      for (let i = 0; i < source.length; i++) {\n        if (predicate(source[i], i, source)) {\n          result.push(state.draft_[i]);\n        }\n      }\n      return result;\n    }\n    if (FIND_METHODS.has(method)) {\n      const predicate = args[0];\n      const isForward = method === \"find\";\n      const step = isForward ? 1 : -1;\n      const start = isForward ? 0 : source.length - 1;\n      for (let i = start; i >= 0 && i < source.length; i += step) {\n        if (predicate(source[i], i, source)) {\n          return state.draft_[i];\n        }\n      }\n      return void 0;\n    }\n    if (method === \"slice\") {\n      const rawStart = args[0] ?? 0;\n      const rawEnd = args[1] ?? source.length;\n      const start = normalizeSliceIndex(rawStart, source.length);\n      const end = normalizeSliceIndex(rawEnd, source.length);\n      const result = [];\n      for (let i = start; i < end; i++) {\n        result.push(state.draft_[i]);\n      }\n      return result;\n    }\n    return source[method](...args);\n  }\n  loadPlugin(PluginArrayMethods, {\n    createMethodInterceptor,\n    isArrayOperationMethod,\n    isMutatingArrayMethod\n  });\n}\n\n// src/immer.ts\nvar immer = new Immer2();\nvar produce = immer.produce;\nvar produceWithPatches = /* @__PURE__ */ immer.produceWithPatches.bind(immer);\nvar setAutoFreeze = /* @__PURE__ */ immer.setAutoFreeze.bind(immer);\nvar setUseStrictShallowCopy = /* @__PURE__ */ immer.setUseStrictShallowCopy.bind(immer);\nvar setUseStrictIteration = /* @__PURE__ */ immer.setUseStrictIteration.bind(immer);\nvar applyPatches = /* @__PURE__ */ immer.applyPatches.bind(immer);\nvar createDraft = /* @__PURE__ */ immer.createDraft.bind(immer);\nvar finishDraft = /* @__PURE__ */ immer.finishDraft.bind(immer);\nvar castDraft = (value) => value;\nvar castImmutable = (value) => value;\nexport {\n  Immer2 as Immer,\n  applyPatches,\n  castDraft,\n  castImmutable,\n  createDraft,\n  current,\n  enableArrayMethods,\n  enableMapSet,\n  enablePatches,\n  finishDraft,\n  freeze,\n  DRAFTABLE as immerable,\n  isDraft,\n  isDraftable,\n  NOTHING as nothing,\n  original,\n  produce,\n  produceWithPatches,\n  setAutoFreeze,\n  setUseStrictIteration,\n  setUseStrictShallowCopy\n};\n//# sourceMappingURL=immer.mjs.map","import { fetch } from '$utils/fetch';\n\n/** Timeline event sends use `PUT /_matrix/client/{ver}/rooms/{roomId}/send/{type}/{txnId}`. */\nconst MATRIX_EVENT_SEND_PATH = /\\/_matrix\\/client\\/[^/]+\\/rooms\\/[^/]+\\/send\\//;\n\nconst EVENT_SEND_TIMEOUT_MS = 30_000;\n\nconst requestUrl = (input: RequestInfo | URL): string =>\n  typeof input === 'string' ? input : input instanceof URL ? input.href : input.url;\n\nconst requestMethod = (input: RequestInfo | URL, init?: RequestInit): string => {\n  if (init?.method) return init.method.toUpperCase();\n  if (input instanceof Request) return input.method.toUpperCase();\n  return 'GET';\n};\n\nconst isMatrixEventSend = (input: RequestInfo | URL, init?: RequestInit): boolean => {\n  const method = requestMethod(input, init);\n  if (method !== 'PUT') return false;\n  return MATRIX_EVENT_SEND_PATH.test(new URL(requestUrl(input)).pathname);\n};\n\nconst mergeAbortSignals = (signals: AbortSignal[]): AbortSignal => {\n  const controller = new AbortController();\n  for (const signal of signals) {\n    if (signal.aborted) {\n      controller.abort(signal.reason);\n      return controller.signal;\n    }\n    signal.addEventListener('abort', () => controller.abort(signal.reason), { once: true });\n  }\n  return controller.signal;\n};\n\n/**\n * Wraps the app fetch so stalled timeline sends abort after 30s. That makes the\n * SDK mark the local echo `NOT_SENT`, which unlocks retry without a global client timeout.\n */\nexport const createMatrixFetch = (baseFetch: typeof fetch = fetch): typeof fetch => {\n  const matrixFetch: typeof fetch = (input, init) => {\n    if (!isMatrixEventSend(input, init)) {\n      return baseFetch(input, init);\n    }\n\n    const timeout = AbortSignal.timeout(EVENT_SEND_TIMEOUT_MS);\n    const existingSignal = init?.signal ?? (input instanceof Request ? input.signal : undefined);\n    const signal = existingSignal ? mergeAbortSignals([existingSignal, timeout]) : timeout;\n\n    return baseFetch(input, { ...init, signal });\n  };\n\n  return matrixFetch;\n};\n\nexport const matrixFetch = createMatrixFetch();\n","import type { WritableAtom } from 'jotai';\nimport { atom } from 'jotai';\nimport { produce } from 'immer';\nimport type { Path } from 'react-router';\nimport {\n  atomWithLocalStorage,\n  getLocalStorageItem,\n  setLocalStorageItem,\n} from './utils/atomWithLocalStorage';\n\nconst NAV_TO_ACTIVE_PATH = 'navToActivePath';\n\nconst getStoreKey = (userId: string): string => `${NAV_TO_ACTIVE_PATH}${userId}`;\n\ntype NavToActivePath = Map<string, Path>;\n\ntype NavToActivePathAction =\n  | {\n      type: 'PUT';\n      navId: string;\n      path: Path;\n    }\n  | {\n      type: 'DELETE';\n      navId: string;\n    };\n\nexport type NavToActivePathAtom = WritableAtom<NavToActivePath, [NavToActivePathAction], undefined>;\n\nexport const makeNavToActivePathAtom = (userId: string): NavToActivePathAtom => {\n  const storeKey = getStoreKey(userId);\n\n  const baseNavToActivePathAtom = atomWithLocalStorage<NavToActivePath>(\n    storeKey,\n    (key) => {\n      const obj: Record<string, Path> = getLocalStorageItem(key, {});\n      return new Map(Object.entries(obj));\n    },\n    (key, value) => {\n      const obj: Record<string, Path> = Object.fromEntries(value);\n      setLocalStorageItem(key, obj);\n    }\n  );\n\n  const navToActivePathAtom = atom<NavToActivePath, [NavToActivePathAction], undefined>(\n    (get) => get(baseNavToActivePathAtom),\n    (get, set, action) => {\n      if (action.type === 'DELETE') {\n        set(\n          baseNavToActivePathAtom,\n          produce(get(baseNavToActivePathAtom), (draft) => {\n            draft.delete(action.navId);\n          })\n        );\n        return;\n      }\n      if (action.type === 'PUT') {\n        set(\n          baseNavToActivePathAtom,\n          produce(get(baseNavToActivePathAtom), (draft) => {\n            draft.set(action.navId, action.path);\n          })\n        );\n      }\n    }\n  );\n\n  return navToActivePathAtom;\n};\n\nexport const clearNavToActivePathStore = (userId: string) => {\n  localStorage.removeItem(getStoreKey(userId));\n};\n","import { useCallback, useEffect, useState, useSyncExternalStore } from 'react';\nimport { useAtomValue } from 'jotai';\nimport { invoke, isTauri } from '@tauri-apps/api/core';\nimport { activeSessionIdAtom } from '$state/sessions';\nimport {\n  fetchMediaBlob,\n  getCurrentMediaSessionScope,\n  getStableMediaCacheKeyFragment,\n} from '$utils/mediaTransport';\nimport {\n  getCachedSWMediaAuthSupport,\n  probeSWMediaAuthSupport,\n  subscribeSWMediaAuthSupport,\n} from '$utils/swMediaAuth';\nimport { rewriteAuthenticatedMediaUrl } from '$utils/matrix';\nimport { addMediaRetryRevision } from '$utils/mediaUrl';\nimport { webviewStripsCustomProtocolCache } from '$utils/platform';\n\ntype ObjectUrlEntry = {\n  refs: number;\n  settled: boolean;\n  objectUrl?: string;\n  promise: Promise<string>;\n};\n\ntype ResolvedMediaUrlState = {\n  cacheKey?: string;\n  url?: string;\n};\n\nconst objectUrlCache = new Map<string, ObjectUrlEntry>();\nconst inflightRequests = new Map<string, Promise<string>>();\nconst unreferencedCacheKeys: string[] = [];\nconst MAX_UNREFERENCED_CACHE_SIZE = 200;\n\nfunction pruneUnreferencedCache(): void {\n  while (unreferencedCacheKeys.length > MAX_UNREFERENCED_CACHE_SIZE) {\n    const oldestKey = unreferencedCacheKeys.shift();\n    if (!oldestKey) break;\n    const entry = objectUrlCache.get(oldestKey);\n    if (entry && entry.refs === 0 && entry.settled) {\n      if (entry.objectUrl) {\n        URL.revokeObjectURL(entry.objectUrl);\n      }\n      objectUrlCache.delete(oldestKey);\n    }\n  }\n}\n\nfunction getObjectUrlCacheKey(sessionScope: string, url: string, retryRevision = 0): string {\n  const retryFragment = retryRevision > 0 ? `\\x00retry=${retryRevision}` : '';\n  return `${sessionScope}\\x00${getStableMediaCacheKeyFragment(url)}${retryFragment}`;\n}\n\nfunction normalizeRenderableMediaUrl(url: string | undefined): string | undefined {\n  if (!url) return undefined;\n  if (url.startsWith('blob:')) return url;\n\n  try {\n    const parsed = new URL(url);\n    if (parsed.protocol === 'http:' || parsed.protocol === 'https:') {\n      return parsed.toString();\n    }\n  } catch {\n    return undefined;\n  }\n\n  return undefined;\n}\n\nfunction createObjectUrlEntry(cacheKey: string, url: string): ObjectUrlEntry {\n  const entry = {\n    refs: 0,\n    settled: false,\n    objectUrl: undefined,\n    promise: Promise.resolve(''),\n  } as ObjectUrlEntry;\n\n  entry.promise = fetchMediaBlob(url)\n    .then((blob) => {\n      const objectUrl = URL.createObjectURL(blob);\n      entry.objectUrl = objectUrl;\n      return objectUrl;\n    })\n    .finally(() => {\n      entry.settled = true;\n      inflightRequests.delete(cacheKey);\n      if (entry.refs === 0 && entry.objectUrl) {\n        if (!unreferencedCacheKeys.includes(cacheKey)) {\n          unreferencedCacheKeys.push(cacheKey);\n        }\n        pruneUnreferencedCache();\n      }\n    });\n\n  objectUrlCache.set(cacheKey, entry);\n  inflightRequests.set(cacheKey, entry.promise);\n\n  return entry;\n}\n\nfunction retainObjectUrlEntry(cacheKey: string, url: string): ObjectUrlEntry {\n  const entry = objectUrlCache.get(cacheKey) ?? createObjectUrlEntry(cacheKey, url);\n  entry.refs += 1;\n  const unrefIndex = unreferencedCacheKeys.indexOf(cacheKey);\n  if (unrefIndex !== -1) {\n    unreferencedCacheKeys.splice(unrefIndex, 1);\n  }\n  return entry;\n}\n\nfunction releaseObjectUrlEntry(cacheKey: string): void {\n  const entry = objectUrlCache.get(cacheKey);\n  if (!entry) return;\n\n  entry.refs -= 1;\n  if (entry.refs > 0 || !entry.settled) return;\n\n  if (!unreferencedCacheKeys.includes(cacheKey)) {\n    unreferencedCacheKeys.push(cacheKey);\n  }\n  pruneUnreferencedCache();\n}\n\ntype LoopbackEntry = { promise: Promise<string>; url?: string };\n\n// Keyed by the `sable-media` URL so one avatar repeated down a timeline resolves once.\nconst loopbackCache = new Map<string, LoopbackEntry>();\n\n// Bumped when the loopback cache is cleared (session or token change). Capability URLs\n// embed the token, so a rotation orphans every resolved URL until consumers re-resolve.\nlet loopbackGeneration = 0;\nconst loopbackGenerationListeners = new Set<() => void>();\n\nfunction subscribeLoopbackGeneration(listener: () => void): () => void {\n  loopbackGenerationListeners.add(listener);\n  return () => {\n    loopbackGenerationListeners.delete(listener);\n  };\n}\n\nfunction getLoopbackGeneration(): number {\n  return loopbackGeneration;\n}\n\n// Resolved up front because wry rejects a 3xx from a protocol handler, so the loopback cannot\n// be reached by redirect. Used on every Tauri platform: it also keeps the immutable caching\n// the runtimes strip from custom-protocol responses.\nfunction resolveLoopbackUrl(protocolUrl: string): LoopbackEntry {\n  const existing = loopbackCache.get(protocolUrl);\n  if (existing) return existing;\n\n  const entry: LoopbackEntry = {\n    promise: invoke<string>('prepare_loopback_media', { url: protocolUrl })\n      .then((loopbackUrl) => {\n        entry.url = loopbackUrl;\n        return loopbackUrl;\n      })\n      .catch(() => {\n        // The custom protocol still works, so a failure here costs performance, not media.\n        entry.url = protocolUrl;\n        return protocolUrl;\n      }),\n  };\n  loopbackCache.set(protocolUrl, entry);\n  return entry;\n}\n\n// Capabilities are keyed by access token, so they do not survive a session change.\nexport function clearLoopbackMediaUrlCache(): void {\n  loopbackCache.clear();\n  loopbackGeneration += 1;\n  for (const listener of loopbackGenerationListeners) {\n    listener();\n  }\n}\n\nexport function clearRenderableMediaUrlCache(): void {\n  for (const [cacheKey, entry] of Array.from(objectUrlCache.entries())) {\n    if (entry.refs === 0 && entry.settled && entry.objectUrl) {\n      URL.revokeObjectURL(entry.objectUrl);\n      objectUrlCache.delete(cacheKey);\n    }\n  }\n  unreferencedCacheKeys.length = 0;\n}\n\nexport function getRenderableMediaUrlStats(): { cacheSize: number; inflightCount: number } {\n  return { cacheSize: objectUrlCache.size, inflightCount: inflightRequests.size };\n}\n\nexport function useRenderableMediaUrl(\n  url: string | undefined,\n  retryRevision = 0\n): string | undefined {\n  const tauri = isTauri();\n  const activeSessionId = useAtomValue(activeSessionIdAtom);\n  const sessionScope = activeSessionId ?? getCurrentMediaSessionScope();\n  const renderableUrl = normalizeRenderableMediaUrl(url);\n  const objectUrlCacheKey =\n    renderableUrl && !renderableUrl.startsWith('blob:')\n      ? getObjectUrlCacheKey(sessionScope, renderableUrl, retryRevision)\n      : undefined;\n  // Media elements and bare URLs are only safe once the (current) service\n  // worker has proven it intercepts authenticated media; until then media goes\n  // through the blob path, which attaches the access token in JavaScript.\n  const [swMediaAuthSupported, setSwMediaAuthSupported] = useState(\n    () => getCachedSWMediaAuthSupport() ?? false\n  );\n  const protocolUrl = tauri ? (rewriteAuthenticatedMediaUrl(url ?? null) ?? undefined) : undefined;\n  const needsLoopback = tauri && webviewStripsCustomProtocolCache();\n  const generation = useSyncExternalStore(\n    subscribeLoopbackGeneration,\n    getLoopbackGeneration,\n    getLoopbackGeneration\n  );\n  // A settled entry resolves synchronously, so a repeated avatar never flashes a fallback.\n  const [loopbackState, setLoopbackState] = useState<{\n    source?: string;\n    url?: string;\n    generation: number;\n  }>(() => ({\n    source: protocolUrl,\n    url: tauri && protocolUrl ? loopbackCache.get(protocolUrl)?.url : undefined,\n    generation,\n  }));\n\n  useEffect(() => {\n    if (!needsLoopback || !protocolUrl) return undefined;\n    const entry = resolveLoopbackUrl(protocolUrl);\n    if (entry.url) {\n      setLoopbackState({ source: protocolUrl, url: entry.url, generation });\n      return undefined;\n    }\n    let cancelled = false;\n    void entry.promise.then((resolved) => {\n      if (!cancelled) {\n        setLoopbackState({ source: protocolUrl, url: resolved, generation });\n      }\n    });\n    return () => {\n      cancelled = true;\n    };\n  }, [needsLoopback, protocolUrl, generation]);\n  const needsBlob = !swMediaAuthSupported;\n  const usesExistingObjectUrl = renderableUrl?.startsWith('blob:') ?? false;\n  const [resolvedState, setResolvedState] = useState<ResolvedMediaUrlState>(() => {\n    const cachedEntry = objectUrlCacheKey ? objectUrlCache.get(objectUrlCacheKey) : undefined;\n    return {\n      cacheKey: objectUrlCacheKey,\n      url: needsBlob && !usesExistingObjectUrl ? cachedEntry?.objectUrl : renderableUrl,\n    };\n  });\n\n  useEffect(() => {\n    if (tauri) return undefined;\n\n    if (getCachedSWMediaAuthSupport() === undefined) {\n      void probeSWMediaAuthSupport();\n    }\n    return subscribeSWMediaAuthSupport(setSwMediaAuthSupported);\n  }, [tauri]);\n\n  useEffect(() => {\n    if (tauri) return undefined;\n    if (!renderableUrl) {\n      setResolvedState({ cacheKey: undefined, url: undefined });\n      return undefined;\n    }\n\n    if (!needsBlob) {\n      setResolvedState({ cacheKey: undefined, url: renderableUrl });\n      return undefined;\n    }\n\n    if (usesExistingObjectUrl) {\n      setResolvedState({ cacheKey: undefined, url: renderableUrl });\n      return undefined;\n    }\n\n    if (!objectUrlCacheKey) {\n      setResolvedState({ cacheKey: undefined, url: undefined });\n      return undefined;\n    }\n\n    const entry = retainObjectUrlEntry(objectUrlCacheKey, renderableUrl);\n    let cancelled = false;\n    const { objectUrl } = entry;\n\n    setResolvedState({ cacheKey: objectUrlCacheKey, url: objectUrl });\n\n    entry.promise\n      .then((resolvedObjectUrl) => {\n        if (!cancelled) {\n          setResolvedState({ cacheKey: objectUrlCacheKey, url: resolvedObjectUrl });\n        }\n      })\n      .catch(() => {\n        if (!cancelled) {\n          setResolvedState({ cacheKey: objectUrlCacheKey, url: undefined });\n        }\n      });\n\n    return () => {\n      cancelled = true;\n      releaseObjectUrlEntry(objectUrlCacheKey);\n    };\n  }, [needsBlob, objectUrlCacheKey, renderableUrl, tauri, usesExistingObjectUrl]);\n\n  if (tauri) {\n    // No protocolUrl fallback while resolving: resolveLoopbackUrl already degrades to it,\n    // and handing out the custom-scheme URL first would fail a media element.\n    if (!protocolUrl) return undefined;\n    if (!needsLoopback) return protocolUrl;\n    // A URL resolved under an older generation is dead after a cache clear; the effect\n    // re-resolves against the current session.\n    if (loopbackState.source === protocolUrl && loopbackState.generation === generation) {\n      return loopbackState.url;\n    }\n    return loopbackCache.get(protocolUrl)?.url;\n  }\n\n  if (!needsBlob || usesExistingObjectUrl) {\n    return renderableUrl;\n  }\n\n  if (resolvedState.cacheKey !== objectUrlCacheKey) {\n    return undefined;\n  }\n\n  return resolvedState.url;\n}\n\n// Undefined while the url is still being prepared: on Tauri, rendering the raw source first\n// only means a second load once the loopback url lands, and an error on either latches.\nexport function useRenderableMediaSource(\n  url: string | undefined,\n  retryRevision = 0\n): string | undefined {\n  const retriedUrl = url && retryRevision > 0 ? addMediaRetryRevision(url, retryRevision) : url;\n  const resolvedUrl = useRenderableMediaUrl(retriedUrl, retryRevision);\n  if (resolvedUrl) return resolvedUrl;\n  return isTauri() ? undefined : retriedUrl;\n}\n\nconst AVATAR_RETRY_DELAYS_MS = [500, 1500, 4500];\n\ntype AvatarMediaSource = {\n  mediaSrc: string | undefined;\n  error: boolean;\n  onError: () => void;\n};\n\nexport function useAvatarMediaSource(src: string | undefined): AvatarMediaSource {\n  const [error, setError] = useState(false);\n  const [retryRevision, setRetryRevision] = useState(0);\n  const mediaSrc = useRenderableMediaSource(src, retryRevision);\n\n  useEffect(() => {\n    setError(false);\n    setRetryRevision(0);\n  }, [src]);\n\n  // Cleared mid-ladder too: a suspended webview cancels loads without firing load or error.\n  useEffect(() => {\n    setError(false);\n  }, [mediaSrc]);\n\n  useEffect(() => {\n    if (!error) return undefined;\n    const delay = AVATAR_RETRY_DELAYS_MS[retryRevision];\n    if (delay === undefined) return undefined;\n    const timer = setTimeout(() => {\n      setError(false);\n      setRetryRevision((revision) => revision + 1);\n    }, delay);\n    return () => clearTimeout(timer);\n  }, [error, retryRevision]);\n\n  const onError = useCallback(() => setError(true), []);\n\n  return { mediaSrc, error, onError };\n}\n","import { isTauri } from '@tauri-apps/api/core';\nimport { clearMediaSession, setMediaSession } from '$generated/tauri/commands';\nimport { createLogger } from './debug';\nimport { getActiveMediaSession } from './mediaTransport';\nimport { clearLoopbackMediaUrlCache } from '$hooks/useRenderableMediaUrl';\n\nconst log = createLogger('tauri-media-auth');\n\nlet pendingNativeWrite: Promise<void> = Promise.resolve();\nlet tauriMediaSessionListenersInstalled = false;\n// In memory only, never logged. Compared so a no-op sync keeps the loopback cache.\nlet lastMediaToken: string | undefined;\n\nexport const updateTauriMediaSession = (\n  baseUrl?: string,\n  accessToken?: string,\n  userId?: string\n): Promise<void> => {\n  if (!isTauri()) return Promise.resolve();\n\n  const write = pendingNativeWrite.then(async () => {\n    try {\n      if (baseUrl && accessToken) {\n        // `scope` keys the native media cache. It must be the stable user ID, never the\n        // access token, which rotates on every OIDC refresh.\n        await setMediaSession({ baseUrl, token: accessToken, scope: userId });\n        // Capabilities embed the access token, so a rotated token orphans every cached URL.\n        if (accessToken !== lastMediaToken) {\n          clearLoopbackMediaUrlCache();\n          lastMediaToken = accessToken;\n        }\n      } else {\n        await clearMediaSession();\n        clearLoopbackMediaUrlCache();\n        lastMediaToken = undefined;\n      }\n    } catch {\n      // Do not log command arguments: they contain the homeserver URL and access token.\n      log.warn('Failed to update Tauri media session');\n    }\n  });\n\n  pendingNativeWrite = write;\n  return write;\n};\n\nconst syncTauriMediaSession = (): Promise<void> => {\n  const session = getActiveMediaSession();\n  if (!session) return Promise.resolve();\n  return updateTauriMediaSession(session.baseUrl, session.accessToken, session.userId);\n};\n\nexport const initTauriMediaSession = (): Promise<void> => {\n  if (!isTauri()) return Promise.resolve();\n\n  if (!tauriMediaSessionListenersInstalled) {\n    const sync = () => {\n      void syncTauriMediaSession();\n    };\n    window.addEventListener('storage', sync);\n    window.addEventListener('sable-session-changed', sync);\n    tauriMediaSessionListenersInstalled = true;\n  }\n\n  return syncTauriMediaSession();\n};\n","import { isTauri } from '@tauri-apps/api/core';\nimport { getStoredSession } from './app/state/sessions';\nimport { updateTauriMediaSession } from './app/utils/tauriMediaAuth';\n\nexport function pushSessionToSW(\n  baseUrl?: string,\n  accessToken?: string,\n  userId?: string\n): Promise<void> {\n  if (isTauri()) {\n    // Tauri has no service worker.\n    return updateTauriMediaSession(baseUrl, accessToken, userId);\n  }\n\n  if (!('serviceWorker' in navigator) || !navigator.serviceWorker.controller) {\n    return Promise.resolve();\n  }\n\n  navigator.serviceWorker.controller.postMessage({\n    type: 'setSession',\n    accessToken,\n    baseUrl,\n    userId,\n    // oxlint-disable-next-line unicorn/require-post-message-target-origin\n  });\n  return Promise.resolve();\n}\n\n// Pushes the persisted session (which may hold a refreshed token) rather than the\n// captured one; falls back to it when nothing is persisted.\nexport function pushPersistedSessionToSW(fallback: {\n  baseUrl: string;\n  accessToken: string;\n  userId: string;\n}): Promise<void> {\n  const session = getStoredSession(fallback.userId) ?? fallback;\n  return pushSessionToSW(session.baseUrl, session.accessToken, session.userId);\n}\n","import type { AccessTokens, ValidatedAuthMetadata } from '$types/matrix-sdk';\nimport { OAuth2, TokenRefresher } from '$types/matrix-sdk';\nimport type { MatrixClient } from '$types/matrix-sdk';\nimport type { Session } from '$state/sessions';\nimport {\n  ACTIVE_SESSION_KEY,\n  MATRIX_SESSIONS_KEY,\n  getStoredSessionRefreshToken,\n  updateSessionTokens,\n} from '$state/sessions';\nimport { getLocalStorageItem } from '$state/utils/atomWithLocalStorage';\nimport { pushSessionToSW } from '../sw-session';\nimport { getAppOrigin } from '$utils/platform';\n\nexport const assertAuthMetadataIssuer = (\n  expectedIssuer: string,\n  metadata: ValidatedAuthMetadata\n): void => {\n  if (metadata.issuer !== expectedIssuer) {\n    throw new Error(\n      `OAuth issuer changed for the stored session: expected ${expectedIssuer}, received ${metadata.issuer}`\n    );\n  }\n};\n\nexport type SessionTokenRefresher = Pick<TokenRefresher, 'tokenRefreshFunction'>;\n\nconst refreshQueues = new Map<string, Promise<unknown>>();\nconst inFlightRefreshes = new Map<string, Promise<unknown>>();\nconst OIDC_REFRESH_LOCK_NAME = 'sable-oidc-refresh';\n\ntype WebLocks = {\n  request<T>(name: string, callback: () => Promise<T>): Promise<T>;\n};\n\nconst getWebLocks = (): WebLocks | undefined => {\n  if (typeof navigator === 'undefined') return undefined;\n  const locks = (navigator as Navigator & { locks?: WebLocks }).locks;\n  return locks && typeof locks.request === 'function' ? locks : undefined;\n};\n\nconst getStoredSession = (userId: string): Session | undefined =>\n  getLocalStorageItem<Session[]>(MATRIX_SESSIONS_KEY, []).find(\n    (stored) => stored.userId === userId\n  );\n\nconst withRefreshQueue = async <T>(userId: string, operation: () => Promise<T>): Promise<T> => {\n  const previous = refreshQueues.get(userId) ?? Promise.resolve();\n  const run = previous.catch(() => undefined).then(operation);\n  const settled = run.then(\n    () => undefined,\n    () => undefined\n  );\n  refreshQueues.set(userId, settled);\n  return run;\n};\n\nexport const waitForSessionTokenRefresh = async (userId: string): Promise<void> => {\n  await inFlightRefreshes.get(userId)?.catch(() => undefined);\n};\n\nexport const createSessionTokenRefresher = (\n  session: Session,\n  mx: MatrixClient\n): SessionTokenRefresher | undefined => {\n  const { oidc } = session;\n  if (!oidc || !session.refreshToken) return undefined;\n\n  const onRefresh = async (tokens: AccessTokens): Promise<void> => {\n    updateSessionTokens(session.userId, {\n      accessToken: tokens.accessToken,\n      refreshToken: tokens.refreshToken,\n      expiresInMs: tokens.expiry ? tokens.expiry.getTime() - Date.now() : undefined,\n    });\n    // Only the active session owns the single service-worker session.\n    const activeSessionId = getLocalStorageItem<string | undefined>(ACTIVE_SESSION_KEY, undefined);\n    if (activeSessionId === session.userId) {\n      await pushSessionToSW(session.baseUrl, tokens.accessToken, session.userId);\n    }\n  };\n\n  let tokenRefresherPromise: Promise<TokenRefresher> | undefined;\n  const getTokenRefresher = (): Promise<TokenRefresher> => {\n    if (!tokenRefresherPromise) {\n      tokenRefresherPromise = mx\n        .getAuthMetadata()\n        .then((metadata: ValidatedAuthMetadata) => {\n          assertAuthMetadataIssuer(oidc.issuer, metadata);\n          const oauth2 = new OAuth2(metadata, {\n            clientId: oidc.clientId,\n            redirectUri: getAppOrigin(),\n            deviceId: session.deviceId,\n          });\n          return new TokenRefresher(oauth2, onRefresh);\n        })\n        .catch((error: unknown) => {\n          tokenRefresherPromise = undefined;\n          throw error;\n        });\n    }\n    return tokenRefresherPromise;\n  };\n\n  return {\n    tokenRefreshFunction: async (refreshToken) => {\n      const refresh = withRefreshQueue(session.userId, async () => {\n        const tokenRefresher = await getTokenRefresher();\n        const refreshWithCurrentState = async () => {\n          // Another tab may have rotated the token; reusing a consumed one revokes the session.\n          const storedSession = getStoredSession(session.userId);\n          const latestRefreshToken =\n            storedSession?.refreshToken ??\n            getStoredSessionRefreshToken(session.userId) ??\n            refreshToken;\n          if (storedSession && latestRefreshToken !== refreshToken) {\n            return {\n              accessToken: storedSession.accessToken,\n              refreshToken: latestRefreshToken,\n            };\n          }\n          const tokens = await tokenRefresher.tokenRefreshFunction(latestRefreshToken);\n          return {\n            ...tokens,\n            // OAuth servers may omit a replacement refresh token, in which case the old one remains valid.\n            refreshToken: tokens.refreshToken ?? latestRefreshToken,\n          };\n        };\n\n        const locks = getWebLocks();\n        return locks\n          ? locks.request(OIDC_REFRESH_LOCK_NAME, refreshWithCurrentState)\n          : refreshWithCurrentState();\n      });\n      inFlightRefreshes.set(session.userId, refresh);\n      try {\n        return await refresh;\n      } finally {\n        if (inFlightRefreshes.get(session.userId) === refresh) {\n          inFlightRefreshes.delete(session.userId);\n        }\n      }\n    },\n  };\n};\n","import type { ValidatedAuthMetadata } from '$types/matrix-sdk';\nimport { fetch } from '$utils/fetch';\n\ntype Fetch = typeof globalThis.fetch;\n\nexport const revokeOAuthToken = async (\n  metadata: ValidatedAuthMetadata,\n  clientId: string,\n  token: string,\n  tokenTypeHint: 'access_token' | 'refresh_token',\n  fetchFn: Fetch = fetch\n): Promise<void> => {\n  const response = await fetchFn(metadata.revocation_endpoint, {\n    method: 'POST',\n    headers: {\n      Accept: 'application/json',\n      'Content-Type': 'application/x-www-form-urlencoded',\n    },\n    body: new URLSearchParams({\n      token,\n      token_type_hint: tokenTypeHint,\n      client_id: clientId,\n    }),\n  });\n\n  if (!response.ok) {\n    throw new Error(`OAuth token revocation failed (${response.status})`);\n  }\n};\n","const secretStorageKeys = new Map();\n\nexport function storePrivateKey(keyId, privateKey) {\n  if (!(privateKey instanceof Uint8Array)) {\n    throw new Error('Unable to store, privateKey is invalid.');\n  }\n  secretStorageKeys.set(keyId, privateKey);\n}\n\nfunction hasPrivateKey(keyId) {\n  return secretStorageKeys.get(keyId) instanceof Uint8Array;\n}\n\nfunction getPrivateKey(keyId) {\n  return secretStorageKeys.get(keyId);\n}\n\nexport function clearSecretStorageKeys() {\n  secretStorageKeys.clear();\n}\n\nasync function getSecretStorageKey({ keys }) {\n  const keyIds = Object.keys(keys);\n  const keyId = keyIds.find(hasPrivateKey);\n  if (!keyId) return undefined;\n  const privateKey = getPrivateKey(keyId);\n  return [keyId, privateKey];\n}\n\nfunction cacheSecretStorageKey(keyId, keyInfo, privateKey) {\n  secretStorageKeys.set(keyId, privateKey);\n}\n\nexport const cryptoCallbacks = {\n  getSecretStorageKey,\n  cacheSecretStorageKey,\n};\n","import type {\n  IRoomEvent,\n  IStateEvent,\n  MatrixClient,\n  MSC3575List,\n  MSC3575RoomData,\n  MSC3575RoomSubscription,\n  MSC3575SlidingSyncResponse,\n  Room,\n  EventTimelineSet,\n} from '$types/matrix-sdk';\nimport {\n  EventStatus,\n  KnownMembership,\n  MatrixEvent,\n  MSC3575_WILDCARD,\n  RoomMemberEvent,\n  SlidingSync,\n  SlidingSyncEvent,\n  SlidingSyncState,\n  MSC3575_STATE_KEY_LAZY,\n  MSC3575_STATE_KEY_ME,\n  EventType,\n  EventTimeline,\n  EventEmitterEvents,\n  ClientEvent,\n  RoomEvent,\n  UNSTABLE_ELEMENT_FUNCTIONAL_USERS,\n} from '$types/matrix-sdk';\nimport { createLogger } from '$utils/debug';\nimport { createDebugLogger } from '$utils/debugLogger';\nimport { CustomStateEvent } from '$types/matrix/room';\nimport * as Sentry from '@sentry/react';\nimport { SlidingSyncSidebarCache } from './slidingSyncSidebarCache';\n\nconst log = createLogger('slidingSync');\nconst debugLog = createDebugLogger('slidingSync');\n\nconst LIST_JOINED = 'joined';\nconst LIST_INVITES = 'invites';\nconst LIST_TIMELINE_LIMIT = 1;\n\n// MSC4186 room_subscriptions maximum.\nconst MAX_ROOM_SUBSCRIPTIONS = 100;\n\nconst LIST_PAGE_SIZE = 30;\nconst DEFAULT_POLL_TIMEOUT_MS = 45000;\n// Mirrors the js-sdk's own BUFFER_PERIOD_MS so our watchdog sits after its `clientTimeout`.\nconst SDK_CLIENT_TIMEOUT_BUFFER_MS = 10_000;\nconst POLL_DEADLINE_MARGIN_MS = 20_000;\n\n// The SDK's to_device extension takes 100 events per response, so a backlog needs several.\nconst MAX_PUSH_DRAIN_POLLS = 5;\n\nconst ACTIVE_ROOM_SUBSCRIPTION_KEY = 'active_room';\nconst CALL_ROOM_SUBSCRIPTION_KEY = 'call_room';\nconst SIDEBAR_ROOM_SUBSCRIPTION_KEY = 'sidebar_room';\nconst SPACE_SUBSCRIPTION_KEY = 'space';\nconst IMAGE_PACK_SUBSCRIPTION_KEY = 'image_packs';\nconst SPACE_IMAGE_PACK_SUBSCRIPTION_KEY = 'space_image_packs';\nconst ACTIVE_ROOM_TIMELINE_LIMIT = 50;\nconst ROUTE_ADOPTION_TIMEOUT_MS = 30_000;\nconst OPTIMISTIC_JOIN_MAX_SYNC_CYCLES = 10;\nconst OPTIMISTIC_JOIN_VERIFY_AFTER_CYCLES = 3;\n\ntype OptimisticJoin = {\n  joinedAtSyncCount: number;\n  lastSeenSyncCount: number;\n  verificationRequested: boolean;\n};\n\nexport type PartialSlidingSyncRequest = {\n  filters?: MSC3575List['filters'];\n  ranges?: [number, number][];\n};\n\ntype SlidingSyncOptions = {\n  timelineLimit?: number;\n  pollTimeoutMs?: number;\n  initialRoomIds?: Iterable<string>;\n};\n\ntype RoomScopedExtensionResponse = {\n  rooms?: Record<string, unknown>;\n};\n\nexport type SlidingSyncListDiagnostics = {\n  key: string;\n  knownCount: number;\n  rangeEnd: number;\n  requestedRangeEnd: number;\n};\n\nexport type SlidingSyncDiagnostics = {\n  baseUrl: string;\n  timelineLimit: number;\n  lists: SlidingSyncListDiagnostics[];\n};\n\nexport type HydrationProgress = { loadedRooms: number; totalRooms: number };\n\nexport type CallRoomSubscription = () => void;\n\nconst clampPositive = (value: number | undefined, fallback: number): number => {\n  if (typeof value !== 'number' || Number.isNaN(value) || value <= 0) return fallback;\n  return Math.round(value);\n};\n\ntype SlidingSyncEventLike = IStateEvent | IRoomEvent;\n\nconst isSelfMemberEvent = (event: SlidingSyncEventLike, userId: string): boolean =>\n  event.type === (EventType.RoomMember as string) &&\n  'state_key' in event &&\n  event.state_key === userId;\n\n// Scans backwards so the newest wins in a timeline that still holds the\n// previous membership.\nconst findSelfMemberEvent = <T extends SlidingSyncEventLike>(\n  events: readonly T[],\n  userId: string\n): T | undefined => {\n  for (let i = events.length - 1; i >= 0; i -= 1) {\n    const event = events[i];\n    if (event && isSelfMemberEvent(event, userId)) return event;\n  }\n  return undefined;\n};\n\nconst membershipOf = (event: SlidingSyncEventLike | undefined): string | undefined => {\n  const content = event?.content;\n  return content && typeof content === 'object'\n    ? ((content as { membership?: unknown }).membership as string | undefined)\n    : undefined;\n};\n\nconst asString = (value: unknown): string | undefined =>\n  typeof value === 'string' ? value : undefined;\n\n// \"~\" is the SDK's local-echo event id prefix (see MatrixClient.sendEvent).\nconst buildSelfJoinEvent = (\n  roomId: string,\n  userId: string,\n  previousContent: unknown\n): IStateEvent & { room_id: string } => {\n  // Only the profile carries over; is_direct and third_party_invite are invite-only.\n  const previous = (previousContent ?? {}) as { displayname?: unknown; avatar_url?: unknown };\n\n  return {\n    type: EventType.RoomMember,\n    state_key: userId,\n    room_id: roomId,\n    sender: userId,\n    event_id: `~sable-self-join:${roomId}`,\n    origin_server_ts: Date.now(),\n    content: {\n      membership: KnownMembership.Join,\n      displayname: asString(previous.displayname),\n      avatar_url: asString(previous.avatar_url),\n    },\n  };\n};\n\nconst buildListRequiredState = (): MSC3575RoomSubscription['required_state'] => [\n  [EventType.RoomAvatar, ''],\n  [EventType.RoomTombstone, ''],\n  [EventType.RoomEncryption, ''],\n  [EventType.RoomCreate, ''],\n  [EventType.RoomName, ''],\n  [EventType.RoomCanonicalAlias, ''],\n  [EventType.RoomJoinRules, ''],\n  [EventType.RoomMember, MSC3575_STATE_KEY_ME],\n  [EventType.GroupCallPrefix, ''],\n  [EventType.GroupCallMemberPrefix, MSC3575_WILDCARD],\n  // Feeds functional-member filtering for bridged DM names/avatars.\n  [UNSTABLE_ELEMENT_FUNCTIONAL_USERS.name, ''],\n];\n\nconst SPACE_REQUIRED_STATE: MSC3575RoomSubscription['required_state'] = [\n  [EventType.RoomCreate, ''],\n  [EventType.RoomName, ''],\n  [EventType.RoomAvatar, ''],\n  [EventType.RoomCanonicalAlias, ''],\n  [EventType.RoomJoinRules, ''],\n  [EventType.RoomEncryption, ''],\n  [EventType.RoomTombstone, ''],\n  [CustomStateEvent.RoomBanner, ''],\n  [EventType.SpaceChild, MSC3575_WILDCARD],\n  [EventType.SpaceParent, MSC3575_WILDCARD],\n];\n\nconst ACTIVE_ROOM_REQUIRED_STATE: MSC3575RoomSubscription['required_state'] = [\n  // active room subscription includes all room data\n  [EventType.RoomPowerLevels, ''],\n  [EventType.RoomName, ''],\n  [EventType.RoomTopic, ''],\n  [EventType.RoomAvatar, ''],\n  [EventType.RoomCanonicalAlias, ''],\n  [EventType.RoomJoinRules, ''],\n  [EventType.RoomHistoryVisibility, ''],\n  [EventType.RoomGuestAccess, ''],\n  [EventType.RoomEncryption, ''],\n  [EventType.RoomTombstone, ''],\n  [EventType.RoomCreate, ''],\n  [EventType.RoomPinnedEvents, ''],\n  [EventType.RoomServerAcl, ''],\n  [EventType.RoomThirdPartyInvite, MSC3575_WILDCARD],\n  [EventType.RoomMember, MSC3575_STATE_KEY_ME],\n  [EventType.RoomMember, MSC3575_STATE_KEY_LAZY],\n  [EventType.SpaceChild, MSC3575_WILDCARD],\n  [EventType.SpaceParent, MSC3575_WILDCARD],\n  [EventType.GroupCallPrefix, ''],\n  [EventType.GroupCallMemberPrefix, MSC3575_WILDCARD],\n  [UNSTABLE_ELEMENT_FUNCTIONAL_USERS.name, ''],\n  ...Object.values(CustomStateEvent).map((type) => [type, MSC3575_WILDCARD] as [string, string]),\n];\n\nconst buildEncryptedSubscription = (timelineLimit: number): MSC3575RoomSubscription => ({\n  timeline_limit: timelineLimit,\n  required_state: ACTIVE_ROOM_REQUIRED_STATE,\n});\n\nconst buildUnencryptedSubscription = (timelineLimit: number): MSC3575RoomSubscription => ({\n  timeline_limit: timelineLimit,\n  required_state: ACTIVE_ROOM_REQUIRED_STATE,\n});\n\nconst buildCallRoomSubscription = (timelineLimit: number): MSC3575RoomSubscription => ({\n  timeline_limit: timelineLimit,\n  // MatrixRTC ignores memberships for users that are absent from the room\n  // roster. Unlike a timeline, calls need every membership continuously.\n  required_state: [...ACTIVE_ROOM_REQUIRED_STATE, [EventType.RoomMember, MSC3575_WILDCARD]],\n});\n\nconst IMAGE_PACK_REQUIRED_STATE: MSC3575RoomSubscription['required_state'] = [\n  [CustomStateEvent.ImagePack, MSC3575_WILDCARD],\n  [CustomStateEvent.PoniesRoomEmotes, MSC3575_WILDCARD],\n];\n\nconst buildImagePackSubscription = (): MSC3575RoomSubscription => ({\n  timeline_limit: 0,\n  required_state: IMAGE_PACK_REQUIRED_STATE,\n});\n\n// Pack rooms that are also spaces need both state sets; room subscriptions\n// use exactly one named key, so register the union as its own subscription.\nconst buildSpaceImagePackSubscription = (): MSC3575RoomSubscription => ({\n  timeline_limit: 0,\n  required_state: [...SPACE_REQUIRED_STATE, ...IMAGE_PACK_REQUIRED_STATE],\n});\n\nconst buildSpaceSubscription = (): MSC3575RoomSubscription => ({\n  timeline_limit: 0,\n  required_state: SPACE_REQUIRED_STATE,\n});\n\nconst buildSidebarRoomSubscription = (): MSC3575RoomSubscription => ({\n  timeline_limit: LIST_TIMELINE_LIMIT,\n  required_state: buildListRequiredState(),\n});\n\nconst buildLists = (): Map<string, MSC3575List> => {\n  const lists = new Map<string, MSC3575List>();\n  const listRequiredState = buildListRequiredState();\n\n  lists.set(LIST_JOINED, {\n    ranges: [[0, LIST_PAGE_SIZE - 1]],\n    timeline_limit: LIST_TIMELINE_LIMIT,\n    required_state: listRequiredState,\n    filters: { is_invite: false },\n  });\n\n  lists.set(LIST_INVITES, {\n    ranges: [[0, LIST_PAGE_SIZE - 1]],\n    timeline_limit: LIST_TIMELINE_LIMIT,\n    required_state: listRequiredState,\n    filters: { is_invite: true },\n  });\n\n  return lists;\n};\n\nconst getListEndIndex = (list: MSC3575List | null): number => {\n  if (!list?.ranges?.length) return -1;\n  return list.ranges.reduce((max, range) => Math.max(max, range[1] ?? -1), -1);\n};\n\ntype RoomScopedExtension = {\n  enabled?: boolean;\n  lists?: string[];\n  rooms?: string[];\n};\n\n// Receipts stay unscoped on purpose: they drive unread state for every room in\n// the sidebar, and a room that never receives one reads as permanently unread.\nexport const scopeTypingExtension = (\n  extensions: object | undefined,\n  roomIds: readonly string[]\n): void => {\n  if (!extensions) return;\n\n  const typing = (extensions as Record<string, unknown>).typing;\n  if (!typing || typeof typing !== 'object') return;\n\n  const scopedTyping = typing as RoomScopedExtension;\n  scopedTyping.lists = [];\n  scopedTyping.rooms = [...roomIds];\n};\n\ntype SlidingSyncTimelineRoomData = MSC3575RoomData & {\n  expanded_timeline?: boolean;\n  unstable_expanded_timeline?: boolean;\n};\n\ntype PreparedRoomSubscription = {\n  afterRequestId: number;\n  requiresSubscriptionResponse: boolean;\n  listener: () => void;\n};\n\ntype TrackedSlidingSyncResponse = {\n  requestId: number;\n  subscriptionRoomIds: ReadonlySet<string>;\n};\n\ntype TimelineResetCompletion = () => void;\n\nexport const prepareSlidingSyncTimelines = (\n  resp: MSC3575SlidingSyncResponse | null,\n  mx?: MatrixClient,\n  subscribedRoomIds?: ReadonlySet<string>\n): TimelineResetCompletion | null => {\n  if (!resp?.rooms) return null;\n  let didResetTimeline = false;\n  const pendingEventsToRestore: Array<{\n    timelineSet: EventTimelineSet;\n    events: MatrixEvent[];\n  }> = [];\n\n  for (const [roomId, roomData] of Object.entries(resp.rooms)) {\n    const timelineData = roomData as SlidingSyncTimelineRoomData;\n    const serverReportedLimited = timelineData.limited === true;\n    const hasExpandedFlag =\n      timelineData.expanded_timeline === true || timelineData.unstable_expanded_timeline === true;\n    const numLive = timelineData.num_live;\n    const timeline = Array.isArray(timelineData.timeline) ? timelineData.timeline : [];\n    const timelineLength = timeline.length;\n    const room = mx?.getRoom(roomId);\n    const timelineSet = room?.getUnfilteredTimelineSet();\n    const liveTimeline = room?.getLiveTimeline();\n    const liveEvents = liveTimeline?.getEvents() ?? [];\n    if (serverReportedLimited && room) {\n      void room.clearLoadedMembersIfNeeded().catch((error: unknown) => {\n        debugLog.warn('sync', 'Failed to flush lazily loaded members after a gap', {\n          roomId,\n          error: error instanceof Error ? error.message : String(error),\n        });\n      });\n    }\n    const liveEventIds: string[] = [];\n    for (const event of liveEvents) {\n      const eventId = event.getId();\n      if (eventId) liveEventIds.push(eventId);\n    }\n    const knownEventIds = new Set(liveEventIds);\n    const hasHistoricalEvents =\n      timelineData.initial !== true &&\n      typeof numLive === 'number' &&\n      Number.isInteger(numLive) &&\n      numLive >= 0 &&\n      numLive < timelineLength;\n    let hasHistoricalOverlap = false;\n    if (!hasExpandedFlag && !hasHistoricalEvents && timelineData.initial !== true) {\n      let sawUnknownEvent = false;\n      hasHistoricalOverlap = timeline.some((event) => {\n        const eventId = event.event_id;\n        if (typeof eventId !== 'string') return false;\n        if (knownEventIds.has(eventId)) return sawUnknownEvent;\n        sawUnknownEvent = true;\n        return false;\n      });\n    }\n\n    const responseEventIds = timeline\n      .map((event) => event.event_id)\n      .filter((eventId): eventId is string => typeof eventId === 'string');\n    const firstKnownResponseIndex = responseEventIds.findIndex((eventId) =>\n      knownEventIds.has(eventId)\n    );\n    const firstKnownLiveIndex =\n      firstKnownResponseIndex < 0\n        ? -1\n        : liveEventIds.indexOf(responseEventIds[firstKnownResponseIndex]!);\n    const hasSparseOverlap = firstKnownResponseIndex > 0 && firstKnownLiveIndex > 0;\n\n    const isRequestedExpansion =\n      subscribedRoomIds?.has(roomId) === true &&\n      knownEventIds.size > 0 &&\n      firstKnownResponseIndex < 0;\n\n    const shouldMarkLimited =\n      timelineLength > 0 &&\n      (hasExpandedFlag || hasHistoricalEvents || hasHistoricalOverlap || isRequestedExpansion);\n\n    if (shouldMarkLimited) timelineData.limited = true;\n\n    const isGapped = firstKnownResponseIndex < 0 || hasSparseOverlap;\n    if (\n      knownEventIds.size > 0 &&\n      room &&\n      timelineSet &&\n      isGapped &&\n      responseEventIds.length > 0 &&\n      typeof timelineData.prev_batch === 'string' &&\n      (timelineData.initial === true || timelineData.limited === true)\n    ) {\n      const pendingEvents = liveEvents.filter((event) => event.isSending());\n      if (pendingEvents.length > 0) {\n        pendingEventsToRestore.push({ timelineSet, events: pendingEvents });\n      }\n      const previousOldState = room.oldState;\n      timelineSet.resetLiveTimeline(\n        typeof timelineData.prev_batch === 'string' ? timelineData.prev_batch : undefined\n      );\n      const newLiveTimeline = timelineSet.getLiveTimeline();\n      room.oldState = newLiveTimeline.getState(EventTimeline.BACKWARDS)!;\n      room.currentState = newLiveTimeline.getState(EventTimeline.FORWARDS)!;\n      if (room.oldState !== previousOldState) {\n        room.emit(RoomEvent.OldStateUpdated, room, previousOldState, room.oldState);\n      }\n      didResetTimeline = true;\n      continue;\n    }\n\n    // The SDK writes prev_batch over the live timeline's BACKWARDS token on every\n    // limited response. When the window starts at an event we already have below\n    // our top, nothing is prepended and the top does not move, so that token would\n    // back-paginate from the wrong stream position and prepend newer events.\n    if (timelineData.limited === true && firstKnownResponseIndex === 0 && firstKnownLiveIndex > 0) {\n      const topToken = liveTimeline?.getPaginationToken(EventTimeline.BACKWARDS);\n      if (typeof topToken === 'string') timelineData.prev_batch = topToken;\n    }\n\n    if (!shouldMarkLimited) {\n      continue;\n    }\n\n    if (typeof timelineData.prev_batch !== 'string') {\n      const token = mx\n        ?.getRoom(roomId)\n        ?.getLiveTimeline()\n        .getPaginationToken(EventTimeline.BACKWARDS);\n      if (typeof token === 'string') timelineData.prev_batch = token;\n    }\n  }\n\n  if (didResetTimeline) mx?.resetNotifTimelineSet();\n  if (pendingEventsToRestore.length === 0) return null;\n\n  return () => {\n    for (const { timelineSet, events } of pendingEventsToRestore) {\n      const liveTimeline = timelineSet.getLiveTimeline();\n      for (const event of events) {\n        const eventId = event.getId();\n        if (\n          event.status === null ||\n          event.status === EventStatus.CANCELLED ||\n          !eventId ||\n          timelineSet.findEventById(eventId)\n        ) {\n          continue;\n        }\n        timelineSet.addEventToTimeline(event, liveTimeline, {\n          toStartOfTimeline: false,\n          addToState: false,\n        });\n      }\n    }\n  };\n};\n\nconst LOCAL_ECHO_MATCH_MAX_CLOCK_SKEW_MS = 60_000;\n\nconst canonicalJson = (value: unknown): string => {\n  if (Array.isArray(value)) return `[${value.map(canonicalJson).join(',')}]`;\n  if (value !== null && typeof value === 'object') {\n    const entries = Object.keys(value as Record<string, unknown>)\n      .toSorted()\n      .map(\n        (key) => `${JSON.stringify(key)}:${canonicalJson((value as Record<string, unknown>)[key])}`\n      );\n    return `{${entries.join(',')}}`;\n  }\n  return JSON.stringify(value);\n};\n\nexport const reconcileLocalEchoes = (room: Room | null | undefined): void => {\n  if (!room) return;\n  const liveEvents = room.getLiveTimeline().getEvents();\n  const pendingEchoes = liveEvents.filter(\n    (event) =>\n      event.status !== null &&\n      event.status !== EventStatus.CANCELLED &&\n      event.status !== EventStatus.SENT\n  );\n  if (pendingEchoes.length === 0) return;\n\n  const claimedEventIds = new Set<string>();\n  const isMergeCandidate = (candidate: MatrixEvent, echo: MatrixEvent): boolean => {\n    const candidateId = candidate.getId();\n    if (!candidateId || candidate === echo || claimedEventIds.has(candidateId)) return false;\n    if (candidate.status !== null) return false;\n    if (candidate.getSender() !== echo.getSender()) return false;\n    return !candidate.isRedacted();\n  };\n\n  for (const echo of pendingEchoes) {\n    const txnId = echo.getTxnId();\n    let match = txnId\n      ? liveEvents.find(\n          (candidate) =>\n            isMergeCandidate(candidate, echo) && candidate.getUnsigned()?.transaction_id === txnId\n        )\n      : undefined;\n    if (!match) {\n      const wireType = echo.getWireType();\n      const wireContent = canonicalJson(echo.getWireContent());\n      match = liveEvents.find((candidate) => {\n        if (!isMergeCandidate(candidate, echo)) return false;\n        if (candidate.getWireType() !== wireType) return false;\n        const candidateTxn = candidate.getUnsigned()?.transaction_id;\n        if (typeof candidateTxn === 'string' && candidateTxn !== txnId) return false;\n        if (candidate.getTs() < echo.getTs() - LOCAL_ECHO_MATCH_MAX_CLOCK_SKEW_MS) return false;\n        return canonicalJson(candidate.getWireContent()) === wireContent;\n      });\n    }\n    const matchId = match?.getId();\n    if (!match || !matchId) continue;\n    claimedEventIds.add(matchId);\n\n    const unsigned = match.getUnsigned();\n    if (txnId && typeof unsigned.transaction_id !== 'string') {\n      unsigned.transaction_id = txnId;\n      match.setUnsigned(unsigned);\n    }\n    room.removeEvent(matchId);\n    room.handleRemoteEcho(match, echo);\n    debugLog.info('sync', 'Reconciled unlinked local echo', {\n      roomId: room.roomId,\n      localEchoId: echo.getId(),\n      remoteEventId: matchId,\n    });\n  }\n};\n\nexport class SlidingSyncManager {\n  private disposed = false;\n\n  private readonly listKeys: string[];\n\n  private readonly activeRoomSubscriptions = new Set<string>();\n\n  private readonly callRoomSubscriptions = new Set<string>();\n\n  /**\n   * Rooms joined locally via reconcileRoomMembership(Join) but not yet confirmed\n   * joined by a sliding-sync response. The SDK reverts these to \"invite\" when the\n   * server still sends invite_state after a join, so we re-assert join each sync.\n   */\n  private readonly optimisticallyJoinedRoomIds = new Map<string, OptimisticJoin>();\n\n  private readonly sidebarRoomSubscriptions = new Set<string>();\n\n  private readonly spaceSubscriptions = new Set<string>();\n\n  private deferredSpaceSubscriptions = new Set<string>();\n\n  private readonly imagePackRoomSubscriptions = new Set<string>();\n\n  private deferredImagePackSubscriptions: Set<string> | null = null;\n\n  /**\n   * Room IDs that received data in the current sync cycle. Used to narrow the\n   * sync-settled unread recompute to only changed rooms instead of all rooms.\n   * Populated by onCacheRoomData, cleared after the settled listeners fire.\n   */\n  private readonly dirtyRoomIds = new Set<string>();\n\n  private roomSubscriptionSyncQueued = false;\n\n  private readonly roomTimelineLimit: number;\n\n  private readonly sidebarCache: SlidingSyncSidebarCache;\n\n  private cacheHydrationPromise: Promise<boolean> = Promise.resolve(false);\n\n  private cacheHydrationNewListener:\n    | ((eventName: string | symbol, listener: (...args: unknown[]) => void) => void)\n    | undefined;\n\n  private cacheHydrationResolve: ((hydrated: boolean) => void) | undefined;\n\n  private hydratingSidebarCache = false;\n\n  private readonly onCacheRoomData: (roomId: string, data: MSC3575RoomData) => void;\n\n  private readonly onCacheAccountData: (event: MatrixEvent) => void;\n\n  private readonly onLifecycle: (\n    state: SlidingSyncState,\n    resp: MSC3575SlidingSyncResponse | null,\n    err?: Error\n  ) => void;\n\n  private readonly onMembershipLeave: (\n    event: unknown,\n    member: { userId: string; roomId: string; membership?: string }\n  ) => void;\n\n  private listsFullyLoaded = false;\n\n  private initialListHydrationCompleted = false;\n\n  private sidebarCacheReconciled = false;\n\n  private sidebarCacheReconciliationQueued = false;\n\n  private readonly serverMembershipRoomIds = new Set<string>();\n\n  private initialSyncCompleted = false;\n\n  private syncCount = 0;\n\n  private responseProcessingStartedAt: number | undefined;\n\n  private responseProcessing = false;\n\n  private readonly responseSettledListeners = new Set<\n    (dirtyRoomIds: ReadonlySet<string>) => void\n  >();\n\n  private readonly trackedResponses = new WeakMap<\n    MSC3575SlidingSyncResponse,\n    TrackedSlidingSyncResponse\n  >();\n\n  private readonly timelineResetCompletions = new WeakMap<\n    MSC3575SlidingSyncResponse,\n    TimelineResetCompletion\n  >();\n\n  private readonly preparedRoomSubscriptions = new Map<string, Set<PreparedRoomSubscription>>();\n\n  private readonly routeActiveRoomSubscriptions = new Set<string>();\n\n  private readonly temporaryRoomSubscriptions = new Set<string>();\n\n  private readonly pendingRouteReleaseTimers = new Map<\n    string,\n    ReturnType<typeof globalThis.setTimeout>\n  >();\n\n  private requestId = 0;\n\n  private previousListCounts: Map<string, number> = new Map();\n\n  private readonly requestedListRangeEnds = new Map<string, number>();\n\n  private readonly confirmedListRangeEnds = new Map<string, number>();\n\n  /**\n   * One-shot RoomData listeners keyed by roomId, used to measure the latency\n   * between subscribeToRoom() and the first data arriving for that room.\n   * Cleaned up automatically after first fire or on unsubscribe/dispose.\n   */\n  private readonly pendingRoomDataListeners = new Map<\n    string,\n    (roomId: string, data: MSC3575RoomData) => void\n  >();\n\n  private readonly roomSubscriptionStatusListeners = new Map<\n    string,\n    Set<(loading: boolean) => void>\n  >();\n\n  private readonly hydrationStatusListeners = new Set<\n    (isHydrating: boolean, progress?: HydrationProgress) => void\n  >();\n\n  private readonly roomDataAwaitingSyncCompletion = new Set<string>();\n\n  /**\n   * Sync cycle each room subscription was requested in. A quiet room can be\n   * subscribed to without the server ever sending a RoomData envelope for it,\n   * so the loading flag needs a deadline of its own rather than waiting on\n   * pendingRoomDataListeners, which would never fire.\n   */\n  private readonly roomSubscriptionLoadingSince = new Map<string, number>();\n\n  /** Wall-clock time recorded in attach() — used to compute true initial-sync latency. */\n  private attachTime: number | null = null;\n\n  private readonly pollDeadlineMs: number;\n\n  private pollWatchdogTimer: ReturnType<typeof globalThis.setTimeout> | undefined;\n\n  private paused = false;\n\n  private pushDrainPollsLeft = 0;\n\n  private readonly resumeWaiters = new Set<() => void>();\n\n  /** Span covering the period from attach() to the first successful complete cycle. */\n  private initialSyncSpan: ReturnType<typeof Sentry.startInactiveSpan> | null = null;\n\n  public readonly slidingSync: SlidingSync;\n\n  public constructor(\n    private readonly mx: MatrixClient,\n    private readonly baseUrl: string,\n    options: SlidingSyncOptions = {}\n  ) {\n    const pollTimeoutMs = clampPositive(options.pollTimeoutMs, DEFAULT_POLL_TIMEOUT_MS);\n    this.pollDeadlineMs = pollTimeoutMs + SDK_CLIENT_TIMEOUT_BUFFER_MS + POLL_DEADLINE_MARGIN_MS;\n\n    const roomTimelineLimit = clampPositive(options.timelineLimit, ACTIVE_ROOM_TIMELINE_LIMIT);\n    this.roomTimelineLimit = roomTimelineLimit;\n    this.sidebarCache = new SlidingSyncSidebarCache(mx.getSafeUserId());\n\n    const defaultSubscription = buildEncryptedSubscription(roomTimelineLimit);\n    const lists = buildLists();\n    this.listKeys = Array.from(lists.keys());\n    lists.forEach((list, key) => {\n      this.requestedListRangeEnds.set(key, getListEndIndex(list));\n    });\n    this.slidingSync = new SlidingSync(baseUrl, lists, defaultSubscription, mx, pollTimeoutMs);\n\n    this.slidingSync.addCustomSubscription(\n      ACTIVE_ROOM_SUBSCRIPTION_KEY,\n      buildUnencryptedSubscription(roomTimelineLimit)\n    );\n    this.slidingSync.addCustomSubscription(\n      CALL_ROOM_SUBSCRIPTION_KEY,\n      buildCallRoomSubscription(roomTimelineLimit)\n    );\n    this.slidingSync.addCustomSubscription(\n      SIDEBAR_ROOM_SUBSCRIPTION_KEY,\n      buildSidebarRoomSubscription()\n    );\n    this.slidingSync.addCustomSubscription(\n      IMAGE_PACK_SUBSCRIPTION_KEY,\n      buildImagePackSubscription()\n    );\n    this.slidingSync.addCustomSubscription(SPACE_SUBSCRIPTION_KEY, buildSpaceSubscription());\n    this.slidingSync.addCustomSubscription(\n      SPACE_IMAGE_PACK_SUBSCRIPTION_KEY,\n      buildSpaceImagePackSubscription()\n    );\n\n    this.onLifecycle = (state, resp, err) => {\n      debugLog.info('sync', `Sliding sync lifecycle: ${state}`, {\n        state,\n        hasError: !!err,\n        isInitialSync: !this.initialSyncCompleted,\n      });\n\n      if (err) {\n        debugLog.error('sync', 'Sliding sync error', {\n          error: err,\n          errorMessage: err.message,\n          syncNumber: this.syncCount,\n          state,\n        });\n        Sentry.metrics.count('sable.sync.error', 1, {\n          attributes: { transport: 'sliding', state },\n        });\n      }\n\n      if (this.disposed) {\n        debugLog.warn('sync', 'Sync lifecycle called after disposal', {\n          state,\n        });\n        return;\n      }\n\n      this.armPollWatchdog();\n\n      if (state === SlidingSyncState.RequestFinished) {\n        if (!err && resp) {\n          this.responseProcessing = true;\n          this.responseProcessingStartedAt = performance.now();\n        }\n        return;\n      }\n\n      if (err || !resp || state !== SlidingSyncState.Complete) return;\n\n      this.timelineResetCompletions.get(resp)?.();\n      this.timelineResetCompletions.delete(resp);\n      for (const roomId of Object.keys(resp.rooms ?? {})) {\n        reconcileLocalEchoes(this.mx.getRoom(roomId));\n      }\n      this.recordServerMembershipRooms(resp);\n      this.reassertOptimisticJoins();\n\n      this.roomDataAwaitingSyncCompletion.forEach((roomId) =>\n        this.notifyRoomSubscriptionStatus(roomId, false)\n      );\n      this.roomDataAwaitingSyncCompletion.clear();\n\n      this.syncCount += 1;\n      this.settlePushDrain(resp);\n\n      // A subscription that saw no room data is settled once a full cycle has\n      // completed after the one it was requested in: the server had nothing to\n      // send for it. The extra cycle is the grace period for the request that\n      // actually carried the subscription.\n      this.roomSubscriptionLoadingSince.forEach((since, roomId) => {\n        if (this.syncCount < since + 2) return;\n        this.roomSubscriptionLoadingSince.delete(roomId);\n        this.notifyRoomSubscriptionStatus(roomId, false);\n      });\n      Sentry.metrics.count('sable.sync.cycle', 1, {\n        attributes: { transport: 'sliding' },\n      });\n\n      this.requestedListRangeEnds.forEach((rangeEnd, key) => {\n        this.confirmedListRangeEnds.set(key, rangeEnd);\n      });\n\n      const changes: Record<string, { previous: number; current: number; delta: number }> = {};\n      let totalRoomCount = 0;\n      let hasChanges = false;\n\n      this.listKeys.forEach((key) => {\n        const listData = this.slidingSync.getListData(key);\n        const currentCount = listData?.joinedCount ?? 0;\n        const previousCount = this.previousListCounts.get(key) ?? 0;\n\n        totalRoomCount += currentCount;\n\n        if (currentCount !== previousCount) {\n          changes[key] = {\n            previous: previousCount,\n            current: currentCount,\n            delta: currentCount - previousCount,\n          };\n          this.previousListCounts.set(key, currentCount);\n          hasChanges = true;\n        }\n      });\n\n      if (hasChanges || !this.initialSyncCompleted) {\n        debugLog.info('sync', 'Room counts changed in sync cycle', {\n          syncNumber: this.syncCount,\n          changes,\n          totalRoomCount,\n          isInitialSync: !this.initialSyncCompleted,\n        });\n      }\n\n      const syncDuration =\n        this.responseProcessingStartedAt === undefined\n          ? 0\n          : performance.now() - this.responseProcessingStartedAt;\n      this.responseProcessingStartedAt = undefined;\n\n      if (!this.initialSyncCompleted) {\n        this.initialSyncCompleted = true;\n        const initialElapsed =\n          this.attachTime != null ? performance.now() - this.attachTime : syncDuration;\n        debugLog.info('sync', 'Initial sync completed', {\n          syncNumber: this.syncCount,\n          totalRoomCount,\n          listCounts: Object.fromEntries(\n            this.listKeys.map((key) => [key, this.slidingSync.getListData(key)?.joinedCount ?? 0])\n          ),\n          timeElapsed: `${initialElapsed.toFixed(2)}ms`,\n        });\n        Sentry.metrics.distribution('sable.sync.initial_ms', initialElapsed, {\n          attributes: { transport: 'sliding' },\n        });\n        this.initialSyncSpan?.setAttributes({\n          'sync.cycles_to_ready': this.syncCount,\n          'sync.rooms_at_ready': totalRoomCount,\n        });\n        this.initialSyncSpan?.end();\n        this.initialSyncSpan = null;\n      }\n\n      this.expandListsByPage();\n      this.ensureListCoverage();\n\n      Sentry.metrics.distribution('sable.sync.processing_ms', syncDuration, {\n        attributes: { transport: 'sliding' },\n      });\n      if (syncDuration > 1000) {\n        debugLog.warn('sync', 'Slow sync cycle detected', {\n          syncNumber: this.syncCount,\n          duration: `${syncDuration.toFixed(2)}ms`,\n          totalRoomCount,\n        });\n      }\n\n      ['receipts', 'account_data'].forEach((extensionName) => {\n        const extension = resp.extensions?.[extensionName] as\n          | RoomScopedExtensionResponse\n          | undefined;\n        const rooms = extension?.rooms ?? {};\n        Object.entries(rooms).forEach(([roomId, data]) => {\n          if (extensionName === 'account_data' && Array.isArray(data) && data.length === 0) return;\n          this.dirtyRoomIds.add(roomId);\n        });\n      });\n\n      this.resolvePreparedRoomSubscriptions(resp);\n\n      globalThis.queueMicrotask(() => {\n        if (this.disposed) return;\n        this.responseProcessing = false;\n        const dirtyRoomIds = new Set(this.dirtyRoomIds);\n        this.dirtyRoomIds.clear();\n        this.responseSettledListeners.forEach((listener) => listener(dirtyRoomIds));\n      });\n    };\n\n    this.onMembershipLeave = (_event, member) => {\n      if (member.userId !== this.mx.getUserId()) return;\n      if (member.membership !== KnownMembership.Leave && member.membership !== KnownMembership.Ban)\n        return;\n      this.handleRoomLeaveSubscriptions(member.roomId);\n    };\n\n    this.onCacheRoomData = (roomId, data) => {\n      this.dirtyRoomIds.add(roomId);\n      this.sidebarCache.cacheRoom(roomId, data);\n\n      if (!this.initialListHydrationCompleted || this.hydratingSidebarCache) return;\n\n      let subscriptionsChanged = false;\n      const completedSidebarHydration = this.sidebarRoomSubscriptions.delete(roomId);\n      if (completedSidebarHydration) subscriptionsChanged = true;\n\n      if (\n        data.initial === true &&\n        !completedSidebarHydration &&\n        !this.activeRoomSubscriptions.has(roomId)\n      ) {\n        this.sidebarRoomSubscriptions.add(roomId);\n        subscriptionsChanged = true;\n      }\n\n      if (subscriptionsChanged) this.queueRoomSubscriptionSync();\n    };\n    this.onCacheAccountData = (event) => this.sidebarCache.cacheAccountData(event);\n\n    for (const roomId of options.initialRoomIds ?? []) {\n      this.subscribeToRoom(roomId);\n    }\n  }\n\n  public attach(): void {\n    debugLog.info('sync', 'Attaching sliding sync listeners', {\n      roomTimelineLimit: this.roomTimelineLimit,\n      lists: this.listKeys,\n    });\n\n    this.attachTime = performance.now();\n    this.initialSyncSpan = Sentry.startInactiveSpan({\n      name: 'sync.initial',\n      op: 'matrix.sync',\n      attributes: {\n        'sync.transport': 'sliding',\n      },\n    });\n\n    this.slidingSync.on(SlidingSyncEvent.Lifecycle, this.onLifecycle);\n    this.slidingSync.on(SlidingSyncEvent.RoomData, this.onCacheRoomData);\n    this.mx.on(RoomMemberEvent.Membership, this.onMembershipLeave);\n    this.mx.on(ClientEvent.AccountData, this.onCacheAccountData);\n\n    this.armPollWatchdog();\n\n    debugLog.info('sync', 'Sliding sync listeners attached successfully');\n  }\n\n  /**\n   * Backstop for the SDK's own `clientTimeout`, which is a JS timer and so cannot fire\n   * while a mobile webview is frozen. Re-arms itself because the SDK's abort path\n   * `continue`s without emitting a lifecycle event.\n   */\n  private armPollWatchdog(): void {\n    if (this.disposed || this.paused) return;\n    globalThis.clearTimeout(this.pollWatchdogTimer);\n    this.pollWatchdogTimer = globalThis.setTimeout(() => {\n      this.pollWatchdogTimer = undefined;\n      if (this.disposed) return;\n      debugLog.warn('sync', 'Sliding sync poll exceeded client-side deadline; cycling transport', {\n        pollDeadlineMs: this.pollDeadlineMs,\n        syncNumber: this.syncCount,\n      });\n      this.slidingSync.resend();\n      this.armPollWatchdog();\n    }, this.pollDeadlineMs);\n  }\n\n  /**\n   * Stop issuing requests without tearing the transport down. `SlidingSync.stop()` is\n   * terminal and drops the `pos` token held in `start()`, so stop/start would force a\n   * full initial sync on every resume; the request patch parks on `waitForResume()`\n   * instead.\n   */\n  public pause(): void {\n    this.pushDrainPollsLeft = 0;\n    if (this.paused || this.disposed) return;\n    this.paused = true;\n    globalThis.clearTimeout(this.pollWatchdogTimer);\n    this.pollWatchdogTimer = undefined;\n    this.slidingSync.resend();\n    debugLog.info('sync', 'Sliding sync paused');\n  }\n\n  private liftPause(): void {\n    this.paused = false;\n    this.releaseResumeWaiters();\n    this.armPollWatchdog();\n  }\n\n  public resume(): void {\n    this.pushDrainPollsLeft = 0;\n    if (!this.paused) return;\n    this.liftPause();\n    debugLog.info('sync', 'Sliding sync resumed');\n  }\n\n  /** Poll on while backgrounded, then park: to-device only arrives over a live `/sync`. */\n  public resumeForPush(): boolean {\n    if (this.disposed || !this.paused) return false;\n    this.pushDrainPollsLeft = MAX_PUSH_DRAIN_POLLS;\n    this.liftPause();\n    debugLog.info('sync', 'Sliding sync resumed to drain to-device after a push');\n    return true;\n  }\n\n  private settlePushDrain(resp: MSC3575SlidingSyncResponse): void {\n    if (this.pushDrainPollsLeft === 0) return;\n    const toDevice = resp.extensions?.to_device as { events?: unknown[] } | undefined;\n    const drained = (toDevice?.events?.length ?? 0) === 0;\n    this.pushDrainPollsLeft -= 1;\n    if (!drained && this.pushDrainPollsLeft > 0) return;\n    this.pause();\n  }\n\n  public isPaused(): boolean {\n    return this.paused;\n  }\n\n  /** Resolves on the next resume(), or immediately when not paused. */\n  public waitForResume(): Promise<void> {\n    if (!this.paused) return Promise.resolve();\n    return new Promise((resolve) => {\n      this.resumeWaiters.add(resolve);\n    });\n  }\n\n  private releaseResumeWaiters(): void {\n    const waiters = Array.from(this.resumeWaiters);\n    this.resumeWaiters.clear();\n    waiters.forEach((resolve) => resolve());\n  }\n\n  public dispose(): void {\n    if (this.disposed) return;\n\n    debugLog.info('sync', 'Disposing sliding sync', {\n      syncCount: this.syncCount,\n      initialSyncCompleted: this.initialSyncCompleted,\n    });\n\n    this.pendingRoomDataListeners.clear();\n    this.roomSubscriptionLoadingSince.clear();\n    this.optimisticallyJoinedRoomIds.clear();\n    this.responseProcessing = false;\n    this.responseSettledListeners.clear();\n    this.preparedRoomSubscriptions.clear();\n    this.pendingRouteReleaseTimers.forEach((timer) => globalThis.clearTimeout(timer));\n    this.pendingRouteReleaseTimers.clear();\n    this.routeActiveRoomSubscriptions.clear();\n    this.temporaryRoomSubscriptions.clear();\n    this.dirtyRoomIds.clear();\n    this.roomDataAwaitingSyncCompletion.clear();\n    this.roomSubscriptionStatusListeners.forEach((listeners) =>\n      listeners.forEach((listener) => listener(false))\n    );\n    this.roomSubscriptionStatusListeners.clear();\n    this.hydrationStatusListeners.forEach((listener) => listener(false));\n    this.hydrationStatusListeners.clear();\n\n    this.disposed = true;\n    this.paused = false;\n    this.pushDrainPollsLeft = 0;\n    this.releaseResumeWaiters();\n    globalThis.clearTimeout(this.pollWatchdogTimer);\n    this.pollWatchdogTimer = undefined;\n    this.slidingSync.stop();\n    this.slidingSync.removeListener(SlidingSyncEvent.Lifecycle, this.onLifecycle);\n    this.slidingSync.removeListener(SlidingSyncEvent.RoomData, this.onCacheRoomData);\n    if (this.cacheHydrationNewListener) {\n      this.slidingSync.removeListener(\n        EventEmitterEvents.NewListener,\n        this.cacheHydrationNewListener as never\n      );\n      this.cacheHydrationNewListener = undefined;\n    }\n    this.cacheHydrationResolve?.(false);\n    this.cacheHydrationResolve = undefined;\n    this.mx.removeListener(RoomMemberEvent.Membership, this.onMembershipLeave);\n    this.mx.removeListener(ClientEvent.AccountData, this.onCacheAccountData);\n    this.sidebarCache.dispose();\n\n    debugLog.info('sync', 'Sliding sync disposed successfully', {\n      totalSyncCycles: this.syncCount,\n    });\n  }\n\n  private recordServerMembershipRooms(response: MSC3575SlidingSyncResponse): void {\n    const userId = this.mx.getSafeUserId();\n    Object.entries(response.rooms ?? {}).forEach(([roomId, roomData]) => {\n      const membership = membershipOf(\n        findSelfMemberEvent(\n          [...(roomData.required_state ?? []), ...(roomData.invite_state ?? [])],\n          userId\n        )\n      );\n\n      if (membership === KnownMembership.Leave || membership === KnownMembership.Ban) {\n        this.serverMembershipRoomIds.delete(roomId);\n      } else {\n        this.serverMembershipRoomIds.add(roomId);\n      }\n    });\n  }\n\n  private reconcileSidebarCacheMembership(): void {\n    if (this.sidebarCacheReconciled || this.sidebarCacheReconciliationQueued) return;\n    this.sidebarCacheReconciliationQueued = true;\n\n    void this.cacheHydrationPromise.then(async () => {\n      if (this.disposed || this.sidebarCacheReconciled) return;\n\n      let joinedRoomIds: string[];\n      try {\n        const response = await this.mx.getJoinedRooms();\n        joinedRoomIds = response.joined_rooms;\n      } catch (error) {\n        debugLog.warn('sync', 'Skipped sidebar cache reconciliation: joined rooms unavailable', {\n          error: error instanceof Error ? error.message : String(error),\n        });\n        return;\n      }\n\n      if (this.disposed || this.sidebarCacheReconciled) return;\n      this.sidebarCacheReconciled = true;\n\n      const validRoomIds = new Set([...this.serverMembershipRoomIds, ...joinedRoomIds]);\n\n      this.sidebarCache.clearInviteStateForRooms(joinedRoomIds);\n\n      joinedRoomIds.forEach((roomId) => {\n        const room = this.mx.getRoom(roomId);\n        if (room?.getMyMembership() === (KnownMembership.Invite as string)) {\n          this.assertLocalJoin(room);\n        }\n      });\n\n      const removedRoomIds = this.sidebarCache.reconcileRooms(validRoomIds);\n      removedRoomIds.forEach((roomId) => {\n        this.mx.getRoom(roomId)?.updateMyMembership(KnownMembership.Leave);\n        this.unsubscribeFromRoom(roomId);\n      });\n\n      if (removedRoomIds.length > 0) {\n        debugLog.info('sync', 'Removed stale rooms from the sliding sync sidebar cache', {\n          removedRoomCount: removedRoomIds.length,\n          joinedRoomCount: joinedRoomIds.length,\n          observedRoomCount: this.serverMembershipRoomIds.size,\n        });\n      }\n    });\n  }\n\n  public getDiagnostics(): SlidingSyncDiagnostics {\n    return {\n      baseUrl: this.baseUrl,\n      timelineLimit: this.roomTimelineLimit,\n      lists: this.listKeys.map((key) => {\n        const listData = this.slidingSync.getListData(key);\n        const params = this.slidingSync.getListParams(key);\n        return {\n          key,\n          knownCount: listData?.joinedCount ?? 0,\n          rangeEnd: this.confirmedListRangeEnds.get(key) ?? -1,\n          requestedRangeEnd: getListEndIndex(params),\n        };\n      }),\n    };\n  }\n\n  public prepareSidebarCacheHydration(): void {\n    if (this.disposed || this.cacheHydrationNewListener) return;\n\n    this.cacheHydrationPromise = new Promise<boolean>((resolve) => {\n      this.cacheHydrationResolve = resolve;\n    });\n\n    this.cacheHydrationNewListener = (eventName) => {\n      if (eventName !== SlidingSyncEvent.RoomData) return;\n      const listener = this.cacheHydrationNewListener;\n      if (listener) {\n        this.slidingSync.removeListener(EventEmitterEvents.NewListener, listener as never);\n      }\n      this.cacheHydrationNewListener = undefined;\n\n      globalThis.queueMicrotask(() => {\n        this.hydratingSidebarCache = true;\n        void this.sidebarCache\n          .hydrate(this.mx, this.slidingSync)\n          .then((hydrated) => this.cacheHydrationResolve?.(hydrated))\n          .catch(() => this.cacheHydrationResolve?.(false))\n          .finally(() => {\n            this.hydratingSidebarCache = false;\n            this.cacheHydrationResolve = undefined;\n          });\n      });\n    };\n\n    this.slidingSync.on(EventEmitterEvents.NewListener, this.cacheHydrationNewListener as never);\n  }\n\n  public waitForSidebarCacheHydration(): Promise<boolean> {\n    return this.cacheHydrationPromise;\n  }\n\n  private expandListsByPage(): void {\n    if (!this.initialSyncCompleted) return;\n    if (this.initialListHydrationCompleted) return;\n\n    let allListsComplete = true;\n    let expandedAny = false;\n\n    const expansionStartTime = performance.now();\n    const expansionDetails: Record<\n      string,\n      {\n        status: string;\n        knownCount: number;\n        currentEnd?: number;\n        desiredEnd?: number;\n        previousEnd?: number;\n        newEnd?: number;\n        roomsToLoad?: number;\n      }\n    > = {};\n\n    this.listKeys.forEach((key) => {\n      const listData = this.slidingSync.getListData(key);\n      const knownCount = listData?.joinedCount ?? 0;\n      if (knownCount <= 0) {\n        expansionDetails[key] = { status: 'empty', knownCount: 0 };\n        return;\n      }\n\n      const existing = this.slidingSync.getListParams(key);\n      const requestedEnd = getListEndIndex(existing);\n      const currentEnd = this.confirmedListRangeEnds.get(key) ?? -1;\n\n      const maxEnd = knownCount - 1;\n\n      if (requestedEnd > currentEnd) {\n        allListsComplete = false;\n        expansionDetails[key] = {\n          status: 'awaiting-response',\n          knownCount,\n          currentEnd,\n          desiredEnd: requestedEnd,\n        };\n        return;\n      }\n\n      if (currentEnd >= maxEnd) {\n        expansionDetails[key] = { status: 'complete', knownCount, currentEnd };\n        return;\n      }\n\n      allListsComplete = false;\n\n      const desiredEnd = Math.min(maxEnd, currentEnd + LIST_PAGE_SIZE);\n\n      if (desiredEnd === currentEnd) {\n        expansionDetails[key] = {\n          status: 'complete',\n          knownCount,\n          currentEnd,\n          desiredEnd,\n        };\n        return;\n      }\n\n      this.slidingSync.setListRanges(key, [[0, desiredEnd]]);\n      this.requestedListRangeEnds.set(key, desiredEnd);\n      expandedAny = true;\n\n      expansionDetails[key] = {\n        status: 'expanding',\n        knownCount,\n        previousEnd: currentEnd,\n        newEnd: desiredEnd,\n        roomsToLoad: desiredEnd - currentEnd,\n      };\n\n      debugLog.info('sync', `Expanding list \"${key}\" by page`, {\n        list: key,\n        knownCount,\n        previousEnd: currentEnd,\n        newEnd: desiredEnd,\n        roomsToLoad: desiredEnd - currentEnd,\n      });\n    });\n\n    const expansionDuration = performance.now() - expansionStartTime;\n    const hasExpansions = Object.values(expansionDetails).some((d) => d.status === 'expanding');\n    if (allListsComplete) {\n      if (!this.listsFullyLoaded) {\n        this.listsFullyLoaded = true;\n        this.initialListHydrationCompleted = true;\n        this.hydrationStatusListeners.forEach((listener) => listener(false));\n        this.reconcileSidebarCacheMembership();\n        globalThis.setTimeout(() => this.flushDeferredSubscriptions(), 0);\n        log.log(`Sliding Sync all lists fully loaded for ${this.mx.getUserId()}`);\n        const totalRooms =\n          (this.slidingSync.getListData(LIST_JOINED)?.joinedCount ?? 0) +\n          (this.slidingSync.getListData(LIST_INVITES)?.joinedCount ?? 0);\n        const listsLoadedMs =\n          this.attachTime != null ? Math.round(performance.now() - this.attachTime) : 0;\n        Sentry.metrics.distribution('sable.sync.lists_loaded_ms', listsLoadedMs, {\n          attributes: { transport: 'sliding' },\n        });\n        Sentry.metrics.gauge('sable.sync.total_rooms', totalRooms, {\n          attributes: { transport: 'sliding' },\n        });\n      }\n    } else if (expandedAny) {\n      if (this.listsFullyLoaded) {\n        this.listsFullyLoaded = false;\n      }\n      this.hydrationStatusListeners.forEach((listener) =>\n        listener(true, this.getHydrationProgress())\n      );\n      log.log(`Sliding Sync lists expanding... for ${this.mx.getUserId()}`);\n    }\n\n    if (hasExpansions) {\n      debugLog.info('sync', 'List expansion completed', {\n        syncNumber: this.syncCount,\n        lists: expansionDetails,\n        timeElapsed: `${expansionDuration.toFixed(2)}ms`,\n      });\n    }\n\n    if (expansionDuration > 500) {\n      debugLog.warn('sync', 'Slow list expansion detected', {\n        duration: `${expansionDuration.toFixed(2)}ms`,\n        expandedLists: Object.keys(expansionDetails).filter(\n          (key) => expansionDetails[key]?.status === 'expanding'\n        ),\n      });\n    }\n  }\n\n  // Paging stops once every list is covered, but the counts keep growing, and a state\n  // change does not bump a room back into the window.\n  private ensureListCoverage(): void {\n    if (!this.initialListHydrationCompleted) return;\n\n    this.listKeys.forEach((key) => {\n      const knownCount = this.slidingSync.getListData(key)?.joinedCount ?? 0;\n      const desiredEnd = knownCount - 1;\n      if (desiredEnd <= getListEndIndex(this.slidingSync.getListParams(key))) return;\n\n      this.slidingSync.setListRanges(key, [[0, desiredEnd]]);\n      this.requestedListRangeEnds.set(key, desiredEnd);\n      debugLog.info('sync', `Extended list \"${key}\" to cover newly joined rooms`, {\n        list: key,\n        newEnd: desiredEnd,\n      });\n    });\n  }\n\n  public ensureListRegistered(listKey: string, updateArgs: PartialSlidingSyncRequest): MSC3575List {\n    let list = this.slidingSync.getListParams(listKey);\n    if (!list) {\n      list = {\n        ranges: [[0, LIST_PAGE_SIZE - 1]],\n        timeline_limit: LIST_TIMELINE_LIMIT,\n        required_state: buildListRequiredState(),\n        ...updateArgs,\n      };\n    } else {\n      const updated = { ...list, ...updateArgs };\n      if (JSON.stringify(list) === JSON.stringify(updated)) return list;\n      list = updated;\n    }\n\n    try {\n      if (updateArgs.ranges && Object.keys(updateArgs).length === 1) {\n        this.slidingSync.setListRanges(listKey, updateArgs.ranges);\n      } else {\n        this.slidingSync.setList(listKey, list);\n      }\n    } catch (error) {\n      debugLog.warn('sync', `Failed to update list \"${listKey}\"`, {\n        list: listKey,\n        error: error instanceof Error ? error.message : String(error),\n        updateType: updateArgs.ranges && Object.keys(updateArgs).length === 1 ? 'ranges' : 'full',\n      });\n    }\n    return this.slidingSync.getListParams(listKey) ?? list;\n  }\n\n  public isRoomActive(roomId: string): boolean {\n    return this.activeRoomSubscriptions.has(roomId);\n  }\n\n  public getHydrationProgress(): HydrationProgress {\n    let loadedRooms = 0;\n    let totalRooms = 0;\n    this.listKeys.forEach((key) => {\n      const existing = this.slidingSync.getListData(key);\n      const knownCount = existing?.joinedCount ?? 0;\n      const currentEnd = this.confirmedListRangeEnds.get(key) ?? -1;\n\n      if (knownCount > 0) {\n        totalRooms += knownCount;\n        loadedRooms += Math.min(knownCount, currentEnd + 1);\n      }\n    });\n    return { loadedRooms, totalRooms };\n  }\n\n  public isSyncingRoomData(): boolean {\n    return !this.listsFullyLoaded;\n  }\n\n  public onHydrationStatusChange(\n    listener: (isHydrating: boolean, progress?: HydrationProgress) => void\n  ): () => void {\n    this.hydrationStatusListeners.add(listener);\n    listener(\n      this.isSyncingRoomData(),\n      this.isSyncingRoomData() ? this.getHydrationProgress() : undefined\n    );\n    return () => {\n      this.hydrationStatusListeners.delete(listener);\n    };\n  }\n\n  public isResponseProcessing(): boolean {\n    return this.responseProcessing;\n  }\n\n  public subscribeToResponseSettled(\n    listener: (dirtyRoomIds: ReadonlySet<string>) => void\n  ): () => void {\n    this.responseSettledListeners.add(listener);\n    return () => this.responseSettledListeners.delete(listener);\n  }\n\n  public trackSubscriptionRequest(\n    roomIds: Iterable<string>\n  ): (response: MSC3575SlidingSyncResponse) => void {\n    const requestId = ++this.requestId;\n    const subscriptionRoomIds = new Set(roomIds);\n    return (response) => {\n      this.trackedResponses.set(response, { requestId, subscriptionRoomIds });\n    };\n  }\n\n  public trackTimelineResetCompletion(\n    response: MSC3575SlidingSyncResponse,\n    completion: TimelineResetCompletion\n  ): void {\n    this.timelineResetCompletions.set(response, completion);\n  }\n\n  public prepareRoomSubscription(roomId: string, listener: () => void): () => void {\n    this.cancelPendingRouteRelease(roomId);\n    const wasActive = this.isRoomActive(roomId);\n    const prepared: PreparedRoomSubscription = {\n      afterRequestId: this.requestId,\n      requiresSubscriptionResponse: !wasActive,\n      listener,\n    };\n    const listeners = this.preparedRoomSubscriptions.get(roomId) ?? new Set();\n    listeners.add(prepared);\n    this.preparedRoomSubscriptions.set(roomId, listeners);\n    if (!wasActive) this.subscribeToRoom(roomId);\n    else this.slidingSync.resend();\n    if (!wasActive && this.isRoomActive(roomId)) {\n      this.temporaryRoomSubscriptions.add(roomId);\n    }\n\n    return () => {\n      listeners.delete(prepared);\n      if (listeners.size === 0) this.preparedRoomSubscriptions.delete(roomId);\n    };\n  }\n\n  public releaseRoomSubscriptionUnlessRouted(roomId: string): void {\n    this.cancelPendingRouteRelease(roomId);\n    if (!this.temporaryRoomSubscriptions.has(roomId)) return;\n    if (this.routeActiveRoomSubscriptions.has(roomId)) {\n      this.temporaryRoomSubscriptions.delete(roomId);\n      return;\n    }\n\n    const timer = globalThis.setTimeout(() => {\n      this.pendingRouteReleaseTimers.delete(roomId);\n      if (\n        this.temporaryRoomSubscriptions.has(roomId) &&\n        !this.routeActiveRoomSubscriptions.has(roomId)\n      ) {\n        this.unsubscribeFromRoom(roomId);\n      }\n    }, ROUTE_ADOPTION_TIMEOUT_MS);\n    this.pendingRouteReleaseTimers.set(roomId, timer);\n  }\n\n  private cancelPendingRouteRelease(roomId: string): void {\n    const timer = this.pendingRouteReleaseTimers.get(roomId);\n    if (timer === undefined) return;\n    globalThis.clearTimeout(timer);\n    this.pendingRouteReleaseTimers.delete(roomId);\n  }\n\n  public isRoomSubscriptionTemporary(roomId: string): boolean {\n    return this.temporaryRoomSubscriptions.has(roomId);\n  }\n\n  private resolvePreparedRoomSubscriptions(response: MSC3575SlidingSyncResponse): void {\n    const tracked = this.trackedResponses.get(response);\n    if (!tracked) return;\n\n    this.preparedRoomSubscriptions.forEach((listeners, roomId) => {\n      [...listeners].forEach((prepared) => {\n        const ready =\n          tracked.requestId > prepared.afterRequestId &&\n          (!prepared.requiresSubscriptionResponse || tracked.subscriptionRoomIds.has(roomId));\n        if (!ready) return;\n        listeners.delete(prepared);\n        prepared.listener();\n      });\n      if (listeners.size === 0) this.preparedRoomSubscriptions.delete(roomId);\n    });\n  }\n\n  /**\n   * Re-assert join for rooms the SDK reverted to \"invite\" because the server's\n   * sliding-sync proxy still sent invite_state after a successful join. Runs\n   * after the SDK has finished processing all room data for the cycle (Complete\n   * fires post-processing) and before the responseSettled microtask that drives\n   * unread computation, so the app sees the corrected membership.\n   *\n   * Release is driven by sanitizeOptimisticJoinResponse, not by the SDK\n   * membership read back here: that would release the room merely because\n   * nothing in the cycle touched it, letting a later stale invite win for good.\n   */\n  private reassertOptimisticJoins(): void {\n    if (this.optimisticallyJoinedRoomIds.size === 0) return;\n    for (const [roomId, tracked] of this.optimisticallyJoinedRoomIds) {\n      const room = this.mx.getRoom(roomId);\n      if (!room) {\n        this.optimisticallyJoinedRoomIds.delete(roomId);\n        continue;\n      }\n      this.assertLocalJoin(room);\n\n      if (\n        !tracked.verificationRequested &&\n        this.syncCount - tracked.joinedAtSyncCount >= OPTIMISTIC_JOIN_VERIFY_AFTER_CYCLES\n      ) {\n        tracked.verificationRequested = true;\n        this.verifyOptimisticJoin(roomId);\n      }\n\n      if (this.syncCount - tracked.lastSeenSyncCount >= OPTIMISTIC_JOIN_MAX_SYNC_CYCLES) {\n        debugLog.warn('sync', 'Stopped re-asserting optimistic join: room no longer reported', {\n          roomId,\n          syncCycles: OPTIMISTIC_JOIN_MAX_SYNC_CYCLES,\n        });\n        this.optimisticallyJoinedRoomIds.delete(roomId);\n      }\n    }\n  }\n\n  /**\n   * Asks the authoritative /joined_rooms who is right when the disagreement\n   * lasts. A \"no\" means our /join is stale (a fresh invite after a kick, or a\n   * join that never committed), so stop overriding the server. Errors keep the\n   * optimistic join: an unreachable server must not strand the user on an invite.\n   */\n  private verifyOptimisticJoin(roomId: string): void {\n    void this.mx\n      .getJoinedRooms()\n      .then((response) => {\n        if (this.disposed || !this.optimisticallyJoinedRoomIds.has(roomId)) return;\n        if (response.joined_rooms.includes(roomId)) return;\n\n        this.optimisticallyJoinedRoomIds.delete(roomId);\n        debugLog.warn('sync', 'Stopped re-asserting optimistic join: server reports not joined', {\n          roomId,\n        });\n        Sentry.addBreadcrumb({\n          category: 'sync.sliding',\n          message: 'Stopped re-asserting optimistic join: server reports not joined',\n          level: 'warning',\n        });\n      })\n      .catch((error: unknown) => {\n        debugLog.warn('sync', 'Could not verify optimistic join; still assuming joined', {\n          roomId,\n          error: error instanceof Error ? error.message : String(error),\n        });\n      });\n  }\n\n  /**\n   * Room.recalculate() derives selfMembership from the m.room.member event, so\n   * fixing only one of the two lets the next recalculate() undo it. The crypto\n   * layer reads membership from that event too.\n   */\n  private assertLocalJoin(room: Room): void {\n    if (room.getMyMembership() !== (KnownMembership.Join as string)) {\n      room.updateMyMembership(KnownMembership.Join);\n    }\n    this.repairSelfJoinMemberEvent(room);\n  }\n\n  private repairSelfJoinMemberEvent(room: Room): void {\n    const myUserId = this.mx.getUserId();\n    if (!myUserId) return;\n    const roomState = room.getLiveTimeline().getState(EventTimeline.FORWARDS);\n    if (!roomState) return;\n    const existing = roomState.getStateEvents(EventType.RoomMember, myUserId)?.getContent();\n    if (existing?.membership === KnownMembership.Join) return;\n\n    roomState.setStateEvents([\n      new MatrixEvent(buildSelfJoinEvent(room.roomId, myUserId, existing)),\n    ]);\n  }\n\n  /**\n   * Strips the stale stripped invite some servers keep sending for a room we\n   * already joined, before the SDK derives an invite from it.\n   *\n   * Which field reports the membership varies: Synapse omits required_state for\n   * invites, and Continuwuity does not substitute the \"$ME\" state key at all, so\n   * our own member event never appears in its required_state.\n   */\n  public sanitizeOptimisticJoinResponse(resp: MSC3575SlidingSyncResponse | null): void {\n    if (!resp?.rooms || this.optimisticallyJoinedRoomIds.size === 0) return;\n    const myUserId = this.mx.getUserId();\n    if (!myUserId) return;\n\n    for (const [roomId, tracked] of this.optimisticallyJoinedRoomIds) {\n      const roomData = resp.rooms[roomId];\n      if (!roomData) continue;\n\n      tracked.lastSeenSyncCount = this.syncCount;\n\n      const stateMember = findSelfMemberEvent(roomData.required_state ?? [], myUserId);\n      const reported =\n        membershipOf(stateMember) ??\n        membershipOf(findSelfMemberEvent(roomData.timeline ?? [], myUserId));\n      const staleInvite = findSelfMemberEvent(roomData.invite_state ?? [], myUserId);\n\n      if (\n        reported !== undefined &&\n        reported !== (KnownMembership.Invite as string) &&\n        reported !== (KnownMembership.Knock as string)\n      ) {\n        // Our join, or something newer we must not suppress.\n        this.optimisticallyJoinedRoomIds.delete(roomId);\n        // The SDK ignores required_state whenever invite_state is present.\n        if (reported === (KnownMembership.Join as string)) delete roomData.invite_state;\n        continue;\n      }\n\n      if (!roomData.invite_state) {\n        // The server stopped treating us as invited.\n        this.optimisticallyJoinedRoomIds.delete(roomId);\n        continue;\n      }\n\n      // Replaced, not removed: the sidebar cache only clears its persisted\n      // invite once required_state says join.\n      delete roomData.invite_state;\n      roomData.required_state = [\n        ...(roomData.required_state ?? []).filter((event) => !isSelfMemberEvent(event, myUserId)),\n        buildSelfJoinEvent(roomId, myUserId, staleInvite?.content ?? stateMember?.content),\n      ];\n\n      debugLog.info('sync', 'Replaced stale invite data for optimistically joined room', {\n        roomId,\n        reported,\n        syncCycle: this.syncCount,\n      });\n      Sentry.addBreadcrumb({\n        category: 'sync.sliding',\n        message: 'Replaced stale invite data for optimistically joined room',\n        level: 'info',\n        data: { reported, syncCycle: this.syncCount },\n      });\n    }\n  }\n\n  public reconcileRoomMembership(\n    roomId: string,\n    membership: KnownMembership.Join | KnownMembership.Leave\n  ): void {\n    const room = this.mx.getRoom(roomId);\n    room?.updateMyMembership(membership);\n\n    if (membership === KnownMembership.Join) {\n      if (room) this.repairSelfJoinMemberEvent(room);\n      // The cache clears its own invite only once required_state says join, which\n      // a server without \"$ME\" substitution never sends, so drop it here.\n      this.sidebarCache.clearInviteStateForRooms([roomId]);\n      // Track the room so we can re-assert join if the SDK reverts it while the\n      // server's sliding-sync proxy still reports the room in the invite list.\n      this.optimisticallyJoinedRoomIds.set(roomId, {\n        joinedAtSyncCount: this.syncCount,\n        lastSeenSyncCount: this.syncCount,\n        verificationRequested: false,\n      });\n      // Subscribe so the next sync pulls real joined member state into the\n      // room's current state, letting recalculate() see \"join\" not \"invite\".\n      this.subscribeToRoom(roomId);\n      return;\n    }\n\n    if (membership === KnownMembership.Leave) {\n      this.optimisticallyJoinedRoomIds.delete(roomId);\n      this.handleRoomLeaveSubscriptions(roomId);\n      this.mx.store.removeRoom(roomId);\n    }\n  }\n\n  private handleRoomLeaveSubscriptions(roomId: string): void {\n    this.sidebarCache.removeRoom(roomId);\n    const removedPassiveSubscription = this.removePassiveSubscriptions(roomId);\n    if (this.activeRoomSubscriptions.has(roomId)) {\n      this.unsubscribeFromRoom(roomId);\n    } else if (removedPassiveSubscription) {\n      this.queueRoomSubscriptionSync();\n    }\n  }\n\n  // Includes the deferred sets so a later flush cannot resubscribe a room we left.\n  private removePassiveSubscriptions(roomId: string): boolean {\n    const removedSpace = this.spaceSubscriptions.delete(roomId);\n    const removedSidebar = this.sidebarRoomSubscriptions.delete(roomId);\n    const removedImagePack = this.imagePackRoomSubscriptions.delete(roomId);\n    this.deferredSpaceSubscriptions.delete(roomId);\n    this.deferredImagePackSubscriptions?.delete(roomId);\n    return removedSpace || removedSidebar || removedImagePack;\n  }\n\n  private flushDeferredSubscriptions(): void {\n    if (this.disposed || !this.listsFullyLoaded) return;\n\n    const spaces = this.deferredSpaceSubscriptions;\n    this.deferredSpaceSubscriptions = new Set();\n    this.setSpaceSubscriptions(spaces);\n\n    const imagePacks = this.deferredImagePackSubscriptions;\n    this.deferredImagePackSubscriptions = null;\n    if (imagePacks) this.setImagePackSubscriptions(imagePacks);\n  }\n\n  private queueRoomSubscriptionSync(): void {\n    if (this.disposed || this.roomSubscriptionSyncQueued) return;\n    this.roomSubscriptionSyncQueued = true;\n    globalThis.queueMicrotask(() => {\n      this.roomSubscriptionSyncQueued = false;\n      if (!this.disposed) this.syncRoomSubscriptions();\n    });\n  }\n\n  private syncRoomSubscriptions(): void {\n    // MSC4186 rejects a request carrying more than MAX_ROOM_SUBSCRIPTIONS with\n    // M_INVALID_PARAM, so fill by priority and drop the rest.\n    const desiredSubscriptions = new Set<string>();\n    let dropped = 0;\n    [\n      this.callRoomSubscriptions,\n      this.activeRoomSubscriptions,\n      this.sidebarRoomSubscriptions,\n      this.spaceSubscriptions,\n      this.imagePackRoomSubscriptions,\n    ].forEach((group) =>\n      group.forEach((roomId) => {\n        if (desiredSubscriptions.has(roomId)) return;\n        if (desiredSubscriptions.size >= MAX_ROOM_SUBSCRIPTIONS) {\n          dropped += 1;\n          return;\n        }\n        desiredSubscriptions.add(roomId);\n      })\n    );\n    if (dropped > 0) {\n      log.warn(\n        `Sliding Sync dropped ${dropped} room subscriptions over the ${MAX_ROOM_SUBSCRIPTIONS} cap`\n      );\n    }\n\n    desiredSubscriptions.forEach((roomId) => {\n      if (this.callRoomSubscriptions.has(roomId)) {\n        this.slidingSync.useCustomSubscription(roomId, CALL_ROOM_SUBSCRIPTION_KEY);\n      } else if (this.activeRoomSubscriptions.has(roomId)) {\n        this.slidingSync.useCustomSubscription(roomId, ACTIVE_ROOM_SUBSCRIPTION_KEY);\n      } else if (this.sidebarRoomSubscriptions.has(roomId)) {\n        this.slidingSync.useCustomSubscription(roomId, SIDEBAR_ROOM_SUBSCRIPTION_KEY);\n      } else if (this.spaceSubscriptions.has(roomId)) {\n        this.slidingSync.useCustomSubscription(\n          roomId,\n          this.imagePackRoomSubscriptions.has(roomId)\n            ? SPACE_IMAGE_PACK_SUBSCRIPTION_KEY\n            : SPACE_SUBSCRIPTION_KEY\n        );\n      } else {\n        this.slidingSync.useCustomSubscription(roomId, IMAGE_PACK_SUBSCRIPTION_KEY);\n      }\n    });\n\n    this.slidingSync.modifyRoomSubscriptions(desiredSubscriptions);\n  }\n\n  private pauseUnconfirmedListExpansion(): void {\n    this.listKeys.forEach((key) => {\n      const confirmedEnd = this.confirmedListRangeEnds.get(key) ?? -1;\n      if (confirmedEnd < 0) return;\n\n      const requestedEnd = getListEndIndex(this.slidingSync.getListParams(key));\n      if (requestedEnd <= confirmedEnd) return;\n\n      this.slidingSync.setListRanges(key, [[0, confirmedEnd]]);\n      this.requestedListRangeEnds.set(key, confirmedEnd);\n    });\n  }\n\n  public setImagePackSubscriptions(roomIds: Iterable<string>): void {\n    if (this.disposed) return;\n    const next = new Set(roomIds);\n    if (!this.listsFullyLoaded) {\n      this.deferredImagePackSubscriptions = next;\n      return;\n    }\n    const unchanged =\n      next.size === this.imagePackRoomSubscriptions.size &&\n      [...next].every((roomId) => this.imagePackRoomSubscriptions.has(roomId));\n    if (unchanged) return;\n\n    this.imagePackRoomSubscriptions.clear();\n    next.forEach((roomId) => this.imagePackRoomSubscriptions.add(roomId));\n    this.syncRoomSubscriptions();\n  }\n\n  /* Listen for raw sliding-sync data for one room */\n  public onRoomData(roomId: string, listener: () => void): () => void {\n    const handler = (dataRoomId: string) => {\n      // Let matrix-js-sdk finish applying the room data before reading state events\n      if (dataRoomId === roomId) globalThis.setTimeout(listener, 0);\n    };\n    this.slidingSync.on(SlidingSyncEvent.RoomData, handler);\n    return () => this.slidingSync.removeListener(SlidingSyncEvent.RoomData, handler);\n  }\n\n  public onRoomSubscriptionStatus(\n    roomId: string,\n    listener: (loading: boolean) => void\n  ): () => void {\n    const listeners = this.roomSubscriptionStatusListeners.get(roomId) ?? new Set();\n    listeners.add(listener);\n    this.roomSubscriptionStatusListeners.set(roomId, listeners);\n    listener(this.isRoomSubscriptionLoading(roomId));\n\n    return () => {\n      listeners.delete(listener);\n      if (listeners.size === 0) this.roomSubscriptionStatusListeners.delete(roomId);\n    };\n  }\n\n  public isRoomSubscriptionLoading(roomId: string): boolean {\n    return (\n      this.roomSubscriptionLoadingSince.has(roomId) ||\n      this.roomDataAwaitingSyncCompletion.has(roomId)\n    );\n  }\n\n  private notifyRoomSubscriptionStatus(roomId: string, loading: boolean): void {\n    this.roomSubscriptionStatusListeners.get(roomId)?.forEach((listener) => listener(loading));\n  }\n\n  private addActiveRoomSubscription(roomId: string): boolean {\n    if (this.activeRoomSubscriptions.has(roomId)) return false;\n    const room = this.mx.getRoom(roomId);\n    const isEncrypted = this.mx.isRoomEncrypted(roomId);\n    this.activeRoomSubscriptions.add(roomId);\n    this.pauseUnconfirmedListExpansion();\n    log.log(`Sliding Sync active room subscription added: ${roomId}`);\n    debugLog.info('sync', 'Room subscription requested (sliding)', {\n      encrypted: isEncrypted,\n      unknownRoom: !room,\n      activeSubscriptions: this.activeRoomSubscriptions.size,\n      syncCycle: this.syncCount,\n    });\n    Sentry.addBreadcrumb({\n      category: 'sync.sliding',\n      message: 'Subscribed to room (active)',\n      level: 'info',\n      data: {\n        encrypted: isEncrypted,\n        activeSubscriptions: this.activeRoomSubscriptions.size,\n      },\n    });\n    const existingListener = this.pendingRoomDataListeners.get(roomId);\n    if (existingListener) {\n      this.slidingSync.removeListener(SlidingSyncEvent.RoomData, existingListener);\n    }\n    const subscribeMs = performance.now();\n    const onFirstRoomData = (dataRoomId: string) => {\n      if (dataRoomId !== roomId) return;\n      if (this.hydratingSidebarCache) return;\n      const latencyMs = Math.round(performance.now() - subscribeMs);\n      const subscribedRoom = this.mx.getRoom(roomId);\n      const eventCount = subscribedRoom?.getLiveTimeline().getEvents().length ?? 0;\n      debugLog.info('sync', 'Room subscription: first data received (sliding)', {\n        latencyMs,\n        syncCycle: this.syncCount,\n        eventCount,\n      });\n      Sentry.metrics.distribution('sable.sync.room_sub_latency_ms', latencyMs, {\n        attributes: { transport: 'sliding' },\n      });\n      Sentry.metrics.distribution('sable.sync.room_sub_event_count', eventCount, {\n        attributes: { transport: 'sliding' },\n      });\n      Sentry.addBreadcrumb({\n        category: 'sync.sliding',\n        message: `Room subscription data arrived (${eventCount} events, ${latencyMs}ms)`,\n        level: 'info',\n        data: { latencyMs, eventCount, syncCycle: this.syncCount },\n      });\n      this.slidingSync.removeListener(SlidingSyncEvent.RoomData, onFirstRoomData);\n      this.pendingRoomDataListeners.delete(roomId);\n      this.roomSubscriptionLoadingSince.delete(roomId);\n      this.roomDataAwaitingSyncCompletion.add(roomId);\n    };\n    this.pendingRoomDataListeners.set(roomId, onFirstRoomData);\n    this.roomSubscriptionLoadingSince.set(roomId, this.syncCount);\n    this.slidingSync.on(SlidingSyncEvent.RoomData, onFirstRoomData);\n    this.notifyRoomSubscriptionStatus(roomId, true);\n    return true;\n  }\n\n  private removeActiveRoomSubscription(roomId: string): boolean {\n    if (!this.activeRoomSubscriptions.has(roomId)) return false;\n    this.cancelPendingRouteRelease(roomId);\n    this.temporaryRoomSubscriptions.delete(roomId);\n    const pendingListener = this.pendingRoomDataListeners.get(roomId);\n    if (pendingListener) {\n      this.slidingSync.removeListener(SlidingSyncEvent.RoomData, pendingListener);\n      this.pendingRoomDataListeners.delete(roomId);\n    }\n    this.roomSubscriptionLoadingSince.delete(roomId);\n    this.roomDataAwaitingSyncCompletion.delete(roomId);\n    this.notifyRoomSubscriptionStatus(roomId, false);\n    this.activeRoomSubscriptions.delete(roomId);\n    log.log(`Sliding Sync active room subscription removed: ${roomId}`);\n    debugLog.info('sync', 'Room subscription removed (sliding)', {\n      remainingSubscriptions: this.activeRoomSubscriptions.size,\n      syncCycle: this.syncCount,\n    });\n    return true;\n  }\n\n  private reportActiveSubscriptionCount(): void {\n    Sentry.metrics.gauge('sable.sync.active_subscriptions', this.activeRoomSubscriptions.size, {\n      attributes: { transport: 'sliding' },\n    });\n  }\n\n  public setActiveRoomSubscriptions(roomIds: Iterable<string>): void {\n    if (this.disposed) return;\n    const next = new Set(roomIds);\n    this.routeActiveRoomSubscriptions.clear();\n    next.forEach((roomId) => {\n      this.routeActiveRoomSubscriptions.add(roomId);\n      this.temporaryRoomSubscriptions.delete(roomId);\n    });\n    this.pendingRouteReleaseTimers.forEach((_timer, roomId) =>\n      this.cancelPendingRouteRelease(roomId)\n    );\n    let changed = false;\n\n    this.activeRoomSubscriptions.forEach((roomId) => {\n      if (!next.has(roomId)) changed = this.removeActiveRoomSubscription(roomId) || changed;\n    });\n    next.forEach((roomId) => {\n      if (!this.activeRoomSubscriptions.has(roomId)) {\n        changed = this.addActiveRoomSubscription(roomId) || changed;\n      }\n    });\n\n    if (!changed) return;\n    this.syncRoomSubscriptions();\n    this.reportActiveSubscriptionCount();\n  }\n\n  public getActiveRoomSubscriptionIds(): string[] {\n    return [...this.activeRoomSubscriptions];\n  }\n\n  public subscribeToRoom(roomId: string): void {\n    this.cancelPendingRouteRelease(roomId);\n    this.temporaryRoomSubscriptions.delete(roomId);\n    if (this.disposed || !this.addActiveRoomSubscription(roomId)) return;\n    this.syncRoomSubscriptions();\n    this.reportActiveSubscriptionCount();\n  }\n\n  public subscribeToCallRoom(roomId: string): CallRoomSubscription {\n    if (this.disposed) return () => undefined;\n\n    this.callRoomSubscriptions.add(roomId);\n    this.syncRoomSubscriptions();\n    return () => this.unsubscribeFromCallRoom(roomId);\n  }\n\n  public unsubscribeFromCallRoom(roomId: string): void {\n    if (this.disposed || !this.callRoomSubscriptions.delete(roomId)) return;\n    this.syncRoomSubscriptions();\n  }\n\n  public unsubscribeFromRoom(roomId: string): void {\n    this.cancelPendingRouteRelease(roomId);\n    if (this.disposed || !this.removeActiveRoomSubscription(roomId)) return;\n    this.syncRoomSubscriptions();\n    this.reportActiveSubscriptionCount();\n  }\n\n  public setSpaceSubscriptions(roomIds: Iterable<string>): void {\n    if (this.disposed) return;\n    const next = new Set(roomIds);\n    if (!this.listsFullyLoaded) {\n      this.deferredSpaceSubscriptions = next;\n      return;\n    }\n    const unchanged =\n      next.size === this.spaceSubscriptions.size &&\n      [...next].every((roomId) => this.spaceSubscriptions.has(roomId));\n    if (unchanged) return;\n\n    this.spaceSubscriptions.clear();\n    next.forEach((roomId) => this.spaceSubscriptions.add(roomId));\n    this.syncRoomSubscriptions();\n    this.expandListsByPage();\n  }\n}\n","import type { CryptoBackend, IDeviceLists, IToDeviceEvent, MatrixClient } from '$types/matrix-sdk';\nimport {\n  ClientEvent,\n  EventType,\n  Filter,\n  Method,\n  processToDeviceMessages,\n  SetPresence,\n  User,\n} from '$types/matrix-sdk';\nimport { createDebugLogger } from '$utils/debugLogger';\n\nconst debugLog = createDebugLogger('presenceSync');\n\ntype PresenceSyncResponse = {\n  next_batch?: string;\n  presence?: { events?: unknown[] };\n  to_device?: { events?: IToDeviceEvent[] };\n  device_lists?: IDeviceLists;\n  device_one_time_keys_count?: Record<string, number>;\n  device_unused_fallback_key_types?: string[];\n  'org.matrix.msc2732.device_unused_fallback_key_types'?: string[];\n};\n\nexport class PresenceSyncManager {\n  private disposed = false;\n\n  private enabled = true;\n\n  private desiredSetPresence = SetPresence.Online;\n\n  private activeRequest: Promise<void> | null = null;\n\n  private abortController: AbortController | undefined;\n\n  private nextPollTimer: ReturnType<typeof setTimeout> | undefined;\n\n  private syncToken: string | undefined;\n\n  public constructor(\n    private readonly mx: MatrixClient,\n    private readonly pollTimeoutMs: number = 30000,\n    private readonly pollingIntervalMs: number = 20000\n  ) {\n    debugLog.info('sync', 'PresenceSyncManager initialized');\n  }\n\n  public setPresenceEnabled(enabled: boolean): void {\n    if (this.enabled === enabled) return;\n    this.enabled = enabled;\n\n    if (!enabled) {\n      if (this.nextPollTimer !== undefined) clearTimeout(this.nextPollTimer);\n      this.nextPollTimer = undefined;\n      this.abortController?.abort();\n      return;\n    }\n\n    if (!this.activeRequest && !this.disposed) this.poll();\n  }\n\n  public setDesiredPresence(presence: SetPresence): void {\n    this.desiredSetPresence = presence;\n  }\n\n  public start(): void {\n    if (this.disposed || this.activeRequest || !this.enabled) return;\n    this.poll();\n  }\n\n  public dispose(): void {\n    this.disposed = true;\n    this.enabled = false;\n    if (this.nextPollTimer !== undefined) clearTimeout(this.nextPollTimer);\n    this.nextPollTimer = undefined;\n    this.abortController?.abort();\n  }\n\n  private async processCrypto(response: PresenceSyncResponse): Promise<void> {\n    const crypto = this.mx.getCrypto() as CryptoBackend | undefined;\n    if (!crypto) return;\n\n    const toDeviceEvents = response.to_device?.events ?? [];\n    if (toDeviceEvents.length > 0) {\n      const processedEvents = await crypto.preprocessToDeviceMessages(toDeviceEvents);\n      processToDeviceMessages(processedEvents, this.mx);\n    }\n\n    if (response.device_lists) {\n      await crypto.processDeviceLists(response.device_lists);\n    }\n\n    await crypto.processKeyCounts(\n      response.device_one_time_keys_count,\n      response.device_unused_fallback_key_types ??\n        response['org.matrix.msc2732.device_unused_fallback_key_types']\n    );\n    crypto.onSyncCompleted({ nextSyncToken: response.next_batch });\n  }\n\n  private processPresence(response: PresenceSyncResponse): void {\n    const events = response.presence?.events;\n    if (!events || !Array.isArray(events)) return;\n\n    const mapper = this.mx.getEventMapper();\n    events.forEach((rawEvent) => {\n      if (\n        typeof rawEvent !== 'object' ||\n        !rawEvent ||\n        (rawEvent as Record<string, unknown>).type !== (EventType.Presence as string)\n      )\n        return;\n\n      const presenceEvent = mapper(rawEvent);\n      const userId =\n        presenceEvent.getSender() ?? (presenceEvent.getContent().user_id as string | undefined);\n      if (!userId) return;\n\n      let user = this.mx.store.getUser(userId);\n      if (!user) {\n        user = User.createUser(userId, this.mx);\n        this.mx.store.storeUser(user);\n      }\n      user.setPresenceEvent(presenceEvent);\n      this.mx.emit(ClientEvent.Event, presenceEvent);\n    });\n  }\n\n  private poll(): void {\n    if (!this.enabled || this.disposed) return;\n\n    this.abortController = new AbortController();\n    const { signal } = this.abortController;\n\n    this.activeRequest = (async () => {\n      try {\n        const filter = new Filter(this.mx.getUserId());\n        filter.setDefinition({\n          room: { rooms: [] },\n          account_data: { types: [] },\n          presence: { types: [EventType.Presence] },\n        });\n\n        const filterId = await this.mx.getOrCreateFilter('presence_only', filter);\n        const response = await this.mx.http.authedRequest<PresenceSyncResponse>(\n          Method.Get,\n          '/sync',\n          {\n            filter: filterId,\n            since: this.syncToken,\n            timeout: this.pollTimeoutMs,\n            set_presence: this.desiredSetPresence,\n          },\n          undefined,\n          { abortSignal: signal }\n        );\n\n        await this.processCrypto(response);\n        this.processPresence(response);\n        this.syncToken = response.next_batch;\n\n        debugLog.info('sync', 'Presence sync response processed', {\n          presenceEvents: response.presence?.events?.length ?? 0,\n          toDeviceEvents: response.to_device?.events?.length ?? 0,\n          hasKeyCounts: response.device_one_time_keys_count !== undefined,\n        });\n      } catch (err) {\n        if (!signal.aborted && !this.disposed) {\n          debugLog.error('sync', 'Error during background presence sync', err);\n        }\n      }\n    })();\n\n    void this.activeRequest.finally(() => {\n      this.activeRequest = null;\n      this.abortController = undefined;\n\n      if (this.enabled && !this.disposed) {\n        this.nextPollTimer = setTimeout(() => {\n          this.nextPollTimer = undefined;\n          this.poll();\n        }, this.pollingIntervalMs);\n      }\n    });\n  }\n}\n","import type { MatrixClient, MatrixEvent } from '$types/matrix-sdk';\nimport { RoomEvent } from '$types/matrix-sdk';\nimport { createDebugLogger } from '$utils/debugLogger';\n\nconst debugLog = createDebugLogger('syncStorePersistence');\n\n// The sync loop writes the store at most once every five minutes, so read\n// receipts, m.fully_read and refreshed notification counts learned since the\n// last write are lost on close and the next startup restores a snapshot from\n// before those rooms were read.\nconst MIN_FLUSH_INTERVAL_MS = 5000;\n// Our receipt only reaches the store once /sync echoes it back, and a write\n// serialises the whole accumulator, so trail it.\nconst RECEIPT_FLUSH_DELAY_MS = 60000;\n\nconst cleanupByClient = new WeakMap<MatrixClient, () => void>();\n\ntype ReceiptContent = Record<string, Record<string, Record<string, unknown>>>;\n\nconst hasOwnReceipt = (event: MatrixEvent, userId: string): boolean =>\n  Object.values(event.getContent<ReceiptContent>()).some((byReceiptType) =>\n    Object.values(byReceiptType).some((byUser) => userId in byUser)\n  );\n\nexport const installSyncStorePersistence = (mx: MatrixClient): void => {\n  cleanupByClient.get(mx)?.();\n\n  let lastFlushTs = 0;\n  let flushing = false;\n  let receiptTimer: ReturnType<typeof globalThis.setTimeout> | undefined;\n\n  const flush = (): boolean => {\n    const now = Date.now();\n    if (flushing || now - lastFlushTs < MIN_FLUSH_INTERVAL_MS) return false;\n    flushing = true;\n    lastFlushTs = now;\n    void mx.store\n      .save(true)\n      .catch((error: unknown) => {\n        debugLog.warn('sync', 'Failed to flush sync store', {\n          error: error instanceof Error ? error.message : String(error),\n        });\n      })\n      .finally(() => {\n        flushing = false;\n      });\n    return true;\n  };\n\n  const scheduleReceiptFlush = () => {\n    if (receiptTimer !== undefined) return;\n    receiptTimer = globalThis.setTimeout(() => {\n      receiptTimer = undefined;\n      if (!flush()) scheduleReceiptFlush();\n    }, RECEIPT_FLUSH_DELAY_MS);\n  };\n\n  const onVisibilityChange = () => {\n    if (document.visibilityState === 'hidden') flush();\n  };\n\n  const onPageHide = () => {\n    flush();\n  };\n\n  const onReceipt = (event: MatrixEvent) => {\n    const userId = mx.getUserId();\n    if (!userId || !hasOwnReceipt(event, userId)) return;\n    scheduleReceiptFlush();\n  };\n\n  document.addEventListener('visibilitychange', onVisibilityChange);\n  window.addEventListener('pagehide', onPageHide);\n  mx.on(RoomEvent.Receipt, onReceipt);\n\n  cleanupByClient.set(mx, () => {\n    if (receiptTimer !== undefined) globalThis.clearTimeout(receiptTimer);\n    document.removeEventListener('visibilitychange', onVisibilityChange);\n    window.removeEventListener('pagehide', onPageHide);\n    mx.removeListener(RoomEvent.Receipt, onReceipt);\n    cleanupByClient.delete(mx);\n  });\n};\n\nexport const disposeSyncStorePersistence = (mx: MatrixClient): void => {\n  cleanupByClient.get(mx)?.();\n};\n","import type { UserProfile } from '$hooks/useUserProfile';\n\nconst CACHE_VERSION = 3;\nconst CACHE_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1000;\nexport const PROFILE_CACHE_FRESH_MS = 10 * 60 * 1000;\nconst MAX_CACHED_PROFILES = 1000;\nconst MAX_SERIALIZED_LENGTH = 1_500_000;\nconst CACHE_KEY_PREFIX = 'sable.userProfiles.v3.';\nconst LEGACY_CACHE_KEY_PREFIXES = ['sable.userProfiles.v2.', 'sable.userProfiles.v1.'];\n\ntype PersistedProfileCache = {\n  version: number;\n  savedAt: number;\n  profiles: Array<[string, UserProfile]>;\n};\n\nconst cacheKey = (accountUserId: string): string =>\n  `${CACHE_KEY_PREFIX}${encodeURIComponent(accountUserId)}`;\nconst legacyCacheKeys = (accountUserId: string): string[] =>\n  LEGACY_CACHE_KEY_PREFIXES.map((prefix) => `${prefix}${encodeURIComponent(accountUserId)}`);\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n  typeof value === 'object' && value !== null && !Array.isArray(value);\n\nexport const readCachedUserProfiles = (\n  accountUserId: string,\n  now = Date.now()\n): Record<string, UserProfile> => {\n  try {\n    legacyCacheKeys(accountUserId).forEach((key) => globalThis.localStorage?.removeItem(key));\n    const raw = globalThis.localStorage?.getItem(cacheKey(accountUserId));\n    if (!raw) return {};\n\n    const parsed = JSON.parse(raw) as Partial<PersistedProfileCache>;\n    if (\n      parsed.version !== CACHE_VERSION ||\n      typeof parsed.savedAt !== 'number' ||\n      now - parsed.savedAt > CACHE_MAX_AGE_MS ||\n      !Array.isArray(parsed.profiles)\n    ) {\n      return {};\n    }\n\n    const profiles: Record<string, UserProfile> = {};\n    parsed.profiles.slice(-MAX_CACHED_PROFILES).forEach((entry) => {\n      if (!Array.isArray(entry) || entry.length !== 2) return;\n      const [userId, profile] = entry;\n      if (typeof userId !== 'string' || !isRecord(profile)) return;\n      const typedProfile = profile as UserProfile;\n      const fetchedAt = typedProfile._fetchedAt;\n      const isFresh =\n        typeof fetchedAt === 'number' &&\n        Number.isFinite(fetchedAt) &&\n        now - fetchedAt < PROFILE_CACHE_FRESH_MS;\n      profiles[userId] = { ...typedProfile, _fetched: isFresh };\n    });\n    return profiles;\n  } catch {\n    return {};\n  }\n};\n\nexport const writeCachedUserProfiles = (\n  accountUserId: string,\n  profiles: Record<string, UserProfile>,\n  now = Date.now()\n): void => {\n  try {\n    let entries = Object.entries(profiles)\n      .filter(([, profile]) =>\n        Object.keys(profile).some((key) => key !== '_fetched' && key !== '_fetchedAt')\n      )\n      .slice(-MAX_CACHED_PROFILES)\n      .map(([userId, profile]) => {\n        const { _fetched: _ignored, ...persistedProfile } = profile;\n        return [userId, persistedProfile] as [string, UserProfile];\n      });\n\n    let serialized = JSON.stringify({ version: CACHE_VERSION, savedAt: now, profiles: entries });\n    while (serialized.length > MAX_SERIALIZED_LENGTH && entries.length > 0) {\n      entries = entries.slice(Math.max(1, Math.ceil(entries.length / 10)));\n      serialized = JSON.stringify({ version: CACHE_VERSION, savedAt: now, profiles: entries });\n    }\n\n    globalThis.localStorage?.setItem(cacheKey(accountUserId), serialized);\n  } catch {\n    // Storage may be unavailable or full. Profiles will simply load from the network next time.\n  }\n};\n\nexport const clearCachedUserProfiles = (accountUserId: string): void => {\n  try {\n    [cacheKey(accountUserId), ...legacyCacheKeys(accountUserId)].forEach((key) =>\n      globalThis.localStorage?.removeItem(key)\n    );\n  } catch {\n    // logout and cache recovery continue if storage is unavailable.\n  }\n};\n","import type { MatrixClient } from '$types/matrix-sdk';\nimport { buildFeatureSupportMap, Method, Thread } from '$types/matrix-sdk';\n\nconst TTL_MS = 24 * 60 * 60 * 1000; // 24 hours\nconst keyFor = (baseUrl: string, userId: string): string =>\n  `sable.versionsCache.${baseUrl}|${userId}`;\n\ntype CachedVersions = {\n  versions: unknown;\n  unstable_features: Record<string, boolean> | undefined;\n  fetchedAt: number;\n};\n\nconst readCache = (baseUrl: string, userId: string): CachedVersions | undefined => {\n  try {\n    const raw = localStorage.getItem(keyFor(baseUrl, userId));\n    if (!raw) return undefined;\n    const parsed = JSON.parse(raw) as CachedVersions;\n    if (typeof parsed.fetchedAt !== 'number') return undefined;\n    if (Date.now() - parsed.fetchedAt > TTL_MS) return undefined;\n    return parsed;\n  } catch {\n    return undefined;\n  }\n};\n\nconst writeCache = (\n  baseUrl: string,\n  userId: string,\n  data: { versions: unknown; unstable_features: Record<string, boolean> | undefined }\n): void => {\n  try {\n    const entry: CachedVersions = { ...data, fetchedAt: Date.now() };\n    localStorage.setItem(keyFor(baseUrl, userId), JSON.stringify(entry));\n  } catch {\n    // localStorage full or disabled — non-fatal, skip caching.\n  }\n};\n\n/** Fetch /versions through the SDK and persist the response for the next startup. */\nexport const cacheVersionsFromClient = async (\n  mx: MatrixClient,\n  baseUrl: string,\n  userId: string\n): Promise<void> => {\n  try {\n    const data = await mx.getVersions();\n    writeCache(baseUrl, userId, {\n      versions: data.versions,\n      unstable_features: data.unstable_features,\n    });\n  } catch {\n    // startup can continue without a cache entry.\n  }\n};\n\n/**\n * Seed mx.serverVersionsPromise AND mx.canSupport from a cached /versions payload.\n * Seeding the promise alone leaves canSupport empty → semantic drift in\n * redaction/relation checks. Both must be set before the first sync request.\n */\nexport const primeVersionsFromCache = async (\n  mx: MatrixClient,\n  baseUrl: string,\n  userId: string\n): Promise<boolean> => {\n  const cached = readCache(baseUrl, userId);\n  if (!cached) return false;\n  const serverVersions = {\n    versions: cached.versions,\n    unstable_features: cached.unstable_features ?? {},\n  };\n  (mx as unknown as { serverVersionsPromise: Promise<unknown> | undefined }).serverVersionsPromise =\n    Promise.resolve(serverVersions);\n  (mx as unknown as { canSupport: Map<unknown, unknown> }).canSupport =\n    await buildFeatureSupportMap(serverVersions as Parameters<typeof buildFeatureSupportMap>[0]);\n  return true;\n};\n\n/**\n * Fire-and-forget revalidation of the /versions cache. Updates both the cache\n * and the in-memory promise/canSupport so the client stays current.\n */\nexport const revalidateVersionsCache = async (\n  mx: MatrixClient,\n  baseUrl: string,\n  userId: string\n): Promise<void> => {\n  try {\n    const resp = await mx.http.authedRequest(\n      Method.Get,\n      '/_matrix/client/versions',\n      undefined,\n      undefined,\n      { prefix: '' }\n    );\n    const data = resp as { versions: unknown; unstable_features?: Record<string, boolean> };\n    writeCache(baseUrl, userId, {\n      versions: data.versions,\n      unstable_features: data.unstable_features,\n    });\n    (\n      mx as unknown as { serverVersionsPromise: Promise<unknown> | undefined }\n    ).serverVersionsPromise = Promise.resolve(data);\n    (mx as unknown as { canSupport: Map<unknown, unknown> }).canSupport =\n      await buildFeatureSupportMap(data as Parameters<typeof buildFeatureSupportMap>[0]);\n    const { threads, list, fwdPagination } = await mx.doesServerSupportThread();\n    Thread.setServerSideSupport(threads);\n    Thread.setServerSideListSupport(list);\n    Thread.setServerSideFwdPaginationSupport(fwdPagination);\n  } catch {\n    // Revalidation failed — cached values remain in effect. Non-fatal.\n  }\n};\n\n/** True only when a cached /versions payload advertised the feature. */\nexport const wasUnstableFeatureCached = (\n  baseUrl: string,\n  userId: string,\n  feature: string\n): boolean => readCache(baseUrl, userId)?.unstable_features?.[feature] === true;\n\n/** Clear the cached versions for a session (used on logout). */\nexport const clearCachedVersions = (baseUrl: string, userId: string): void => {\n  try {\n    localStorage.removeItem(keyFor(baseUrl, userId));\n  } catch {\n    // non-fatal\n  }\n};\n","import type {\n  CryptoCallbacks,\n  MatrixClient,\n  MSC3575SlidingSyncRequest,\n  MSC3575SlidingSyncResponse,\n} from '$types/matrix-sdk';\nimport {\n  ClientEvent,\n  createClient,\n  IndexedDBStore,\n  IndexedDBCryptoStore,\n  KnownMembership,\n  SyncState,\n} from '$types/matrix-sdk';\nimport { fetch } from '$utils/fetch';\nimport { matrixFetch } from './matrixFetch';\nimport { clearMediaCache } from '$utils/mediaCache';\n\nimport { clearNavToActivePathStore } from '$state/navToActivePath';\nimport type { Session, Sessions, SessionStoreName } from '$state/sessions';\nimport {\n  ACTIVE_SESSION_KEY,\n  getSessionStoreName,\n  getStoredSessionRefreshToken,\n  MATRIX_SESSIONS_KEY,\n} from '$state/sessions';\nimport { getLocalStorageItem } from '$state/utils/atomWithLocalStorage';\nimport { createLogger } from '$utils/debug';\nimport { createDebugLogger } from '$utils/debugLogger';\nimport { isMobileTauri } from '$utils/platform';\nimport * as Sentry from '@sentry/react';\nimport { pushSessionToSW } from '../sw-session';\nimport { assertAuthMetadataIssuer, createSessionTokenRefresher } from './oidcTokenRefresher';\nimport { revokeOAuthToken } from './oauthTokenRevocation';\nimport { clearSecretStorageKeys, cryptoCallbacks } from './secretStorageKeys';\nimport type { SlidingSyncDiagnostics } from './slidingSync';\nimport {\n  prepareSlidingSyncTimelines,\n  scopeTypingExtension,\n  SlidingSyncManager,\n} from './slidingSync';\nimport { PresenceSyncManager } from './presenceSync';\nimport { SlidingSyncSidebarCache } from './slidingSyncSidebarCache';\nimport { disposeSyncStorePersistence, installSyncStorePersistence } from './syncStorePersistence';\nimport { clearCachedUserProfiles } from './userProfileCache';\nimport {\n  clearLocalNotificationCache,\n  destroyLocalNotificationCache,\n} from './localNotificationCache';\nimport {\n  primeVersionsFromCache,\n  revalidateVersionsCache,\n  clearCachedVersions,\n  cacheVersionsFromClient,\n  wasUnstableFeatureCached,\n} from './versionsCache';\n\nconst log = createLogger('initMatrix');\nconst debugLog = createDebugLogger('initMatrix');\nconst slidingSyncByClient = new WeakMap<MatrixClient, SlidingSyncManager>();\nconst membershipActionCleanupByClient = new WeakMap<MatrixClient, () => void>();\nconst presenceSyncByClient = new WeakMap<MatrixClient, PresenceSyncManager>();\n\nexport const ownsActiveMediaSession = (session?: Session): boolean => {\n  if (!session) return true;\n  const sessions = getLocalStorageItem<Sessions>(MATRIX_SESSIONS_KEY, []);\n  const activeSessionId = getLocalStorageItem<string | undefined>(ACTIVE_SESSION_KEY, undefined);\n  const activeSession = sessions.find((item) => item.userId === activeSessionId) ?? sessions[0];\n  return activeSession?.userId === session.userId;\n};\nconst presenceStartCleanupByClient = new WeakMap<MatrixClient, () => void>();\nconst SLIDING_SYNC_POLL_TIMEOUT_MS = 45000;\nconst SLIDING_SYNC_POLL_TIMEOUT_MOBILE_MS = 30000;\n\n/** Shorter poll on mobile: a wedged long-poll costs more when the OS freezes the webview. */\nexport const resolvePollTimeoutMs = (configured?: number): number =>\n  configured ??\n  (isMobileTauri() ? SLIDING_SYNC_POLL_TIMEOUT_MOBILE_MS : SLIDING_SYNC_POLL_TIMEOUT_MS);\n\nconst isInitialSyncReady = (state: string | null): boolean =>\n  state === SyncState.Prepared || state === SyncState.Syncing || state === SyncState.Catchup;\n\nconst startPresenceAfterInitialSync = (\n  mx: MatrixClient,\n  manager: PresenceSyncManager\n): (() => void) => {\n  let started = false;\n  let startTimer: ReturnType<typeof globalThis.setTimeout> | undefined;\n\n  const start = () => {\n    if (started) return;\n    started = true;\n    presenceStartCleanupByClient.delete(mx);\n    mx.removeListener(ClientEvent.Sync, onSync);\n    manager.start();\n  };\n\n  const scheduleStart = () => {\n    if (startTimer !== undefined) return;\n    startTimer = globalThis.setTimeout(() => {\n      startTimer = undefined;\n      start();\n    }, 0);\n  };\n\n  const onSync = (state: SyncState) => {\n    if (isInitialSyncReady(state)) scheduleStart();\n  };\n\n  if (isInitialSyncReady(mx.getSyncState())) scheduleStart();\n  else mx.on(ClientEvent.Sync, onSync);\n\n  const cleanup = () => {\n    if (startTimer !== undefined) globalThis.clearTimeout(startTimer);\n    mx.removeListener(ClientEvent.Sync, onSync);\n    presenceStartCleanupByClient.delete(mx);\n  };\n  presenceStartCleanupByClient.set(mx, cleanup);\n  return cleanup;\n};\n\n// The SDK's only check runs inside `initRustCrypto`, before the client starts, and latches off.\nexport const recheckKeyBackupAfterInitialSync = (mx: MatrixClient): void => {\n  const recheck = () => {\n    mx.removeListener(ClientEvent.Sync, onSync);\n    const crypto = mx.getCrypto();\n    if (!crypto) return;\n    crypto.checkKeyBackupAndEnable().catch((error: unknown) => {\n      debugLog.warn('sync', 'Failed to re-check key backup after initial sync', {\n        error: error instanceof Error ? error.message : String(error),\n      });\n    });\n  };\n\n  const onSync = (state: SyncState) => {\n    if (isInitialSyncReady(state)) recheck();\n  };\n\n  if (isInitialSyncReady(mx.getSyncState())) recheck();\n  else mx.on(ClientEvent.Sync, onSync);\n};\n\ntype StartupPhase = 'sync_store' | 'rust_crypto' | 'client_init' | 'client_start';\n\nconst measureStartupPhase = async <T>(\n  phase: StartupPhase,\n  task: () => Promise<T>,\n  attributes?: Record<string, string>\n): Promise<T> => {\n  const startTime = performance.now();\n  try {\n    const result = await task();\n    Sentry.metrics.distribution('sable.startup.phase_ms', performance.now() - startTime, {\n      attributes: { phase, outcome: 'success', ...attributes },\n    });\n    return result;\n  } catch (error) {\n    Sentry.metrics.distribution('sable.startup.phase_ms', performance.now() - startTime, {\n      attributes: { phase, outcome: 'error', ...attributes },\n    });\n    throw error;\n  }\n};\n\nconst slidingSyncRequestCleanupByClient = new WeakMap<MatrixClient, () => void>();\n\ntype SlidingSyncMethod = (\n  reqBody: MSC3575SlidingSyncRequest,\n  baseUrl?: string,\n  abortSignal?: AbortSignal\n) => Promise<MSC3575SlidingSyncResponse>;\n\ntype MatrixClientWithWritableSlidingSync = MatrixClient & {\n  slidingSync: SlidingSyncMethod;\n};\n\ntype SlidingSyncRequestWithConnId = MSC3575SlidingSyncRequest & {\n  conn_id?: string;\n};\n\n// Synapse keys connection state on (user, device, conn_id) and keeps only the two\n// latest positions, so two clients sharing an id invalidate each other's `pos`.\nexport const newSlidingSyncConnId = (): string =>\n  `sable-${globalThis.crypto?.randomUUID?.().slice(0, 8) ?? `${Date.now()}-${Math.random().toString(16).slice(2)}`}`;\n\nexport function installSlidingSyncRequestPatch(\n  mx: MatrixClient,\n  manager: SlidingSyncManager\n): void {\n  slidingSyncRequestCleanupByClient.get(mx)?.();\n\n  const connId = newSlidingSyncConnId();\n  const mxWritable = mx as MatrixClientWithWritableSlidingSync;\n  const original = mx.slidingSync.bind(mx) as SlidingSyncMethod;\n  mxWritable.slidingSync = async (reqBody, baseUrl, abortSignal) => {\n    const req = reqBody as SlidingSyncRequestWithConnId;\n    const subscribedRoomIds = new Set(Object.keys(req.room_subscriptions ?? {}));\n    const trackResponse = manager.trackSubscriptionRequest(subscribedRoomIds);\n\n    // AbortError makes the SDK loop `continue` and reissue at the same `pos`, no sleep.\n    if (manager.isPaused()) {\n      await manager.waitForResume();\n      const aborted = new Error('Sliding sync paused while backgrounded');\n      aborted.name = 'AbortError';\n      throw aborted;\n    }\n\n    if (req.conn_id === undefined) {\n      req.conn_id = connId;\n    }\n\n    const roomIds = manager.getActiveRoomSubscriptionIds();\n    scopeTypingExtension(req.extensions, roomIds);\n\n    const response = await original(reqBody, baseUrl, abortSignal);\n    trackResponse(response);\n    // Must run before the SDK processes the response. A throw would reach the SDK's\n    // loop, which drops the response and retries the same `pos` forever.\n    try {\n      const completeTimelineReset = prepareSlidingSyncTimelines(response, mx, subscribedRoomIds);\n      if (completeTimelineReset) {\n        manager.trackTimelineResetCompletion(response, completeTimelineReset);\n      }\n      manager.sanitizeOptimisticJoinResponse(response);\n    } catch (error) {\n      Sentry.captureException(error, { tags: { area: 'sliding_sync_response' } });\n      debugLog.error('sync', 'Failed to prepare sliding sync response', {\n        error: error instanceof Error ? error.message : String(error),\n      });\n    }\n    return response;\n  };\n\n  slidingSyncRequestCleanupByClient.set(mx, () => {\n    slidingSyncRequestCleanupByClient.delete(mx);\n    mxWritable.slidingSync = original;\n  });\n}\n\nconst deleteDatabase = (name: string): Promise<void> =>\n  new Promise((resolve) => {\n    const req = window.indexedDB.deleteDatabase(name);\n    req.addEventListener('success', () => resolve());\n    req.addEventListener('error', () => resolve()); // resolve anyway — we tried\n    req.addEventListener('blocked', () => resolve());\n  });\n\nconst deleteSessionStores = async (storeName: SessionStoreName): Promise<void> => {\n  await Promise.all([\n    deleteDatabase(storeName.sync),\n    deleteDatabase(storeName.crypto),\n    deleteDatabase(`${storeName.rustCryptoPrefix}::matrix-sdk-crypto`),\n  ]);\n};\n\nconst isMismatch = (err: unknown): boolean => {\n  const msg = err instanceof Error ? err.message : String(err);\n  return (\n    msg.includes(\"doesn't match\") ||\n    msg.includes('does not match') ||\n    msg.includes('account in the store') ||\n    msg.includes('account in the constructor')\n  );\n};\n\ntype BuiltClient = {\n  mx: MatrixClient;\n  indexedDBStore: IndexedDBStore;\n};\n\nconst buildClient = async (session: Session): Promise<BuiltClient> => {\n  const storeName = getSessionStoreName(session);\n\n  const indexedDBStore = new IndexedDBStore({\n    indexedDB: global.indexedDB,\n    localStorage: global.localStorage,\n    dbName: storeName.sync,\n  });\n\n  const legacyCryptoStore = new IndexedDBCryptoStore(global.indexedDB, storeName.crypto);\n\n  const tempClient = createClient({\n    baseUrl: session.baseUrl,\n    fetchFn: fetch,\n  });\n  const tokenRefresher = createSessionTokenRefresher(session, tempClient);\n\n  const mx = createClient({\n    baseUrl: session.baseUrl,\n    fetchFn: matrixFetch,\n    accessToken: session.accessToken,\n    refreshToken: session.refreshToken,\n    userId: session.userId,\n    store: indexedDBStore,\n    cryptoStore: legacyCryptoStore,\n    deviceId: session.deviceId,\n    timelineSupport: true,\n    cryptoCallbacks: cryptoCallbacks as unknown as CryptoCallbacks,\n    verificationMethods: ['m.sas.v1'],\n    tokenRefreshFunction: tokenRefresher?.tokenRefreshFunction,\n  });\n\n  return { mx, indexedDBStore };\n};\n\ntype ClientInitializationResult =\n  | { ok: true; mx: MatrixClient }\n  | { ok: false; error: unknown; phase: 'sync_store' | 'rust_crypto' };\n\nconst initializeClient = async (\n  session: Session,\n  cryptoDatabasePrefix: string\n): Promise<ClientInitializationResult> => {\n  let builtClient: BuiltClient;\n  try {\n    builtClient = await buildClient(session);\n  } catch (error) {\n    return { ok: false, error, phase: 'sync_store' };\n  }\n  const { mx, indexedDBStore } = builtClient;\n\n  void primeVersionsFromCache(mx, session.baseUrl, session.userId).then((primed) => {\n    if (primed) void revalidateVersionsCache(mx, session.baseUrl, session.userId);\n    else void cacheVersionsFromClient(mx, session.baseUrl, session.userId);\n  });\n\n  const syncStorePromise = measureStartupPhase('sync_store', () => indexedDBStore.startup());\n  const cryptoPromise = measureStartupPhase('rust_crypto', () =>\n    mx.initRustCrypto({ cryptoDatabasePrefix })\n  );\n  const [syncStoreResult, cryptoResult] = await Promise.allSettled([\n    syncStorePromise,\n    cryptoPromise,\n  ]);\n\n  if (syncStoreResult.status === 'rejected') {\n    mx.stopClient();\n    return { ok: false, error: syncStoreResult.reason, phase: 'sync_store' };\n  }\n  if (cryptoResult.status === 'rejected') {\n    mx.stopClient();\n    return { ok: false, error: cryptoResult.reason, phase: 'rust_crypto' };\n  }\n\n  return { ok: true, mx };\n};\n\nexport const initClient = async (session: Session): Promise<MatrixClient> => {\n  const storeName = getSessionStoreName(session);\n  debugLog.info('sync', 'Initializing Matrix client', {\n    userId: session.userId,\n    baseUrl: session.baseUrl,\n  });\n\n  const wipeAllStores = async () => {\n    log.warn('initClient: wiping all stores for', session.userId);\n    debugLog.warn('sync', 'Wiping all stores due to mismatch', {\n      userId: session.userId,\n    });\n    Sentry.addBreadcrumb({\n      category: 'crypto',\n      message: 'Crypto store mismatch — wiping local stores and retrying',\n      level: 'warning',\n    });\n    Sentry.metrics.count('sable.crypto.store_wipe', 1);\n    await deleteSessionStores(storeName);\n    try {\n      const allDbs = await window.indexedDB.databases();\n      await Promise.all(\n        allDbs.map(async ({ name }) => {\n          if (name && name.includes(session.userId)) {\n            log.warn('initClient: also wiping db', name);\n            await deleteDatabase(name);\n          }\n        })\n      );\n    } catch {\n      // databases() not available in all browsers\n    }\n  };\n\n  const initStartTime = performance.now();\n  let initOutcome = 'success';\n  try {\n    const result = await initializeClient(session, storeName.rustCryptoPrefix);\n    if (!result.ok) {\n      if (!isMismatch(result.error)) {\n        debugLog.error('sync', 'Failed to initialize client', {\n          phase: result.phase,\n          error: result.error,\n        });\n        throw result.error;\n      }\n\n      log.warn(`initClient: mismatch during ${result.phase} — wiping and reloading:`, result.error);\n      debugLog.warn('sync', 'Client initialization mismatch - wiping stores and reloading', {\n        phase: result.phase,\n        error: result.error,\n      });\n      await wipeAllStores();\n      window.location.reload();\n      throw result.error;\n    }\n\n    result.mx.setMaxListeners(50);\n    return result.mx;\n  } catch (error) {\n    initOutcome = 'error';\n    throw error;\n  } finally {\n    Sentry.metrics.distribution('sable.startup.phase_ms', performance.now() - initStartTime, {\n      attributes: { phase: 'client_init', outcome: initOutcome },\n    });\n  }\n};\n\nexport type StartClientConfig = {\n  baseUrl?: string;\n  sessionSlidingSyncOptIn?: boolean;\n  pollTimeoutMs?: number;\n  timelineLimit?: number;\n  initialRoomIds?: Iterable<string>;\n  onCachedRoomsLoaded?: () => void;\n};\n\nexport type ClientSyncDiagnostics = {\n  transport: 'sliding' | 'classic';\n  syncState: string | null;\n  sliding?: SlidingSyncDiagnostics;\n};\n\nconst SLIDING_SYNC_UNSTABLE_FEATURE = 'org.matrix.simplified_msc3575';\n\nconst SLIDING_SYNC_CAPABILITY_TIMEOUT_MS = 5000;\n\n// The SDK retries an unsupported endpoint forever instead of erroring, so anything\n// short of a confirmation falls back to classic sync. /versions has no timeout of\n// its own, hence the race.\nexport const supportsSlidingSync = async (\n  mx: MatrixClient,\n  baseUrl: string\n): Promise<{\n  supported: boolean;\n  reason: 'advertised' | 'unadvertised' | 'cached' | 'unknown';\n}> => {\n  let timer: ReturnType<typeof globalThis.setTimeout> | undefined;\n  const timeout = new Promise<boolean | undefined>((resolve) => {\n    timer = globalThis.setTimeout(() => resolve(undefined), SLIDING_SYNC_CAPABILITY_TIMEOUT_MS);\n  });\n\n  let confirmed: boolean | undefined;\n  try {\n    confirmed = await Promise.race([\n      mx.doesServerSupportUnstableFeature(SLIDING_SYNC_UNSTABLE_FEATURE),\n      timeout,\n    ]);\n  } catch {\n    confirmed = undefined;\n  } finally {\n    globalThis.clearTimeout(timer);\n  }\n\n  if (confirmed !== undefined) {\n    return { supported: confirmed, reason: confirmed ? 'advertised' : 'unadvertised' };\n  }\n  // We never reached /versions, so a previous confirmation is all we have to go on.\n  const cached = wasUnstableFeatureCached(\n    baseUrl,\n    mx.getSafeUserId(),\n    SLIDING_SYNC_UNSTABLE_FEATURE\n  );\n  return { supported: cached, reason: cached ? 'cached' : 'unknown' };\n};\n\nconst disposeSlidingSync = (mx: MatrixClient): void => {\n  membershipActionCleanupByClient.get(mx)?.();\n  const manager = slidingSyncByClient.get(mx);\n  if (!manager) return;\n  manager.dispose();\n  slidingSyncByClient.delete(mx);\n};\n\ntype MatrixClientWithWritableMembershipActions = MatrixClient & {\n  joinRoom: MatrixClient['joinRoom'];\n  leave: MatrixClient['leave'];\n};\n\nconst installMembershipActionReconciliation = (\n  mx: MatrixClient,\n  manager: SlidingSyncManager\n): void => {\n  membershipActionCleanupByClient.get(mx)?.();\n\n  const writableMx = mx as MatrixClientWithWritableMembershipActions;\n  // Keep the exact methods so cleanup restores the client without leaving bound replacements behind.\n  // oxlint-disable-next-line typescript/unbound-method\n  const originalJoinRoom = mx.joinRoom;\n  // oxlint-disable-next-line typescript/unbound-method\n  const originalLeave = mx.leave;\n\n  writableMx.joinRoom = async (...args) => {\n    const room = await originalJoinRoom.apply(mx, args);\n    manager.reconcileRoomMembership(room.roomId, KnownMembership.Join);\n    return room;\n  };\n  writableMx.leave = async (...args) => {\n    const result = await originalLeave.apply(mx, args);\n    manager.reconcileRoomMembership(args[0], KnownMembership.Leave);\n    return result;\n  };\n\n  membershipActionCleanupByClient.set(mx, () => {\n    membershipActionCleanupByClient.delete(mx);\n    writableMx.joinRoom = originalJoinRoom;\n    writableMx.leave = originalLeave;\n  });\n};\n\nconst disposePresenceSync = (mx: MatrixClient): void => {\n  presenceStartCleanupByClient.get(mx)?.();\n  const manager = presenceSyncByClient.get(mx);\n  if (!manager) return;\n  manager.dispose();\n  presenceSyncByClient.delete(mx);\n};\n\nexport const getSlidingSyncManager = (mx: MatrixClient): SlidingSyncManager | undefined =>\n  slidingSyncByClient.get(mx);\n\nexport const getPresenceSyncManager = (mx: MatrixClient): PresenceSyncManager | undefined =>\n  presenceSyncByClient.get(mx);\n\nexport const startClient = async (mx: MatrixClient, config?: StartClientConfig): Promise<void> => {\n  disposeSlidingSync(mx);\n  disposePresenceSync(mx);\n\n  const baseUrl = config?.baseUrl ?? mx.baseUrl;\n  const optedIntoSliding = config?.sessionSlidingSyncOptIn === true;\n  const slidingSupport = optedIntoSliding\n    ? await supportsSlidingSync(mx, baseUrl)\n    : { supported: false, reason: 'unadvertised' as const };\n  const useSliding = optedIntoSliding && slidingSupport.supported;\n\n  if (optedIntoSliding && !useSliding) {\n    debugLog.warn('sync', 'Falling back to classic sync', {\n      userId: mx.getUserId(),\n      baseUrl,\n      reason: slidingSupport.reason,\n    });\n    Sentry.metrics.count('sable.sync.transport_downgrade', 1, {\n      attributes: { reason: slidingSupport.reason },\n    });\n  }\n\n  debugLog.info('sync', 'Starting Matrix client', { userId: mx.getUserId() });\n\n  let manager: SlidingSyncManager | undefined;\n\n  if (useSliding) {\n    const presenceManager = new PresenceSyncManager(mx);\n    presenceSyncByClient.set(mx, presenceManager);\n    startPresenceAfterInitialSync(mx, presenceManager);\n\n    manager = new SlidingSyncManager(mx, baseUrl, {\n      pollTimeoutMs: resolvePollTimeoutMs(config?.pollTimeoutMs),\n      timelineLimit: config?.timelineLimit,\n      initialRoomIds: config?.initialRoomIds,\n    });\n\n    installSlidingSyncRequestPatch(mx, manager);\n\n    manager.attach();\n    manager.prepareSidebarCacheHydration();\n    installMembershipActionReconciliation(mx, manager);\n    slidingSyncByClient.set(mx, manager);\n  }\n\n  try {\n    await measureStartupPhase(\n      'client_start',\n      () =>\n        mx.startClient({\n          lazyLoadMembers: true,\n          slidingSync: manager?.slidingSync,\n          threadSupport: true,\n        }),\n      { transport: useSliding ? 'sliding' : 'classic' }\n    );\n    if (!useSliding) installSyncStorePersistence(mx);\n    recheckKeyBackupAfterInitialSync(mx);\n    if (manager && (await manager.waitForSidebarCacheHydration())) {\n      config?.onCachedRoomsLoaded?.();\n    }\n  } catch (err) {\n    debugLog.error('network', 'Failed to start client with sliding sync', {\n      error: err instanceof Error ? err.message : String(err),\n      userId: mx.getUserId(),\n      baseUrl: useSliding ? baseUrl : undefined,\n      stack: err instanceof Error ? err.stack : undefined,\n    });\n    slidingSyncRequestCleanupByClient.get(mx)?.();\n    membershipActionCleanupByClient.get(mx)?.();\n    disposeSlidingSync(mx);\n    disposePresenceSync(mx);\n    throw err;\n  }\n};\n\nexport const stopClient = (mx: MatrixClient): void => {\n  log.log('stopClient', mx.getUserId());\n  debugLog.info('sync', 'Stopping client', { userId: mx.getUserId() });\n  slidingSyncRequestCleanupByClient.get(mx)?.();\n  disposeSyncStorePersistence(mx);\n  disposeSlidingSync(mx);\n  disposePresenceSync(mx);\n  mx.stopClient();\n};\n\nexport const clearCacheAndReload = async (mx: MatrixClient) => {\n  log.log('clearCacheAndReload', mx.getUserId());\n  stopClient(mx);\n  clearNavToActivePathStore(mx.getSafeUserId());\n  SlidingSyncSidebarCache.clear(mx.getSafeUserId());\n  clearCachedUserProfiles(mx.getSafeUserId());\n  await mx.store.deleteAllData();\n  window.location.reload();\n};\n\nexport const getClientSyncDiagnostics = (mx: MatrixClient): ClientSyncDiagnostics => {\n  const slidingManager = slidingSyncByClient.get(mx);\n  return {\n    transport: slidingManager ? 'sliding' : 'classic',\n    syncState: mx.getSyncState(),\n    sliding: slidingManager?.getDiagnostics(),\n  };\n};\n\nconst revokeOidcSession = async (mx: MatrixClient, session: Session): Promise<void> => {\n  const oidc = session.oidc;\n  if (!oidc) return;\n  const metadata = await mx.getAuthMetadata();\n  assertAuthMetadataIssuer(oidc.issuer, metadata);\n\n  const refreshToken = getStoredSessionRefreshToken(session.userId) ?? session.refreshToken;\n  const token = refreshToken ?? mx.getAccessToken() ?? undefined;\n  if (!token) return;\n\n  try {\n    await revokeOAuthToken(\n      metadata,\n      oidc.clientId,\n      token,\n      refreshToken ? 'refresh_token' : 'access_token'\n    );\n  } catch {\n    debugLog.warn('general', 'OIDC token revocation had failures', { userId: session.userId });\n  }\n};\n\n/**\n * Logs out a Matrix client and cleans up its SDK stores + IndexedDB databases.\n * Does NOT touch the Jotai sessions atom — callers must do that themselves\n * so the correct Jotai Provider store is used.\n */\nexport const logoutClient = async (mx: MatrixClient, session?: Session) => {\n  log.log('logoutClient', {\n    userId: mx.getUserId(),\n    sessionUserId: session?.userId,\n  });\n  debugLog.info('general', 'Logging out client', { userId: mx.getUserId() });\n  stopClient(mx);\n  try {\n    if (session?.oidc) {\n      await revokeOidcSession(mx, session);\n    } else {\n      await mx.logout();\n    }\n    debugLog.info('general', 'Logout successful', { userId: mx.getUserId() });\n  } catch {\n    // ignore\n  }\n\n  if (session) {\n    SlidingSyncSidebarCache.clear(session.userId);\n    clearCachedVersions(session.baseUrl, session.userId);\n    clearCachedUserProfiles(session.userId);\n    clearSecretStorageKeys();\n    destroyLocalNotificationCache(session.userId);\n    clearLocalNotificationCache(session.userId);\n    const storeName: SessionStoreName = getSessionStoreName(session);\n    await mx.clearStores({ cryptoDatabasePrefix: storeName.rustCryptoPrefix });\n    await deleteDatabase(storeName.sync);\n    await deleteDatabase(storeName.crypto);\n    await deleteDatabase(`${storeName.rustCryptoPrefix}::matrix-sdk-crypto`);\n  } else {\n    await mx.clearStores();\n    window.localStorage.clear();\n  }\n\n  try {\n    await clearMediaCache();\n  } finally {\n    if (ownsActiveMediaSession(session)) {\n      // Queue the final clear after any in-flight refresh.\n      await pushSessionToSW();\n    }\n  }\n};\n\nexport const clearLoginData = async () => {\n  debugLog.info('general', 'Clearing all login data and reloading');\n  const dbs = await window.indexedDB.databases();\n  dbs.forEach((idbInfo) => {\n    const { name } = idbInfo;\n    if (name) window.indexedDB.deleteDatabase(name);\n  });\n  window.localStorage.clear();\n  await clearMediaCache();\n  window.location.reload();\n};\n","import { EventType } from 'matrix-js-sdk/lib/@types/event';\n\nexport const DEFAULT_NOTIFICATION_ICON = '/public/res/logo-maskable/logo-maskable-180x180.png';\nexport const DEFAULT_NOTIFICATION_BADGE = '/public/res/logo-maskable/logo-maskable-72x72.png';\nconst DEFAULT_MESSAGE_PREVIEW = 'new message';\nexport const ENCRYPTED_MESSAGE_PREVIEW = 'Encrypted message';\n\ntype RoomMessageNotificationInput = {\n  roomName?: string;\n  username?: string;\n  roomAvatar?: string;\n  previewText?: string;\n  silent?: boolean;\n  eventId?: string;\n  data?: unknown;\n  /** Matrix user ID of the account that received the notification. When provided,\n   * the account's localpart is appended to the title so multi-account users know\n   * which account the notification is for. */\n  recipientId?: string;\n};\n\ntype NotificationPayload = {\n  title: string;\n  options: NotificationOptions;\n};\n\ntype NotificationPreviewInput = {\n  content?: unknown;\n  eventType?: string;\n  isEncryptedRoom?: boolean;\n  showMessageContent: boolean;\n  showEncryptedMessageContent: boolean;\n};\n\nconst getString = (value: unknown, fallback: string): string => {\n  if (typeof value !== 'string') return fallback;\n  const normalized = value.trim();\n  return normalized.length > 0 ? normalized : fallback;\n};\n\nconst getBodyFromContent = (content: unknown): string | undefined => {\n  if (!content || typeof content !== 'object') return undefined;\n  const { body } = content as Record<string, unknown>;\n  if (typeof body !== 'string') return undefined;\n  const normalized = body.trim();\n  return normalized.length > 0 ? normalized : undefined;\n};\n\nexport const resolveNotificationPreviewText = ({\n  content,\n  eventType,\n  isEncryptedRoom,\n  showMessageContent,\n  showEncryptedMessageContent,\n}: NotificationPreviewInput): string => {\n  // Handle reactions specially - show the reaction emoji\n  if (eventType === 'm.reaction' && content && typeof content === 'object') {\n    const relatesTo = (content as Record<string, unknown>)['m.relates_to'];\n    if (relatesTo && typeof relatesTo === 'object') {\n      const { key } = relatesTo as Record<string, unknown>;\n      if (typeof key === 'string') {\n        return `Reacted with ${key}`;\n      }\n    }\n    return 'Added a reaction';\n  }\n\n  const encryptedContext = isEncryptedRoom || eventType === EventType.RoomMessageEncrypted;\n\n  if (!showMessageContent) {\n    return encryptedContext ? ENCRYPTED_MESSAGE_PREVIEW : DEFAULT_MESSAGE_PREVIEW;\n  }\n  if (encryptedContext && !showEncryptedMessageContent) {\n    return ENCRYPTED_MESSAGE_PREVIEW;\n  }\n\n  const body = getBodyFromContent(content);\n  if (body) return body;\n\n  return encryptedContext ? ENCRYPTED_MESSAGE_PREVIEW : DEFAULT_MESSAGE_PREVIEW;\n};\n\n/** Extracts the localpart (everything between @ and the first :) from a Matrix user ID. */\nconst toLocalpart = (userId: string): string => userId.match(/^@([^:]+):/)?.[1] ?? userId;\n\nexport const buildRoomMessageNotification = ({\n  roomName,\n  username,\n  roomAvatar,\n  previewText,\n  silent,\n  eventId,\n  data,\n  recipientId,\n}: RoomMessageNotificationInput): NotificationPayload => {\n  const sender = getString(username, 'Someone');\n  const room = getString(roomName, 'Unknown');\n  const message = getString(previewText, DEFAULT_MESSAGE_PREVIEW);\n  const avatar = getString(roomAvatar, DEFAULT_NOTIFICATION_ICON);\n  const recipientSuffix = recipientId ? ` • ${toLocalpart(recipientId)}` : '';\n\n  return {\n    title: `${sender} in ${room}${recipientSuffix}`,\n    options: {\n      icon: avatar,\n      badge: avatar || DEFAULT_NOTIFICATION_BADGE,\n      body: `${sender}: ${message}`,\n      silent,\n      tag: eventId ?? `${room}-${sender}`,\n      data,\n    },\n  };\n};\n","import { invoke } from '@tauri-apps/api/core';\n\nexport type UnifiedPushRegistration = {\n  deviceToken: string;\n  p256dh?: string;\n  auth?: string;\n};\n\nexport type UnifiedPushTransportApi = {\n  isPermissionGranted: () => Promise<boolean | null>;\n  requestPermission: () => Promise<NotificationPermission>;\n  registerForPushNotifications: (vapid?: string) => Promise<UnifiedPushRegistration>;\n  unregisterForPushNotifications: () => Promise<void>;\n  listDistributors: () => Promise<string[]>;\n  setDistributor: (name: string) => Promise<void>;\n  setToken: (token: string) => Promise<void>;\n};\n\nexport async function getUnifiedPushTransportApi(): Promise<UnifiedPushTransportApi> {\n  const notificationsApi = await import('@sableclient/tauri-plugin-notifications-api');\n  return {\n    isPermissionGranted: notificationsApi.isPermissionGranted,\n    requestPermission: notificationsApi.requestPermission,\n    registerForPushNotifications: (vapid?: string) =>\n      invoke<UnifiedPushRegistration>('plugin:notifications|register_for_push_notifications', {\n        vapid,\n        provider: 'unifiedpush',\n      }),\n    unregisterForPushNotifications: notificationsApi.unregisterForPushNotifications,\n    listDistributors: notificationsApi.listDistributors,\n    setDistributor: notificationsApi.setDistributor,\n    setToken: notificationsApi.setToken,\n  };\n}\n","import { getUnifiedPushTransportApi } from './UnifiedPushTransportApiClient';\n\nexport type UnifiedPushPermissionState = 'granted' | 'denied' | 'default';\n\nexport type UnifiedPushRegistrationStatus =\n  | 'registered'\n  | 'temp-unavailable'\n  | 'hard-failure'\n  | 'denied'\n  | 'missing-distributor';\n\nexport type UnifiedPushDistributorState = {\n  distributors: string[];\n  selectedDistributor: string;\n};\n\nexport type UnifiedPushRegistrationResult =\n  | {\n      status: 'registered';\n      permissionState: 'granted';\n      endpoint: string;\n      distributor: string;\n      p256dh?: string;\n      auth?: string;\n    }\n  | {\n      status: 'temp-unavailable';\n      permissionState: UnifiedPushPermissionState;\n      distributor?: string;\n      error: string;\n    }\n  | {\n      status: 'hard-failure';\n      permissionState: UnifiedPushPermissionState;\n      distributor?: string;\n      error: string;\n    }\n  | {\n      status: 'missing-distributor';\n      permissionState: UnifiedPushPermissionState;\n      distributors: string[];\n      error: string;\n      distributor?: string;\n    }\n  | {\n      status: 'denied';\n      permissionState: Exclude<UnifiedPushPermissionState, 'granted'>;\n      error: string;\n    };\n\nconst DISTRIBUTUTOR_STORAGE_KEY = 'unifiedpush_distributor';\n\nexport function normalizeErrorMessage(error: unknown): string {\n  if (error instanceof Error) return error.message;\n  if (typeof error === 'string') return error;\n  if (error && typeof error === 'object') {\n    const message = 'message' in error ? (error as { message?: unknown }).message : undefined;\n    if (typeof message === 'string') return message;\n    const code = 'code' in error ? (error as { code?: unknown }).code : undefined;\n    if (typeof code === 'string') return code;\n  }\n  return String(error);\n}\n\nfunction normalizeErrorCode(error: unknown): string {\n  if (!error || typeof error !== 'object') return '';\n  if ('code' in error && typeof (error as { code?: unknown }).code === 'string') {\n    return String((error as { code?: string }).code).toLowerCase();\n  }\n  if ('name' in error && typeof (error as { name?: unknown }).name === 'string') {\n    return String((error as { name?: string }).name).toLowerCase();\n  }\n  return '';\n}\n\nexport function classifyUnifiedPushFailure(\n  error: unknown\n): Exclude<UnifiedPushRegistrationStatus, 'registered' | 'denied'> {\n  const message = normalizeErrorMessage(error).toLowerCase();\n  const code = normalizeErrorCode(error);\n\n  if (\n    code.includes('temp_unavailable') ||\n    code.includes('temporary_unavailable') ||\n    message.includes('temp-unavailable') ||\n    message.includes('temp unavailable') ||\n    message.includes('temporarily unavailable')\n  ) {\n    return 'temp-unavailable';\n  }\n\n  if (\n    code.includes('missing_distributor') ||\n    message.includes('missing distributor') ||\n    message.includes('no unifiedpush distributor') ||\n    message.includes('no distributor') ||\n    message.includes('distributor parameter is required')\n  ) {\n    return 'missing-distributor';\n  }\n\n  return 'hard-failure';\n}\n\nasync function getUnifiedPushPermissionState(): Promise<UnifiedPushPermissionState> {\n  const api = await getUnifiedPushTransportApi();\n  if (await api.isPermissionGranted()) return 'granted';\n\n  const permission = await api.requestPermission();\n  return permission === 'granted' ? 'granted' : permission;\n}\n\nexport async function isUnifiedPushPermissionGranted(): Promise<boolean | null> {\n  const api = await getUnifiedPushTransportApi();\n  return api.isPermissionGranted();\n}\n\nasync function getUnifiedPushDistributors(): Promise<string[]> {\n  const api = await getUnifiedPushTransportApi();\n  return api.listDistributors();\n}\n\nasync function getUnifiedPushDistributor(): Promise<{ distributor: string }> {\n  const distributor = localStorage.getItem(DISTRIBUTUTOR_STORAGE_KEY) ?? '';\n  return { distributor };\n}\n\nasync function saveUnifiedPushDistributor(distributor: string): Promise<void> {\n  localStorage.setItem(DISTRIBUTUTOR_STORAGE_KEY, distributor);\n  const api = await getUnifiedPushTransportApi();\n  await api.setDistributor(distributor);\n}\n\nexport async function loadUnifiedPushDistributorState(): Promise<UnifiedPushDistributorState> {\n  const [distributorResult, distributorsResult] = await Promise.allSettled([\n    getUnifiedPushDistributor(),\n    getUnifiedPushDistributors(),\n  ]);\n\n  const savedDistributor =\n    distributorsResult.status === 'fulfilled'\n      ? distributorResult.status === 'fulfilled'\n        ? distributorResult.value.distributor\n        : ''\n      : '';\n  const distributors = distributorsResult.status === 'fulfilled' ? distributorsResult.value : [];\n\n  if (savedDistributor && distributors.includes(savedDistributor)) {\n    return { distributors, selectedDistributor: savedDistributor };\n  }\n\n  if (distributors.length === 1) {\n    const [onlyDistributor] = distributors;\n    if (onlyDistributor) {\n      await saveUnifiedPushDistributor(onlyDistributor);\n      return { distributors, selectedDistributor: onlyDistributor };\n    }\n  }\n\n  return { distributors, selectedDistributor: '' };\n}\n\nexport async function ensureUnifiedPushDistributorSelection(\n  distributors: string[],\n  selectedDistributor: string\n): Promise<string> {\n  const distributor =\n    selectedDistributor && distributors.includes(selectedDistributor)\n      ? selectedDistributor\n      : distributors[0];\n\n  if (!distributor) return '';\n\n  await saveUnifiedPushDistributor(distributor);\n  return distributor;\n}\n\nexport async function setUnifiedPushDistributorSelection(distributor: string): Promise<void> {\n  await saveUnifiedPushDistributor(distributor);\n}\n\nexport async function switchUnifiedPushDistributorSelection<T>(\n  nextDistributor: string,\n  previousDistributor: string,\n  register: () => Promise<T>\n): Promise<T> {\n  if (nextDistributor === previousDistributor) {\n    return register();\n  }\n\n  await saveUnifiedPushDistributor(nextDistributor);\n\n  try {\n    return await register();\n  } catch (error) {\n    await saveUnifiedPushDistributor(previousDistributor);\n    throw error;\n  }\n}\n\nexport async function registerUnifiedPushTransport(\n  vapid?: string\n): Promise<UnifiedPushRegistrationResult> {\n  let permissionState: UnifiedPushPermissionState = 'default';\n  let selectedDistributor: string | undefined;\n\n  try {\n    permissionState = await getUnifiedPushPermissionState();\n    if (permissionState !== 'granted') {\n      return {\n        status: 'denied',\n        permissionState,\n        error:\n          permissionState === 'denied'\n            ? 'UnifiedPush permission denied'\n            : 'UnifiedPush permission dismissed',\n      };\n    }\n\n    const { distributors, selectedDistributor: distributor } =\n      await loadUnifiedPushDistributorState();\n    selectedDistributor = distributor || undefined;\n    if (!distributor) {\n      return {\n        status: 'missing-distributor',\n        permissionState: 'granted',\n        distributors,\n        error:\n          distributors.length === 0\n            ? 'No UnifiedPush distributor installed'\n            : 'No UnifiedPush distributor selected',\n      };\n    }\n\n    const api = await getUnifiedPushTransportApi();\n    const registration = await api.registerForPushNotifications(vapid);\n    const endpoint = registration?.deviceToken;\n    if (!endpoint || !endpoint.trim()) {\n      return {\n        status: 'hard-failure',\n        permissionState: 'granted',\n        error: 'UnifiedPush registration returned an invalid endpoint',\n        ...(selectedDistributor ? { distributor: selectedDistributor } : {}),\n      };\n    }\n\n    return {\n      status: 'registered',\n      permissionState: 'granted',\n      endpoint,\n      distributor,\n      p256dh: registration.p256dh,\n      auth: registration.auth,\n    };\n  } catch (error) {\n    const failureStatus = classifyUnifiedPushFailure(error);\n    return {\n      status: failureStatus,\n      permissionState,\n      error: normalizeErrorMessage(error),\n      ...(selectedDistributor ? { distributor: selectedDistributor } : {}),\n    } as UnifiedPushRegistrationResult;\n  }\n}\n\nexport async function unregisterUnifiedPushTransport(): Promise<void> {\n  const api = await getUnifiedPushTransportApi();\n  await api.unregisterForPushNotifications();\n}\n","export type UnifiedPushMessageHandler = (data: Record<string, unknown>) => Promise<void>;\nexport type UnifiedPushMessageErrorHandler = (error: unknown) => void;\n\nexport function createUnifiedPushMessageListener(\n  handler: UnifiedPushMessageHandler,\n  onError: UnifiedPushMessageErrorHandler\n) {\n  return (data: Record<string, unknown>) => {\n    handler(data).catch(onError);\n  };\n}\n\nexport function parseUnifiedPushMessage(raw: unknown): Record<string, unknown> | null {\n  const message = (raw as { message?: unknown })?.message;\n  if (typeof message !== 'string') return null;\n\n  let payload: unknown;\n  try {\n    payload = JSON.parse(message);\n  } catch {\n    return null;\n  }\n  if (!payload || typeof payload !== 'object') return null;\n\n  const notification = (payload as { notification?: unknown }).notification;\n  if (notification && typeof notification === 'object') {\n    return notification as Record<string, unknown>;\n  }\n  return payload as Record<string, unknown>;\n}\n","export type PushPusherSettings = {\n  useRichPushPayloads?: boolean;\n  pushNotifyUrlOverride?: string;\n};\n\nexport function resolvePushNotifyUrl(\n  configuredUrl: string | undefined,\n  override: string | undefined\n): string {\n  const candidate = override?.trim() || configuredUrl?.trim();\n  if (!candidate)\n    throw new Error('Push requires pushNotificationDetails.pushNotifyUrl in config.json.');\n\n  let url: URL;\n  try {\n    url = new URL(candidate);\n  } catch {\n    throw new Error('Push gateway URL must be a full HTTPS URL ending in /notify.');\n  }\n  if (\n    url.protocol !== 'https:' ||\n    url.username ||\n    url.password ||\n    url.hash ||\n    url.pathname !== '/_matrix/push/v1/notify'\n  ) {\n    throw new Error('Push gateway URL must be an HTTPS Matrix /_matrix/push/v1/notify endpoint.');\n  }\n  return url.toString();\n}\n\nexport function withPushPayloadFormat<T extends Record<string, unknown>>(\n  data: T,\n  useRichPushPayloads = false\n): T | (T & { format: 'event_id_only' }) {\n  return useRichPushPayloads ? data : { ...data, format: 'event_id_only' };\n}\n","import {\n  type IPusherRequest,\n  type MatrixClient,\n  MatrixEvent,\n  MatrixEventEvent,\n} from '$types/matrix-sdk';\nimport { EventType } from 'matrix-js-sdk/lib/@types/event';\nimport {\n  resolveNotificationPreviewText,\n  ENCRYPTED_MESSAGE_PREVIEW,\n} from '$utils/notificationStyle';\nimport { getMxIdLocalPart } from '$utils/matrix';\nimport { getStateEvent } from '$utils/room/hierarchy';\nimport { createDebugLogger } from '$utils/debugLogger';\nimport {\n  registerUnifiedPushTransport,\n  type UnifiedPushRegistrationResult,\n  unregisterUnifiedPushTransport,\n} from './UnifiedPushTransport';\nimport {\n  createUnifiedPushMessageListener,\n  parseUnifiedPushMessage,\n} from './UnifiedPushMessageListener';\nimport { addPluginListener, invoke } from '@tauri-apps/api/core';\nimport { getSlidingSyncManager } from '$client/initMatrix';\nimport type { PushTransportConfig } from './NotificationTransport';\nimport { getTauriNotificationsApi, isMobileTauri } from './TauriNotificationsApiClient';\nimport {\n  resolvePushNotifyUrl,\n  withPushPayloadFormat,\n  type PushPusherSettings,\n} from './PushPusherConfig';\n\nconst UP_PUBLIC_GATEWAY = 'https://matrix.gateway.unifiedpush.org/_matrix/push/v1/notify';\nexport const DEFAULT_UNIFIED_PUSH_APP_ID = 'moe.sable.up';\nconst unifiedPushLog = createDebugLogger('unifiedpush');\n\n/**\n * Shape of a UnifiedPush payload delivered to the message listener.\n * Fields are optional because both rich (full event) and minimal\n * (event_id + counts) payloads arrive through the same entry point.\n */\ntype UnifiedPushPayload = {\n  type?: string;\n  content?: Record<string, unknown>;\n  room_id?: string;\n  room_name?: string;\n  sender_display_name?: string;\n  sender?: string;\n  event_id?: string;\n  user_id?: string;\n  counts?: { unread?: number };\n  notification?: unknown;\n  [key: string]: unknown;\n};\n\nconst UP_REGISTER_TIMEOUT_MS = 30_000;\n\n// Android freezes a channel's importance at creation, so raising `messages` from\n// Default to High needs a new id. Mirrored in the plugin's UnifiedPushNotifier.\nconst MESSAGES_CHANNEL_ID = 'messages.v2';\nconst INVITES_CHANNEL_ID = 'invites';\nconst LEGACY_MESSAGES_CHANNEL_ID = 'messages';\n\nasync function ensureNotificationChannels(\n  notificationsApi: Awaited<ReturnType<typeof getTauriNotificationsApi>>\n): Promise<void> {\n  await notificationsApi.createChannel({\n    id: MESSAGES_CHANNEL_ID,\n    name: 'Messages',\n    description: 'Matrix message notifications',\n    importance: notificationsApi.Importance.High,\n    vibration: true,\n  });\n  await notificationsApi.createChannel({\n    id: INVITES_CHANNEL_ID,\n    name: 'Invitations',\n    description: 'Room and space invitations',\n    importance: notificationsApi.Importance.Default,\n    vibration: true,\n  });\n  await notificationsApi.removeChannel(LEGACY_MESSAGES_CHANNEL_ID).catch(() => {\n    // Never created on this device, or already gone.\n  });\n}\n\nexport type UnifiedPushTransportConfigInput = Pick<\n  PushTransportConfig,\n  'unifiedPushGatewayUrl' | 'unifiedPushAppID'\n> & {\n  vapidPublicKey?: string;\n  webPushAppID?: string;\n  pushNotifyUrl?: string;\n} & PushPusherSettings;\n\ntype UnifiedPushPusherConfig = {\n  appId: string;\n  gatewayUrl?: string;\n};\n\nfunction trimConfigValue(value: string | undefined): string | undefined {\n  const trimmed = value?.trim();\n  return trimmed || undefined;\n}\n\nfunction resolveUnifiedPushPusherConfig(\n  config?: UnifiedPushTransportConfigInput\n): UnifiedPushPusherConfig {\n  return {\n    appId: trimConfigValue(config?.unifiedPushAppID) ?? DEFAULT_UNIFIED_PUSH_APP_ID,\n    gatewayUrl: trimConfigValue(config?.unifiedPushGatewayUrl),\n  };\n}\n\nexport type EnableUnifiedPushResult =\n  | {\n      status: 'registered';\n      endpoint: string;\n      gatewayUrl: string;\n      distributor: string;\n    }\n  | Exclude<UnifiedPushRegistrationResult, { status: 'registered' }>;\n\nasync function registerUnifiedPushWithTimeout(\n  vapid?: string\n): Promise<UnifiedPushRegistrationResult> {\n  let timeoutId: ReturnType<typeof setTimeout> | undefined;\n  const timeout = new Promise<never>((_, reject) => {\n    timeoutId = setTimeout(() => {\n      reject(new Error('UnifiedPush registration timed out'));\n    }, UP_REGISTER_TIMEOUT_MS);\n  });\n\n  try {\n    return await Promise.race([registerUnifiedPushTransport(vapid), timeout]);\n  } finally {\n    if (timeoutId !== undefined) {\n      clearTimeout(timeoutId);\n    }\n  }\n}\n\nexport async function tryEnableUnifiedPush(\n  mx: MatrixClient,\n  config?: UnifiedPushTransportConfigInput\n): Promise<EnableUnifiedPushResult> {\n  const notificationsApi = await getTauriNotificationsApi();\n  await ensureNotificationChannels(notificationsApi);\n\n  const registration = await registerUnifiedPushWithTimeout(config?.vapidPublicKey);\n\n  if (registration.status !== 'registered') {\n    return registration;\n  }\n\n  const { endpoint } = registration;\n  const deviceDisplayName =\n    (await mx.getDevice(mx.getDeviceId() ?? ''))?.display_name ?? 'Android Device';\n\n  if (registration.p256dh && registration.auth && config?.webPushAppID && config?.pushNotifyUrl) {\n    const pushNotifyUrl = resolvePushNotifyUrl(config.pushNotifyUrl, config?.pushNotifyUrlOverride);\n    await mx.setPusher({\n      kind: 'http',\n      app_id: config.webPushAppID,\n      pushkey: registration.p256dh,\n      app_display_name: 'Sable (UnifiedPush)',\n      device_display_name: deviceDisplayName,\n      lang: navigator.language || 'en',\n      data: withPushPayloadFormat(\n        {\n          url: pushNotifyUrl,\n          endpoint,\n          p256dh: registration.p256dh,\n          auth: registration.auth,\n          default_payload: { user_id: mx.getSafeUserId() },\n        },\n        config?.useRichPushPayloads\n      ),\n      append: false,\n    } as unknown as IPusherRequest);\n\n    return {\n      status: 'registered',\n      endpoint,\n      gatewayUrl: pushNotifyUrl,\n      distributor: registration.distributor,\n    };\n  }\n\n  const resolvedConfig = resolveUnifiedPushPusherConfig(config);\n  const gatewayUrl = resolvedConfig.gatewayUrl ?? UP_PUBLIC_GATEWAY;\n\n  await mx.setPusher({\n    kind: 'http',\n    app_id: resolvedConfig.appId,\n    pushkey: endpoint,\n    app_display_name: 'Sable (UnifiedPush)',\n    device_display_name: deviceDisplayName,\n    lang: navigator.language || 'en',\n    data: withPushPayloadFormat(\n      { url: gatewayUrl, default_payload: { user_id: mx.getSafeUserId() } },\n      config?.useRichPushPayloads\n    ),\n    append: false,\n  } as unknown as IPusherRequest);\n\n  return {\n    status: 'registered',\n    endpoint,\n    gatewayUrl,\n    distributor: registration.distributor,\n  };\n}\n\nexport async function enableUnifiedPush(\n  mx: MatrixClient,\n  config?: UnifiedPushTransportConfigInput\n): Promise<{ endpoint: string; gatewayUrl: string }> {\n  const result = await tryEnableUnifiedPush(mx, config);\n  if (result.status !== 'registered') {\n    throw new Error(result.error ?? 'UnifiedPush registration failed');\n  }\n\n  return {\n    endpoint: result.endpoint,\n    gatewayUrl: result.gatewayUrl,\n  };\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n  return typeof value === 'string' && value.trim().length > 0;\n}\n\nasync function getCurrentDeviceUnifiedPushPushkeys(\n  mx: MatrixClient,\n  appId: string\n): Promise<string[]> {\n  const deviceId = mx.getDeviceId() ?? '';\n  if (!deviceId) {\n    return [];\n  }\n\n  const currentDevice = await mx.getDevice(deviceId);\n  const deviceDisplayName = currentDevice?.display_name;\n  if (!deviceDisplayName) {\n    return [];\n  }\n\n  const response = await mx.getPushers();\n  const pushers = response.pushers ?? [];\n  return pushers\n    .filter(\n      (pusher) =>\n        pusher.app_id === appId &&\n        pusher.device_display_name === deviceDisplayName &&\n        pusher.kind === 'http' &&\n        isNonEmptyString(pusher.pushkey)\n    )\n    .map((pusher) => pusher.pushkey);\n}\n\nasync function getUnifiedPushCleanupPushkeys(\n  mx: MatrixClient,\n  appId: string,\n  pushkey?: string\n): Promise<string[]> {\n  const pushkeys = new Set<string>();\n\n  if (isNonEmptyString(pushkey)) {\n    pushkeys.add(pushkey);\n  }\n\n  const currentDevicePushkeys = await getCurrentDeviceUnifiedPushPushkeys(mx, appId);\n  currentDevicePushkeys.forEach((candidate) => pushkeys.add(candidate));\n\n  return Array.from(pushkeys);\n}\n\nexport type DisableUnifiedPushOptions = {\n  config?: UnifiedPushTransportConfigInput;\n  pushkey?: string;\n};\n\nexport async function disableUnifiedPush(\n  mx: MatrixClient,\n  options: DisableUnifiedPushOptions = {}\n): Promise<void> {\n  const { appId } = resolveUnifiedPushPusherConfig(options.config);\n  const pushkeys = await getUnifiedPushCleanupPushkeys(mx, appId, options.pushkey);\n\n  await Promise.allSettled(\n    pushkeys.map((pushkey) =>\n      mx.setPusher({\n        kind: null,\n        app_id: appId,\n        pushkey,\n      } as unknown as IPusherRequest)\n    )\n  );\n\n  const webPushAppId = trimConfigValue(options.config?.webPushAppID);\n  if (webPushAppId && webPushAppId !== appId) {\n    const webPushKeys = await getCurrentDeviceUnifiedPushPushkeys(mx, webPushAppId);\n    await Promise.allSettled(\n      webPushKeys.map((pushkey) =>\n        mx.setPusher({\n          kind: null,\n          app_id: webPushAppId,\n          pushkey,\n        } as unknown as IPusherRequest)\n      )\n    );\n  }\n\n  await unregisterUnifiedPushTransport();\n}\n\ntype NotificationSettings = {\n  mx: MatrixClient;\n  showMessageContent: boolean;\n  showEncryptedMessageContent: boolean;\n  notificationSoundEnabled: boolean;\n  useInAppNotifications: boolean;\n};\n\nconst NOTIF_GROUP_KEY = 'matrix_messages';\nconst MAX_MESSAGES = 10;\nconst MAX_SEEN_EVENT_IDS = 200;\nconst ENCRYPTED_PREVIEW_RETRY_WINDOW_MS = 5 * 60_000;\n\ntype NotifPerson = {\n  name: string;\n  key?: string;\n};\n\ntype NotifMessage = {\n  text: string;\n  timestamp: number;\n  sender?: NotifPerson;\n};\n\nfunction hashCode(str: string): number {\n  let hash = 0;\n  for (let i = 0; i < str.length; i += 1) {\n    // eslint-disable-next-line no-bitwise\n    hash = (Math.imul(31, hash) + str.charCodeAt(i)) | 0;\n  }\n  return Math.abs(hash);\n}\n\nasync function resolvePreviewEvent(\n  mx: MatrixClient,\n  roomId: string,\n  eventId: string\n): Promise<MatrixEvent | undefined> {\n  try {\n    const evt = await mx.fetchRoomEvent(roomId, eventId);\n    const mEvent = new MatrixEvent(evt);\n    if (mEvent.isEncrypted()) {\n      await mx.decryptEventIfNeeded(mEvent);\n    }\n    return mEvent;\n  } catch (error) {\n    unifiedPushLog.warn(\n      'notification',\n      'Failed to fetch/decrypt event for push preview',\n      error instanceof Error ? error : new Error(String(error))\n    );\n    return undefined;\n  }\n}\n\n/**\n * Rebuilds the encrypted event from a rich push payload so it can be decrypted\n * locally — no homeserver fetch needed, the Megolm keys are in the crypto store.\n */\nfunction buildEncryptedPreviewEvent(\n  roomId: string,\n  eventId: string,\n  pushData: UnifiedPushPayload\n): MatrixEvent | undefined {\n  if (!pushData.content) return undefined;\n  return new MatrixEvent({\n    type: 'm.room.encrypted',\n    content: pushData.content,\n    room_id: roomId,\n    event_id: eventId,\n    sender: pushData.sender,\n    origin_server_ts: Date.now(),\n  });\n}\n\nfunction holdsPlaintext(event: MatrixEvent): boolean {\n  return (\n    !event.isDecryptionFailure() && event.getType() !== EventType.RoomMessageEncrypted.toString()\n  );\n}\n\n/**\n * Runs `apply` as soon as `event` holds plaintext: right away when it is already\n * decrypted, or later once the Megolm key arrives — a backgrounded app routinely\n * receives the push before the to-device key, and the SDK retries decryption on\n * its own when the key lands.\n */\nfunction whenDecrypted(event: MatrixEvent, apply: () => Promise<void>): void {\n  if (holdsPlaintext(event)) {\n    void apply();\n    return;\n  }\n\n  const onDecrypted = () => {\n    if (!holdsPlaintext(event)) return;\n    event.off(MatrixEventEvent.Decrypted, onDecrypted);\n    clearTimeout(retryWindowTimer);\n    void apply();\n  };\n\n  event.on(MatrixEventEvent.Decrypted, onDecrypted);\n  const retryWindowTimer = setTimeout(() => {\n    event.off(MatrixEventEvent.Decrypted, onDecrypted);\n    unifiedPushLog.warn('notification', 'Encrypted preview never decrypted within retry window');\n  }, ENCRYPTED_PREVIEW_RETRY_WINDOW_MS);\n}\n\nconst roomNotifId = (userId: string, roomId: string) => hashCode(`${userId}\\u0000${roomId}`);\nconst summaryNotifId = (userId: string) => hashCode(`sable-group-summary\\u0000${userId}`);\n\ntype RoomNotifCache = {\n  key: string;\n  generation: number;\n  roomName: string;\n  messages: NotifMessage[];\n  pendingEventIds: Set<string>;\n  seenEventIds: Set<string>;\n  isGroupConversation: boolean;\n};\n\nconst roomNotifCaches = new Map<string, RoomNotifCache>();\nconst roomNotifGenerations = new Map<string, number>();\nconst roomNotifQueues = new Map<string, Promise<void>>();\n\nfunction enqueueRoomOperation<T>(key: string, operation: () => Promise<T>): Promise<T> {\n  const previous = roomNotifQueues.get(key) ?? Promise.resolve();\n  const task = previous.then(operation, operation);\n  const completion = task.then(\n    () => undefined,\n    () => undefined\n  );\n  roomNotifQueues.set(key, completion);\n  void completion.then(() => {\n    if (roomNotifQueues.get(key) === completion) roomNotifQueues.delete(key);\n  });\n  return task;\n}\n\nfunction getOrCreateRoomCache(userId: string, roomId: string, roomName: string): RoomNotifCache {\n  const key = `${userId}\\u0000${roomId}`;\n  let cache = roomNotifCaches.get(key);\n  if (!cache) {\n    cache = {\n      key,\n      generation: roomNotifGenerations.get(key) ?? 0,\n      roomName,\n      messages: [],\n      pendingEventIds: new Set(),\n      seenEventIds: new Set(),\n      isGroupConversation: false,\n    };\n    roomNotifCaches.set(key, cache);\n  }\n  cache.roomName = roomName;\n  return cache;\n}\n\nfunction isCurrentRoomCache(cache: RoomNotifCache): boolean {\n  return (\n    roomNotifCaches.get(cache.key) === cache &&\n    (roomNotifGenerations.get(cache.key) ?? 0) === cache.generation\n  );\n}\n\nexport function resetUnifiedPushNotificationStateForTests(): void {\n  roomNotifCaches.clear();\n  roomNotifGenerations.clear();\n  roomNotifQueues.clear();\n}\n\n// Older versions posted an account-level summary that collapsed every room into\n// one entry; Android bundles the per-room notifications on its own.\nasync function dismissLegacyGroupSummary(userId: string): Promise<void> {\n  if (!userId) return;\n  try {\n    const notificationsApi = await getTauriNotificationsApi();\n    await notificationsApi.removeActive([{ id: summaryNotifId(userId) }]);\n  } catch {\n    // Nothing to dismiss, or the plugin is unavailable.\n  }\n}\n\n/** Clears accumulated messages for a room and dismisses its notification. */\nexport async function clearRoomNotification(userId: string, roomId: string) {\n  const key = `${userId}\\u0000${roomId}`;\n  await enqueueRoomOperation(key, async () => {\n    roomNotifCaches.delete(key);\n    roomNotifGenerations.set(key, (roomNotifGenerations.get(key) ?? 0) + 1);\n    try {\n      const notificationsApi = await getTauriNotificationsApi();\n      await notificationsApi.removeActive([{ id: roomNotifId(userId, roomId) }]);\n    } catch {\n      // already dismissed\n    }\n  });\n}\n\nasync function postRoomNotification(\n  userId: string,\n  roomId: string,\n  cache: RoomNotifCache,\n  isSilent: boolean,\n  extra: Record<string, unknown>,\n  isCurrent?: () => boolean\n): Promise<boolean> {\n  const notificationsApi = await getTauriNotificationsApi();\n  if (isCurrent && !isCurrent()) return false;\n  const { messages, roomName } = cache;\n  const latestMsg = messages[messages.length - 1];\n  const latestBody = latestMsg ? `${latestMsg.sender?.name ?? 'You'}: ${latestMsg.text}` : '';\n\n  const inboxLines = messages.slice(-5).map((m) => `${m.sender?.name ?? 'You'}: ${m.text}`);\n\n  await notificationsApi.sendNotification({\n    id: roomNotifId(userId, roomId),\n    title: roomName,\n    body: latestBody,\n    channelId: MESSAGES_CHANNEL_ID,\n    group: NOTIF_GROUP_KEY,\n    icon: 'notification_icon',\n    silent: isSilent,\n    autoCancel: true,\n    extra,\n    ...(isMobileTauri() ? { actionTypeId: 'sable-message' } : {}),\n    // Android renders these as a conversation; inbox/big-text covers the rest.\n    messages: messages.map((m) => ({\n      body: m.text,\n      timestamp: m.timestamp,\n      senderName: m.sender?.name,\n      senderKey: m.sender?.key,\n    })),\n    groupConversation: cache.isGroupConversation,\n    inboxLines: inboxLines.length > 1 ? inboxLines : undefined,\n    largeBody: inboxLines.length > 1 ? undefined : latestBody,\n  });\n  return true;\n}\n\n/** Handles a rich push payload containing full event details (type, room_name, content, etc.). */\nasync function handleRichPushPayload(\n  pushData: UnifiedPushPayload,\n  settings: NotificationSettings,\n  userId: string,\n  getSettings: () => NotificationSettings\n) {\n  const eventType = pushData.type as EventType;\n\n  switch (eventType) {\n    case EventType.RoomMessage:\n    case EventType.Sticker:\n    case EventType.RoomMessageEncrypted: {\n      const isEncrypted = eventType === EventType.RoomMessageEncrypted;\n\n      let previewText = resolveNotificationPreviewText({\n        content: pushData?.content,\n        eventType: pushData?.type,\n        isEncryptedRoom: isEncrypted,\n        showMessageContent: settings.showMessageContent,\n        showEncryptedMessageContent: settings.showEncryptedMessageContent,\n      });\n\n      const roomId: string | undefined = pushData?.room_id;\n      const roomName: string =\n        pushData?.room_name ?? pushData?.sender_display_name ?? 'Unknown Room';\n      const senderName: string | undefined = pushData?.sender_display_name;\n      const senderId: string | undefined = pushData?.sender;\n      const isSilent = !settings.notificationSoundEnabled;\n\n      if (!roomId) {\n        const notificationsApi = await getTauriNotificationsApi();\n        await notificationsApi.sendNotification({\n          title: roomName,\n          body: senderName ? `${senderName}: ${previewText}` : previewText,\n          channelId: MESSAGES_CHANNEL_ID,\n          icon: 'notification_icon',\n          silent: isSilent,\n          autoCancel: true,\n        });\n        break;\n      }\n\n      const eventId: string | undefined = pushData?.event_id;\n\n      let needsEncryptedPreviewEnrichment = false;\n\n      if (\n        previewText === ENCRYPTED_MESSAGE_PREVIEW &&\n        eventId &&\n        settings.showMessageContent &&\n        settings.showEncryptedMessageContent\n      ) {\n        // Try local timeline first (decryption already done by SDK).\n        const room = settings.mx.getRoom(roomId);\n        const mEvent = room\n          ?.getLiveTimeline()\n          .getEvents()\n          .find((e) => e.getId() === eventId);\n        if (mEvent) {\n          previewText = resolveNotificationPreviewText({\n            content: mEvent.getContent(),\n            eventType: mEvent.getType(),\n            isEncryptedRoom: true,\n            showMessageContent: settings.showMessageContent,\n            showEncryptedMessageContent: settings.showEncryptedMessageContent,\n          });\n          needsEncryptedPreviewEnrichment =\n            mEvent.getType() === EventType.RoomMessageEncrypted.toString();\n        } else {\n          needsEncryptedPreviewEnrichment = true;\n        }\n      }\n\n      const sender: NotifPerson | undefined = senderName\n        ? { name: senderName, key: senderId }\n        : undefined;\n\n      const message: NotifMessage = {\n        text: previewText,\n        timestamp: Date.now(),\n        sender,\n      };\n\n      const key = `${userId}\\u0000${roomId}`;\n      let enrichmentCache: RoomNotifCache | undefined;\n      let enrichmentMessage: NotifMessage | undefined;\n      const posted = await enqueueRoomOperation(key, async () => {\n        const cache = getOrCreateRoomCache(userId, roomId, roomName);\n        if (eventId && (cache.pendingEventIds.has(eventId) || cache.seenEventIds.has(eventId))) {\n          return false;\n        }\n        if (eventId) cache.pendingEventIds.add(eventId);\n        const previousMessages = cache.messages.slice();\n        cache.messages.push(message);\n        if (cache.messages.length > MAX_MESSAGES) {\n          cache.messages = cache.messages.slice(-MAX_MESSAGES);\n        }\n\n        const currentRoom = settings.mx.getRoom(roomId);\n        if (currentRoom) {\n          cache.isGroupConversation = (currentRoom.getJoinedMemberCount() ?? 0) > 2;\n        }\n\n        try {\n          await postRoomNotification(userId, roomId, cache, isSilent, {\n            room_id: roomId,\n            event_id: pushData?.event_id,\n            user_id: pushData?.user_id,\n          });\n        } catch {\n          cache.messages = previousMessages;\n          if (eventId) cache.pendingEventIds.delete(eventId);\n          if (cache.messages.length === 0) roomNotifCaches.delete(cache.key);\n          unifiedPushLog.warn('notification', 'UnifiedPush baseline notification failed');\n          return false;\n        }\n\n        if (eventId) {\n          cache.pendingEventIds.delete(eventId);\n          cache.seenEventIds.add(eventId);\n          if (cache.seenEventIds.size > MAX_SEEN_EVENT_IDS) {\n            const oldest = cache.seenEventIds.values().next().value;\n            if (oldest !== undefined) cache.seenEventIds.delete(oldest);\n          }\n        }\n        enrichmentCache = cache;\n        enrichmentMessage = message;\n        return true;\n      });\n\n      if (\n        posted &&\n        needsEncryptedPreviewEnrichment &&\n        eventId &&\n        enrichmentCache &&\n        enrichmentMessage\n      ) {\n        scheduleEncryptedPreviewEnrichment(\n          pushData,\n          roomId,\n          eventId,\n          enrichmentCache,\n          enrichmentMessage,\n          userId,\n          getSettings\n        );\n      }\n      break;\n    }\n    case EventType.RoomMember: {\n      if (pushData?.content?.membership !== 'invite') break;\n      const senderName: string | undefined = pushData?.sender_display_name;\n      const roomName: string | undefined = pushData?.room_name;\n      let body = '';\n      if (senderName && roomName) body = `${senderName} invites you to ${roomName}`;\n      else if (senderName) body = `from ${senderName}`;\n      else if (roomName) body = `to ${roomName}`;\n\n      const notificationsApi = await getTauriNotificationsApi();\n      await notificationsApi.sendNotification({\n        title: 'New Invitation',\n        body,\n        largeBody: body,\n        channelId: INVITES_CHANNEL_ID,\n        group: NOTIF_GROUP_KEY,\n        icon: 'notification_icon',\n        autoCancel: true,\n        extra: {\n          type: 'invite',\n          room_id: pushData?.room_id,\n          event_id: pushData?.event_id,\n          user_id: pushData?.user_id,\n        },\n      });\n      break;\n    }\n    default:\n      break;\n  }\n}\n\nfunction scheduleEncryptedPreviewEnrichment(\n  pushData: UnifiedPushPayload,\n  roomId: string,\n  eventId: string,\n  cache: RoomNotifCache,\n  message: NotifMessage,\n  userId: string,\n  getSettings: () => NotificationSettings\n): void {\n  const initialSettings = getSettings();\n  if (!initialSettings.showMessageContent || !initialSettings.showEncryptedMessageContent) return;\n\n  const crypto = initialSettings.mx.getCrypto();\n  const decrypted = buildEncryptedPreviewEvent(roomId, eventId, pushData);\n  if (!crypto || !decrypted) return;\n\n  const applyDecryptedPreview = async (): Promise<void> => {\n    await enqueueRoomOperation(cache.key, async () => {\n      const liveSettings = getSettings();\n      const isAllowed =\n        liveSettings.showMessageContent &&\n        liveSettings.showEncryptedMessageContent &&\n        !(document.visibilityState === 'visible' && liveSettings.useInAppNotifications);\n      if (!isAllowed || !isCurrentRoomCache(cache) || !cache.messages.includes(message)) {\n        return;\n      }\n\n      const enrichedPreview = resolveNotificationPreviewText({\n        content: decrypted.getContent(),\n        eventType: decrypted.getType(),\n        isEncryptedRoom: true,\n        showMessageContent: liveSettings.showMessageContent,\n        showEncryptedMessageContent: liveSettings.showEncryptedMessageContent,\n      });\n      if (!enrichedPreview || enrichedPreview === ENCRYPTED_MESSAGE_PREVIEW) return;\n\n      const liveRoom = liveSettings.mx.getRoom(roomId);\n      const decryptedSender = decrypted.getSender();\n      const senderName = decryptedSender\n        ? (liveRoom?.getMember(decryptedSender)?.name ??\n          getMxIdLocalPart(decryptedSender) ??\n          decryptedSender)\n        : undefined;\n      const previousText = message.text;\n      const previousSender = message.sender;\n      message.text = enrichedPreview;\n      message.sender = senderName ? { name: senderName, key: decryptedSender } : message.sender;\n\n      const current = () => {\n        const currentSettings = getSettings();\n        return (\n          isCurrentRoomCache(cache) &&\n          cache.messages.includes(message) &&\n          currentSettings.showMessageContent &&\n          currentSettings.showEncryptedMessageContent &&\n          !(document.visibilityState === 'visible' && currentSettings.useInAppNotifications)\n        );\n      };\n      try {\n        const posted = await postRoomNotification(\n          userId,\n          roomId,\n          cache,\n          true,\n          {\n            room_id: roomId,\n            event_id: eventId,\n            user_id: pushData?.user_id,\n          },\n          current\n        );\n        if (!posted) {\n          message.text = previousText;\n          message.sender = previousSender;\n        }\n      } catch {\n        message.text = previousText;\n        message.sender = previousSender;\n      }\n    });\n  };\n\n  whenDecrypted(decrypted, applyDecryptedPreview);\n  void initialSettings.mx.decryptEventIfNeeded(decrypted).catch(() => {\n    unifiedPushLog.warn('notification', 'Encrypted preview decryption failed');\n  });\n}\n\n/**\n * Handles a minimal push payload (event_id + room_id + counts) from\n * the public UnifiedPush gateway, looking up context from local SDK state.\n */\nasync function handleMinimalPushPayload(\n  pushData: UnifiedPushPayload,\n  settings: NotificationSettings,\n  userId: string,\n  getSettings: () => NotificationSettings\n) {\n  const roomId: string | undefined = pushData?.room_id;\n  const eventId: string | undefined = pushData?.event_id;\n  const unread: number | undefined =\n    typeof pushData?.counts?.unread === 'number' ? pushData.counts.unread : undefined;\n\n  if (!roomId) return;\n\n  // Unread count of zero means the room was read — dismiss the notification.\n  if (unread === 0) {\n    await clearRoomNotification(userId, roomId);\n    return;\n  }\n\n  const room = settings.mx.getRoom(roomId);\n  const roomName = room?.name ?? pushData?.sender_display_name ?? 'Unknown Room';\n  const isEncryptedRoom = room ? !!getStateEvent(room, EventType.RoomEncryption) : false;\n\n  let senderName: string | undefined;\n  let senderId: string | undefined;\n  let previewText: string | undefined;\n  if (room && eventId) {\n    const timeline = room.getLiveTimeline().getEvents();\n    const mEvent = timeline.find((e) => e.getId() === eventId);\n    if (mEvent) {\n      const sender = mEvent.getSender();\n      if (sender) {\n        const member = room.getMember(sender);\n        senderName = member?.name ?? getMxIdLocalPart(sender) ?? sender;\n        senderId = sender;\n      }\n\n      previewText = resolveNotificationPreviewText({\n        content: mEvent.getContent(),\n        eventType: mEvent.getType(),\n        isEncryptedRoom,\n        showMessageContent: settings.showMessageContent,\n        showEncryptedMessageContent: settings.showEncryptedMessageContent,\n      });\n    }\n  }\n\n  const hasInMemoryPreview = Boolean(previewText);\n  if (!previewText) {\n    previewText = isEncryptedRoom ? 'Encrypted message' : 'New message';\n  }\n\n  const sender: NotifPerson | undefined = senderName\n    ? { name: senderName, key: senderId }\n    : undefined;\n\n  const message: NotifMessage = {\n    text: previewText,\n    timestamp: Date.now(),\n    sender,\n  };\n\n  const key = `${userId}\\u0000${roomId}`;\n  let baselineCache: RoomNotifCache | undefined;\n  const posted = await enqueueRoomOperation(key, async () => {\n    const cache = getOrCreateRoomCache(userId, roomId, roomName);\n    if (eventId && (cache.pendingEventIds.has(eventId) || cache.seenEventIds.has(eventId)))\n      return false;\n    if (eventId) cache.pendingEventIds.add(eventId);\n    const previousMessages = cache.messages.slice();\n    cache.messages.push(message);\n    if (cache.messages.length > MAX_MESSAGES) {\n      cache.messages = cache.messages.slice(-MAX_MESSAGES);\n    }\n\n    if (room) {\n      cache.isGroupConversation = (room.getJoinedMemberCount() ?? 0) > 2;\n    }\n\n    try {\n      await postRoomNotification(userId, roomId, cache, !settings.notificationSoundEnabled, {\n        room_id: roomId,\n        event_id: eventId,\n        user_id: pushData?.user_id,\n      });\n    } catch (error) {\n      cache.messages = previousMessages;\n      if (eventId) cache.pendingEventIds.delete(eventId);\n      if (cache.messages.length === 0) roomNotifCaches.delete(cache.key);\n      throw error;\n    }\n\n    if (eventId) {\n      cache.pendingEventIds.delete(eventId);\n      cache.seenEventIds.add(eventId);\n      if (cache.seenEventIds.size > MAX_SEEN_EVENT_IDS) {\n        const oldest = cache.seenEventIds.values().next().value;\n        if (oldest !== undefined) cache.seenEventIds.delete(oldest);\n      }\n    }\n    baselineCache = cache;\n    return true;\n  });\n  if (!posted || !baselineCache) return;\n  const cache = baselineCache;\n\n  if (\n    !hasInMemoryPreview &&\n    eventId &&\n    settings.showMessageContent &&\n    (!isEncryptedRoom || settings.showEncryptedMessageContent)\n  ) {\n    resolvePreviewEvent(settings.mx, roomId, eventId)\n      .then((fetched) => {\n        if (!fetched) return;\n\n        const applyFetchedPreview = () =>\n          enqueueRoomOperation(cache.key, async () => {\n            const liveSettings = getSettings();\n            const eventEncrypted = isEncryptedRoom || fetched.isEncrypted();\n            const isAllowed =\n              liveSettings.showMessageContent &&\n              (!eventEncrypted || liveSettings.showEncryptedMessageContent) &&\n              !(document.visibilityState === 'visible' && liveSettings.useInAppNotifications);\n            if (!isAllowed || !isCurrentRoomCache(cache) || !cache.messages.includes(message)) {\n              return;\n            }\n\n            const enrichedPreview = resolveNotificationPreviewText({\n              content: fetched.getContent(),\n              eventType: fetched.getType(),\n              isEncryptedRoom: eventEncrypted,\n              showMessageContent: liveSettings.showMessageContent,\n              showEncryptedMessageContent: liveSettings.showEncryptedMessageContent,\n            });\n            if (!enrichedPreview) return;\n\n            const fetchedSender = fetched.getSender();\n            const liveRoom = liveSettings.mx.getRoom(roomId);\n            const nextSenderName = fetchedSender\n              ? (liveRoom?.getMember(fetchedSender)?.name ??\n                getMxIdLocalPart(fetchedSender) ??\n                fetchedSender)\n              : undefined;\n            const previousText = message.text;\n            const previousSender = message.sender;\n            message.text = enrichedPreview;\n            message.sender = nextSenderName ? { name: nextSenderName, key: fetchedSender } : sender;\n\n            const current = () => {\n              const currentSettings = getSettings();\n              return (\n                isCurrentRoomCache(cache) &&\n                cache.messages.includes(message) &&\n                currentSettings.showMessageContent &&\n                (!eventEncrypted || currentSettings.showEncryptedMessageContent) &&\n                !(document.visibilityState === 'visible' && currentSettings.useInAppNotifications)\n              );\n            };\n            try {\n              const sent = await postRoomNotification(\n                userId,\n                roomId,\n                cache,\n                true,\n                {\n                  room_id: roomId,\n                  event_id: eventId,\n                  user_id: pushData?.user_id,\n                },\n                current\n              );\n              if (!sent) {\n                message.text = previousText;\n                message.sender = previousSender;\n              }\n            } catch {\n              message.text = previousText;\n              message.sender = previousSender;\n            }\n          });\n\n        whenDecrypted(fetched, applyFetchedPreview);\n      })\n      .catch((error) => {\n        unifiedPushLog.warn(\n          'notification',\n          'Background preview fetch failed',\n          error instanceof Error ? error : new Error(String(error))\n        );\n      });\n  }\n}\n\nasync function handleUnifiedPushPayload(\n  raw: Record<string, unknown>,\n  getSettings: () => NotificationSettings\n) {\n  const settings = getSettings();\n\n  // Skip system notification when in-app banners are active and visible.\n  if (document.visibilityState === 'visible' && settings.useInAppNotifications) {\n    return;\n  }\n\n  const pushData = (raw.extra ?? raw) as UnifiedPushPayload;\n  const eventType = pushData?.type as EventType | undefined;\n  const userId = isNonEmptyString(pushData?.user_id) ? pushData.user_id.trim() : undefined;\n  if (!userId || userId !== settings.mx.getUserId()) {\n    unifiedPushLog.warn('notification', 'Ignoring push without an exact active-account match');\n    return;\n  }\n\n  if (eventType) {\n    await handleRichPushPayload(pushData, settings, userId, getSettings);\n  } else {\n    await handleMinimalPushPayload(pushData, settings, userId, getSettings);\n  }\n}\n\nconst SET_PUSH_MESSAGE_LISTENER_ACTIVE = 'plugin:notifications|set_push_message_listener_active';\n\nexport async function listenForUnifiedPushMessages(getSettings: () => NotificationSettings) {\n  const dispatch = createUnifiedPushMessageListener(\n    (notification) => handleUnifiedPushPayload(notification, getSettings),\n    (error) => {\n      unifiedPushLog.error(\n        'notification',\n        'UnifiedPush payload handling failed',\n        error instanceof Error ? error : new Error(String(error))\n      );\n    }\n  );\n\n  const listener = await addPluginListener('notifications', 'push-message', (data: unknown) => {\n    const notification = parseUnifiedPushMessage(data);\n    if (!notification) return;\n    getSlidingSyncManager(getSettings().mx)?.resumeForPush();\n    dispatch(notification);\n  });\n\n  try {\n    await invoke(SET_PUSH_MESSAGE_LISTENER_ACTIVE, { active: true });\n  } catch (error) {\n    await listener.unregister().catch(() => {});\n    throw error;\n  }\n\n  void dismissLegacyGroupSummary(getSettings().mx.getUserId() ?? '');\n\n  return {\n    unregister: async () => {\n      try {\n        await invoke(SET_PUSH_MESSAGE_LISTENER_ACTIVE, { active: false });\n      } finally {\n        await listener.unregister();\n      }\n    },\n  };\n}\n"],"file":"UnifiedPushNotifications-BpPSgRJ6.js"}